Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2733 lines
88 KiB

/*++
Copyright (c) 2000-2000 Microsoft Corporation
Module Name:
Address.c
Abstract:
This module implements Address handling routines
for the PGM Transport
Author:
Mohammad Shabbir Alam (MAlam) 3-30-2000
Revision History:
--*/
#include "precomp.h"
#include <ipinfo.h> // for IPInterfaceInfo
#include <tcpinfo.h> // for AO_OPTION_xxx, TCPSocketOption
#include <tdiinfo.h> // for CL_TL_ENTITY, TCP_REQUEST_SET_INFORMATION_EX
#include <ipexport.h> // for IP_OPT_ROUTER_ALERT
//******************* Pageable Routine Declarations ****************
#ifdef ALLOC_PRAGMA
#endif
//******************* Pageable Routine Declarations ****************
//----------------------------------------------------------------------------
BOOLEAN
GetIpAddress(
IN TRANSPORT_ADDRESS UNALIGNED *pTransportAddr,
IN ULONG BufferLength, // Total Buffer length
OUT tIPADDRESS *pIpAddress,
OUT USHORT *pPort
)
/*++
Routine Description:
This routine extracts the IP address from the TDI address block
Arguments:
IN pTransportAddr -- the block of TDI address(es)
IN BufferLength -- length of the block
OUT pIpAddress -- contains the IpAddress if we succeeded
OUT pPort -- contains the port if we succeeded
Return Value:
TRUE if we succeeded in extracting the IP address, FALSE otherwise
--*/
{
ULONG MinBufferLength; // Minimun reqd to read next AddressType and AddressLength
TA_ADDRESS *pAddress;
TDI_ADDRESS_IP UNALIGNED *pValidAddr;
INT i;
BOOLEAN fAddressFound = FALSE;
MinBufferLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address);
if (BufferLength < sizeof(TA_IP_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "GetIpAddress",
"Rejecting Open Address request -- BufferLength<%d> < Min<%d>\n",
BufferLength, sizeof(TA_IP_ADDRESS));
return (FALSE);
}
try
{
pAddress = (TA_ADDRESS *) &pTransportAddr->Address[0]; // address type + the actual address
for (i=0; i<pTransportAddr->TAAddressCount; i++)
{
//
// We support only IP address types:
//
if ((pAddress->AddressType == TDI_ADDRESS_TYPE_IP) &&
(pAddress->AddressLength >= TDI_ADDRESS_LENGTH_IP)) // sizeof (TDI_ADDRESS_IP)
{
pValidAddr = (TDI_ADDRESS_IP UNALIGNED *) pAddress->Address;
*pIpAddress = pValidAddr->in_addr;
*pPort = pValidAddr->sin_port;
fAddressFound = TRUE;
break;
}
//
// Set pAddress to point to the next address
//
pAddress = (TA_ADDRESS *) ((PUCHAR)pAddress->Address + pAddress->AddressLength);
//
// Verify that we have enough Buffer space to read in next Address if IP address
//
MinBufferLength += pAddress->AddressLength + FIELD_OFFSET(TA_ADDRESS,Address);
if (BufferLength < (MinBufferLength + sizeof(TDI_ADDRESS_IP)))
{
break;
}
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "GetIpAddress",
"Exception <0x%x> trying to access Addr info\n", GetExceptionCode());
}
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_ADDRESS | DBG_CONNECT), "GetIpAddress",
"%s!\n", (fAddressFound ? "SUCCEEDED" : "FAILED"));
return (fAddressFound);
}
//----------------------------------------------------------------------------
NTSTATUS
SetSenderMCastOutIf(
IN tADDRESS_CONTEXT *pAddress,
IN tIPADDRESS IpAddress // Net format
)
/*++
Routine Description:
This routine sets the outgoing interface for multicast traffic
Arguments:
IN pAddress -- Pgm's Address object (contains file handle over IP)
IN IpAddress -- interface address
Return Value:
NTSTATUS - Final status of the set Interface operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
ULONG BufferLength = 50;
UCHAR pBuffer[50];
IPInterfaceInfo *pIpIfInfo = (IPInterfaceInfo *) pBuffer;
status = PgmSetTcpInfo (pAddress->FileHandle,
AO_OPTION_MCASTIF,
&IpAddress,
sizeof (tIPADDRESS));
if (NT_SUCCESS (status))
{
status = PgmSetTcpInfo (pAddress->RAlertFileHandle,
AO_OPTION_MCASTIF,
&IpAddress,
sizeof (tIPADDRESS));
if (NT_SUCCESS (status))
{
//
// Now, determine the MTU
//
status = PgmQueryTcpInfo (pAddress->RAlertFileHandle,
IP_INTFC_INFO_ID,
&IpAddress,
sizeof (tIPADDRESS),
pBuffer,
BufferLength);
if ((NT_SUCCESS (status)) &&
(pIpIfInfo->iii_mtu <= (sizeof(IPV4Header) +
ROUTER_ALERT_SIZE +
PGM_MAX_FEC_DATA_HEADER_LENGTH)))
{
status = STATUS_UNSUCCESSFUL;
}
}
}
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "SetSenderMCastOutIf",
" AO_OPTION_MCASTIF or IP_INTFC_INFO_ID for <%x> returned <%x>, MTU=<%d>\n",
IpAddress, status, pIpIfInfo->iii_mtu);
return (status);
}
PgmLock (pAddress, OldIrq);
//
// get the length of the mac address in case is is less than 6 bytes
//
BufferLength = pIpIfInfo->iii_addrlength < sizeof(tMAC_ADDRESS) ?
pIpIfInfo->iii_addrlength : sizeof(tMAC_ADDRESS);
PgmZeroMemory (pAddress->OutIfMacAddress.Address, sizeof(tMAC_ADDRESS));
PgmCopyMemory (&pAddress->OutIfMacAddress, pIpIfInfo->iii_addr, BufferLength);
pAddress->OutIfMTU = pIpIfInfo->iii_mtu - (sizeof(IPV4Header) + ROUTER_ALERT_SIZE);
pAddress->OutIfFlags = pIpIfInfo->iii_flags;
pAddress->SenderMCastOutIf = ntohl (IpAddress);
PgmUnlock (pAddress, OldIrq);
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "SetSenderMCastOutIf",
"OutIf=<%x>, MTU=<%d>==><%d>\n", pAddress->SenderMCastOutIf, pIpIfInfo->iii_mtu, pAddress->OutIfMTU);
return (status);
}
//----------------------------------------------------------------------------
VOID
PgmDestroyAddress(
IN tADDRESS_CONTEXT *pAddress,
IN PVOID Unused1,
IN PVOID Unused2
)
/*++
Routine Description:
This routine closes the Files handles opened earlier and free's the memory
It should only be called if there is no Reference on the Address Context
Arguments:
IN pAddress -- Pgm's Address object
Return Value:
NONE
--*/
{
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmDestroyAddress",
"Destroying Address=<%x>\n", pAddress);
if (pAddress->RAlertFileHandle)
{
CloseAddressHandles (pAddress->RAlertFileHandle, pAddress->pRAlertFileObject);
}
CloseAddressHandles (pAddress->FileHandle, pAddress->pFileObject);
PgmFreeMem (pAddress);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmCreateAddress(
IN tPGM_DEVICE *pPgmDevice,
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp,
IN PFILE_FULL_EA_INFORMATION TargetEA
)
/*++
Routine Description:
This routine is called to create an address context for the client
It's main task is to allocate the memory, open handles on IP, and
set the initial IP options
Arguments:
IN pPgmDevice -- Pgm's Device object context
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
IN TargetEA -- contains the MCast address info (determines whether
the client is a sender or receiver)
Return Value:
NTSTATUS - Final status of the CreateAddress operation
--*/
{
tADDRESS_CONTEXT *pAddress = NULL;
TRANSPORT_ADDRESS UNALIGNED *pTransportAddr;
tMCAST_INFO MCastInfo;
NTSTATUS status;
tIPADDRESS IpAddress;
LIST_ENTRY *pEntry;
USHORT Port;
PGMLockHandle OldIrq;
UCHAR RouterAlert[4] = {IP_OPT_ROUTER_ALERT, ROUTER_ALERT_SIZE, 0, 0};
//
// Verify Minimum Buffer length!
//
pTransportAddr = (TRANSPORT_ADDRESS UNALIGNED *) &(TargetEA->EaName[TargetEA->EaNameLength+1]);
if (!GetIpAddress (pTransportAddr, TargetEA->EaValueLength, &IpAddress, &Port))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"GetIpAddress FAILed to return valid Address!\n");
return (STATUS_INVALID_ADDRESS_COMPONENT);
}
//
// Convert the parameters to host format
//
IpAddress = ntohl (IpAddress);
Port = ntohs (Port);
//
// If we have been supplied an address at bind time, it has to
// be a Multicast address
//
if ((IpAddress) &&
(!IS_MCAST_ADDRESS (IpAddress)))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"IP=<%x> is not MCast addr!\n", IpAddress);
return (STATUS_UNSUCCESSFUL);
}
//
// So, we found a valid address -- now, open it!
//
if (!(pAddress = PgmAllocMem (sizeof(tADDRESS_CONTEXT), PGM_TAG('0'))))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"STATUS_INSUFFICIENT_RESOURCES!\n");
return (STATUS_INSUFFICIENT_RESOURCES);
}
PgmZeroMemory (pAddress, sizeof (tADDRESS_CONTEXT));
InitializeListHead (&pAddress->Linkage);
InitializeListHead (&pAddress->AssociatedConnections); // List of associated connections
InitializeListHead (&pAddress->ListenHead); // List of Clients listening on this address
PgmInitLock (pAddress, ADDRESS_LOCK);
pAddress->Verify = PGM_VERIFY_ADDRESS;
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_CREATE, TRUE); // Set Locked to TRUE since it not in use
pAddress->Process = (PEPROCESS) PsGetCurrentProcess();
//
// Now open a handle on IP
//
status = TdiOpenAddressHandle (pgPgmDevice,
(PVOID) pAddress,
0, // Open any Src address
IPPROTO_RM, // PGM port
&pAddress->FileHandle,
&pAddress->pFileObject,
&pAddress->pDeviceObject);
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"TdiOpenAddressHandle returned <%x>\n", status);
PgmFreeMem (pAddress);
return (status);
}
if (IpAddress)
{
//
// We are now ready to start receiving data (if we designated an MCast receiver)
// Save the MCast addresses (if any were provided)
//
pAddress->ReceiverMCastAddr = IpAddress; // Saved in Host format
pAddress->ReceiverMCastPort = Port;
PgmInterlockedInsertTailList (&PgmDynamicConfig.ReceiverAddressHead, &pAddress->Linkage, &PgmDynamicConfig);
}
else
{
//
// This is an address for sending mcast packets, so
// Open another FileObject for sending packets with RouterAlert option
//
status = TdiOpenAddressHandle (pgPgmDevice,
NULL,
0, // Open any Src address
IPPROTO_RM, // PGM port
&pAddress->RAlertFileHandle,
&pAddress->pRAlertFileObject,
&pAddress->pRAlertDeviceObject);
if (NT_SUCCESS (status))
{
//
//
// This is an address for sending RouterAlert packets, so set the Router Alert option
//
status = PgmSetTcpInfo (pAddress->RAlertFileHandle,
AO_OPTION_IPOPTIONS,
RouterAlert,
sizeof (RouterAlert));
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"AO_OPTION_IPOPTIONS for Router Alert returned <%x>\n", status);
}
}
else
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmCreateAddress",
"AO_OPTION_IPOPTIONS for Router Alert returned <%x>\n", status);
}
if (!NT_SUCCESS (status))
{
PgmDestroyAddress (pAddress, NULL, NULL);
return (status);
}
PgmLock (&PgmDynamicConfig, OldIrq);
//
// Set the default sender parameters
// Since we don't know the MTU at this time, we
// will assume 1.4K window size for Ethernet
//
pAddress->RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
pAddress->WindowSizeInBytes = SENDER_DEFAULT_WINDOW_SIZE_BYTES;
pAddress->MaxWindowSizeBytes = SENDER_MAX_WINDOW_SIZE_PACKETS;
pAddress->MaxWindowSizeBytes *= 1400;
ASSERT (pAddress->MaxWindowSizeBytes >= SENDER_DEFAULT_WINDOW_SIZE_BYTES);
pAddress->WindowSizeInMSecs = (BITS_PER_BYTE * pAddress->WindowSizeInBytes) /
SENDER_DEFAULT_RATE_KBITS_PER_SEC;
pAddress->WindowAdvancePercentage = SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE;
pAddress->LateJoinerPercentage = SENDER_DEFAULT_LATE_JOINER_PERCENTAGE;
pAddress->FECGroupSize = 1; // ==> No FEC packets!
pAddress->MCastPacketTtl = MAX_MCAST_TTL;
InsertTailList (&PgmDynamicConfig.SenderAddressHead, &pAddress->Linkage);
PgmUnlock (&PgmDynamicConfig, OldIrq);
}
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmCreateAddress",
"%s -- pAddress=<%x>, IP:Port=<%x:%x>\n", (IpAddress ? "Receiver" : "Sender"),
pAddress, IpAddress, Port);
pIrpSp->FileObject->FsContext = pAddress;
pIrpSp->FileObject->FsContext2 = (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
VOID
PgmDereferenceAddress(
IN tADDRESS_CONTEXT *pAddress,
IN ULONG RefContext
)
/*++
Routine Description:
This routine decrements the RefCount on the address object
and causes a cleanup to occur if the RefCount went to 0
Arguments:
IN pAddress -- Pgm's address object
IN RefContext -- context for which this address object
was referenced earlier
Return Value:
NONE
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
PIRP pIrpCleanUp;
PgmLock (pAddress, OldIrq);
ASSERT (PGM_VERIFY_HANDLE2 (pAddress,PGM_VERIFY_ADDRESS, PGM_VERIFY_ADDRESS_DOWN));
ASSERT (pAddress->RefCount); // Check for too many derefs
ASSERT (pAddress->ReferenceContexts[RefContext]--);
if (--pAddress->RefCount)
{
PgmUnlock (pAddress, OldIrq);
return;
}
ASSERT (IsListEmpty (&pAddress->AssociatedConnections));
PgmUnlock (pAddress, OldIrq);
//
// Just Remove from the global list and Put it on the Cleaned up list!
//
PgmLock (&PgmDynamicConfig, OldIrq);
PgmLock (pAddress, OldIrq1);
pIrpCleanUp = pAddress->pIrpCleanUp;
pAddress->pIrpCleanUp = NULL;
RemoveEntryList (&pAddress->Linkage);
InsertTailList (&PgmDynamicConfig.CleanedUpAddresses, &pAddress->Linkage);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
//
// pIrpCleanUp will be NULL if we dereferencing the address
// as a result of an error during the Create
//
if (pIrpCleanUp)
{
PgmIoComplete (pIrpCleanUp, STATUS_SUCCESS, 0);
}
}
//----------------------------------------------------------------------------
NTSTATUS
PgmCleanupAddress(
IN tADDRESS_CONTEXT *pAddress,
IN PIRP pIrp
)
/*++
Routine Description:
This routine is called as a result of a close on the client's
address handle. Our main job here is to mark the address
as being cleaned up (so it that subsequent operations will
fail) and complete the request only when the last RefCount
has been dereferenced.
Arguments:
IN pAddress -- Pgm's address object
IN pIrp -- Client's request Irp
Return Value:
NTSTATUS - Final status of the set event operation (STATUS_PENDING)
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmCleanupAddress",
"Address=<%x> FileHandle=<%x>, FileObject=<%x>\n",
pAddress, pAddress->FileHandle, pAddress->pFileObject);
PgmLock (&PgmDynamicConfig, OldIrq);
PgmLock (pAddress, OldIrq1);
ASSERT (PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS));
pAddress->Verify = PGM_VERIFY_ADDRESS_DOWN;
pAddress->pIrpCleanUp = pIrp;
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_CREATE);
//
// The final Dereference will complete the Irp!
//
return (STATUS_PENDING);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmCloseAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is the final dispatch operation to be performed
after the cleanup, which should result in the address being
completely destroyed -- our RefCount must have already
been set to 0 when we completed the Cleanup request.
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- Current request stack location
Return Value:
NTSTATUS - Final status of the operation (STATUS_SUCCESS)
--*/
{
PGMLockHandle OldIrq, OldIrq1;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
pIrpSp->FileObject->FsContext = NULL;
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_ADDRESS, "PgmCloseAddress",
"Address=<%x>, RefCount=<%d>\n", pAddress, pAddress->RefCount);
//
// Remove from the CleanedUp list
//
PgmLock (&PgmDynamicConfig, OldIrq);
PgmLock (pAddress, OldIrq1);
RemoveEntryList (&pAddress->Linkage);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PgmDestroyAddress (pAddress, NULL, NULL);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmAssociateAddress(
IN tPGM_DEVICE *pPgmDevice,
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine associates a connection with an address object
Arguments:
IN pPgmDevice -- Pgm's Device object context
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
tADDRESS_CONTEXT *pAddress = NULL;
tCOMMON_SESSION_CONTEXT *pSession = pIrpSp->FileObject->FsContext;
PTDI_REQUEST_KERNEL_ASSOCIATE pParameters = (PTDI_REQUEST_KERNEL_ASSOCIATE) &pIrpSp->Parameters;
PFILE_OBJECT pFileObject = NULL;
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1, OldIrq2;
//
// Get a pointer to the file object, which points to the address
// element by calling a kernel routine to convert the filehandle into
// a file object pointer.
//
status = ObReferenceObjectByHandle (pParameters->AddressHandle,
FILE_READ_DATA,
*IoFileObjectType,
pIrp->RequestorMode,
(PVOID *) &pFileObject,
NULL);
if (!NT_SUCCESS(status))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmAssociateAddress",
"Invalid Address Handle=<%x>\n", pParameters->AddressHandle);
return (STATUS_INVALID_HANDLE);
}
//
// Acquire the DynamicConfig lock so as to ensure that the Address
// and Connection cannot get removed while we are processing it!
//
PgmLock (&PgmDynamicConfig, OldIrq);
//
// Verify the Connection handle
//
if ((!PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_UNASSOCIATED)) ||
(pSession->pAssociatedAddress)) // Ensure the connection is not already associated!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmAssociateAddress",
"Invalid Session Handle=<%x>\n", pSession);
PgmUnlock (&PgmDynamicConfig, OldIrq);
ObDereferenceObject ((PVOID) pFileObject);
return (STATUS_INVALID_HANDLE);
}
//
// Verify the Address handle
//
pAddress = pFileObject->FsContext;
if ((pFileObject->DeviceObject->DriverObject != PgmStaticConfig.DriverObject) ||
(PtrToUlong (pFileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE) ||
(!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmAssociateAddress",
"Invalid Address Context=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
ObDereferenceObject ((PVOID) pFileObject);
return (STATUS_INVALID_HANDLE);
}
PgmLock (pAddress, OldIrq1);
PgmLock (pSession, OldIrq2);
ASSERT (!pSession->pReceiver && !pSession->pSender);
//
// Now try to allocate the send / receive context
//
if (((pAddress->ReceiverMCastAddr) &&
!(pSession->pReceiver = PgmAllocMem (sizeof(tRECEIVE_CONTEXT), PGM_TAG('0')))) ||
(!(pAddress->ReceiverMCastAddr) &&
!(pSession->pSender = PgmAllocMem (sizeof(tSEND_CONTEXT), PGM_TAG('0')))))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmAssociateAddress",
"STATUS_INSUFFICIENT_RESOURCES allocating <%d> bytes for pAddress=<%x>, pSession=<%x>\n",
(pAddress->ReceiverMCastAddr ? sizeof(tRECEIVE_CONTEXT) : sizeof(tSEND_CONTEXT)),
pAddress, pSession);
PgmUnlock (pSession, OldIrq2);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
ObDereferenceObject ((PVOID) pFileObject);
return (STATUS_INSUFFICIENT_RESOURCES);
}
//
// Now associate the connection with the address!
// Unlink from the ConnectionsCreated list which was linked
// when the connection was created, and put on the AssociatedConnections list
//
pSession->pAssociatedAddress = pAddress;
RemoveEntryList (&pSession->Linkage);
InsertTailList (&pAddress->AssociatedConnections, &pSession->Linkage);
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_ASSOCIATED, TRUE);
//
// Now mark the Connect structure as for whether it is for
// Sender or a receiver
//
if (pAddress->ReceiverMCastAddr)
{
//
// We are a receiver
//
PgmZeroMemory (pSession->pReceiver, sizeof(tRECEIVE_CONTEXT));
InitializeListHead (&pSession->pReceiver->Linkage);
InitializeListHead (&pSession->pReceiver->NaksForwardDataList);
InitializeListHead (&pSession->pReceiver->ReceiveIrpsList);
InitializeListHead (&pSession->pReceiver->BufferedDataList);
InitializeListHead (&pSession->pReceiver->PendingNaksList);
pSession->Verify = PGM_VERIFY_SESSION_RECEIVE;
PGM_REFERENCE_SESSION_RECEIVE (pSession, REF_SESSION_ASSOCIATED, TRUE);
pSession->pReceiver->ListenMCastIpAddress = pAddress->ReceiverMCastAddr;
pSession->pReceiver->ListenMCastPort = pAddress->ReceiverMCastPort;
pSession->pReceiver->pReceive = pSession;
/*
pSession->pReceiver->NakMaxWaitTime = (2 * NAK_MAX_INITIAL_BACKOFF_TIMEOUT_MSECS) /
BASIC_TIMER_GRANULARITY_IN_MSECS;
*/
}
else
{
//
// We are a sender
//
PgmZeroMemory (pSession->pSender, sizeof(tSEND_CONTEXT));
InitializeListHead (&pSession->pSender->Linkage);
InitializeListHead (&pSession->pSender->PendingSends);
InitializeListHead (&pSession->pSender->CompletedSendsInWindow);
InitializeListHead (&pSession->pSender->PendingRDataRequests);
InitializeListHead (&pSession->pSender->HandledRDataRequests);
ExInitializeResourceLite (&pSession->pSender->Resource);
pSession->Verify = PGM_VERIFY_SESSION_SEND;
PgmCopyMemory (pSession->GSI, &pAddress->OutIfMacAddress, SOURCE_ID_LENGTH);
PGM_REFERENCE_SESSION_SEND (pSession, REF_SESSION_ASSOCIATED, TRUE);
}
PgmUnlock (pSession, OldIrq2);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
ObDereferenceObject ((PVOID) pFileObject);
PgmLog (PGM_LOG_INFORM_STATUS, (DBG_ADDRESS | DBG_CONNECT), "PgmAssociateAddress",
"Associated pSession=<%x> with pAddress=<%x>\n", pSession, pAddress);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmDisassociateAddress(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine disassociates a connection from an address object
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
tCOMMON_SESSION_CONTEXT *pSession = pIrpSp->FileObject->FsContext;
tADDRESS_CONTEXT *pAddress = NULL;
PGMLockHandle OldIrq, OldIrq1, OldIrq2;
//
// Acquire the DynamicConfig lock so as to ensure that the Address
// and Connection Linkages cannot change while we are processing it!
//
PgmLock (&PgmDynamicConfig, OldIrq);
//
// First verify all the handles
//
if (!PGM_VERIFY_HANDLE3 (pSession, PGM_VERIFY_SESSION_SEND,
PGM_VERIFY_SESSION_RECEIVE,
PGM_VERIFY_SESSION_DOWN))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmDisassociateAddress",
"Invalid Session Handle=<%x>, Verify=<%x>\n", pSession, pSession->Verify);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
pAddress = pSession->pAssociatedAddress;
if (!PGM_VERIFY_HANDLE2 (pAddress, PGM_VERIFY_ADDRESS, PGM_VERIFY_ADDRESS_DOWN))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmDisassociateAddress",
"pSession=<%x>, Invalid Address Context=<%x>\n", pSession, pSession->pAssociatedAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
PgmLog (PGM_LOG_INFORM_STATUS, (DBG_ADDRESS | DBG_CONNECT), "PgmDisassociateAddress",
"Disassociating pSession=<%x:%x> from pAddress=<%x>\n",
pSession, pSession->ClientSessionContext, pSession->pAssociatedAddress);
PgmLock (pAddress, OldIrq1);
PgmLock (pSession, OldIrq2);
//
// Unlink from the AssociatedConnections list, which was linked
// when the connection was created.
//
pSession->pAssociatedAddress = NULL; // Disassociated!
RemoveEntryList (&pSession->Linkage);
if (PGM_VERIFY_HANDLE2 (pSession, PGM_VERIFY_SESSION_SEND, PGM_VERIFY_SESSION_RECEIVE))
{
//
// The connection is still active, so just put it on the CreatedConnections list
//
InsertTailList (&PgmDynamicConfig.ConnectionsCreated, &pSession->Linkage);
}
else // PGM_VERIFY_SESSION_DOWN
{
//
// The Connection was CleanedUp and may even be closed,
// so put it on the CleanedUp list!
//
InsertTailList (&PgmDynamicConfig.CleanedUpConnections, &pSession->Linkage);
}
PgmUnlock (pSession, OldIrq2);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
if (PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_RECEIVE))
{
PGM_DEREFERENCE_SESSION_RECEIVE (pSession, REF_SESSION_ASSOCIATED);
}
else if (PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_SEND))
{
PGM_DEREFERENCE_SESSION_SEND (pSession, REF_SESSION_ASSOCIATED);
}
else // we have already been cleaned up, so just do unassociated!
{
PGM_DEREFERENCE_SESSION_UNASSOCIATED (pSession, REF_SESSION_ASSOCIATED);
}
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_ASSOCIATED);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetMCastOutIf(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called as a result of the client attempting
to set the outgoing interface for MCast traffic
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set outgoing interface operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
ULONG Length;
ULONG BufferLength = 50;
UCHAR pBuffer[50];
IPInterfaceInfo *pIpIfInfo = (IPInterfaceInfo *) pBuffer;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
ULONG *pInfoBuffer = (PULONG) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetMCastOutIf",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetMCastOutIf",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Cannot set OutIf on Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetMCastOutIf",
"Invalid Option for Receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, FALSE);
PgmUnlock (&PgmDynamicConfig, OldIrq);
status = SetSenderMCastOutIf (pAddress, pInputBuffer->MCastOutIf);
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmSetMCastOutIf",
"OutIf = <%x>\n", pAddress->SenderMCastOutIf);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
ReceiverAddMCastIf(
IN tADDRESS_CONTEXT *pAddress,
IN tIPADDRESS IpAddress, // In host format
IN PGMLockHandle *pOldIrqDynamicConfig,
IN PGMLockHandle *pOldIrqAddress
)
/*++
Routine Description:
This routine is called as a result of the client attempting
to add an interface to the list of interfaces listening for
MCast traffic
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the add interface operation
--*/
{
NTSTATUS status;
tMCAST_INFO MCastInfo;
ULONG IpInterfaceContext;
USHORT i;
if (!pAddress->ReceiverMCastAddr) // Cannot set ReceiveIf on Sender!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "ReceiverAddMCastIf",
"Invalid Option for Sender, pAddress=<%x>\n", pAddress);
return (STATUS_NOT_SUPPORTED);
}
status = GetIpInterfaceContextFromAddress (IpAddress, &IpInterfaceContext);
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "ReceiverAddMCastIf",
"GetIpInterfaceContextFromAddress returned <%x> for Address=<%x>\n",
status, IpAddress);
return (STATUS_SUCCESS);
}
//
// If we are already listening on this interface, return success
//
for (i=0; i <pAddress->NumReceiveInterfaces; i++)
{
#ifdef IP_FIX
if (pAddress->ReceiverInterfaceList[i] == IpInterfaceContext)
#else
if (pAddress->ReceiverInterfaceList[i] == IpAddress)
#endif // IP_FIX
{
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "ReceiverAddMCastIf",
"InAddress=<%x> -- Already listening on IfContext=<%x>\n",
IpAddress, IpInterfaceContext);
return (STATUS_SUCCESS);
}
}
//
// If we have reached the limit on the interfaces we can listen on,
// return error
//
if (pAddress->NumReceiveInterfaces >= MAX_RECEIVE_INTERFACES)
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "ReceiverAddMCastIf",
"Listening on too many interfaces!, pAddress=<%x>\n", pAddress);
return (STATUS_NOT_SUPPORTED);
}
PgmUnlock (pAddress, *pOldIrqAddress);
PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
//
// This is the interface for receiving mcast packets on, so do JoinLeaf
//
MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
#ifdef IP_FIX
MCastInfo.MCastInIf = IpInterfaceContext;
status = PgmSetTcpInfo (pAddress->FileHandle,
AO_OPTION_INDEX_ADD_MCAST,
&MCastInfo,
sizeof (tMCAST_INFO));
#else
MCastInfo.MCastInIf = ntohl (IpAddress);
status = PgmSetTcpInfo (pAddress->FileHandle,
AO_OPTION_ADD_MCAST,
&MCastInfo,
sizeof (tMCAST_INFO));
#endif // IP_FIX
PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
PgmLock (pAddress, *pOldIrqAddress);
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "\tReceiverAddMCastIf",
"PgmSetTcpInfo returned: <%x>, If=<%x>\n", status, IpAddress);
return (status);
}
#ifdef IP_FIX
pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = IpInterfaceContext;
#else
pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = IpAddress;
#endif // IP_FIX
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "\tReceiverAddMCastIf",
"Added Ip=<%x>, IfContext=<%x>\n", IpAddress, IpInterfaceContext);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetEventHandler(
IN tPGM_DEVICE *pPgmDevice,
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine sets the client's Event Handlers wrt its address context
Arguments:
IN pPgmDevice -- Pgm's Device object context
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
NTSTATUS status = STATUS_SUCCESS;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
PTDI_REQUEST_KERNEL_SET_EVENT pKeSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT) &pIrpSp->Parameters;
PVOID pEventHandler = pKeSetEvent->EventHandler;
PVOID pEventContext = pKeSetEvent->EventContext;
PGMLockHandle OldIrq, OldIrq1;
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetEventHandler",
"Invalid Address Handle=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_ADDRESS, "PgmSetEventHandler",
"Type=<%x>, Handler=<%x>, Context=<%x>\n", pKeSetEvent->EventType, pEventHandler, pEventContext);
if (!pEventHandler)
{
//
// We will set it to use the default Tdi Handler!
//
pEventContext = NULL;
}
PgmLock (pAddress, OldIrq1);
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
switch (pKeSetEvent->EventType)
{
case TDI_EVENT_CONNECT:
{
if (!pAddress->ReceiverMCastAddr)
{
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetEventHandler",
"TDI_EVENT_CONNECT: pAddress=<%x> is not a Receiver\n", pAddress);
return (STATUS_UNSUCCESSFUL);
}
pAddress->evConnect = (pEventHandler ? pEventHandler : TdiDefaultConnectHandler);
pAddress->ConEvContext = pEventContext;
//
// If no default interface was specified, we need to set one now
//
if (!pAddress->NumReceiveInterfaces)
{
if (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList))
{
status = ListenOnAllInterfaces (pAddress, &OldIrq, &OldIrq1);
if (NT_SUCCESS (status))
{
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmSetEventHandler",
"CONNECT: ListenOnAllInterfaces for pAddress=<%x> succeeded\n", pAddress);
}
else
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetEventHandler",
"CONNECT: ListenOnAllInterfaces for pAddress=<%x> returned <%x>\n",
pAddress, status);
}
}
pAddress->Flags |= (PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE |
PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES);
}
break;
}
case TDI_EVENT_DISCONNECT:
{
pAddress->evDisconnect = (pEventHandler ? pEventHandler : TdiDefaultDisconnectHandler);
pAddress->DiscEvContext = pEventContext;
break;
}
case TDI_EVENT_ERROR:
{
pAddress->evError = (pEventHandler ? pEventHandler : TdiDefaultErrorHandler);
pAddress->ErrorEvContext = pEventContext;
break;
}
case TDI_EVENT_RECEIVE:
{
pAddress->evReceive = (pEventHandler ? pEventHandler : TdiDefaultReceiveHandler);
pAddress->RcvEvContext = pEventContext;
break;
}
case TDI_EVENT_RECEIVE_DATAGRAM:
{
pAddress->evRcvDgram = (pEventHandler ? pEventHandler : TdiDefaultRcvDatagramHandler);
pAddress->RcvDgramEvContext = pEventContext;
break;
}
case TDI_EVENT_RECEIVE_EXPEDITED:
{
pAddress->evRcvExpedited = (pEventHandler ? pEventHandler : TdiDefaultRcvExpeditedHandler);
pAddress->RcvExpedEvContext = pEventContext;
break;
}
case TDI_EVENT_SEND_POSSIBLE:
{
pAddress->evSendPossible = (pEventHandler ? pEventHandler : TdiDefaultSendPossibleHandler);
pAddress->SendPossEvContext = pEventContext;
break;
}
case TDI_EVENT_CHAINED_RECEIVE:
case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
case TDI_EVENT_ERROR_EX:
{
status = STATUS_NOT_SUPPORTED;
break;
}
default:
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetEventHandler",
"Invalid Event Type = <%x>\n", pKeSetEvent->EventType);
status = STATUS_UNSUCCESSFUL;
break;
}
}
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmAddMCastReceiveIf(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called as a result of the client attempting
to add an interface to the list of interfaces listening for
MCast traffic
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the add interface operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmAddMCastReceiveIf",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmAddMCastReceiveIf",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
PgmLock (pAddress, OldIrq1);
if (!pInputBuffer->MCastInfo.MCastInIf)
{
//
// We will use default behavior
//
pAddress->Flags |= PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES;
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PgmLog (PGM_LOG_INFORM_PATH, DBG_ADDRESS, "PgmAddMCastReceiveIf",
"Application requested bind to IP=<%x>\n", pInputBuffer->MCastInfo.MCastInIf);
return (STATUS_SUCCESS);
}
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
status = ReceiverAddMCastIf (pAddress, ntohl (pInputBuffer->MCastInfo.MCastInIf), &OldIrq, &OldIrq1);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
if (NT_SUCCESS (status))
{
PgmLog (PGM_LOG_INFORM_PATH, DBG_ADDRESS, "PgmAddMCastReceiveIf",
"Added Address=<%x>\n", pInputBuffer->MCastInfo.MCastInIf);
}
else
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmAddMCastReceiveIf",
"ReceiverAddMCastIf returned <%x>, Address=<%x>\n", status, pInputBuffer->MCastInfo.MCastInIf);
}
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmDelMCastReceiveIf(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client to remove an interface from the list
of interfaces we are currently listening on
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the delete interface operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
tMCAST_INFO MCastInfo;
ULONG IpInterfaceContext;
USHORT i;
BOOLEAN fFound;
#ifndef IP_FIX
tIPADDRESS IpAddress;
#endif // !IP_FIX
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"Invalid Handles pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (!pAddress->ReceiverMCastAddr) // Cannot set ReceiveIf on Sender!
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"Invalid Option for Sender, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
status = GetIpInterfaceContextFromAddress (ntohl(pInputBuffer->MCastInfo.MCastInIf), &IpInterfaceContext);
if (!NT_SUCCESS (status))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmDelMCastReceiveIf",
"GetIpInterfaceContextFromAddress returned <%x> for Address=<%x>\n",
status, pInputBuffer->MCastInfo.MCastInIf);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_ADDRESS);
}
PgmLock (pAddress, OldIrq1);
//
// Now see if we are even listening on this interface
//
fFound = FALSE;
#ifndef IP_FIX
IpAddress = ntohl(pInputBuffer->MCastInfo.MCastInIf);
#endif // !IP_FIX
for (i=0; i <pAddress->NumReceiveInterfaces; i++)
{
#ifdef IP_FIX
if (pAddress->ReceiverInterfaceList[i] == IpInterfaceContext)
#else
if (pAddress->ReceiverInterfaceList[i] == IpAddress)
#endif // IP_FIX
{
fFound = TRUE;
break;
}
}
if (!fFound)
{
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"Receiver is no longer listening on InAddress=<%x>, IfContext=<%x>\n",
pInputBuffer->MCastInfo.MCastInIf, IpInterfaceContext);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_SUCCESS);
}
pAddress->NumReceiveInterfaces--;
while (i < pAddress->NumReceiveInterfaces)
{
pAddress->ReceiverInterfaceList[i] = pAddress->ReceiverInterfaceList[i+1];
i++;
}
PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
#ifdef IP_FIX
MCastInfo.MCastInIf = IpInterfaceContext;
status = PgmSetTcpInfo (pAddress->FileHandle,
AO_OPTION_INDEX_DEL_MCAST,
&MCastInfo,
sizeof (tMCAST_INFO));
#else
MCastInfo.MCastInIf = pInputBuffer->MCastInfo.MCastInIf;
status = PgmSetTcpInfo (pAddress->FileHandle,
AO_OPTION_DEL_MCAST,
&MCastInfo,
sizeof (tMCAST_INFO));
#endif // IP_FIX
if (NT_SUCCESS (status))
{
PgmLog (PGM_LOG_INFORM_STATUS, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"MCast Addr:Port=<%x:%x>, OutIf=<%x>\n",
pAddress->ReceiverMCastAddr, pAddress->ReceiverMCastPort,
pInputBuffer->MCastInfo.MCastInIf);
}
else
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmDelMCastReceiveIf",
"PgmSetTcpInfo returned: <%x> for IP=<%x>, IfContext=<%x>\n",
status, pInputBuffer->MCastInfo.MCastInIf, IpInterfaceContext);
return (status);
}
PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetWindowSizeAndSendRate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to override the default
Send Rate and Window size specifications
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
ULONGLONG RateKbitsPerSec; // Send rate
ULONGLONG WindowSizeInBytes;
ULONGLONG WindowSizeInMSecs;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetWindowSizeAndSendRate",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowSizeAndSendRate",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if ((pAddress->ReceiverMCastAddr) || // Cannot set OutIf on Receiver!
(!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowSizeAndSendRate",
"Invalid Option, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
RateKbitsPerSec = pInputBuffer->TransmitWindowInfo.RateKbitsPerSec;
WindowSizeInBytes = pInputBuffer->TransmitWindowInfo.WindowSizeInBytes;
WindowSizeInMSecs = pInputBuffer->TransmitWindowInfo.WindowSizeInMSecs;
//
// Now, fill in missing info
//
if ((RateKbitsPerSec || WindowSizeInMSecs || WindowSizeInBytes) && // no paramter specified -- error
(!(RateKbitsPerSec && WindowSizeInMSecs && WindowSizeInBytes))) // all parameters specified
{
//
// If 2 parameters have been specified, we only need to compute the third one
//
if (RateKbitsPerSec && WindowSizeInMSecs)
{
ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
}
else if (RateKbitsPerSec && WindowSizeInBytes)
{
WindowSizeInMSecs = (BITS_PER_BYTE * WindowSizeInBytes) / RateKbitsPerSec;
}
else if (WindowSizeInBytes && WindowSizeInMSecs)
{
RateKbitsPerSec = (WindowSizeInBytes * BITS_PER_BYTE) / WindowSizeInMSecs;
ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
}
// for the remainder of the scenarios only 1 parameter has been specified
// Since WindowSizeInMSecs does not really affect our boundaries,
// it is the easiest to ignore while picking the defaults
else if (RateKbitsPerSec)
{
// Use default Window size
WindowSizeInBytes = SENDER_DEFAULT_WINDOW_SIZE_BYTES;
WindowSizeInMSecs = (BITS_PER_BYTE * WindowSizeInBytes) / RateKbitsPerSec;
if (WindowSizeInMSecs < MIN_RECOMMENDED_WINDOW_MSECS)
{
WindowSizeInMSecs = MIN_RECOMMENDED_WINDOW_MSECS;
WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
if (WindowSizeInBytes > pAddress->MaxWindowSizeBytes)
{
WindowSizeInBytes = pAddress->MaxWindowSizeBytes;
WindowSizeInMSecs = (WindowSizeInBytes * BITS_PER_BYTE) / RateKbitsPerSec;
}
}
}
else if ((WindowSizeInBytes) &&
(WindowSizeInBytes >= pAddress->OutIfMTU)) // Necessary so that Win Adv rate!=0
{
RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
WindowSizeInMSecs = (BITS_PER_BYTE * WindowSizeInBytes) / RateKbitsPerSec;
ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
}
else if ((WindowSizeInMSecs < pAddress->MaxWindowSizeBytes) && // Necessary so that Rate >= 1
(WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS) &&
(WindowSizeInMSecs >= pAddress->OutIfMTU)) // Necessary so that Win Adv rate!=0
{
// This is trickier -- we will first try to determine our constraints
// and try to use default settings, otherwise attempt to use the median value.
if (WindowSizeInMSecs <= (BITS_PER_BYTE * (pAddress->MaxWindowSizeBytes /
SENDER_DEFAULT_RATE_KBITS_PER_SEC)))
{
RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
}
// Hmm, we have to drop below out preferred rate -- try to pick the median range
else if (RateKbitsPerSec = BITS_PER_BYTE * (pAddress->MaxWindowSizeBytes /
(WindowSizeInMSecs * 2)))
{
WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
}
else
{
//
// Darn, we have to go with a huge file size and the min. rate!
//
RateKbitsPerSec = 1;
WindowSizeInBytes = WindowSizeInMSecs;
}
}
}
//
// Check validity of requested settings
//
if ((!(RateKbitsPerSec && WindowSizeInMSecs && WindowSizeInBytes)) || // all 3 must be specified from above
(RateKbitsPerSec != (WindowSizeInBytes * BITS_PER_BYTE / WindowSizeInMSecs)) ||
(WindowSizeInBytes > pAddress->MaxWindowSizeBytes) ||
(WindowSizeInBytes < pAddress->OutIfMTU))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowSizeAndSendRate",
"Invalid settings for pAddress=<%x>, Rate=<%d>, WSizeBytes=<%d>, WSizeMS=<%d>, MaxWSize=<%d:%d>\n",
pAddress,
pInputBuffer->TransmitWindowInfo.RateKbitsPerSec,
pInputBuffer->TransmitWindowInfo.WindowSizeInBytes,
pInputBuffer->TransmitWindowInfo.WindowSizeInMSecs,
pAddress->MaxWindowSizeBytes);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_PARAMETER);
}
pAddress->RateKbitsPerSec = (ULONG) RateKbitsPerSec;
pAddress->WindowSizeInBytes = (ULONG) WindowSizeInBytes;
pAddress->WindowSizeInMSecs = (ULONG) WindowSizeInMSecs;
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryWindowSizeAndSendRate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Send Rate and Window size specifications
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryWindowSizeAndSendRate",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowSizeAndSendRate",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Invalid option for Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowSizeAndSendRate",
"Invalid option ofr receiver pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
pBuffer->TransmitWindowInfo.RateKbitsPerSec = (ULONG) pAddress->RateKbitsPerSec;
pBuffer->TransmitWindowInfo.WindowSizeInBytes = (ULONG) pAddress->WindowSizeInBytes;
pBuffer->TransmitWindowInfo.WindowSizeInMSecs = (ULONG) pAddress->WindowSizeInMSecs;
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetWindowAdvanceRate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to override the default
Window Advance rate
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set event operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetWindowAdvanceRate",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
status = STATUS_SUCCESS;
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowAdvanceRate",
"Invalid Handle pAddress=<%x>\n", pAddress);
status = STATUS_INVALID_HANDLE;
}
else if ((pAddress->ReceiverMCastAddr) || // Cannot set OutIf on Receiver!
(!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowAdvanceRate",
"Invalid pAddress type or state <%x>\n", pAddress);
status = STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS (status))
{
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
if ((pInputBuffer->WindowAdvancePercentage) &&
(pInputBuffer->WindowAdvancePercentage <= MAX_WINDOW_INCREMENT_PERCENTAGE))
{
pAddress->WindowAdvancePercentage = pInputBuffer->WindowAdvancePercentage;
status = STATUS_SUCCESS;
}
else
{
status = STATUS_INVALID_PARAMETER;
}
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryWindowAdvanceRate(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Send Window advance rate
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryWindowAdvanceRate",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowAdvanceRate",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Invalid option for Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowAdvanceRate",
"Invalid option for receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
pBuffer->WindowAdvancePercentage = pAddress->WindowAdvancePercentage;
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetLateJoinerPercentage(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to override the default
Late Joiner percentage (i.e. % of Window late joiner can request)
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetLateJoinerPercentage",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
status = STATUS_SUCCESS;
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetLateJoinerPercentage",
"Invalid Handle pAddress=<%x>\n", pAddress);
status = STATUS_INVALID_HANDLE;
}
else if ((pAddress->ReceiverMCastAddr) || // Cannot set LateJoin % on Receiver!
(!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetLateJoinerPercentage",
"Invalid pAddress type or state <%x>\n", pAddress);
status = STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS (status))
{
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
if (pInputBuffer->LateJoinerPercentage <= SENDER_MAX_LATE_JOINER_PERCENTAGE)
{
pAddress->LateJoinerPercentage = pInputBuffer->LateJoinerPercentage;
}
else
{
status = STATUS_INVALID_PARAMETER;
}
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryLateJoinerPercentage(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Late Joiner percentage
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryLateJoinerPercentage",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryLateJoinerPercentage",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Cannot query LateJoin % on Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryLateJoinerPercentage",
"Invalid option for receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
pBuffer->LateJoinerPercentage = pAddress->LateJoinerPercentage;
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetWindowAdvanceMethod(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to override the default
Late Joiner percentage (i.e. % of Window late joiner can request)
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetWindowAdvanceMethod",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
status = STATUS_SUCCESS;
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowAdvanceMethod",
"Invalid Handle pAddress=<%x>\n", pAddress);
status = STATUS_INVALID_HANDLE;
}
else if (pAddress->ReceiverMCastAddr) // Cannot set WindowAdvanceMethod on Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmSetWindowAdvanceMethod",
"Invalid pAddress type or state <%x>\n", pAddress);
status = STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS (status))
{
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
if (pInputBuffer->WindowAdvanceMethod == E_WINDOW_ADVANCE_BY_TIME)
{
pAddress->Flags &= ~PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE;
}
else if (pInputBuffer->WindowAdvanceMethod == E_WINDOW_USE_AS_DATA_CACHE)
{
// pAddress->Flags |= PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE;
status = STATUS_NOT_SUPPORTED; // Not supported for now!
}
else
{
status = STATUS_INVALID_PARAMETER;
}
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryWindowAdvanceMethod(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Late Joiner percentage
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryWindowAdvanceMethod",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowAdvanceMethod",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Cannot query WindowAdvanceMethod on Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryWindowAdvanceMethod",
"Invalid option for receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
if (pAddress->Flags & PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE)
{
pBuffer->WindowAdvanceMethod = E_WINDOW_USE_AS_DATA_CACHE;
}
else
{
pBuffer->WindowAdvanceMethod = E_WINDOW_ADVANCE_BY_TIME;
}
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetNextMessageBoundary(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to set the Message length
for the next set of messages (typically, 1 send is sent as 1 Message).
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetNextMessageBoundary",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if ((!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND)) ||
(!pSend->pAssociatedAddress))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetNextMessageBoundary",
"Invalid Handle pSend=<%x>\n", pSend);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (!pSend->pSender)
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetNextMessageBoundary",
"Invalid Option for Receiver, pSend=<%x>\n", pSend);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
PgmLock (pSend, OldIrq1);
if ((pInputBuffer->NextMessageBoundary) &&
(!pSend->pSender->ThisSendMessageLength))
{
pSend->pSender->ThisSendMessageLength = pInputBuffer->NextMessageBoundary;
status = STATUS_SUCCESS;
}
else
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetNextMessageBoundary",
"Invalid parameter = <%d>\n", pInputBuffer->NextMessageBoundary);
status = STATUS_INVALID_PARAMETER;
}
PgmUnlock (pSend, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetFECInfo(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to set the parameters
for using FEC
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetFECInfo",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
status = STATUS_SUCCESS;
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetFECInfo",
"Invalid Handle pAddress=<%x>\n", pAddress);
status = STATUS_INVALID_HANDLE;
}
else if ((pAddress->ReceiverMCastAddr) || // Cannot set FEC on Receiver!
(!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetFECInfo",
"Invalid pAddress type or state <%x>\n", pAddress);
status = STATUS_NOT_SUPPORTED;
}
if (!NT_SUCCESS (status))
{
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
PgmLock (pAddress, OldIrq1);
if (!(pInputBuffer->FECInfo.FECProActivePackets || pInputBuffer->FECInfo.fFECOnDemandParityEnabled) ||
!(pInputBuffer->FECInfo.FECBlockSize && pInputBuffer->FECInfo.FECGroupSize) ||
(pInputBuffer->FECInfo.FECBlockSize > FEC_MAX_BLOCK_SIZE) ||
(pInputBuffer->FECInfo.FECBlockSize <= pInputBuffer->FECInfo.FECGroupSize) ||
(!gFECLog2[pInputBuffer->FECInfo.FECGroupSize])) // FECGroup size has to be power of 2
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetFECInfo",
"Invalid parameters, FECBlockSize= <%d>, FECGroupSize=<%d>\n",
pInputBuffer->FECInfo.FECBlockSize, pInputBuffer->FECInfo.FECGroupSize);
status = STATUS_INVALID_PARAMETER;
}
else
{
status = STATUS_SUCCESS;
pAddress->FECBlockSize = pInputBuffer->FECInfo.FECBlockSize;
pAddress->FECGroupSize = pInputBuffer->FECInfo.FECGroupSize;
pAddress->FECOptions = 0; // Init
if (pInputBuffer->FECInfo.FECProActivePackets)
{
pAddress->FECProActivePackets = pInputBuffer->FECInfo.FECProActivePackets;
pAddress->FECOptions |= PACKET_OPTION_SPECIFIC_FEC_PRO_BIT;
}
if (pInputBuffer->FECInfo.fFECOnDemandParityEnabled)
{
pAddress->FECOptions |= PACKET_OPTION_SPECIFIC_FEC_OND_BIT;
}
}
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryFecInfo(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Send Window advance rate
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryFecInfo",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryFecInfo",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if ((pAddress->ReceiverMCastAddr) || // Cannot query Fec on Receiver!
(!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot query options on active sender
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryFecInfo",
"Invalid Option for receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
pBuffer->FECInfo.FECBlockSize = pAddress->FECBlockSize;
pBuffer->FECInfo.FECGroupSize = pAddress->FECGroupSize;
pBuffer->FECInfo.FECProActivePackets = pAddress->FECProActivePackets;
if (pAddress->FECOptions & PACKET_OPTION_SPECIFIC_FEC_OND_BIT)
{
pBuffer->FECInfo.fFECOnDemandParityEnabled = TRUE;
}
else
{
pBuffer->FECInfo.fFECOnDemandParityEnabled = FALSE;
}
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmSetMCastTtl(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to set the Message length
for the next set of messages (typically, 1 send is sent as 1 Message).
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the set operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmSetMCastTtl",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetMCastTtl",
"Invalid Handle pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
if (pAddress->ReceiverMCastAddr) // Cannot set MCast Ttl on Receiver!
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetMCastTtl",
"Invalid Options for Receiver, pAddress=<%x>\n", pAddress);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_NOT_SUPPORTED);
}
PgmLock (pAddress, OldIrq1);
if ((pInputBuffer->MCastTtl) &&
(pInputBuffer->MCastTtl <= MAX_MCAST_TTL))
{
pAddress->MCastPacketTtl = pInputBuffer->MCastTtl;
status = STATUS_SUCCESS;
}
else
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT | DBG_SEND), "PgmSetMCastTtl",
"Invalid parameter = <%d>\n", pInputBuffer->MCastTtl);
status = STATUS_INVALID_PARAMETER;
}
PgmUnlock (pAddress, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (status);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQuerySenderStats(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Sender-side statistics
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQuerySenderStats",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if ((!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND)) ||
(!pSend->pSender) ||
(!pSend->pAssociatedAddress))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQuerySenderStats",
"Invalid Handle pSend=<%x>\n", pSend);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
PgmLock (pSend, OldIrq1);
pBuffer->SenderStats.DataBytesSent = pSend->DataBytes;
pBuffer->SenderStats.TotalBytesSent = pSend->TotalBytes;
pBuffer->SenderStats.RateKBitsPerSecLast = pSend->RateKBitsPerSecLast;
pBuffer->SenderStats.RateKBitsPerSecOverall = pSend->RateKBitsPerSecOverall;
pBuffer->SenderStats.NaksReceived = pSend->pSender->NaksReceived;
pBuffer->SenderStats.NaksReceivedTooLate = pSend->pSender->NaksReceivedTooLate;
pBuffer->SenderStats.NumOutstandingNaks = pSend->pSender->NumOutstandingNaks;
pBuffer->SenderStats.NumNaksAfterRData = pSend->pSender->NumNaksAfterRData;
pBuffer->SenderStats.RepairPacketsSent = pSend->pSender->RepairPacketsSent;
pBuffer->SenderStats.BufferSpaceAvailable = pSend->pSender->BufferSizeAvailable;
pBuffer->SenderStats.TrailingEdgeSeqId = (SEQ_TYPE) pSend->pSender->TrailingEdgeSequenceNumber;
pBuffer->SenderStats.LeadingEdgeSeqId = (SEQ_TYPE) pSend->pSender->LastODataSentSequenceNumber;
PgmUnlock (pSend, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------
NTSTATUS
PgmQueryReceiverStats(
IN PIRP pIrp,
IN PIO_STACK_LOCATION pIrpSp
)
/*++
Routine Description:
This routine is called by the client via setopt to query the current
Sender-side statistics
Arguments:
IN pIrp -- Client's request Irp
IN pIrpSp -- current request's stack pointer
Return Value:
NTSTATUS - Final status of the query operation
--*/
{
NTSTATUS status;
PGMLockHandle OldIrq, OldIrq1;
tRECEIVE_SESSION *pReceive = (tRECEIVE_SESSION *) pIrpSp->FileObject->FsContext;
tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
{
PgmLog (PGM_LOG_ERROR, DBG_ADDRESS, "PgmQueryReceiverStats",
"Invalid BufferLength, <%d> < <%d>\n",
pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST));
return (STATUS_INVALID_PARAMETER);
}
PgmLock (&PgmDynamicConfig, OldIrq);
if ((!PGM_VERIFY_HANDLE (pReceive, PGM_VERIFY_SESSION_RECEIVE)) ||
(!pReceive->pReceiver) ||
(!pReceive->pAssociatedAddress))
{
PgmLog (PGM_LOG_ERROR, (DBG_ADDRESS | DBG_CONNECT), "PgmQueryReceiverStats",
"Invalid Handle pReceive=<%x>\n", pReceive);
PgmUnlock (&PgmDynamicConfig, OldIrq);
return (STATUS_INVALID_HANDLE);
}
PgmLock (pReceive, OldIrq1);
pBuffer->ReceiverStats.NumODataPacketsReceived = pReceive->pReceiver->NumODataPacketsReceived;
pBuffer->ReceiverStats.NumRDataPacketsReceived = pReceive->pReceiver->NumRDataPacketsReceived;
pBuffer->ReceiverStats.NumDuplicateDataPackets = pReceive->pReceiver->NumDupPacketsOlderThanWindow +
pReceive->pReceiver->NumDupPacketsBuffered;
pBuffer->ReceiverStats.DataBytesReceived = pReceive->DataBytes;
pBuffer->ReceiverStats.TotalBytesReceived = pReceive->TotalBytes;
pBuffer->ReceiverStats.RateKBitsPerSecLast = pReceive->RateKBitsPerSecLast;
pBuffer->ReceiverStats.RateKBitsPerSecOverall = pReceive->RateKBitsPerSecOverall;
pBuffer->ReceiverStats.TrailingEdgeSeqId = (SEQ_TYPE) pReceive->pReceiver->LastTrailingEdgeSeqNum;
pBuffer->ReceiverStats.LeadingEdgeSeqId = (SEQ_TYPE) pReceive->pReceiver->FurthestKnownGroupSequenceNumber;
pBuffer->ReceiverStats.AverageSequencesInWindow = pReceive->pReceiver->AverageSequencesInWindow;
pBuffer->ReceiverStats.MinSequencesInWindow = pReceive->pReceiver->MinSequencesInWindow;
pBuffer->ReceiverStats.MaxSequencesInWindow = pReceive->pReceiver->MaxSequencesInWindow;
pBuffer->ReceiverStats.FirstNakSequenceNumber = pReceive->pReceiver->FirstNakSequenceNumber;
pBuffer->ReceiverStats.NumPendingNaks = pReceive->pReceiver->NumPendingNaks;
pBuffer->ReceiverStats.NumOutstandingNaks = pReceive->pReceiver->NumOutstandingNaks;
pBuffer->ReceiverStats.NumDataPacketsBuffered = pReceive->pReceiver->TotalDataPacketsBuffered;
pBuffer->ReceiverStats.TotalSelectiveNaksSent = pReceive->pReceiver->TotalSelectiveNaksSent;
pBuffer->ReceiverStats.TotalParityNaksSent = pReceive->pReceiver->TotalParityNaksSent;
PgmUnlock (pReceive, OldIrq1);
PgmUnlock (&PgmDynamicConfig, OldIrq);
pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
return (STATUS_SUCCESS);
}
//----------------------------------------------------------------------------