mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5691 lines
139 KiB
5691 lines
139 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
routing\ip\rtrmgr\access.c
|
|
|
|
Abstract:
|
|
|
|
All the "access" functions take similar arguments:
|
|
|
|
dwQueryType This is the type of the query and can be
|
|
ACCESS_GET
|
|
ACCESS_GET_FIRST,
|
|
ACCESS_GET_NEXT,
|
|
ACCESS_SET,
|
|
ACCESS_CREATE_ENTRY,
|
|
ACCESS_DELETE_ENTRY
|
|
|
|
dwInEntrySize Size of the input buffer. The information
|
|
in the input buffer is dependent on the query type and
|
|
the information being queried. The input buffer stores
|
|
the QueryInfo which is a variable sized structure taking
|
|
an array of instance ids. The dwInEntrySize is used to
|
|
figure out how many instance ids are in the array (since
|
|
and explicit count is not given)
|
|
|
|
pInEntry Pointer to the input buffer. This is a MIB_OPAQUE_QUERY
|
|
structure which contains an integer (dwType) which
|
|
indicates the object being queried (which is not used
|
|
since the demuxing based on that has already been done)
|
|
and a variable length array of integer instance ids
|
|
The instance id must be completely specified in case of
|
|
ACCESS_GET,
|
|
ACCESS_SET,
|
|
ACCESS_CREATE_ENTRY,
|
|
ACCESS_DELETE_ENTRY
|
|
but for the rest only the first 'n' components of
|
|
the instance id may be specified.
|
|
|
|
pOutEntrySize Pointer to the size of the output buffer. If this is 0
|
|
the caller is querying us for the size of buffer needed
|
|
If the supplied buffer size is too small, we set this
|
|
to the minimum required size and return
|
|
ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
pOutEntry The output buffer which is a MIB_OPAQUE_INFO structure.
|
|
The function fills in the dwTyoe to indicate the object
|
|
being returned. That type is used to cast the opaque
|
|
variable sized buffer following the type
|
|
|
|
pbCache Pointer to BOOL which is set to TRUE if the corresponding
|
|
cache was updated. This is not used currently, but may
|
|
be used later for optimizations
|
|
|
|
Revision History:
|
|
|
|
Amritansh Raghav 7/8/95 Created
|
|
|
|
--*/
|
|
|
|
#include "allinc.h"
|
|
|
|
DWORD
|
|
SetIpForwardRow(
|
|
PMIB_IPFORWARDROW pOldIpForw,
|
|
PMIB_IPFORWARDROW pNewIpForw
|
|
);
|
|
|
|
DWORD
|
|
DeleteIpForwardRow(
|
|
PMIB_IPFORWARDROW pIpForw
|
|
);
|
|
|
|
|
|
DWORD
|
|
AccessMcastMfeStatsInternal(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache,
|
|
DWORD dwStatsFlag
|
|
);
|
|
|
|
DWORD
|
|
AccessIfNumber(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves the number of interfaces
|
|
|
|
Locks
|
|
|
|
None since g_IfInfo.dwNumberOfInterfaces is InterlockXxx()ed
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
dwInEntrySize Dont care
|
|
pInEntry Dont care
|
|
pOutEntrySize Minimum: MAX_MIB_OFFSET + sizeof(MIB_IFNUMBER)
|
|
|
|
Return Value
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IFNUMBER pIfNumber;
|
|
DWORD dwNumInterfaces;
|
|
|
|
TraceEnter("AccessIfNumber");
|
|
|
|
pIfNumber = (PMIB_IFNUMBER)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIfNumber");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IFNUMBER))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFNUMBER);
|
|
|
|
TraceLeave("AccessIfNumber");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFNUMBER);
|
|
|
|
//
|
|
// The variable is only inc/dec using interlocked ops
|
|
// so we dont need to take a lock here
|
|
//
|
|
|
|
pIfNumber->dwValue = g_ulNumInterfaces;
|
|
|
|
pOutEntry->dwId = IF_NUMBER;
|
|
|
|
*pbCache = TRUE;
|
|
|
|
TraceLeave("AccessIfNumber");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIfTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves the Interface table
|
|
|
|
Locks
|
|
|
|
Takes ICB list lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IFTABLE)
|
|
|
|
Return Value
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IFTABLE pIfTable;
|
|
DWORD count;
|
|
PLIST_ENTRY currentList;
|
|
PICB picb;
|
|
DWORD dwNumInterfaces, dwResult;
|
|
|
|
TraceEnter("AccessIfTable");
|
|
|
|
pIfTable = (PMIB_IFTABLE)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIfTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
dwNumInterfaces = g_ulNumNonClientInterfaces;
|
|
|
|
if(dwNumInterfaces is 0)
|
|
{
|
|
Trace0(MIB,"AccessIfTable: No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IFTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pIfTable->dwNumEntries = 0;
|
|
|
|
pOutEntry->dwId = IF_TABLE;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + SIZEOF_IFTABLE(dwNumInterfaces))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + SIZEOF_IFTABLE(dwNumInterfaces);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
pOutEntry->dwId = IF_TABLE;
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + SIZEOF_IFTABLE(dwNumInterfaces);
|
|
|
|
for(currentList = ICBList.Flink, count = 0 ;
|
|
currentList isnot &ICBList;
|
|
currentList = currentList->Flink)
|
|
{
|
|
picb = CONTAINING_RECORD (currentList, ICB, leIfLink) ;
|
|
|
|
//
|
|
// NOTE WE DO NOT RETURN ANY CLIENT INTERFACES
|
|
//
|
|
|
|
if((picb->ritType is ROUTER_IF_TYPE_CLIENT) or
|
|
((picb->ritType is ROUTER_IF_TYPE_INTERNAL) and
|
|
(picb->bBound is FALSE)))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwResult = GetInterfaceStatistics(picb,
|
|
pIfTable->table + count);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
count++;
|
|
}
|
|
else
|
|
{
|
|
Trace2(ERR,
|
|
"AccessIfTable: Error %d getting statistics for %S",
|
|
dwResult,
|
|
picb->pwszName);
|
|
}
|
|
}
|
|
|
|
pIfTable->dwNumEntries = count;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
*pbCache = TRUE;
|
|
|
|
TraceLeave("AccessIfTable");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIfRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to set or retrieve an IFRow
|
|
|
|
Locks
|
|
|
|
ICB List lock are READER in caces of queries, WRITER in case of SETs
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be anything other than ACCESS_DELETE_ENTRY or
|
|
ACCESS_CREATE_ENTRY. The only field that can be Set is
|
|
the adminStatus
|
|
pInEntry Interface index in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IFROW)
|
|
For sets, the OutEntry contains the row to set
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PICB picb;
|
|
PMIB_IFROW pIfRow;
|
|
DWORD dwNumIndices, dwResult;
|
|
|
|
TraceEnter("AccessIfRow");
|
|
|
|
pIfRow = (PMIB_IFROW)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IFROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFROW);
|
|
|
|
TraceLeave("AccessIfRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFROW);
|
|
|
|
pOutEntry->dwId = IF_ROW;
|
|
|
|
do
|
|
{
|
|
if(dwQueryType is ACCESS_SET)
|
|
{
|
|
ENTER_WRITER(ICB_LIST);
|
|
}
|
|
else
|
|
{
|
|
ENTER_READER(ICB_LIST);
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateIfRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&picb,
|
|
FALSE);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
case ACCESS_GET_NEXT:
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
dwResult = GetInterfaceStatistics(picb,pIfRow);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
dwResult = SetInterfaceStatistics(picb,pIfRow);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIfRow: Wrong query type %d",dwQueryType);
|
|
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
*pbCache = TRUE;
|
|
|
|
TraceLeave("AccessIfRow");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AccessIcmpStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get ICMP statistics
|
|
|
|
Locks
|
|
|
|
None, since the stats are not cached
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_ICMP)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_ICMP pIcmp;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessIcmpStats");
|
|
|
|
pIcmp = (PMIB_ICMP)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIcmpStats");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_ICMP))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = ICMP_STATS;
|
|
|
|
dwResult = GetIcmpStatsFromStack(pIcmp);
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_ICMP);
|
|
|
|
*pbCache = TRUE;
|
|
|
|
TraceLeave("AccessIcmpStats");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessUdpStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get UDP statistics
|
|
|
|
Locks
|
|
|
|
None, since the stats are not cached
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_UDPSTATS)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_UDPSTATS pUdpStats;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessUdpStats");
|
|
|
|
pUdpStats = (PMIB_UDPSTATS)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessUdpStats");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_UDPSTATS))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = UDP_STATS;
|
|
|
|
*pbCache = TRUE;
|
|
|
|
dwResult = GetUdpStatsFromStack(pUdpStats);
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_UDPSTATS);
|
|
|
|
TraceLeave("AccessUdpStats");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessUdpTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get UDP Table
|
|
|
|
Locks
|
|
|
|
UDP Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + SIZEOF_UDPTABLE(NumUdpEntries)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_UDPTABLE pUdpTable = (PMIB_UDPTABLE)(pOutEntry->rgbyData);
|
|
DWORD i,dwResult;
|
|
|
|
TraceEnter("AccessUdpTable");
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessUdpTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
dwResult = UpdateCache(UDPCACHE,pbCache);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessUdpTable: Couldnt update Udp Cache. Error %d",dwResult);
|
|
|
|
TraceLeave("AccessUdpTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(UDPCACHE);
|
|
|
|
if((g_UdpInfo.pUdpTable is NULL) or
|
|
(g_UdpInfo.pUdpTable->dwNumEntries is 0))
|
|
{
|
|
Trace0(MIB,"AccessUdpTable: No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_UDPTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = UDP_TABLE;
|
|
|
|
pUdpTable->dwNumEntries = 0;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_UDPTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize <
|
|
MAX_MIB_OFFSET + SIZEOF_UDPTABLE(g_UdpInfo.pUdpTable->dwNumEntries))
|
|
{
|
|
*pOutEntrySize =
|
|
MAX_MIB_OFFSET + SIZEOF_UDPTABLE(g_UdpInfo.pUdpTable->dwNumEntries);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
*pOutEntrySize =
|
|
MAX_MIB_OFFSET + SIZEOF_UDPTABLE(g_UdpInfo.pUdpTable->dwNumEntries);
|
|
|
|
pOutEntry->dwId = UDP_TABLE;
|
|
|
|
for(i = 0; i < g_UdpInfo.pUdpTable->dwNumEntries; i++)
|
|
{
|
|
pUdpTable->table[i] = g_UdpInfo.pUdpTable->table[i];
|
|
}
|
|
|
|
pUdpTable->dwNumEntries = g_UdpInfo.pUdpTable->dwNumEntries;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(UDPCACHE);
|
|
|
|
TraceLeave("AccessUdpTable");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AccessUdpRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to retrieve a UDP Row
|
|
|
|
Locks
|
|
|
|
Takes the UDP Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be ACCESS_GET, ACCESS_GET_NEXT or ACCESS_GET_FIRST
|
|
pInEntry LocalAddr & LocalPort for the row filled in the
|
|
rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_UDPROW);
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
{
|
|
PMIB_UDPROW pUdpRow;
|
|
DWORD dwResult, dwIndex, dwNumIndices;
|
|
|
|
TraceEnter("AccessUdpRow");
|
|
|
|
pUdpRow = (PMIB_UDPROW)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_UDPROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_UDPROW);
|
|
|
|
TraceLeave("AccessUdpRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_UDPROW);
|
|
|
|
pOutEntry->dwId = UDP_ROW;
|
|
|
|
if((dwResult = UpdateCache(UDPCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessUdpRow: Couldnt update Udp Cache. Error %d", dwResult);
|
|
|
|
TraceLeave("AccessUdpRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(UDPCACHE);
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateUdpRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&dwIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
*pUdpRow = g_UdpInfo.pUdpTable->table[dwIndex];
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(UDPCACHE);
|
|
|
|
TraceLeave("AccessUdpRow");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AccessTcpStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get TCP statistics
|
|
|
|
Locks
|
|
|
|
None, since the stats are not cached
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_TCPSTATS)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_TCPSTATS pTcpStats;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessTcpStats");
|
|
|
|
pTcpStats = (PMIB_TCPSTATS)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessTcpStats");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_TCPSTATS))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = TCP_STATS;
|
|
|
|
*pbCache = TRUE;
|
|
|
|
dwResult = GetTcpStatsFromStack(pTcpStats);
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_TCPSTATS);
|
|
|
|
TraceLeave("AccessTcpStats");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessTcpTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get TCP Table
|
|
|
|
Locks
|
|
|
|
TCP Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + SIZEOF_TCPTABLE(NumTcpEntries)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMIB_TCPTABLE pTcpTable;
|
|
DWORD i, dwResult;
|
|
|
|
TraceEnter("AccessTcpTable");
|
|
|
|
pTcpTable = (PMIB_TCPTABLE)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(TCPCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
|
|
Trace1(MIB,
|
|
"AccessTcpTable: Couldnt update Tcp Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessTcpTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(TCPCACHE);
|
|
|
|
if((g_TcpInfo.pTcpTable is NULL) or
|
|
(g_TcpInfo.pTcpTable->dwNumEntries is 0))
|
|
{
|
|
Trace0(MIB,"AccessTcpTable: No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_TCPTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = TCP_TABLE;
|
|
|
|
pTcpTable->dwNumEntries = 0;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_TCPTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize <
|
|
MAX_MIB_OFFSET + SIZEOF_TCPTABLE(g_TcpInfo.pTcpTable->dwNumEntries))
|
|
{
|
|
*pOutEntrySize =
|
|
MAX_MIB_OFFSET + SIZEOF_TCPTABLE(g_TcpInfo.pTcpTable->dwNumEntries);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
pOutEntry->dwId = TCP_TABLE;
|
|
|
|
*pOutEntrySize =
|
|
MAX_MIB_OFFSET + SIZEOF_TCPTABLE(g_TcpInfo.pTcpTable->dwNumEntries);
|
|
|
|
for(i = 0; i < g_TcpInfo.pTcpTable->dwNumEntries; i++)
|
|
{
|
|
pTcpTable->table[i] = g_TcpInfo.pTcpTable->table[i];
|
|
}
|
|
|
|
pTcpTable->dwNumEntries = g_TcpInfo.pTcpTable->dwNumEntries;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(TCPCACHE);
|
|
|
|
TraceLeave("AccessTcpTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessTcpRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to retrieve or set a TCP Row
|
|
|
|
Locks
|
|
|
|
Takes the TCP Cache lock as READER for queries and as a WRITER for
|
|
Sets
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be anything except ACCESS_DELETE_ENTRY and
|
|
ACCESS_CREATE_ENTRY.
|
|
For ACCESS_SET, the state is the only thing that can
|
|
be set and it can only be set to TCP_DELETE_TCB
|
|
pInEntry LocalAddr, LocalPort, RemoteAddr, RemotePort for the
|
|
row filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_TCPROW);
|
|
For Sets, the OutEntry contains the row to set
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult, dwNumIndices, dwIndex;
|
|
PMIB_TCPROW pTcpRow;
|
|
|
|
TraceEnter("AccessTcpRow");
|
|
|
|
pTcpRow = (PMIB_TCPROW)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_DELETE_ENTRY)
|
|
{
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_TCPROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_TCPROW);
|
|
|
|
TraceLeave("AccessTcpRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_TCPROW);
|
|
|
|
pOutEntry->dwId = TCP_ROW;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(TCPCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessTcpRow: Couldnt update Tcp Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessTcpRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
if(dwQueryType is ACCESS_SET)
|
|
{
|
|
ENTER_WRITER(TCPCACHE);
|
|
}
|
|
else
|
|
{
|
|
ENTER_READER(TCPCACHE);
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateTcpRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&dwIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
case ACCESS_GET_NEXT:
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
*pTcpRow = g_TcpInfo.pTcpTable->table[dwIndex];
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
break;
|
|
}
|
|
case ACCESS_SET:
|
|
{
|
|
//
|
|
// The only thing you can do is set it to a state and that
|
|
// too only to TCP_DELETE_TCB
|
|
//
|
|
|
|
if(pTcpRow->dwState isnot TCP_DELETE_TCB)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessTcpRow: TCP State can only be set to delete. Tried to set to %d",
|
|
pTcpRow->dwState);
|
|
|
|
dwResult = ERROR_INVALID_DATA;
|
|
|
|
break;
|
|
}
|
|
|
|
dwResult = SetTcpEntryToStack(pTcpRow);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_TcpInfo.pTcpTable->table[dwIndex].dwState =
|
|
pTcpRow->dwState;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Trace1(ERR,
|
|
"AccessTcpRow: Query type %d is wrong",
|
|
dwQueryType);
|
|
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(TCPCACHE);
|
|
|
|
TraceLeave("AccessTcpRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessIpStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get IP statistics
|
|
|
|
Locks
|
|
|
|
None, since the stats are not cached
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET or ACCESS_SET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPSTATS)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IPSTATS pIpStats;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessIpStats");
|
|
|
|
pIpStats = (PMIB_IPSTATS)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPSTATS))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPSTATS);
|
|
|
|
TraceLeave("AccessIpStats");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPSTATS);
|
|
|
|
pOutEntry->dwId = IP_STATS;
|
|
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
{
|
|
//
|
|
// Since we need to write the number of routes addresses etc
|
|
// Update the two caches
|
|
//
|
|
|
|
UpdateCache(IPADDRCACHE,pbCache);
|
|
UpdateCache(IPFORWARDCACHE,pbCache);
|
|
|
|
dwResult = GetIpStatsFromStack(pIpStats);
|
|
|
|
pIpStats->dwNumIf = g_ulNumInterfaces;
|
|
|
|
pIpStats->dwNumRoutes = 0;
|
|
|
|
if(g_IpInfo.pForwardTable)
|
|
{
|
|
pIpStats->dwNumRoutes = g_IpInfo.pForwardTable->dwNumEntries;
|
|
}
|
|
|
|
pIpStats->dwNumAddr = 0;
|
|
|
|
if(g_IpInfo.pAddrTable)
|
|
{
|
|
pIpStats->dwNumAddr = g_IpInfo.pAddrTable->dwNumEntries;
|
|
}
|
|
|
|
TraceLeave("AccessIpStats");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
MIB_IPSTATS CurrentIpStats;
|
|
DWORD dwErr;
|
|
|
|
dwErr = GetIpStatsFromStack(&CurrentIpStats);
|
|
|
|
if(dwErr isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessIpStats: Couldnt get IPSNMP info from stack to initiate set. Error %d",
|
|
dwErr);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//
|
|
// See what the current forwarding status is. We allow one to go
|
|
// Forward -> notForward but not the other way.
|
|
//
|
|
|
|
if(pIpStats->dwDefaultTTL isnot MIB_USE_CURRENT_TTL)
|
|
{
|
|
if(pIpStats->dwDefaultTTL > 255)
|
|
{
|
|
Trace0(ERR,"AccessIpStats: Cant set TTL > 255");
|
|
|
|
TraceLeave("AccessIpStats");
|
|
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
|
|
dwErr = SetIpStatsToStack(pIpStats);
|
|
|
|
if(dwErr isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessIpStats: Error %d setting TTL in stack",
|
|
dwErr);
|
|
}
|
|
}
|
|
|
|
if(pIpStats->dwForwarding isnot MIB_USE_CURRENT_FORWARDING)
|
|
{
|
|
if((pIpStats->dwForwarding isnot MIB_IP_FORWARDING) and
|
|
(pIpStats->dwForwarding isnot MIB_IP_NOT_FORWARDING))
|
|
{
|
|
Trace1(ERR,
|
|
"AccessIpStats: Fwding state %d is invalid",
|
|
pIpStats->dwForwarding);
|
|
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
//
|
|
// See if its to switch off forwarding
|
|
//
|
|
|
|
EnterCriticalSection(&g_csFwdState);
|
|
|
|
g_bEnableFwdRequest = (pIpStats->dwForwarding is MIB_IP_FORWARDING);
|
|
|
|
Trace1(GLOBAL,
|
|
"AccessIpStats: Signalling worker to %s forwarding",
|
|
g_bEnableFwdRequest ? "enable" : "disable");
|
|
|
|
SetEvent(g_hSetForwardingEvent);
|
|
|
|
LeaveCriticalSection(&g_csFwdState);
|
|
}
|
|
|
|
TraceLeave("AccessIpStats");
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Trace1(ERR,
|
|
"AccessIpStats: Query type %d is wrong",
|
|
dwQueryType);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpAddrTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get IP Address Table
|
|
|
|
Locks
|
|
|
|
IP Address Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + SIZEOF_IPADDRTABLE(NumIpAddrEntries)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IPADDRTABLE pIpAddrTable;
|
|
DWORD dwResult, i;
|
|
|
|
TraceEnter("AccessIpAddrTable");
|
|
|
|
pIpAddrTable = (PMIB_IPADDRTABLE)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIpAddrTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(IPADDRCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpAddrTable: Error %d updating IpAddr Cache",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpAddrTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(IPADDRCACHE);
|
|
|
|
if((g_IpInfo.pAddrTable is NULL) or
|
|
(g_IpInfo.pAddrTable->dwNumEntries is 0))
|
|
{
|
|
Trace0(MIB,"No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPADDRTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = IP_ADDRTABLE;
|
|
|
|
pIpAddrTable->dwNumEntries = 0;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPADDRTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize <
|
|
MAX_MIB_OFFSET + SIZEOF_IPADDRTABLE(g_IpInfo.pAddrTable->dwNumEntries))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET +
|
|
SIZEOF_IPADDRTABLE(g_IpInfo.pAddrTable->dwNumEntries);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
pOutEntry->dwId = IP_ADDRTABLE;
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET +
|
|
SIZEOF_IPADDRTABLE(g_IpInfo.pAddrTable->dwNumEntries);
|
|
|
|
for(i = 0; i < g_IpInfo.pAddrTable->dwNumEntries; i ++)
|
|
{
|
|
pIpAddrTable->table[i] = g_IpInfo.pAddrTable->table[i];
|
|
}
|
|
|
|
pIpAddrTable->dwNumEntries = g_IpInfo.pAddrTable->dwNumEntries;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPADDRCACHE);
|
|
|
|
TraceLeave("AccessIpAddrTable");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
DWORD
|
|
AccessIpForwardNumber(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPFORWARDNUMBER pNum;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessIpForwardNumber");
|
|
|
|
pNum = (PMIB_IPFORWARDNUMBER)pOutEntry;
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIpForwardNumber");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDNUMBER))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDNUMBER);
|
|
|
|
TraceLeave("AccessIpForwardNumber");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDNUMBER);
|
|
|
|
if((dwResult = UpdateCache(IPFORWARDCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpForwardNumber: Couldnt update IpForward Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpForwardNumber");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
ENTER_READER(IPFORWARDCACHE);
|
|
|
|
pNum->dwValue = 0;
|
|
|
|
if(g_IpInfo.pForwardTable)
|
|
{
|
|
pNum->dwValue = g_IpInfo.pForwardTable->dwNumEntries;
|
|
}
|
|
|
|
pOutEntry->dwId = IP_FORWARDNUMBER;
|
|
|
|
*pbCache = TRUE;
|
|
|
|
EXIT_LOCK(IPFORWARDCACHE);
|
|
|
|
TraceLeave("AccessIpForwardNumber");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpForwardTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get IFTable
|
|
|
|
Arguments
|
|
dwQueryType Can only be ACCESS_GET
|
|
dwInEntrySize Size of pInEntry in bytes
|
|
pInEntry Nothing important since the whole table is retrieved
|
|
pOutEntrySize IN: Size of pOutEntry in bytes
|
|
OUT:Size of information filled in OR size of memory needed
|
|
pOutEntry Points to information filled into an MIB_IFTABLE structure
|
|
pbCache Unused
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
{
|
|
PMIB_IPFORWARDTABLE pIpForwardTable;
|
|
DWORD i,dwResult;
|
|
|
|
TraceEnter("AccessIpForwardTable");
|
|
|
|
pIpForwardTable = (PMIB_IPFORWARDTABLE)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessIpForwardTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(IPFORWARDCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpForwardTable: Couldnt update IpForward Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpForwardTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
do
|
|
{
|
|
ENTER_READER(IPFORWARDCACHE);
|
|
|
|
if((g_IpInfo.pForwardTable is NULL) or
|
|
(g_IpInfo.pForwardTable->dwNumEntries is 0))
|
|
{
|
|
Trace0(MIB,"No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = IP_FORWARDTABLE;
|
|
|
|
pIpForwardTable->dwNumEntries = 0;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + SIZEOF_IPFORWARDTABLE(g_IpInfo.pForwardTable->dwNumEntries))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + SIZEOF_IPFORWARDTABLE(g_IpInfo.pForwardTable->dwNumEntries);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
pOutEntry->dwId = IP_FORWARDTABLE;
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + SIZEOF_IPFORWARDTABLE(g_IpInfo.pForwardTable->dwNumEntries);
|
|
|
|
for(i = 0; i < g_IpInfo.pForwardTable->dwNumEntries; i ++)
|
|
{
|
|
pIpForwardTable->table[i] = g_IpInfo.pForwardTable->table[i];
|
|
}
|
|
|
|
pIpForwardTable->dwNumEntries = g_IpInfo.pForwardTable->dwNumEntries;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPFORWARDCACHE);
|
|
|
|
TraceLeave("AccessIpForwardTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpNetTable(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to get ARP Table
|
|
|
|
Locks
|
|
|
|
IP Net Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET or ACCESS_DELETE_ENTRY
|
|
dwInEntrySize (only for delete)
|
|
pOutEntrySize MAX_MIB_OFFSET + SIZEOF_IPNETTABLE(NumArpEntries)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IPNETTABLE pIpNetTable;
|
|
DWORD i,dwResult;
|
|
|
|
TraceEnter("AccessIpNetTable");
|
|
|
|
pIpNetTable = (PMIB_IPNETTABLE)(pOutEntry->rgbyData);
|
|
|
|
if((dwQueryType isnot ACCESS_GET) and
|
|
(dwQueryType isnot ACCESS_DELETE_ENTRY))
|
|
{
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(dwQueryType is ACCESS_GET)
|
|
{
|
|
dwResult = UpdateCache(IPNETCACHE,pbCache);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpNetTable: Couldnt update IpNet Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return dwResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwIfIndex;
|
|
PICB pIcb;
|
|
|
|
if(dwInEntrySize < sizeof(MIB_OPAQUE_QUERY))
|
|
{
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
dwIfIndex = pInEntry->rgdwVarIndex[0];
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(dwIfIndex);
|
|
|
|
if((pIcb is NULL) or
|
|
(pIcb->bBound is FALSE))
|
|
{
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
dwIfIndex = pIcb->dwIfIndex;
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
dwResult = FlushIpNetTableFromStack(dwIfIndex);
|
|
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
ENTER_READER(IPNETCACHE);
|
|
|
|
if((g_IpInfo.pNetTable is NULL) or
|
|
(g_IpInfo.pNetTable->dwNumEntries is 0))
|
|
{
|
|
Trace0(MIB,"No valid entries found");
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPNETTABLE))
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
else
|
|
{
|
|
pOutEntry->dwId = IP_NETTABLE;
|
|
|
|
pIpNetTable->dwNumEntries = 0;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPNETTABLE);
|
|
|
|
break;
|
|
}
|
|
|
|
if(*pOutEntrySize <
|
|
MAX_MIB_OFFSET + SIZEOF_IPNETTABLE(g_IpInfo.pNetTable->dwNumEntries))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET +
|
|
SIZEOF_IPNETTABLE(g_IpInfo.pNetTable->dwNumEntries);
|
|
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
break;
|
|
}
|
|
|
|
pOutEntry->dwId = IP_NETTABLE;
|
|
|
|
*pOutEntrySize =
|
|
MAX_MIB_OFFSET + SIZEOF_IPNETTABLE(g_IpInfo.pNetTable->dwNumEntries);
|
|
|
|
for(i = 0; i < g_IpInfo.pNetTable->dwNumEntries; i ++)
|
|
{
|
|
pIpNetTable->table[i] = g_IpInfo.pNetTable->table[i];
|
|
}
|
|
|
|
pIpNetTable->dwNumEntries = g_IpInfo.pNetTable->dwNumEntries;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPNETCACHE);
|
|
|
|
TraceLeave("AccessIpNetTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpAddrRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to retrieve a IP Address Row
|
|
|
|
Locks
|
|
|
|
Takes the IP Address Cache lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be ACCESS_GET, ACCESS_GET_NEXT or ACCESS_GET_FIRST
|
|
pInEntry Address for the row filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPADDRROW)
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult, dwNumIndices, dwIndex;
|
|
PMIB_IPADDRROW pIpAddrRow;
|
|
|
|
TraceEnter("AccessIpAddrRow");
|
|
|
|
pIpAddrRow = (PMIB_IPADDRROW)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPADDRROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPADDRROW);
|
|
|
|
TraceLeave("AccessIpAddrRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPADDRROW);
|
|
|
|
pOutEntry->dwId = IP_ADDRROW;
|
|
|
|
if((dwResult = UpdateCache(IPADDRCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpAddrRow: Couldnt update Ip Addr Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpAddrRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
ENTER_READER(IPADDRCACHE);
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateIpAddrRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&dwIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
*pIpAddrRow = g_IpInfo.pAddrTable->table[dwIndex];
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPADDRCACHE);
|
|
|
|
TraceLeave("AccessIpAddrRow");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpForwardRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to retrieve or set a route (IP Forward Row)
|
|
|
|
Locks
|
|
|
|
Takes the IP Forward Cache lock as READER for queries, WRITER for sets
|
|
|
|
Arguments
|
|
|
|
dwQueryType All permitted
|
|
pInEntry Dest, Proto, Policy and NextHop for the row filled in the
|
|
rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDROW). For Sets the
|
|
OutBuffer has the row to set
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult,dwNumIndices,dwIndex;
|
|
PMIB_IPFORWARDROW pIpForwardRow;
|
|
|
|
TraceEnter("AccessIpForwardRow");
|
|
|
|
pIpForwardRow = (PMIB_IPFORWARDROW)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_DELETE_ENTRY)
|
|
{
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDROW);
|
|
|
|
TraceLeave("AccessIpForwardRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPFORWARDROW);
|
|
|
|
pOutEntry->dwId = IP_FORWARDROW;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(IPFORWARDCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpForwardRow: Error %d updating IpForward Cache",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpForwardRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
if(dwQueryType > ACCESS_GET_NEXT)
|
|
{
|
|
ENTER_WRITER(IPFORWARDCACHE);
|
|
}
|
|
else
|
|
{
|
|
ENTER_READER(IPFORWARDCACHE);
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateIpForwardRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&dwIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
case ACCESS_GET_NEXT:
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
*pIpForwardRow = g_IpInfo.pForwardTable->table[dwIndex];
|
|
|
|
break;
|
|
}
|
|
case ACCESS_SET:
|
|
{
|
|
dwResult =
|
|
SetIpForwardRow(&(g_IpInfo.pForwardTable->table[dwIndex]),
|
|
pIpForwardRow);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_IpInfo.pForwardTable->table[dwIndex] = *pIpForwardRow;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
dwResult =
|
|
DeleteIpForwardRow(&(g_IpInfo.pForwardTable->table[dwIndex]));
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_LastUpdateTable[IPFORWARDCACHE] = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
//
|
|
//
|
|
// This is the case where you have tried to create a
|
|
// route which matches an existing entry
|
|
//
|
|
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((dwQueryType is ACCESS_CREATE_ENTRY) or
|
|
(dwQueryType is ACCESS_SET))
|
|
{
|
|
//
|
|
// Cannot set PROTO_IP_LOCAL routes (other protos will
|
|
// be weeded out when we search for the RTM handle)
|
|
//
|
|
|
|
if(pIpForwardRow->dwForwardProto is PROTO_IP_LOCAL)
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
|
|
dwResult = SetIpForwardRow(NULL,
|
|
pIpForwardRow);
|
|
|
|
//
|
|
// Since its too much hassle to create, malloc (possibly)
|
|
// sorted insert we make just invalidate the route cache
|
|
//
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_LastUpdateTable[IPFORWARDCACHE] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPFORWARDCACHE);
|
|
|
|
TraceLeave("AccessIpForwardRow");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessIpNetRow(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to retrieve or set an ARP entry (IP Net Row)
|
|
|
|
Locks
|
|
|
|
Takes the IP Net Cache lock as READER for queries, as WRITER for sets
|
|
|
|
Arguments
|
|
|
|
dwQueryType All permitted
|
|
pInEntry IfIndex and IPAddress for the row filled in the
|
|
rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPNETROW);
|
|
For Sets, the OutEntry contains the row to set
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult, dwNumIndices, dwIndex;
|
|
PMIB_IPNETROW pIpNetRow;
|
|
PICB pIcb;
|
|
|
|
TraceEnter("AccessIpNetRow");
|
|
|
|
pIpNetRow = (PMIB_IPNETROW)(pOutEntry->rgbyData);
|
|
|
|
if(dwQueryType isnot ACCESS_DELETE_ENTRY)
|
|
{
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPNETROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPNETROW);
|
|
|
|
TraceLeave("AccessIpNetRow");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPNETROW);
|
|
|
|
pOutEntry->dwId = IP_NETROW;
|
|
}
|
|
|
|
if((dwResult = UpdateCache(IPNETCACHE,pbCache)) isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpNetRow: Couldnt update Ip Addr Cache. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("AccessIpNetRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
do
|
|
{
|
|
if(dwQueryType > ACCESS_GET_NEXT)
|
|
{
|
|
ENTER_WRITER(IPNETCACHE);
|
|
}
|
|
else
|
|
{
|
|
ENTER_READER(IPNETCACHE);
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateIpNetRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&dwIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
case ACCESS_GET_NEXT:
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
|
|
*pIpNetRow = g_IpInfo.pNetTable->table[dwIndex];
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
if((pIpNetRow->dwType isnot MIB_IPNET_TYPE_DYNAMIC) and
|
|
(pIpNetRow->dwType isnot MIB_IPNET_TYPE_STATIC))
|
|
{
|
|
dwResult = ERROR_INVALID_DATA;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Need to map the interface index to the adapter index
|
|
//
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(pIpNetRow->dwIndex);
|
|
|
|
if((pIcb is NULL) or
|
|
(!pIcb->bBound))
|
|
{
|
|
//
|
|
// Could not find interface
|
|
//
|
|
|
|
dwResult = ERROR_INVALID_INDEX;
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
break;
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
//
|
|
// No need to force cache updates
|
|
//
|
|
|
|
dwResult = SetIpNetEntryToStack(pIpNetRow, FALSE);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_IpInfo.pNetTable->table[dwIndex] = *pIpNetRow;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
MIB_IPNETROW tempRow;
|
|
|
|
g_IpInfo.pNetTable->table[dwIndex].dwType =
|
|
MIB_IPNET_TYPE_INVALID;
|
|
|
|
tempRow = g_IpInfo.pNetTable->table[dwIndex];
|
|
|
|
dwResult = SetIpNetEntryToStack(&tempRow,
|
|
FALSE);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_LastUpdateTable[IPNETCACHE] = 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((dwQueryType is ACCESS_CREATE_ENTRY) or
|
|
(dwQueryType is ACCESS_SET))
|
|
{
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(pIpNetRow->dwIndex);
|
|
|
|
if((pIcb is NULL) or
|
|
(!pIcb->bBound))
|
|
{
|
|
//
|
|
// Could not find interface
|
|
//
|
|
|
|
dwResult = ERROR_INVALID_INDEX;
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
break;
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
dwResult = SetIpNetEntryToStack(pIpNetRow,
|
|
FALSE);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
g_LastUpdateTable[IPNETCACHE] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(IPNETCACHE);
|
|
|
|
TraceLeave("AccessIpNetRow");
|
|
|
|
return dwResult;
|
|
|
|
}
|
|
|
|
//
|
|
// The ACCESS_SETs and ACCESS_CREATEs require a bit more work in that the
|
|
// values have to be written back to the stack. The actual code for setting
|
|
// to stack (or RTM) is elsewhere, the following functions are merely
|
|
// wrappers around the actual calls
|
|
//
|
|
|
|
DWORD
|
|
SetIpForwardRow(
|
|
PMIB_IPFORWARDROW pOldIpForw,
|
|
PMIB_IPFORWARDROW pNewIpForw
|
|
)
|
|
{
|
|
DWORD i, dwResult, dwMask;
|
|
HANDLE hRtmHandle;
|
|
PICB pIcb;
|
|
|
|
TraceEnter("SetIpForwardRow");
|
|
|
|
hRtmHandle = NULL;
|
|
|
|
for(i = 0;
|
|
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
|
|
i++)
|
|
{
|
|
if(pNewIpForw->dwForwardProto is g_rgRtmHandles[i].dwProtoId)
|
|
{
|
|
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if(hRtmHandle is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"SetIpForwardRow: Protocol %d not valid",
|
|
pNewIpForw->dwForwardProto);
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if((pNewIpForw->dwForwardDest & pNewIpForw->dwForwardMask) isnot pNewIpForw->dwForwardDest)
|
|
{
|
|
Trace2(ERR,
|
|
"SetIpForwardRow: Dest %d.%d.%d.%d and Mask %d.%d.%d.%d wrong",
|
|
PRINT_IPADDR(pNewIpForw->dwForwardDest),
|
|
PRINT_IPADDR(pNewIpForw->dwForwardMask));
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(((DWORD)(pNewIpForw->dwForwardDest & 0x000000FF)) >= (DWORD)0x000000E0)
|
|
{
|
|
//
|
|
// This will catch the CLASS D/E and all 1's bcast
|
|
//
|
|
|
|
Trace1(ERR,
|
|
"SetIpForwardRow: Dest %d.%d.%d.%d is invalid",
|
|
PRINT_IPADDR(pNewIpForw->dwForwardDest));
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
#if 0
|
|
// Removed this since metric=0 is legal for routes to the loopback
|
|
// interface.
|
|
if(pNewIpForw->dwForwardMetric1 is 0)
|
|
{
|
|
Trace0(ERR,
|
|
"SetIpForwardRow: Metric1 cant be 0");
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If we are changing values, we need to blow the old row away.
|
|
// Just a quirk of how
|
|
// RTM and our stack works
|
|
//
|
|
|
|
if(pOldIpForw isnot NULL)
|
|
{
|
|
dwResult = DeleteIpForwardRow(pOldIpForw);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"SetIpForwardRow: Unable to delete route from RTM. Error %d",
|
|
dwResult);
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
|
|
UpdateStackRoutesToRestoreList(pOldIpForw, IRNO_FLAG_DELETE);
|
|
}
|
|
|
|
if(pNewIpForw->dwForwardProto isnot PROTO_IP_NETMGMT)
|
|
{
|
|
pNewIpForw->dwForwardAge = INFINITE;
|
|
}
|
|
|
|
//
|
|
// Add the RTM route from the ip forward entry
|
|
//
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
dwMask = GetBestNextHopMaskGivenIndex(pNewIpForw->dwForwardIfIndex,
|
|
pNewIpForw->dwForwardNextHop);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(pNewIpForw->dwForwardIfIndex);
|
|
|
|
if(pIcb is NULL)
|
|
{
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
Trace1(ERR,
|
|
"SetIpForwardRow: I/f 0x%x doesnt exist",
|
|
pNewIpForw->dwForwardIfIndex);
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(IsIfP2P(pIcb->ritType))
|
|
{
|
|
pNewIpForw->dwForwardNextHop = 0;
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
dwResult = AddRtmRoute(hRtmHandle,
|
|
ConvertMibRouteToRouteInfo(pNewIpForw),
|
|
IP_VALID_ROUTE | IP_STACK_ROUTE,
|
|
dwMask,
|
|
pNewIpForw->dwForwardAge,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"SetIpForwardRow: Could not set route to RTM: Dest %x\n",
|
|
pNewIpForw->dwForwardDest) ;
|
|
}
|
|
|
|
else
|
|
{
|
|
UpdateStackRoutesToRestoreList(pNewIpForw, IRNO_FLAG_ADD);
|
|
}
|
|
|
|
TraceLeave("SetIpForwardRow");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
DeleteIpForwardRow(
|
|
PMIB_IPFORWARDROW pIpForw
|
|
)
|
|
{
|
|
DWORD i, dwResult;
|
|
HANDLE hRtmHandle;
|
|
|
|
hRtmHandle = NULL;
|
|
|
|
for(i = 0;
|
|
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
|
|
i++)
|
|
{
|
|
if(pIpForw->dwForwardProto is g_rgRtmHandles[i].dwProtoId)
|
|
{
|
|
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if(hRtmHandle is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"DeleteIpForwardRow: Protocol %d not valid",
|
|
pIpForw->dwForwardProto);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Delete the RTM route corr. to the ip forward entry
|
|
//
|
|
|
|
dwResult = DeleteRtmRoute(hRtmHandle,
|
|
ConvertMibRouteToRouteInfo(pIpForw));
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"DeleteIpForwardRow: RtmDeleteRoute returned %d", dwResult);
|
|
}
|
|
else
|
|
{
|
|
UpdateStackRoutesToRestoreList(pIpForw, IRNO_FLAG_DELETE);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessMcastMfe(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This
|
|
|
|
Locks
|
|
|
|
None
|
|
|
|
Arguments
|
|
|
|
None
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult,dwNumIndices,dwIndex;
|
|
DWORD dwOutBufferSize, dwNumMfes;
|
|
MIB_IPMCAST_MFE mimInMfe;
|
|
|
|
TraceEnter("AccessMcastMfe");
|
|
|
|
#if 1
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
{
|
|
//
|
|
// The in index better be a good size
|
|
// The user must specify Group, Source and SrcMask. The
|
|
// SrcMask is not used and MUST be 0xFFFFFFFF
|
|
//
|
|
|
|
if(dwNumIndices < 3)
|
|
{
|
|
TraceLeave("AccessMcastMfe");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
ZeroMemory(&mimInMfe, sizeof(mimInMfe));
|
|
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
mimInMfe.dwSource = pInEntry->rgdwVarIndex[1];
|
|
|
|
//
|
|
// NOTE: Change when doing source aggregation
|
|
//
|
|
|
|
mimInMfe.dwSrcMask = 0xFFFFFFFF;
|
|
|
|
dwOutBufferSize =
|
|
(*pOutEntrySize < MAX_MIB_OFFSET)? 0 : (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
|
|
dwResult = MgmGetMfe(
|
|
&mimInMfe, &dwOutBufferSize, pOutEntry->rgbyData
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
PMIB_MFE_TABLE pMfeTable;
|
|
|
|
//
|
|
// We always gets chunks of 1KB
|
|
//
|
|
|
|
if(*pOutEntrySize < MIB_MFE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_MFE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// MGM wants a flat buffer for MFEs. We however return a
|
|
// MIB_MFE_TABLE to the user that starts (in the worst case) after
|
|
// MAX_MIB_OFFSET bytes of the input buffer
|
|
//
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_MFE_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pMfeTable = (PMIB_MFE_TABLE)pOutEntry->rgbyData;
|
|
|
|
pMfeTable->dwNumEntries = 0;
|
|
|
|
// pMfe = (PMIB_IPMCAST_MFE)(pMfeTable->table);
|
|
|
|
dwNumMfes = 0;
|
|
|
|
dwResult = MgmGetFirstMfe(
|
|
&dwOutBufferSize, (PBYTE)pMfeTable->table,
|
|
&dwNumMfes
|
|
);
|
|
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pMfeTable->dwNumEntries = dwNumMfes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_NEXT:
|
|
{
|
|
PMIB_MFE_TABLE pMfeTable;
|
|
|
|
//
|
|
// For this, too we always get chunks of 1K pages
|
|
//
|
|
|
|
if(*pOutEntrySize < MIB_MFE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_MFE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_MFE_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pMfeTable = (PMIB_MFE_TABLE)pOutEntry->rgbyData;
|
|
|
|
pMfeTable->dwNumEntries = 0;
|
|
|
|
// pMfe = (PMIB_IPMCAST_MFE)(pMfeTable->table);
|
|
|
|
dwNumMfes = 0;
|
|
|
|
//
|
|
// Set up the "first" mfe
|
|
//
|
|
|
|
ZeroMemory(&mimInMfe, sizeof(mimInMfe));
|
|
|
|
//
|
|
// NOTE: Change when doing source aggregation
|
|
//
|
|
|
|
mimInMfe.dwSrcMask = 0xFFFFFFFF;
|
|
|
|
switch(dwNumIndices)
|
|
{
|
|
case 0:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// 2 or more indices
|
|
//
|
|
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
mimInMfe.dwSource = pInEntry->rgdwVarIndex[1];
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwResult = MgmGetNextMfe(
|
|
&mimInMfe, &dwOutBufferSize, (PBYTE)pMfeTable->table,
|
|
&dwNumMfes
|
|
);
|
|
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pMfeTable->dwNumEntries = dwNumMfes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
//
|
|
// Validate the MFE size
|
|
//
|
|
|
|
if(dwInEntrySize < SIZEOF_BASIC_MFE)
|
|
{
|
|
}
|
|
|
|
//dwResult = SetMfe(pMfe);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
|
|
break;
|
|
}
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
//
|
|
//
|
|
// This is the case where you have tried to create a route which
|
|
// matches an existing entry
|
|
//
|
|
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
TraceLeave("AccessMcastMfe");
|
|
|
|
//return dwResult;
|
|
|
|
return NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessMcastMfeStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
return AccessMcastMfeStatsInternal(
|
|
dwQueryType,
|
|
dwInEntrySize,
|
|
pInEntry,
|
|
pOutEntrySize,
|
|
pOutEntry,
|
|
pbCache,
|
|
MGM_MFE_STATS_0
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessMcastMfeStatsEx(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
return AccessMcastMfeStatsInternal(
|
|
dwQueryType,
|
|
dwInEntrySize,
|
|
pInEntry,
|
|
pOutEntrySize,
|
|
pOutEntry,
|
|
pbCache,
|
|
MGM_MFE_STATS_1
|
|
);
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessMcastMfeStatsInternal(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache,
|
|
DWORD dwStatsFlag
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This
|
|
|
|
Locks
|
|
|
|
None
|
|
|
|
Arguments
|
|
|
|
None
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult = NO_ERROR,dwNumIndices,dwIndex;
|
|
DWORD dwOutBufferSize, dwNumMfes;
|
|
MIB_IPMCAST_MFE mimInMfe;
|
|
|
|
|
|
TraceEnter("AccessMcastMfeStatsInternal");
|
|
#if 1
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
{
|
|
//
|
|
// The in index better be a good size
|
|
// The user must specify Group, Source and SrcMask. The
|
|
// SrcMask is not used and MUST be 0xFFFFFFFF
|
|
//
|
|
|
|
if(dwNumIndices < 3)
|
|
{
|
|
TraceLeave("AccessMcastMfeStatsInternal");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
ZeroMemory(&mimInMfe, sizeof(mimInMfe));
|
|
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
mimInMfe.dwSource = pInEntry->rgdwVarIndex[1];
|
|
|
|
//
|
|
// NOTE: Change when doing source aggregation
|
|
//
|
|
|
|
mimInMfe.dwSrcMask = 0xFFFFFFFF;
|
|
|
|
dwOutBufferSize =
|
|
(*pOutEntrySize < MAX_MIB_OFFSET)? 0 : (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
|
|
|
|
dwResult = MgmGetMfeStats(
|
|
&mimInMfe, &dwOutBufferSize,
|
|
pOutEntry->rgbyData, dwStatsFlag
|
|
);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
PMIB_MFE_STATS_TABLE pMfeStatsTable;
|
|
|
|
//
|
|
// We always get chunks of 1KB
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_MFE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_MFE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
//
|
|
// MGM wants a flat buffer for MFEs. We however return a
|
|
// MIB_MFE_TABLE to the user that starts (in the worst case) after
|
|
// MAX_MIB_OFFSET bytes of the input buffer
|
|
//
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_MFE_STATS_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pMfeStatsTable = (PMIB_MFE_STATS_TABLE)pOutEntry->rgbyData;
|
|
|
|
pMfeStatsTable->dwNumEntries = 0;
|
|
|
|
// pMfeStats = (PMIB_IPMCAST_MFE_STATS)(pMfeStatsTable->table);
|
|
|
|
dwNumMfes = 0;
|
|
|
|
dwResult = MgmGetFirstMfeStats(
|
|
&dwOutBufferSize, (PBYTE)pMfeStatsTable->table,
|
|
&dwNumMfes, dwStatsFlag
|
|
);
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pMfeStatsTable->dwNumEntries = dwNumMfes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_NEXT:
|
|
{
|
|
PMIB_MFE_STATS_TABLE pMfeStatsTable;
|
|
|
|
//
|
|
// For this, too we always get chunks of 1K pages
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_MFE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_MFE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_MFE_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pMfeStatsTable = (PMIB_MFE_STATS_TABLE)pOutEntry->rgbyData;
|
|
|
|
pMfeStatsTable->dwNumEntries = 0;
|
|
|
|
//pMfeStats = (PIPMCAST_MFE_STATS)(pMfeStatsTable->table);
|
|
|
|
dwNumMfes = 0;
|
|
|
|
//
|
|
// Set up the "first" mfe
|
|
//
|
|
|
|
ZeroMemory(&mimInMfe, sizeof(mimInMfe));
|
|
|
|
//
|
|
// NOTE: Change when doing source aggregation
|
|
//
|
|
|
|
mimInMfe.dwSrcMask = 0xFFFFFFFF;
|
|
|
|
switch(dwNumIndices)
|
|
{
|
|
case 0:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// 2 or more indices
|
|
//
|
|
|
|
mimInMfe.dwGroup = pInEntry->rgdwVarIndex[0];
|
|
mimInMfe.dwSource = pInEntry->rgdwVarIndex[1];
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwResult = MgmGetNextMfeStats(
|
|
&mimInMfe, &dwOutBufferSize,
|
|
(PBYTE)pMfeStatsTable->table, &dwNumMfes,
|
|
dwStatsFlag
|
|
);
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pMfeStatsTable->dwNumEntries = dwNumMfes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
//
|
|
// Validate the MFE size
|
|
//
|
|
|
|
if(dwInEntrySize < SIZEOF_BASIC_MFE)
|
|
{
|
|
}
|
|
|
|
//dwResult = SetMfe(pMfe);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
|
|
break;
|
|
}
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
//
|
|
//
|
|
// This is the case where you have tried to create a route which
|
|
// matches an existing entry
|
|
//
|
|
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
TraceLeave("AccessMcastMfeStatsInternal");
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessMcastIfStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves the IP Multicast Interface table
|
|
|
|
Locks
|
|
|
|
Takes ICB list lock as READER
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IFTABLE)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PICB picb;
|
|
PMIB_IPMCAST_IF_ENTRY pIfRow;
|
|
DWORD dwNumIndices, dwResult;
|
|
|
|
TraceEnter("AccessMcastIfTable");
|
|
|
|
pIfRow = (PMIB_IPMCAST_IF_ENTRY)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_IF_ENTRY))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_IF_ENTRY);
|
|
TraceLeave("AccessMcastIfTable");
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_IF_ENTRY);
|
|
|
|
pOutEntry->dwId = MCAST_IF_ENTRY;
|
|
|
|
do
|
|
{
|
|
if(dwQueryType is ACCESS_SET)
|
|
{
|
|
ENTER_WRITER(ICB_LIST);
|
|
}
|
|
else
|
|
{
|
|
ENTER_READER(ICB_LIST);
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
dwResult = LocateIfRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&picb,
|
|
FALSE);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
case ACCESS_GET_NEXT:
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
dwResult = GetInterfaceMcastStatistics(picb,pIfRow);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
dwResult = SetInterfaceMcastStatistics(picb,pIfRow);
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIfRow: Wrong query type %d",dwQueryType);
|
|
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}while(FALSE);
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
*pbCache = TRUE;
|
|
|
|
TraceLeave("AccessMcastIfTable");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessMcastStats(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves the IP Multicast scalar information
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_GLOBAL)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PMIB_IPMCAST_GLOBAL pMcastStats;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessMcastStats");
|
|
|
|
if (dwQueryType isnot ACCESS_GET) {
|
|
TraceLeave("AccessMcastStats");
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pMcastStats = (PMIB_IPMCAST_GLOBAL)(pOutEntry->rgbyData);
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_GLOBAL))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_GLOBAL);
|
|
|
|
TraceLeave("AccessMcastStats");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_GLOBAL);
|
|
|
|
pOutEntry->dwId = MCAST_GLOBAL;
|
|
|
|
dwResult = NO_ERROR;
|
|
|
|
// Retrieve statistics
|
|
pMcastStats->dwEnable = (g_hMcastDevice isnot NULL)? 1 : 2;
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessMcastBoundary(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves multicast boundary information
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_BOUNDARY)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult = NO_ERROR,dwNumIndices,dwIndex;
|
|
DWORD dwOutBufferSize, dwNumBoundaries;
|
|
MIB_IPMCAST_BOUNDARY imInBoundary;
|
|
|
|
TraceEnter("AccessMcastBoundary");
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
{
|
|
//
|
|
// The in index better be a good size
|
|
// The user must specify IfIndex, Group, GrpMask.
|
|
//
|
|
|
|
if(dwNumIndices < 3)
|
|
{
|
|
TraceLeave("AccessMcastBoundary");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
//
|
|
// We always get chunks of 1KB
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_BOUNDARY_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_BOUNDARY_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
ZeroMemory(&imInBoundary, sizeof(imInBoundary));
|
|
|
|
imInBoundary.dwIfIndex = pInEntry->rgdwVarIndex[0];
|
|
imInBoundary.dwGroupAddress = pInEntry->rgdwVarIndex[1];
|
|
imInBoundary.dwGroupMask = pInEntry->rgdwVarIndex[2];
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
|
|
dwResult = RmGetBoundary(&imInBoundary,
|
|
&dwOutBufferSize,
|
|
pOutEntry->rgbyData);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
PMIB_IPMCAST_BOUNDARY_TABLE pBoundaryTable;
|
|
#endif
|
|
PMIB_IPMCAST_BOUNDARY pBoundary;
|
|
|
|
//
|
|
// We always get chunks of 1KB
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_BOUNDARY_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_BOUNDARY_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
//
|
|
// RM wants a flat buffer for boundaries. We however return a
|
|
// MIB_IPMCAST_BOUNDARY_TABLE to the user that starts (in the worst case)
|
|
// after MAX_MIB_OFFSET bytes of the input buffer
|
|
//
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_IPMCAST_BOUNDARY_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pBoundaryTable = (PMIB_IPMCAST_BOUNDARY_TABLE)pOutEntry->rgbyData;
|
|
|
|
pBoundaryTable->dwNumEntries = 0;
|
|
|
|
pBoundary = (PMIB_IPMCAST_BOUNDARY)(pBoundaryTable->table);
|
|
#else
|
|
pBoundary = (PMIB_IPMCAST_BOUNDARY)pOutEntry->rgbyData;
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
#endif
|
|
|
|
dwNumBoundaries = 1; // get one
|
|
|
|
dwResult = RmGetFirstBoundary(&dwOutBufferSize,
|
|
(PBYTE)pBoundary,
|
|
&dwNumBoundaries);
|
|
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pBoundaryTable->dwNumEntries = dwNumBoundaries;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_NEXT:
|
|
{
|
|
PMIB_IPMCAST_BOUNDARY pBoundary;
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
PMIB_IPMCAST_BOUNDARY_TABLE pBoundaryTable;
|
|
#endif
|
|
|
|
//
|
|
// For this, too we always get chunks of 1K pages
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_BOUNDARY_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_BOUNDARY_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_IPMCAST_BOUNDARY_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pBoundaryTable = (PMIB_IPMCAST_BOUNDARY_TABLE)pOutEntry->rgbyData;
|
|
|
|
pBoundaryTable->dwNumEntries = 0;
|
|
|
|
pBoundary = (PMIB_IPMCAST_BOUNDARY)(pBoundaryTable->table);
|
|
#else
|
|
pBoundary = (PMIB_IPMCAST_BOUNDARY)pOutEntry->rgbyData;
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
#endif
|
|
|
|
dwNumBoundaries = 1; // get one
|
|
|
|
//
|
|
// Set up the "first" boundary
|
|
//
|
|
|
|
ZeroMemory(&imInBoundary, sizeof(imInBoundary));
|
|
|
|
switch(dwNumIndices)
|
|
{
|
|
case 0:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
imInBoundary.dwIfIndex = pInEntry->rgdwVarIndex[0];
|
|
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
imInBoundary.dwIfIndex = pInEntry->rgdwVarIndex[0];
|
|
imInBoundary.dwGroupAddress = pInEntry->rgdwVarIndex[1];
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// 3 or more indices
|
|
//
|
|
|
|
imInBoundary.dwIfIndex = pInEntry->rgdwVarIndex[0];
|
|
imInBoundary.dwGroupAddress = pInEntry->rgdwVarIndex[1];
|
|
imInBoundary.dwGroupMask = pInEntry->rgdwVarIndex[2];
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwResult = RmGetNextBoundary(&imInBoundary,
|
|
&dwOutBufferSize,
|
|
(PBYTE)pBoundary,
|
|
&dwNumBoundaries);
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
#ifdef USE_BOUNDARY_TABLE
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pBoundaryTable->dwNumEntries = dwNumBoundaries;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
PMIB_IPMCAST_BOUNDARY pBound;
|
|
PICB picb;
|
|
|
|
//
|
|
// Validate the buffer size
|
|
//
|
|
|
|
if (*pOutEntrySize < sizeof(MIB_IPMCAST_BOUNDARY)) {
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
//
|
|
// Make sure the ifIndex is a valid one
|
|
//
|
|
|
|
dwResult = LocateIfRow(dwQueryType,
|
|
1,
|
|
(PDWORD)pOutEntry->rgbyData,
|
|
&picb,
|
|
FALSE);
|
|
|
|
if (dwResult isnot NO_ERROR)
|
|
return dwResult;
|
|
|
|
pBound = (PMIB_IPMCAST_BOUNDARY)(pOutEntry->rgbyData);
|
|
if (pBound->dwStatus == ROWSTATUS_CREATEANDGO) {
|
|
dwResult = SNMPAddBoundaryToInterface(pBound->dwIfIndex,
|
|
pBound->dwGroupAddress, pBound->dwGroupMask);
|
|
} else if (pBound->dwStatus == ROWSTATUS_DESTROY) {
|
|
dwResult =SNMPDeleteBoundaryFromInterface(pBound->dwIfIndex,
|
|
pBound->dwGroupAddress, pBound->dwGroupMask);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
break;
|
|
}
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
//
|
|
//
|
|
// This is the case where you have tried to create a boundary which
|
|
// matches an existing entry
|
|
//
|
|
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
dwResult = ERROR_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
TraceLeave("AccessMcastBoundary");
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessMcastScope(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves multicast scope information
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPMCAST_SCOPE)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
DWORD dwResult = NO_ERROR,
|
|
dwNumIndices,dwIndex;
|
|
DWORD dwOutBufferSize, dwNumScopes;
|
|
MIB_IPMCAST_SCOPE imInScope;
|
|
|
|
TraceEnter("AccessMcastScope");
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
switch(dwQueryType)
|
|
{
|
|
case ACCESS_GET:
|
|
{
|
|
//
|
|
// The in index better be a good size
|
|
// The user must specify Group, GrpMask.
|
|
//
|
|
|
|
if(dwNumIndices < 2)
|
|
{
|
|
TraceLeave("AccessMcastScope");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
//
|
|
// We always get chunks of 1KB
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_SCOPE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_SCOPE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
ZeroMemory(&imInScope, sizeof(imInScope));
|
|
|
|
imInScope.dwGroupAddress = pInEntry->rgdwVarIndex[0];
|
|
imInScope.dwGroupMask = pInEntry->rgdwVarIndex[1];
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
|
|
dwResult = RmGetScope(&imInScope,
|
|
&dwOutBufferSize,
|
|
pOutEntry->rgbyData);
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_FIRST:
|
|
{
|
|
#ifdef USE_SCOPE_TABLE
|
|
PMIB_IPMCAST_SCOPE_TABLE pScopeTable;
|
|
#endif
|
|
PMIB_IPMCAST_SCOPE pScope;
|
|
|
|
//
|
|
// We always get chunks of 1KB
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_SCOPE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_SCOPE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#ifdef USE_SCOPE_TABLE
|
|
//
|
|
// RM wants a flat buffer for scopes. We however return a
|
|
// MIB_IPMCAST_SCOPE_TABLE to the user that starts (in the worst case)
|
|
// after MAX_MIB_OFFSET bytes of the input buffer
|
|
//
|
|
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_IPMCAST_SCOPE_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pScopeTable = (PMIB_IPMCAST_SCOPE_TABLE)pOutEntry->rgbyData;
|
|
|
|
pScopeTable->dwNumEntries = 0;
|
|
|
|
pScope = (PMIB_IPMCAST_SCOPE)(pScopeTable->table);
|
|
#else
|
|
pScope = (PMIB_IPMCAST_SCOPE)pOutEntry->rgbyData;
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
#endif
|
|
|
|
dwNumScopes = 1; // get one
|
|
|
|
dwResult = RmGetFirstScope(&dwOutBufferSize,
|
|
(PBYTE)pScope,
|
|
&dwNumScopes);
|
|
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
#ifdef USE_SCOPE_TABLE
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pScopeTable->dwNumEntries = dwNumScopes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_GET_NEXT:
|
|
{
|
|
PMIB_IPMCAST_SCOPE pScope;
|
|
#ifdef USE_SCOPE_TABLE
|
|
PMIB_IPMCAST_SCOPE_TABLE pScopeTable;
|
|
#endif
|
|
|
|
//
|
|
// For this, too we always get chunks of 1K pages
|
|
//
|
|
|
|
if (*pOutEntrySize < MIB_SCOPE_BUFFER_SIZE)
|
|
{
|
|
*pOutEntrySize = MIB_SCOPE_BUFFER_SIZE;
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
#ifdef USE_SCOPE_TABLE
|
|
#define _MIN_SIZE \
|
|
(MAX_MIB_OFFSET + FIELD_OFFSET(MIB_IPMCAST_SCOPE_TABLE,table[0]))
|
|
|
|
dwOutBufferSize = *pOutEntrySize - _MIN_SIZE;
|
|
|
|
#undef _MIN_SIZE
|
|
|
|
pScopeTable = (PMIB_IPMCAST_Scope_TABLE)pOutEntry->rgbyData;
|
|
|
|
pScopeTable->dwNumEntries = 0;
|
|
|
|
pScope = (PMIB_IPMCAST_SCOPE)(pScopeTable->table);
|
|
#else
|
|
pScope = (PMIB_IPMCAST_SCOPE)pOutEntry->rgbyData;
|
|
|
|
dwOutBufferSize = (*pOutEntrySize < MAX_MIB_OFFSET)
|
|
? 0
|
|
: (*pOutEntrySize - MAX_MIB_OFFSET);
|
|
#endif
|
|
|
|
dwNumScopes = 1; // get one
|
|
|
|
//
|
|
// Set up the "first" scope
|
|
//
|
|
|
|
ZeroMemory(&imInScope, sizeof(imInScope));
|
|
|
|
switch(dwNumIndices)
|
|
{
|
|
case 0:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
imInScope.dwGroupAddress = pInEntry->rgdwVarIndex[0];
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// 2 or more indices
|
|
//
|
|
|
|
imInScope.dwGroupAddress = pInEntry->rgdwVarIndex[0];
|
|
imInScope.dwGroupMask = pInEntry->rgdwVarIndex[1];
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwResult = RmGetNextScope(&imInScope,
|
|
&dwOutBufferSize,
|
|
(PBYTE)pScope,
|
|
&dwNumScopes);
|
|
|
|
//
|
|
// We should NEVER get back ERROR_INSUFFICIENT_BUFFER
|
|
//
|
|
|
|
IpRtAssert(dwResult isnot ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
#ifdef USE_SCOPE_TABLE
|
|
if((dwResult is ERROR_MORE_DATA) or
|
|
(dwResult is ERROR_NO_MORE_ITEMS))
|
|
{
|
|
pScopeTable->dwNumEntries = dwNumScopes;
|
|
|
|
dwResult = NO_ERROR;
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_SET:
|
|
{
|
|
PMIB_IPMCAST_SCOPE pScope;
|
|
|
|
//
|
|
// Validate the buffer size
|
|
//
|
|
|
|
if (*pOutEntrySize < sizeof(MIB_IPMCAST_SCOPE)) {
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
pScope = (PMIB_IPMCAST_SCOPE)(pOutEntry->rgbyData);
|
|
if ( !pScope->dwStatus )
|
|
{
|
|
dwResult = SNMPSetScope( pScope->dwGroupAddress,
|
|
pScope->dwGroupMask,
|
|
pScope->snNameBuffer
|
|
);
|
|
} else if (pScope->dwStatus == ROWSTATUS_CREATEANDGO)
|
|
{
|
|
PSCOPE_ENTRY pNew;
|
|
|
|
dwResult = SNMPAddScope( pScope->dwGroupAddress,
|
|
pScope->dwGroupMask,
|
|
pScope->snNameBuffer,
|
|
&pNew
|
|
);
|
|
}
|
|
else if (pScope->dwStatus == ROWSTATUS_DESTROY)
|
|
{
|
|
dwResult = SNMPDeleteScope( pScope->dwGroupAddress,
|
|
pScope->dwGroupMask
|
|
);
|
|
}
|
|
else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
{
|
|
|
|
break;
|
|
}
|
|
case ACCESS_CREATE_ENTRY:
|
|
{
|
|
//
|
|
//
|
|
// This is the case where you have tried to create a scope which
|
|
// matches an existing entry
|
|
//
|
|
|
|
dwResult = ERROR_ALREADY_EXISTS;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
TraceLeave("AccessMcastScope");
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessBestIf(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function services the BEST_IF var id
|
|
|
|
Locks
|
|
|
|
Takes the ICB_LIST as READER to map from adapter to interface index
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can only be ACCESS_GET
|
|
pInEntry Destination address filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_BEST_IF)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwNumIndices, dwResult;
|
|
DWORD dwIfIndex;
|
|
PICB pIcb;
|
|
|
|
PMIB_BEST_IF pBestIf;
|
|
|
|
TraceEnter("AccessBestIf");
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_BEST_IF))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_BEST_IF);
|
|
|
|
TraceLeave("AccessBestIf");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
|
|
if((dwNumIndices < 1) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessBestIf");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_BEST_IF);
|
|
|
|
dwResult = GetBestInterfaceFromStack(pInEntry->rgdwVarIndex[0],
|
|
&dwIfIndex);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
|
|
#if DBG
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(dwIfIndex);
|
|
|
|
if(pIcb is NULL)
|
|
{
|
|
Trace2(ERR,
|
|
"AccessBestIf: Couldnt find i/f for Index %d for dest %d.%d.%d.%d\n",
|
|
dwIfIndex,
|
|
PRINT_IPADDR(pInEntry->rgdwVarIndex[0]));
|
|
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
#endif
|
|
|
|
pBestIf = (PMIB_BEST_IF)(pOutEntry->rgbyData);
|
|
|
|
pOutEntry->dwId = BEST_IF;
|
|
|
|
pBestIf->dwDestAddr = pInEntry->rgdwVarIndex[0];
|
|
pBestIf->dwIfIndex = dwIfIndex;
|
|
|
|
}
|
|
|
|
TraceLeave("AccessBestIf");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessBestRoute(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function services the BEST_IF var id
|
|
|
|
Locks
|
|
|
|
Takes the ICB_LIST as READER to map from adapter to interface index
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can only be ACCESS_GET
|
|
pInEntry Destination address filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_BEST_IF)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwNumIndices, dwResult;
|
|
PICB pIcb;
|
|
RTM_NET_ADDRESS rnaDest;
|
|
RTM_DEST_INFO rdiInfo;
|
|
PRTM_ROUTE_INFO prriInfo;
|
|
RTM_NEXTHOP_INFO rniInfo;
|
|
RTM_ENTITY_INFO reiInfo;
|
|
PINTERFACE_ROUTE_INFO pRoute;
|
|
|
|
TraceEnter("AccessBestRoute");
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(INTERFACE_ROUTE_INFO))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(INTERFACE_ROUTE_INFO);
|
|
|
|
TraceLeave("AccessBestRoute");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
|
|
if((dwNumIndices < 2) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessBestRoute");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(INTERFACE_ROUTE_INFO);
|
|
|
|
pRoute = (PINTERFACE_ROUTE_INFO)(pOutEntry->rgbyData);
|
|
|
|
// Get the best route from RTM instead of the stack (chaitk)
|
|
|
|
// dwResult = GetBestRouteFromStack(pInEntry->rgdwVarIndex[0],
|
|
// pInEntry->rgdwVarIndex[0],
|
|
// pRoute);
|
|
|
|
RTM_IPV4_MAKE_NET_ADDRESS(&rnaDest, pInEntry->rgdwVarIndex[0], 32);
|
|
|
|
dwResult = RtmGetMostSpecificDestination(g_hLocalRoute,
|
|
&rnaDest,
|
|
RTM_BEST_PROTOCOL,
|
|
RTM_VIEW_MASK_UCAST,
|
|
&rdiInfo);
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
ASSERT(rdiInfo.ViewInfo[0].ViewId is RTM_VIEW_ID_UCAST);
|
|
|
|
prriInfo = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
|
|
);
|
|
|
|
if ( prriInfo != NULL)
|
|
{
|
|
dwResult = RtmGetRouteInfo(g_hLocalRoute,
|
|
rdiInfo.ViewInfo[0].Route,
|
|
prriInfo,
|
|
NULL);
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
dwResult = RtmGetEntityInfo(g_hLocalRoute,
|
|
prriInfo->RouteOwner,
|
|
&reiInfo);
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
// We are working on the first nexthop only
|
|
|
|
ASSERT(prriInfo->NextHopsList.NumNextHops > 0);
|
|
|
|
dwResult = RtmGetNextHopInfo(g_hLocalRoute,
|
|
prriInfo->NextHopsList.NextHops[0],
|
|
&rniInfo);
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
ConvertRtmToRouteInfo(reiInfo.EntityId.EntityProtocolId,
|
|
&rdiInfo.DestAddress,
|
|
prriInfo,
|
|
&rniInfo,
|
|
pRoute);
|
|
|
|
RtmReleaseNextHopInfo(g_hLocalRoute, &rniInfo);
|
|
}
|
|
}
|
|
|
|
RtmReleaseRouteInfo(g_hLocalRoute, prriInfo);
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, prriInfo);
|
|
}
|
|
|
|
else
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtmReleaseDestInfo(g_hLocalRoute, &rdiInfo);
|
|
}
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
|
|
#if DBG
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
pIcb = InterfaceLookupByIfIndex(pRoute->dwRtInfoIfIndex);
|
|
|
|
if(pIcb is NULL)
|
|
{
|
|
Trace2(ERR,
|
|
"AccessBestRoute: Couldnt find i/f for index %d for dest %d.%d.%d.%d\n",
|
|
pRoute->dwRtInfoIfIndex,
|
|
PRINT_IPADDR(pInEntry->rgdwVarIndex[0]));
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
#endif // DBG
|
|
|
|
//
|
|
// Not need to map since the indices are the same
|
|
//
|
|
|
|
// pRoute->dwRtInfoIfIndex = dwIfIndex;
|
|
}
|
|
|
|
TraceLeave("AccessBestRoute");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessProxyArp(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function services the PROXY_ARP id
|
|
|
|
Locks
|
|
|
|
Takes the ICB_LIST as READER to map from interface to adapter index
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can only be ACCESS_CREATE_ENTRY or ACCESS_DELETE_ENTRY
|
|
pInEntry Destination address filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_BEST_IF)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
MIB_PROXYARP mpEntry;
|
|
PMIB_PROXYARP pProxyEntry;
|
|
PADAPTER_INFO pBinding;
|
|
BOOL bAdd;
|
|
DWORD dwResult;
|
|
|
|
TraceEnter("AccessProxyArp");
|
|
|
|
|
|
if(dwQueryType is ACCESS_DELETE_ENTRY)
|
|
{
|
|
mpEntry.dwAddress = pInEntry->rgdwVarIndex[0];
|
|
mpEntry.dwMask = pInEntry->rgdwVarIndex[1];
|
|
mpEntry.dwIfIndex = pInEntry->rgdwVarIndex[2];
|
|
|
|
pProxyEntry = &mpEntry;
|
|
|
|
bAdd = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if(dwQueryType is ACCESS_CREATE_ENTRY)
|
|
{
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_PROXYARP))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_PROXYARP);
|
|
|
|
TraceLeave("AccessProxyArp");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
pProxyEntry = (PMIB_PROXYARP)(pOutEntry->rgbyData);
|
|
|
|
bAdd = TRUE;
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_PROXYARP);
|
|
|
|
pOutEntry->dwId = PROXY_ARP;
|
|
}
|
|
else
|
|
{
|
|
TraceLeave("AccessProxyArp");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
ENTER_READER(BINDING_LIST);
|
|
|
|
pBinding = GetInterfaceBinding(pProxyEntry->dwIfIndex);
|
|
|
|
if(pBinding is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessProxyArp: Cant find binding for i/f %d",
|
|
pProxyEntry->dwIfIndex);
|
|
|
|
EXIT_LOCK(BINDING_LIST);
|
|
|
|
TraceLeave("AccessProxyArp");
|
|
|
|
return ERROR_INVALID_INDEX;
|
|
}
|
|
|
|
if(!pBinding->bBound)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessProxyArp: I/f %d is not bound",
|
|
pProxyEntry->dwIfIndex);
|
|
|
|
EXIT_LOCK(BINDING_LIST);
|
|
|
|
TraceLeave("AccessProxyArp");
|
|
|
|
return ERROR_NOT_READY;
|
|
}
|
|
|
|
EXIT_LOCK(BINDING_LIST);
|
|
|
|
dwResult = SetProxyArpEntryToStack(pProxyEntry->dwAddress,
|
|
pProxyEntry->dwMask,
|
|
pProxyEntry->dwIfIndex,
|
|
bAdd,
|
|
TRUE);
|
|
|
|
TraceLeave("AccessProxyArp");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessIfStatus(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function services the BEST_IF var id
|
|
|
|
Locks
|
|
|
|
Takes the ICB_LIST as READER to map from adapter to interface index
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be ACCESS_GET, ACCESS_GET_FIRST or ACCESS_GET_NEXT
|
|
pInEntry Destination address filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_BEST_IF)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwNumIndices, dwResult;
|
|
DWORD dwIfIndex;
|
|
PICB picb;
|
|
|
|
PMIB_IFSTATUS pIfStatus;
|
|
SYSTEMTIME stSysTime;
|
|
ULARGE_INTEGER uliTime;
|
|
|
|
|
|
TraceEnter("AccessIfStatus");
|
|
|
|
if(dwQueryType > ACCESS_GET_NEXT)
|
|
{
|
|
TraceLeave("AccessIfStatus");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IFSTATUS))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFSTATUS);
|
|
|
|
TraceLeave("AccessIfStatus");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IFSTATUS);
|
|
|
|
pIfStatus = (PMIB_IFSTATUS)(pOutEntry->rgbyData);
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
dwResult = LocateIfRow(dwQueryType,
|
|
dwNumIndices,
|
|
pInEntry->rgdwVarIndex,
|
|
&picb,
|
|
FALSE);
|
|
|
|
|
|
if(dwResult is NO_ERROR)
|
|
{
|
|
pIfStatus->dwIfIndex = picb->dwIfIndex;
|
|
pIfStatus->dwAdminStatus = picb->dwAdminState;
|
|
pIfStatus->dwOperationalStatus = picb->dwOperationalState;
|
|
|
|
pIfStatus->bMHbeatActive = picb->mhcHeartbeatInfo.bActive;
|
|
|
|
|
|
if(pIfStatus->bMHbeatActive)
|
|
{
|
|
GetSystemTime(&stSysTime);
|
|
|
|
SystemTimeToFileTime(&stSysTime,
|
|
(PFILETIME)&uliTime);
|
|
|
|
//
|
|
// Its alive if the currenttime - lastheard < deadinterval
|
|
//
|
|
|
|
pIfStatus->bMHbeatAlive =
|
|
(uliTime.QuadPart - picb->mhcHeartbeatInfo.ullLastHeard < picb->mhcHeartbeatInfo.ullDeadInterval);
|
|
}
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
}
|
|
|
|
TraceLeave("AccessIfStatus");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AccessSetRouteState(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This function services ROUTE_STATE id
|
|
|
|
Locks
|
|
|
|
Takes the g_csFwdState lock
|
|
|
|
Arguments
|
|
|
|
dwQueryType Can be ACCESS_GET only
|
|
pInEntry Destination address filled in the rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_ROUTESTATE)
|
|
|
|
Return Value
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwResult;
|
|
|
|
PMIB_ROUTESTATE pState;
|
|
|
|
if(dwQueryType isnot ACCESS_GET)
|
|
{
|
|
TraceLeave("AccessSetRouteState");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_ROUTESTATE))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_ROUTESTATE);
|
|
|
|
TraceLeave("AccessSetRouteState");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_ROUTESTATE);
|
|
|
|
pOutEntry->dwId = ROUTE_STATE;
|
|
|
|
pState = (PMIB_ROUTESTATE)(pOutEntry->rgbyData);
|
|
|
|
EnterCriticalSection(&g_csFwdState);
|
|
|
|
pState->bRoutesSetToStack = g_bSetRoutesToStack;
|
|
|
|
LeaveCriticalSection(&g_csFwdState);
|
|
|
|
TraceLeave("AccessSetRouteState");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
AddDestinationRows(
|
|
IN PRTM_DEST_INFO pRdi,
|
|
IN RTM_VIEW_SET dwViews,
|
|
OUT DWORD *pdwCount,
|
|
IN DWORD dwSpaceCount,
|
|
OUT PMIB_IPDESTTABLE pDestTable
|
|
)
|
|
{
|
|
DWORD dwFinalResult, dwResult, i, j, k;
|
|
PRTM_ROUTE_INFO pri;
|
|
RTM_NEXTHOP_INFO nhi;
|
|
PMIB_IPDESTROW pRow;
|
|
|
|
pri = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
|
|
);
|
|
|
|
if ( pri == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// XXX how do I walk all next hops which get added to the stack???
|
|
// For now, let's assume only one route per view.
|
|
|
|
dwFinalResult = NO_ERROR;
|
|
|
|
for (i = 0; i < pRdi->NumberOfViews; i++)
|
|
{
|
|
if (pRdi->ViewInfo[i].Route == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Skip if we have seen this route already
|
|
|
|
for (k = 0; k < i; k++)
|
|
{
|
|
if (pRdi->ViewInfo[k].Route == pRdi->ViewInfo[i].Route)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (k < i)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwResult = RtmGetRouteInfo( g_hLocalRoute,
|
|
pRdi->ViewInfo[i].Route,
|
|
pri,
|
|
NULL );
|
|
|
|
if (dwResult isnot NO_ERROR)
|
|
{
|
|
dwFinalResult = dwResult;
|
|
continue;
|
|
}
|
|
|
|
*pdwCount += pri->NextHopsList.NumNextHops;
|
|
|
|
if (dwSpaceCount >= *pdwCount)
|
|
{
|
|
ULARGE_INTEGER now, then;
|
|
ULONG age;
|
|
RTM_ENTITY_INFO rei;
|
|
|
|
RtmGetEntityInfo( g_hLocalRoute,
|
|
pri->RouteOwner,
|
|
&rei );
|
|
|
|
GetSystemTimeAsFileTime( (LPFILETIME)&now );
|
|
|
|
//
|
|
// Explicit copy reqd as '&pRdi->LastChanged'
|
|
// might not be 64-bit aligned (its FILETIME)
|
|
//
|
|
(*(FILETIME *)&then) = *(&pRdi->LastChanged);
|
|
|
|
age = (ULONG)((now.QuadPart - then.QuadPart) / 10000000);
|
|
|
|
for (j=0; j<pri->NextHopsList.NumNextHops; j++)
|
|
{
|
|
if (RtmGetNextHopInfo( g_hLocalRoute,
|
|
pri->NextHopsList.NextHops[j],
|
|
&nhi ) is NO_ERROR )
|
|
{
|
|
pRow = &pDestTable->table[pDestTable->dwNumEntries++];
|
|
|
|
RTM_IPV4_GET_ADDR_AND_MASK( pRow->dwForwardDest,
|
|
pRow->dwForwardMask,
|
|
(&pRdi->DestAddress) );
|
|
|
|
pRow->dwForwardPolicy = 0;
|
|
pRow->dwForwardNextHop
|
|
= *((ULONG*)nhi.NextHopAddress.AddrBits);
|
|
|
|
pRow->dwForwardIfIndex = nhi.InterfaceIndex;
|
|
pRow->dwForwardType
|
|
= (pri->RouteOwner == g_hLocalRoute)?3:4;
|
|
|
|
pRow->dwForwardProto
|
|
= PROTO_FROM_PROTO_ID(rei.EntityId.EntityProtocolId);
|
|
|
|
pRow->dwForwardAge = age;
|
|
|
|
pRow->dwForwardNextHopAS= 0; // XXX
|
|
pRow->dwForwardPreference = pri->PrefInfo.Preference;
|
|
pRow->dwForwardMetric1 = pri->PrefInfo.Metric;
|
|
pRow->dwForwardMetric2 = 0;
|
|
pRow->dwForwardMetric3 = 0;
|
|
pRow->dwForwardMetric4 = 0;
|
|
pRow->dwForwardMetric5 = 0;
|
|
|
|
pRow->dwForwardViewSet = pri->BelongsToViews;
|
|
|
|
RtmReleaseNextHopInfo( g_hLocalRoute, &nhi );
|
|
}
|
|
}
|
|
}
|
|
|
|
RtmReleaseRouteInfo( g_hLocalRoute, pri );
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, pri);
|
|
|
|
return dwFinalResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessDestMatching(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Retrieves all destinations matching a given criteria
|
|
|
|
Locks
|
|
|
|
XXX
|
|
|
|
Arguments
|
|
|
|
dwQueryType ACCESS_GET
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPDESTTABLE)
|
|
|
|
Return Value
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IPDESTTABLE pDestTable;
|
|
DWORD count, i;
|
|
DWORD dwNumDests, dwResult, dwNumIndices, dwSpaceCount;
|
|
RTM_NET_ADDRESS naDest;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
PRTM_DEST_INFO prdi;
|
|
|
|
TraceEnter("AccessDestMatching");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pDestTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pDestTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pDestTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessDestMatching");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
prdi = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if (prdi != NULL)
|
|
{
|
|
dwResult = RtmGetExactMatchDestination( g_hLocalRoute,
|
|
&naDest,
|
|
pInEntry->rgdwVarIndex[3], // Proto
|
|
pInEntry->rgdwVarIndex[2], // Views
|
|
prdi );
|
|
if (dwResult is ERROR_NOT_FOUND)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
else
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
AddDestinationRows( prdi,
|
|
pInEntry->rgdwVarIndex[2],
|
|
&count,
|
|
dwSpaceCount,
|
|
pDestTable );
|
|
|
|
RtmReleaseDestInfo( g_hLocalRoute, prdi );
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi);
|
|
}
|
|
|
|
else
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
TraceLeave("AccessDestMatching");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessDestShorter(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPDESTTABLE pDestTable;
|
|
DWORD count, i;
|
|
DWORD dwNumDests, dwResult, dwNumIndices, dwSpaceCount;
|
|
RTM_NET_ADDRESS naDest;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
PRTM_DEST_INFO prdi1, prdi2;
|
|
|
|
TraceEnter("AccessDestShorter");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pDestTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pDestTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pDestTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessDestShorter");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
prdi1 = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if ( prdi1 == NULL)
|
|
{
|
|
TraceLeave("AccessDestShorter");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
prdi2 = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if ( prdi2 == NULL)
|
|
{
|
|
TraceLeave("AccessDestShorter");
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi1);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
|
|
dwResult = RtmGetMostSpecificDestination( g_hLocalRoute,
|
|
&naDest,
|
|
pInEntry->rgdwVarIndex[3],//Proto
|
|
pInEntry->rgdwVarIndex[2],//Views
|
|
prdi1 );
|
|
while (dwResult is NO_ERROR)
|
|
{
|
|
AddDestinationRows( prdi1,
|
|
pInEntry->rgdwVarIndex[2],
|
|
&count,
|
|
dwSpaceCount,
|
|
pDestTable );
|
|
|
|
dwResult = RtmGetLessSpecificDestination( g_hLocalRoute,
|
|
prdi1->DestHandle,
|
|
pInEntry->rgdwVarIndex[3],
|
|
pInEntry->rgdwVarIndex[2],
|
|
prdi2);
|
|
|
|
RtmReleaseDestInfo( g_hLocalRoute, prdi1 );
|
|
|
|
if (dwResult != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
AddDestinationRows( prdi2,
|
|
pInEntry->rgdwVarIndex[2],
|
|
&count,
|
|
dwSpaceCount,
|
|
pDestTable );
|
|
|
|
dwResult = RtmGetLessSpecificDestination( g_hLocalRoute,
|
|
prdi2->DestHandle,
|
|
pInEntry->rgdwVarIndex[3],
|
|
pInEntry->rgdwVarIndex[2],
|
|
prdi1);
|
|
|
|
RtmReleaseDestInfo( g_hLocalRoute, prdi2 );
|
|
|
|
if (dwResult != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwResult is ERROR_NOT_FOUND)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi1);
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi2);
|
|
|
|
TraceLeave("AccessDestShorter");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessDestLonger(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPDESTTABLE pDestTable;
|
|
DWORD count, i;
|
|
DWORD dwNumDests, dwResult, dwNumIndices, dwSpaceCount;
|
|
DWORD dwViews;
|
|
RTM_NET_ADDRESS naDest;
|
|
ULONG ulNumViews, ulNumInfos, ulDestInfoSize;
|
|
RTM_DEST_HANDLE hDest;
|
|
RTM_ENUM_HANDLE hEnum;
|
|
PRTM_DEST_INFO pDestInfos, pRdi;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
|
|
TraceEnter("AccessDestLonger");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pDestTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pDestTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pDestTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessDestLonger");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
|
|
dwResult = RtmCreateDestEnum( g_hLocalRoute,
|
|
pInEntry->rgdwVarIndex[2], // Views
|
|
RTM_ENUM_RANGE,
|
|
&naDest,
|
|
pInEntry->rgdwVarIndex[3], // Proto
|
|
&hEnum );
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
//
|
|
// Count the number of views as we have list of dests in buffer
|
|
//
|
|
|
|
dwViews = pInEntry->rgdwVarIndex[2];
|
|
ulNumViews = 0;
|
|
while (dwViews)
|
|
{
|
|
dwViews &= (dwViews - 1);
|
|
ulNumViews++;
|
|
}
|
|
|
|
ulDestInfoSize = RTM_SIZE_OF_DEST_INFO(ulNumViews);
|
|
|
|
pDestInfos = (PRTM_DEST_INFO) HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
ulDestInfoSize *
|
|
g_rtmProfile.MaxHandlesInEnum
|
|
);
|
|
|
|
if ( pDestInfos != NULL)
|
|
{
|
|
do
|
|
{
|
|
ulNumInfos = g_rtmProfile.MaxHandlesInEnum;
|
|
|
|
dwResult = RtmGetEnumDests( g_hLocalRoute,
|
|
hEnum,
|
|
&ulNumInfos,
|
|
pDestInfos );
|
|
|
|
for (i=0; i<ulNumInfos; i++)
|
|
{
|
|
pRdi=(PRTM_DEST_INFO)(((PUCHAR)pDestInfos)+(i*ulDestInfoSize));
|
|
|
|
AddDestinationRows( pRdi,
|
|
pInEntry->rgdwVarIndex[2],
|
|
&count,
|
|
dwSpaceCount,
|
|
pDestTable );
|
|
}
|
|
|
|
RtmReleaseDests( g_hLocalRoute,
|
|
ulNumInfos,
|
|
pDestInfos );
|
|
|
|
} while (dwResult is NO_ERROR);
|
|
|
|
HeapFree(IPRouterHeap, 0, pDestInfos);
|
|
}
|
|
|
|
else
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtmDeleteEnumHandle( g_hLocalRoute, hEnum );
|
|
}
|
|
|
|
if (dwResult is ERROR_NO_MORE_ITEMS)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
TraceLeave("AccessDestLonger");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AddRouteRows(
|
|
IN PRTM_ROUTE_HANDLE hRoute,
|
|
IN DWORD dwProtocolId,
|
|
OUT DWORD *pdwCount,
|
|
IN DWORD dwSpaceCount,
|
|
OUT PMIB_IPDESTTABLE pRouteTable
|
|
)
|
|
{
|
|
DWORD dwResult, dwRouteProto, j;
|
|
PRTM_ROUTE_INFO pri;
|
|
RTM_NEXTHOP_INFO nhi;
|
|
PMIB_IPDESTROW pRow;
|
|
RTM_NET_ADDRESS naDest;
|
|
RTM_ENTITY_INFO rei;
|
|
|
|
pri = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_ROUTE_INFO(g_rtmProfile.MaxNextHopsInRoute)
|
|
);
|
|
|
|
if ( pri == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
dwResult = RtmGetRouteInfo( g_hLocalRoute,
|
|
hRoute,
|
|
pri,
|
|
&naDest );
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
RtmGetEntityInfo( g_hLocalRoute,
|
|
pri->RouteOwner,
|
|
&rei );
|
|
|
|
dwRouteProto = PROTO_FROM_PROTO_ID(rei.EntityId.EntityProtocolId);
|
|
|
|
if ((dwProtocolId is 0)
|
|
|| (dwRouteProto is dwProtocolId))
|
|
{
|
|
*pdwCount += pri->NextHopsList.NumNextHops;
|
|
|
|
if (dwSpaceCount >= *pdwCount)
|
|
{
|
|
for (j=0; j<pri->NextHopsList.NumNextHops; j++)
|
|
{
|
|
if (RtmGetNextHopInfo( g_hLocalRoute,
|
|
pri->NextHopsList.NextHops[j],
|
|
&nhi ) is NO_ERROR )
|
|
{
|
|
pRow= &pRouteTable->table[pRouteTable->dwNumEntries++];
|
|
|
|
RTM_IPV4_GET_ADDR_AND_MASK( pRow->dwForwardDest,
|
|
pRow->dwForwardMask,
|
|
&naDest );
|
|
|
|
pRow->dwForwardPolicy = 0;
|
|
pRow->dwForwardNextHop
|
|
= *((ULONG*)nhi.NextHopAddress.AddrBits);
|
|
|
|
pRow->dwForwardIfIndex = nhi.InterfaceIndex;
|
|
pRow->dwForwardType
|
|
= (pri->RouteOwner == g_hLocalRoute)?3:4;
|
|
|
|
pRow->dwForwardProto = dwRouteProto;
|
|
pRow->dwForwardAge = 0;
|
|
pRow->dwForwardNextHopAS= 0; // XXX
|
|
pRow->dwForwardPreference = pri->PrefInfo.Preference;
|
|
pRow->dwForwardMetric1 = pri->PrefInfo.Metric;
|
|
pRow->dwForwardMetric2 = 0;
|
|
pRow->dwForwardMetric3 = 0;
|
|
pRow->dwForwardMetric4 = 0;
|
|
pRow->dwForwardMetric5 = 0;
|
|
pRow->dwForwardViewSet = pri->BelongsToViews;
|
|
|
|
RtmReleaseNextHopInfo( g_hLocalRoute, &nhi );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RtmReleaseRouteInfo( g_hLocalRoute, pri );
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, pri);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AddRouteRowsOnDest(
|
|
IN PRTM_DEST_INFO prdi,
|
|
IN PMIB_OPAQUE_QUERY pInEntry,
|
|
OUT DWORD *pdwCount,
|
|
IN DWORD dwSpaceCount,
|
|
OUT PMIB_IPDESTTABLE pRouteTable
|
|
)
|
|
{
|
|
DWORD count, i;
|
|
PHANDLE RouteHandles;
|
|
ULONG ulNumHandles;
|
|
RTM_ENUM_HANDLE hEnum;
|
|
DWORD dwResult;
|
|
|
|
RouteHandles = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
|
|
);
|
|
|
|
if ( RouteHandles == NULL)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
dwResult = RtmCreateRouteEnum( g_hLocalRoute,
|
|
prdi->DestHandle,
|
|
pInEntry->rgdwVarIndex[2], // Views
|
|
RTM_ENUM_ALL_ROUTES,
|
|
NULL,
|
|
RTM_MATCH_NONE,
|
|
NULL,
|
|
0,
|
|
&hEnum );
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
do
|
|
{
|
|
ulNumHandles = g_rtmProfile.MaxHandlesInEnum;
|
|
|
|
dwResult = RtmGetEnumRoutes( g_hLocalRoute,
|
|
hEnum,
|
|
&ulNumHandles,
|
|
RouteHandles );
|
|
|
|
for (i=0; i<ulNumHandles; i++)
|
|
{
|
|
AddRouteRows( RouteHandles[i],
|
|
pInEntry->rgdwVarIndex[3],//Proto
|
|
pdwCount,
|
|
dwSpaceCount,
|
|
pRouteTable );
|
|
}
|
|
|
|
RtmReleaseRoutes( g_hLocalRoute,
|
|
ulNumHandles,
|
|
RouteHandles );
|
|
|
|
} while (dwResult is NO_ERROR);
|
|
|
|
if (dwResult is ERROR_NO_MORE_ITEMS)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
RtmDeleteEnumHandle( g_hLocalRoute, hEnum );
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, RouteHandles);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessRouteMatching(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPDESTTABLE pRouteTable;
|
|
DWORD dwResult, dwNumIndices, dwSpaceCount;
|
|
DWORD count;
|
|
RTM_NET_ADDRESS naDest;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
PRTM_DEST_INFO prdi;
|
|
|
|
TraceEnter("AccessRouteMatching");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pRouteTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pRouteTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pRouteTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessRouteMatching");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
prdi = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if ( prdi == NULL)
|
|
{
|
|
TraceLeave("AccessRouteMatching");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
|
|
dwResult = RtmGetExactMatchDestination( g_hLocalRoute,
|
|
&naDest,
|
|
pInEntry->rgdwVarIndex[3],
|
|
pInEntry->rgdwVarIndex[2],
|
|
prdi );
|
|
|
|
if (dwResult is ERROR_NOT_FOUND)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
else
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
dwResult = AddRouteRowsOnDest( prdi,
|
|
pInEntry,
|
|
&count,
|
|
dwSpaceCount,
|
|
pRouteTable );
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi);
|
|
|
|
TraceLeave("AccessRouteMatching");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessRouteShorter(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPDESTTABLE pRouteTable;
|
|
DWORD dwResult, dwNumIndices, dwSpaceCount;
|
|
DWORD count;
|
|
RTM_NET_ADDRESS naDest;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
PRTM_DEST_INFO prdi1, prdi2;
|
|
|
|
TraceEnter("AccessRouteShorter");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pRouteTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pRouteTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pRouteTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessRouteShorter");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
prdi1 = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if ( prdi1 == NULL)
|
|
{
|
|
TraceLeave("AccessRouteShorter");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
prdi2 = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
RTM_SIZE_OF_DEST_INFO(g_rtmProfile.NumberOfViews)
|
|
);
|
|
|
|
if ( prdi2 == NULL)
|
|
{
|
|
TraceLeave("AccessRouteShorter");
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi1);
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
|
|
dwResult = RtmGetMostSpecificDestination( g_hLocalRoute,
|
|
&naDest,
|
|
pInEntry->rgdwVarIndex[3],//Proto
|
|
pInEntry->rgdwVarIndex[2],//Views
|
|
prdi1 );
|
|
while (dwResult is NO_ERROR)
|
|
{
|
|
AddRouteRowsOnDest( prdi1,
|
|
pInEntry,
|
|
&count,
|
|
dwSpaceCount,
|
|
pRouteTable );
|
|
|
|
dwResult = RtmGetLessSpecificDestination( g_hLocalRoute,
|
|
prdi1->DestHandle,
|
|
pInEntry->rgdwVarIndex[3],
|
|
pInEntry->rgdwVarIndex[2],
|
|
prdi2);
|
|
|
|
RtmReleaseDestInfo( g_hLocalRoute, prdi1 );
|
|
|
|
if (dwResult != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
AddRouteRowsOnDest( prdi2,
|
|
pInEntry,
|
|
&count,
|
|
dwSpaceCount,
|
|
pRouteTable );
|
|
|
|
dwResult = RtmGetLessSpecificDestination( g_hLocalRoute,
|
|
prdi2->DestHandle,
|
|
pInEntry->rgdwVarIndex[3],
|
|
pInEntry->rgdwVarIndex[2],
|
|
prdi1);
|
|
|
|
RtmReleaseDestInfo( g_hLocalRoute, prdi2 );
|
|
|
|
if (dwResult != NO_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwResult is ERROR_NOT_FOUND)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, prdi1);
|
|
HeapFree(IPRouterHeap, 0, prdi2);
|
|
|
|
TraceLeave("AccessRouteShorter");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
AccessRouteLonger(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
{
|
|
PMIB_IPDESTTABLE pRouteTable;
|
|
DWORD count, i;
|
|
DWORD dwResult, dwNumIndices, dwSpaceCount;
|
|
RTM_NET_ADDRESS naDest;
|
|
ULONG ulNumHandles;
|
|
RTM_ENUM_HANDLE hEnum;
|
|
PHANDLE RouteHandles;
|
|
DWORD dwOffset = MAX_MIB_OFFSET + sizeof(DWORD);
|
|
|
|
TraceEnter("AccessRouteLonger");
|
|
|
|
count = dwSpaceCount = 0;
|
|
|
|
pRouteTable = NULL;
|
|
|
|
if (*pOutEntrySize > dwOffset)
|
|
{
|
|
dwSpaceCount = (*pOutEntrySize - dwOffset)
|
|
/ sizeof(MIB_IPDESTROW);
|
|
|
|
pRouteTable = (PMIB_IPDESTTABLE)(pOutEntry->rgbyData);
|
|
|
|
pRouteTable->dwNumEntries = 0;
|
|
}
|
|
|
|
dwNumIndices = dwInEntrySize/sizeof(DWORD) - 1;
|
|
|
|
if ((dwNumIndices < 4) or
|
|
(dwQueryType isnot ACCESS_GET))
|
|
{
|
|
TraceLeave("AccessRouteLonger");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
RouteHandles = HeapAlloc(
|
|
IPRouterHeap,
|
|
0,
|
|
g_rtmProfile.MaxHandlesInEnum * sizeof(HANDLE)
|
|
);
|
|
|
|
if ( RouteHandles == NULL)
|
|
{
|
|
TraceLeave("AccessRouteLonger");
|
|
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RTM_IPV4_SET_ADDR_AND_MASK(&naDest,
|
|
pInEntry->rgdwVarIndex[0], // Addr
|
|
pInEntry->rgdwVarIndex[1]); // Mask
|
|
|
|
dwResult = RtmCreateRouteEnum( g_hLocalRoute,
|
|
NULL,
|
|
pInEntry->rgdwVarIndex[2], // Views
|
|
RTM_ENUM_RANGE,
|
|
&naDest,
|
|
RTM_MATCH_NONE,
|
|
NULL,
|
|
0,
|
|
&hEnum );
|
|
|
|
if (dwResult is NO_ERROR)
|
|
{
|
|
do
|
|
{
|
|
ulNumHandles = g_rtmProfile.MaxHandlesInEnum;
|
|
|
|
dwResult = RtmGetEnumRoutes( g_hLocalRoute,
|
|
hEnum,
|
|
&ulNumHandles,
|
|
RouteHandles );
|
|
|
|
for (i=0; i<ulNumHandles; i++)
|
|
{
|
|
AddRouteRows( RouteHandles[i],
|
|
pInEntry->rgdwVarIndex[3], // Proto
|
|
&count,
|
|
dwSpaceCount,
|
|
pRouteTable );
|
|
}
|
|
|
|
RtmReleaseRoutes( g_hLocalRoute,
|
|
ulNumHandles,
|
|
RouteHandles );
|
|
|
|
} while (dwResult is NO_ERROR);
|
|
|
|
RtmDeleteEnumHandle( g_hLocalRoute, hEnum );
|
|
}
|
|
|
|
if (dwResult is ERROR_NO_MORE_ITEMS)
|
|
{
|
|
dwResult = NO_ERROR;
|
|
}
|
|
|
|
*pOutEntrySize = dwOffset + count * sizeof(MIB_IPDESTROW);
|
|
|
|
if (dwSpaceCount < count)
|
|
{
|
|
dwResult = ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
HeapFree(IPRouterHeap, 0, RouteHandles);
|
|
|
|
TraceLeave("AccessRouteLonger");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
PINTERFACE_ROUTE_INFO
|
|
ConvertDestRowToRouteInfo(
|
|
IN PMIB_IPDESTROW pMibRow
|
|
)
|
|
{
|
|
PINTERFACE_ROUTE_INFO pRouteInfo = (PINTERFACE_ROUTE_INFO)pMibRow;
|
|
|
|
//
|
|
// Note that it is important to note that here
|
|
// the source and dest buffers are the same
|
|
//
|
|
|
|
pRouteInfo->dwRtInfoPreference = pMibRow->dwForwardPreference;
|
|
pRouteInfo->dwRtInfoViewSet = pMibRow->dwForwardViewSet;
|
|
|
|
#if 0
|
|
// Removed this since metric=0 is legal for routes to the loopback
|
|
// interface.
|
|
|
|
// Make sure Metric1 isn't 0
|
|
|
|
if (pRouteInfo->dwForwardMetric1 is 0)
|
|
{
|
|
pRouteInfo->dwForwardMetric1 = 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
return pRouteInfo;
|
|
}
|
|
|
|
DWORD
|
|
AccessIpMatchingRoute(
|
|
DWORD dwQueryType,
|
|
DWORD dwInEntrySize,
|
|
PMIB_OPAQUE_QUERY pInEntry,
|
|
PDWORD pOutEntrySize,
|
|
PMIB_OPAQUE_INFO pOutEntry,
|
|
PBOOL pbCache
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to add, delete or set a route (IP Dest Row)
|
|
|
|
Arguments
|
|
|
|
dwQueryType Create, Set, Delete permitted
|
|
pInEntry Dest, Mask, IfIndex, and NextHop for the row filled in the
|
|
rgdwVarIndex field.
|
|
pOutEntrySize MAX_MIB_OFFSET + sizeof(MIB_IPDESTROW). For Sets the
|
|
OutBuffer has the row to set
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or some error code defined in iprtrmib
|
|
|
|
--*/
|
|
|
|
{
|
|
PMIB_IPDESTROW pIpRouteRow;
|
|
DWORD dwMask, i;
|
|
DWORD dwResult;
|
|
HANDLE hRtmHandle;
|
|
|
|
TraceEnter("AccessIpMatchingRoute");
|
|
|
|
pIpRouteRow = (PMIB_IPDESTROW)(pOutEntry->rgbyData);
|
|
|
|
if (dwQueryType != ACCESS_DELETE_ENTRY)
|
|
{
|
|
// Make sure we have a buffer of the right size
|
|
|
|
if(*pOutEntrySize < MAX_MIB_OFFSET + sizeof(MIB_IPDESTROW))
|
|
{
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPDESTROW);
|
|
|
|
TraceLeave("AccessIpMatchingRoute");
|
|
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
*pOutEntrySize = MAX_MIB_OFFSET + sizeof(MIB_IPDESTROW);
|
|
|
|
pOutEntry->dwId = ROUTE_MATCHING;
|
|
}
|
|
else
|
|
{
|
|
MIB_IPDESTROW IpRouteRow;
|
|
|
|
pIpRouteRow = &IpRouteRow;
|
|
|
|
// Do you need to check the input buffer size here ?
|
|
|
|
pIpRouteRow->dwForwardDest = pInEntry->rgdwVarIndex[0];
|
|
pIpRouteRow->dwForwardMask = pInEntry->rgdwVarIndex[1];
|
|
pIpRouteRow->dwForwardIfIndex = pInEntry->rgdwVarIndex[2];
|
|
pIpRouteRow->dwForwardNextHop = pInEntry->rgdwVarIndex[3];
|
|
pIpRouteRow->dwForwardProto = pInEntry->rgdwVarIndex[4];
|
|
}
|
|
|
|
//
|
|
// Do validation before adding or deleting the route
|
|
//
|
|
|
|
if((pIpRouteRow->dwForwardDest & pIpRouteRow->dwForwardMask) isnot
|
|
pIpRouteRow->dwForwardDest)
|
|
{
|
|
Trace2(ERR,
|
|
"AccessIpMatchingRoute: Dest %d.%d.%d.%d and Mask %d.%d.%d.%d wrong",
|
|
PRINT_IPADDR(pIpRouteRow->dwForwardDest),
|
|
PRINT_IPADDR(pIpRouteRow->dwForwardMask));
|
|
|
|
TraceLeave("AccessIpMatchingRoute");
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Get the RTM handle used to add or delete the route
|
|
//
|
|
|
|
hRtmHandle = NULL;
|
|
|
|
for(i = 0;
|
|
i < sizeof(g_rgRtmHandles)/sizeof(RTM_HANDLE_INFO);
|
|
i++)
|
|
{
|
|
if(pIpRouteRow->dwForwardProto is g_rgRtmHandles[i].dwProtoId)
|
|
{
|
|
hRtmHandle = g_rgRtmHandles[i].hRouteHandle;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(hRtmHandle is NULL)
|
|
{
|
|
Trace1(ERR,
|
|
"AccessIpMatchingRoute: Protocol %d not valid",
|
|
pIpRouteRow->dwForwardProto);
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (dwQueryType)
|
|
{
|
|
case ACCESS_CREATE_ENTRY:
|
|
case ACCESS_SET:
|
|
|
|
//
|
|
// Add the RTM route from the ip row entry
|
|
//
|
|
|
|
ENTER_READER(ICB_LIST);
|
|
|
|
dwMask = GetBestNextHopMaskGivenIndex(pIpRouteRow->dwForwardIfIndex,
|
|
pIpRouteRow->dwForwardNextHop);
|
|
|
|
EXIT_LOCK(ICB_LIST);
|
|
|
|
//
|
|
// Convert input to INTERFACE_ROUTE_INFO and add
|
|
//
|
|
|
|
dwResult = AddRtmRoute(hRtmHandle,
|
|
ConvertDestRowToRouteInfo(pIpRouteRow),
|
|
IP_VALID_ROUTE | IP_STACK_ROUTE,
|
|
dwMask,
|
|
pIpRouteRow->dwForwardAge,
|
|
NULL);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(MIB,
|
|
"AccessIpMatchingRoute: Could not set route to RTM: Dest %x\n",
|
|
pIpRouteRow->dwForwardDest);
|
|
}
|
|
|
|
break;
|
|
|
|
case ACCESS_DELETE_ENTRY:
|
|
|
|
dwResult = DeleteRtmRoute(hRtmHandle,
|
|
ConvertDestRowToRouteInfo(pIpRouteRow));
|
|
break;
|
|
|
|
default:
|
|
|
|
dwResult = ERROR_INVALID_FUNCTION;
|
|
}
|
|
|
|
TraceLeave("AccessIpMatchingRoute");
|
|
|
|
return dwResult;
|
|
}
|