957 lines
20 KiB
C
957 lines
20 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "allinc.h"
|
||
|
|
||
|
PCHAR g_pszMsg[] = {
|
||
|
"Packet Received",
|
||
|
"MFE Deleted",
|
||
|
"Wrong I/f Upcall"
|
||
|
};
|
||
|
|
||
|
DWORD
|
||
|
QueueAsyncFunction(
|
||
|
WORKERFUNCTION pfnFunction,
|
||
|
PVOID pvContext,
|
||
|
BOOL bAlertable
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
ValidateMfe(
|
||
|
IN OUT PIPMCAST_MFE pMfe
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
HandleRcvPkt(
|
||
|
PVOID pvContext
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PIP_HEADER pHdr;
|
||
|
DWORD dwResult, dwOldIf;
|
||
|
ULONG ulIndex;
|
||
|
|
||
|
PIPMCAST_PKT_MSG pPktInfo;
|
||
|
PIPMCAST_NOTIFICATION pMsg;
|
||
|
|
||
|
ulIndex = PtrToUlong(pvContext);
|
||
|
|
||
|
pMsg = &(g_rginMcastMsg[ulIndex].msg);
|
||
|
pPktInfo = &(pMsg->ipmPkt);
|
||
|
|
||
|
pHdr = (PIP_HEADER)(pPktInfo->rgbyData);
|
||
|
|
||
|
Trace3(MCAST,
|
||
|
"HandleRcvPkt: Rcvd pkt from %d.%d.%d.%d to %d.%d.%d.%d on %d",
|
||
|
PRINT_IPADDR(pHdr->dwSrc),
|
||
|
PRINT_IPADDR(pHdr->dwDest),
|
||
|
pPktInfo->dwInIfIndex);
|
||
|
|
||
|
dwResult = g_pfnMgmNewPacket(pHdr->dwSrc,
|
||
|
pHdr->dwDest,
|
||
|
pPktInfo->dwInIfIndex,
|
||
|
pPktInfo->dwInNextHopAddress,
|
||
|
pPktInfo->cbyDataLen,
|
||
|
pPktInfo->rgbyData);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"HandleRcvPkt: MGM returned error %d\n", dwResult);
|
||
|
}
|
||
|
|
||
|
PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
|
||
|
g_hMcastEvents[ulIndex]);
|
||
|
|
||
|
ExitRouterApi();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HandleDeleteMfe(
|
||
|
PVOID pvContext
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
ULONG ulIndex, i;
|
||
|
|
||
|
PIPMCAST_MFE_MSG pMfeInfo;
|
||
|
PIPMCAST_NOTIFICATION pMsg;
|
||
|
|
||
|
ulIndex = PtrToUlong(pvContext);
|
||
|
|
||
|
pMsg = &(g_rginMcastMsg[ulIndex].msg);
|
||
|
pMfeInfo = &(pMsg->immMfe);
|
||
|
|
||
|
Trace1(MCAST,
|
||
|
"HandleDeleteMfe: Kernel deleted %d MFEs\n",
|
||
|
pMfeInfo->ulNumMfes);
|
||
|
|
||
|
for(i = 0; i < pMfeInfo->ulNumMfes; i++)
|
||
|
{
|
||
|
Trace3(MCAST,
|
||
|
"HandleDeleteMfe: Group %d.%d.%d.%d Source %d.%d.%d.%d/%d.%d.%d.%d\n",
|
||
|
PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwGroup),
|
||
|
PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwSource),
|
||
|
PRINT_IPADDR(pMsg->immMfe.idmMfe[i].dwSrcMask));
|
||
|
}
|
||
|
|
||
|
dwResult = g_pfnMgmMfeDeleted(pMfeInfo->ulNumMfes,
|
||
|
pMfeInfo->idmMfe);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"HandleDeleteMfe: MGM returned error %d\n", dwResult);
|
||
|
}
|
||
|
|
||
|
PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
|
||
|
g_hMcastEvents[ulIndex]);
|
||
|
|
||
|
ExitRouterApi();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HandleWrongIfUpcall(
|
||
|
PVOID pvContext
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PIP_HEADER pHdr;
|
||
|
DWORD dwResult, dwOldIf;
|
||
|
ULONG ulIndex;
|
||
|
|
||
|
PIPMCAST_PKT_MSG pPktInfo;
|
||
|
PIPMCAST_NOTIFICATION pMsg;
|
||
|
|
||
|
ulIndex = PtrToUlong(pvContext);
|
||
|
|
||
|
pMsg = &(g_rginMcastMsg[ulIndex].msg);
|
||
|
pPktInfo = &(pMsg->ipmPkt);
|
||
|
|
||
|
pHdr = (PIP_HEADER)(pPktInfo->rgbyData);
|
||
|
|
||
|
Trace3(MCAST,
|
||
|
"HandleWrongIfUpcall: Pkt from %d.%d.%d.%d to %d.%d.%d.%d on %d is wrong",
|
||
|
PRINT_IPADDR(pHdr->dwSrc),
|
||
|
PRINT_IPADDR(pHdr->dwDest),
|
||
|
pPktInfo->dwInIfIndex);
|
||
|
|
||
|
dwResult = g_pfnMgmWrongIf(pHdr->dwSrc,
|
||
|
pHdr->dwDest,
|
||
|
pPktInfo->dwInIfIndex,
|
||
|
pPktInfo->dwInNextHopAddress,
|
||
|
pPktInfo->cbyDataLen,
|
||
|
pPktInfo->rgbyData);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"HandleWrongIfUpcall: MGM returned error %d\n", dwResult);
|
||
|
}
|
||
|
|
||
|
PostNotificationForMcastEvents(&(g_rginMcastMsg[ulIndex]),
|
||
|
g_hMcastEvents[ulIndex]);
|
||
|
|
||
|
ExitRouterApi();
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HandleMcastNotification(
|
||
|
DWORD dwIndex
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
ULONG i;
|
||
|
|
||
|
PIPMCAST_NOTIFICATION pMsg;
|
||
|
|
||
|
|
||
|
pMsg = &(g_rginMcastMsg[dwIndex].msg);
|
||
|
|
||
|
|
||
|
//
|
||
|
// read the notification
|
||
|
//
|
||
|
|
||
|
|
||
|
Trace1(MCAST,
|
||
|
"HandleMcastNotification: Notification received for %s\n",
|
||
|
g_pszMsg[pMsg->dwEvent]);
|
||
|
|
||
|
switch(pMsg->dwEvent)
|
||
|
{
|
||
|
case IPMCAST_RCV_PKT_MSG:
|
||
|
{
|
||
|
QueueAsyncFunction(HandleRcvPkt,
|
||
|
(PVOID)(ULONG_PTR)dwIndex,
|
||
|
FALSE);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IPMCAST_DELETE_MFE_MSG:
|
||
|
{
|
||
|
QueueAsyncFunction(HandleDeleteMfe,
|
||
|
(PVOID)(ULONG_PTR)dwIndex,
|
||
|
FALSE);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IPMCAST_WRONG_IF_MSG:
|
||
|
{
|
||
|
QueueAsyncFunction(HandleWrongIfUpcall,
|
||
|
(PVOID)(ULONG_PTR)dwIndex,
|
||
|
FALSE);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"HandleMcastNotification: Bad event code %d\n",
|
||
|
pMsg->dwEvent);
|
||
|
|
||
|
PostNotificationForMcastEvents(&(g_rginMcastMsg[dwIndex]),
|
||
|
g_hMcastEvents[dwIndex]);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PostNotificationForMcastEvents(
|
||
|
PMCAST_OVERLAPPED pOverlapped,
|
||
|
HANDLE hEvent
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
NTSTATUS nsStatus;
|
||
|
|
||
|
nsStatus = SendIoctlToMcastDevice(IOCTL_IPMCAST_POST_NOTIFICATION,
|
||
|
hEvent,
|
||
|
&pOverlapped->ioStatus,
|
||
|
&pOverlapped->msg,
|
||
|
sizeof(IPMCAST_NOTIFICATION),
|
||
|
&pOverlapped->msg,
|
||
|
sizeof(IPMCAST_NOTIFICATION));
|
||
|
|
||
|
if((nsStatus isnot STATUS_SUCCESS) and
|
||
|
(nsStatus isnot STATUS_PENDING))
|
||
|
{
|
||
|
Trace1(ERR,
|
||
|
"PostNotificationForMcastEvents: Error %X",
|
||
|
nsStatus);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
SendIoctlToMcastDevice(
|
||
|
DWORD dwIoctl,
|
||
|
HANDLE hEvent,
|
||
|
PIO_STATUS_BLOCK pIoStatus,
|
||
|
PVOID pvInBuffer,
|
||
|
DWORD dwInBufLen,
|
||
|
PVOID pvOutBuffer,
|
||
|
DWORD dwOutBufLen
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS ntStatus;
|
||
|
|
||
|
ntStatus = NtDeviceIoControlFile(g_hMcastDevice,
|
||
|
hEvent,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
pIoStatus,
|
||
|
dwIoctl,
|
||
|
pvInBuffer,
|
||
|
dwInBufLen,
|
||
|
pvOutBuffer,
|
||
|
dwOutBufLen);
|
||
|
|
||
|
return ntStatus;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
SetMfe(
|
||
|
PIPMCAST_MFE pMfe
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
|
||
|
dwResult = ValidateMfe(pMfe);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
//
|
||
|
// Something bad happened while validating the MFE
|
||
|
//
|
||
|
|
||
|
Trace1(ERR,
|
||
|
"SetMfe: Error %d validating MFE",
|
||
|
dwResult);
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_MFE,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
pMfe,
|
||
|
SIZEOF_MFE(pMfe->ulNumOutIf),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"SetMfe: NtStatus %x while setting MFE",
|
||
|
dwResult);
|
||
|
}
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
GetMfe(
|
||
|
PIPMCAST_MFE_STATS pMfeStats
|
||
|
)
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
|
||
|
dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_GET_MFE,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
pMfeStats,
|
||
|
SIZEOF_MFE_STATS(pMfeStats->ulNumOutIf),
|
||
|
pMfeStats,
|
||
|
SIZEOF_MFE_STATS(pMfeStats->ulNumOutIf));
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"GetMfe: NtStatus %x while getting MFE",
|
||
|
dwResult);
|
||
|
}
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
DeleteMfe(
|
||
|
PIPMCAST_DELETE_MFE pDelMfe
|
||
|
)
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
|
||
|
dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_DELETE_MFE,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
pDelMfe,
|
||
|
sizeof(IPMCAST_DELETE_MFE),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace1(MCAST,
|
||
|
"DeleteMfe: NtStatus %x while deleting MFE",
|
||
|
dwResult);
|
||
|
}
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ActivateMcastLimits(
|
||
|
PICB picb
|
||
|
)
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
IPMCAST_IF_TTL iitTtl;
|
||
|
DWORD dwTtl = picb->dwMcastTtl;
|
||
|
|
||
|
// Set the TTL threshold
|
||
|
|
||
|
iitTtl.dwIfIndex = picb->dwIfIndex;
|
||
|
iitTtl.byTtl = LOBYTE(LOWORD(dwTtl));
|
||
|
|
||
|
dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_TTL,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
&iitTtl,
|
||
|
sizeof(IPMCAST_IF_TTL),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace2(ERR,
|
||
|
"SetMcastTtl: NtStatus %x from SendIoctl when setting TTL for %S",
|
||
|
dwResult,
|
||
|
picb->pwszName);
|
||
|
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the rate limit for multicast traffic on an interface.
|
||
|
// Currently, the kernel does not support rate limiting.
|
||
|
//
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
SetMcastLimits(
|
||
|
PICB picb,
|
||
|
DWORD dwTtl,
|
||
|
DWORD dwRateLimit
|
||
|
)
|
||
|
{
|
||
|
if (dwTtl > 255)
|
||
|
{
|
||
|
Trace2(ERR,
|
||
|
"SetMcastTtl: TTL for %S is %d which is invalid",
|
||
|
picb->pwszName,
|
||
|
dwTtl);
|
||
|
|
||
|
return ERROR_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
picb->dwMcastTtl = dwTtl;
|
||
|
|
||
|
//
|
||
|
// Set the rate limit for multicast traffic on an interface.
|
||
|
// Currently, the kernel does not support rate limiting, so
|
||
|
// the only valid value is 0 (=none).
|
||
|
//
|
||
|
|
||
|
if (dwRateLimit != 0)
|
||
|
{
|
||
|
Trace2(ERR,
|
||
|
"SetMcastRateLimit: RateLimit for %S is %d which is invalid",
|
||
|
picb->pwszName,
|
||
|
dwRateLimit);
|
||
|
|
||
|
return ERROR_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
picb->dwMcastRateLimit = dwRateLimit;
|
||
|
|
||
|
if ( picb->dwOperationalState is IF_OPER_STATUS_OPERATIONAL )
|
||
|
{
|
||
|
return ActivateMcastLimits(picb);
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
SetMcastLimitInfo(
|
||
|
PICB picb,
|
||
|
PRTR_INFO_BLOCK_HEADER pInfoHdr
|
||
|
)
|
||
|
/*++
|
||
|
Routine Description:
|
||
|
Sets the TTL and rate limit info associated with an interface.
|
||
|
Arguments:
|
||
|
picb The ICB of the interface
|
||
|
Called by:
|
||
|
AddInterface() in iprtrmgr.c
|
||
|
SetInterfaceInfo() in iprtrmgr.c
|
||
|
Locks:
|
||
|
BOUNDARY_TABLE for writing
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwResult = NO_ERROR,
|
||
|
i, j;
|
||
|
|
||
|
PRTR_TOC_ENTRY pToc;
|
||
|
|
||
|
PMIB_MCAST_LIMIT_ROW pLimit;
|
||
|
|
||
|
BOOL bFound;
|
||
|
|
||
|
Trace1( MCAST, "ENTERED SetMcastLimitInfo for If %x", picb->dwIfIndex );
|
||
|
|
||
|
pToc = GetPointerToTocEntry(IP_MCAST_LIMIT_INFO, pInfoHdr);
|
||
|
|
||
|
if (pToc is NULL)
|
||
|
{
|
||
|
// No TOC means no change
|
||
|
Trace0( MCAST, "LEFT SetMcastLimitInfo" );
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
pLimit = (PMIB_MCAST_LIMIT_ROW)GetInfoFromTocEntry(pInfoHdr, pToc);
|
||
|
|
||
|
if (pLimit is NULL)
|
||
|
{
|
||
|
Trace0( MCAST, "LEFT SetMcastLimitInfo" );
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
dwResult = SetMcastLimits( picb, pLimit->dwTtl, pLimit->dwRateLimit );
|
||
|
|
||
|
Trace0( MCAST, "LEFT SetMcastLimitInfo" );
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
SetMcastOnIf(
|
||
|
PICB picb,
|
||
|
BOOL bActivate
|
||
|
)
|
||
|
{
|
||
|
DWORD dwResult;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
IPMCAST_IF_STATE iisState;
|
||
|
|
||
|
iisState.dwIfIndex = picb->dwIfIndex;
|
||
|
iisState.byState = bActivate?1:0;
|
||
|
|
||
|
dwResult = SendIoctlToMcastDevice(IOCTL_IPMCAST_SET_IF_STATE,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
&iisState,
|
||
|
sizeof(IPMCAST_IF_STATE),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR)
|
||
|
{
|
||
|
Trace2(ERR,
|
||
|
"SetMcastOnIf: NtStatus %x from SendIoctl for %S",
|
||
|
dwResult,
|
||
|
picb->pwszName);
|
||
|
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
StartMulticast(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
DWORD i, dwStart;
|
||
|
NTSTATUS nStatus;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
|
||
|
dwStart = 1;
|
||
|
|
||
|
nStatus = SendIoctlToMcastDevice(IOCTL_IPMCAST_START_STOP,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
&dwStart,
|
||
|
sizeof(DWORD),
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
if(nStatus isnot STATUS_SUCCESS)
|
||
|
{
|
||
|
Trace1(MCAST, "StartMulticast: Error %x starting driver",
|
||
|
nStatus);
|
||
|
|
||
|
return ERROR_OPEN_FAILED;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < NUM_MCAST_IRPS; i++)
|
||
|
{
|
||
|
PostNotificationForMcastEvents(&(g_rginMcastMsg[i]),
|
||
|
g_hMcastEvents[i]);
|
||
|
}
|
||
|
|
||
|
// Start up mrinfo and mtrace services
|
||
|
StartMcMisc();
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
ValidateMfe(
|
||
|
IN OUT PIPMCAST_MFE pMfe
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Locks:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
NO_ERROR
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PADAPTER_INFO pBinding;
|
||
|
ULONG i;
|
||
|
|
||
|
|
||
|
ENTER_READER(BINDING_LIST);
|
||
|
|
||
|
//
|
||
|
// First find the interface index for incoming i/f
|
||
|
// If there are no outgoing interfaces, then this is a NEGATIVE
|
||
|
// MFE and the incoming interface index must be 0 (and need not
|
||
|
// be mapped)
|
||
|
//
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
if(pMfe->ulNumOutIf is 0)
|
||
|
{
|
||
|
IpRtAssert(pMfe->dwInIfIndex is 0);
|
||
|
|
||
|
pMfe->dwInIfIndex = 0;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
for(i = 0; i < pMfe->ulNumOutIf; i++)
|
||
|
{
|
||
|
pBinding = GetInterfaceBinding(pMfe->rgioOutInfo[i].dwOutIfIndex);
|
||
|
|
||
|
if(!pBinding)
|
||
|
{
|
||
|
Trace1(ERR,
|
||
|
"ValidateMfe: Unable to find binding for outgoing i/f %d",
|
||
|
pMfe->rgioOutInfo[i].dwOutIfIndex);
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
return ERROR_INVALID_INDEX;
|
||
|
}
|
||
|
|
||
|
|
||
|
if(pBinding->bBound)
|
||
|
{
|
||
|
//
|
||
|
// valid index
|
||
|
//
|
||
|
|
||
|
pMfe->rgioOutInfo[i].dwOutIfIndex = pBinding->dwIfIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Demand dial interface
|
||
|
//
|
||
|
|
||
|
pMfe->rgioOutInfo[i].dwOutIfIndex = INVALID_IF_INDEX;
|
||
|
|
||
|
pMfe->rgioOutInfo[i].dwDialContext = pBinding->dwSeqNumber;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXIT_LOCK(BINDING_LIST);
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
GetInterfaceMcastCounters(
|
||
|
IN PICB picb,
|
||
|
OUT PIP_MCAST_COUNTER_INFO pOutBuffer
|
||
|
)
|
||
|
{
|
||
|
DWORD dwAdapterId,dwResult;
|
||
|
PPROTO_CB pcbOwner;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
ULONG Request = picb->dwIfIndex;
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
dwResult = NO_ERROR;
|
||
|
|
||
|
hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
|
||
|
|
||
|
if(hEvent is NULL)
|
||
|
{
|
||
|
dwResult = GetLastError();
|
||
|
|
||
|
Trace1(ERR,
|
||
|
"GetInterfaceMcastCounters: Error %d creating event",
|
||
|
dwResult);
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
dwResult = NtDeviceIoControlFile(g_hIpDevice,
|
||
|
hEvent,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&ioStatus,
|
||
|
IOCTL_IP_GET_MCAST_COUNTERS,
|
||
|
&Request,
|
||
|
sizeof(Request),
|
||
|
pOutBuffer,
|
||
|
sizeof(IP_MCAST_COUNTER_INFO));
|
||
|
|
||
|
if(dwResult is STATUS_PENDING)
|
||
|
{
|
||
|
Trace0(ERR,
|
||
|
"GetInterfaceMcastCounters: Pending from ioctl");
|
||
|
|
||
|
dwResult = WaitForSingleObject(hEvent,
|
||
|
INFINITE);
|
||
|
|
||
|
if(dwResult isnot WAIT_OBJECT_0) // 0
|
||
|
{
|
||
|
Trace1(ERR,
|
||
|
"GetInterfaceMcastCounters: Error %d from wait",
|
||
|
dwResult);
|
||
|
|
||
|
dwResult = GetLastError();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwResult = STATUS_SUCCESS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
GetInterfaceMcastStatistics(
|
||
|
IN PICB picb,
|
||
|
OUT PMIB_IPMCAST_IF_ENTRY pOutBuffer
|
||
|
)
|
||
|
{
|
||
|
DWORD dwAdapterId,dwResult;
|
||
|
PPROTO_CB pcbOwner;
|
||
|
IO_STATUS_BLOCK ioStatus;
|
||
|
IP_MCAST_COUNTER_INFO ifStats;
|
||
|
|
||
|
dwResult = NO_ERROR;
|
||
|
|
||
|
TraceEnter("GetInterfaceMcastStatistics");
|
||
|
|
||
|
pOutBuffer->dwIfIndex = picb->dwIfIndex;
|
||
|
pOutBuffer->dwTtl = picb->dwMcastTtl;
|
||
|
pOutBuffer->dwRateLimit = 0; // XXX change when we have rate limiting
|
||
|
|
||
|
dwResult = GetInterfaceMcastCounters(picb, &ifStats);
|
||
|
if (dwResult isnot STATUS_SUCCESS)
|
||
|
{
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
pOutBuffer->ulOutMcastOctets = (ULONG)ifStats.OutMcastOctets;
|
||
|
pOutBuffer->ulInMcastOctets = (ULONG)ifStats.InMcastOctets;
|
||
|
pOutBuffer->dwProtocol = 2; // "local" (static only) is default
|
||
|
|
||
|
dwResult = MulticastOwner(picb, &pcbOwner, NULL);
|
||
|
if (dwResult == NO_ERROR && pcbOwner != NULL) {
|
||
|
switch(pcbOwner->dwProtocolId) {
|
||
|
#ifdef MS_IP_DVMRP
|
||
|
case MS_IP_DVMRP: pOutBuffer->dwProtocol = 4; break;
|
||
|
#endif
|
||
|
#ifdef MS_IP_MOSPF
|
||
|
case MS_IP_MOSPF: pOutBuffer->dwProtocol = 5; break;
|
||
|
#endif
|
||
|
#ifdef MS_IP_CBT
|
||
|
case MS_IP_CBT : pOutBuffer->dwProtocol = 7; break;
|
||
|
#endif
|
||
|
#ifdef MS_IP_PIMSM
|
||
|
case MS_IP_PIMSM: pOutBuffer->dwProtocol = 8; break;
|
||
|
#endif
|
||
|
#ifdef MS_IP_PIMDM
|
||
|
case MS_IP_PIMDM: pOutBuffer->dwProtocol = 9; break;
|
||
|
#endif
|
||
|
case MS_IP_IGMP : pOutBuffer->dwProtocol = 10; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceLeave("GetInterfaceMcastStatistics");
|
||
|
return dwResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
SetInterfaceMcastStatistics(
|
||
|
IN PICB picb,
|
||
|
IN PMIB_IPMCAST_IF_ENTRY lpInBuffer
|
||
|
)
|
||
|
{
|
||
|
DWORD dwResult = NO_ERROR;
|
||
|
|
||
|
TraceEnter("SetInterfaceMcastStatistics");
|
||
|
|
||
|
dwResult = SetMcastLimits(picb, lpInBuffer->dwTtl, lpInBuffer->dwRateLimit);
|
||
|
|
||
|
if(dwResult isnot NO_ERROR) {
|
||
|
Trace2(ERR,
|
||
|
"SetInterfaceStatistics: Error %d setting %S",
|
||
|
dwResult,
|
||
|
picb->pwszName);
|
||
|
}
|
||
|
|
||
|
TraceLeave("SetInterfaceMcastStatistics");
|
||
|
return dwResult;
|
||
|
}
|