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.
 
 
 
 
 
 

851 lines
18 KiB

/*++
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
RCACoCl.c
Abstract:
The module implements the RCA Co-NDIS client.
Author:
Shyam Pather (SPATHER)
Revision History:
Who When What
-------- -------- ----------------------------------------------
SPATHER 04-20-99 Created / adapted from original RCA code by RMachin/JameelH
--*/
#include <precomp.h>
#define MODULE_NUMBER MODULE_COCL
#define _FILENUMBER 'LCOC'
#if PACKET_POOL_OPTIMIZATION
// RecvPPOpt - Start
LONG g_alRecvPPOptBuckets[RECVPPOPT_NUM_BUCKETS];
LONG g_lRecvPPOptOutstanding;
NDIS_SPIN_LOCK g_RecvPPOptLock;
// RecvPPOpt - End
#endif
BOOLEAN
RCAReferenceVc(
IN PRCA_VC pRcaVc
)
{
PRCA_ADAPTER pAdapter = pRcaVc->pAdapter;
BOOLEAN rc = FALSE;
RCADEBUGP(RCA_INFO, ("RCAReferenceVc: Enter\n"));
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
if ((pRcaVc->Flags & VC_CLOSING) == 0)
{
pRcaVc->RefCount++;
rc = TRUE;
}
RCADEBUGP(RCA_LOUD, ("RCAReferenceVc: pRcaVc (0x%x) ref count is %d\n",
pRcaVc, pRcaVc->RefCount));
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
RCADEBUGP(RCA_INFO, ("RCAReferenceVc: Exit, returning 0x%x\n", rc));
return(rc);
}
VOID
RCADereferenceVc(
IN PRCA_VC pRcaVc
)
{
PRCA_ADAPTER pAdapter = pRcaVc->pAdapter;
RCADEBUGP(RCA_INFO, ("RCADerefenceVc: Enter\n"));
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
pRcaVc->RefCount--;
RCADEBUGP(RCA_LOUD, ("RCADereferenceVc: pRcaVc (0x%x) ref count is %d\n",
pRcaVc, pRcaVc->RefCount));
if (pRcaVc->RefCount == 0)
{
ASSERT((pRcaVc->Flags & VC_ACTIVE) == 0);
//
// Take VC out of the adapter list
//
UnlinkDouble(pRcaVc, NextVcOnAdapter, PrevVcOnAdapter);
RCADEBUGP(RCA_LOUD, ("RCADereferenceVc: Took vc out of list\n"));
RCAFreeLock(&(pRcaVc->Lock));
RCAFreeMem(pRcaVc);
}
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
RCADEBUGP(RCA_INFO, ("RCADerefenceVc: Exit\n"));
}
VOID
RCACoSendComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolVcContext,
IN PNDIS_PACKET pNdisPacket)
/*++
Routine Description
Handle completion of a send. All we need to do is free the resources and
complete the event.
Arguments
Status - Result of the send
ProtocolVcContext - RCA VC
Packet - The Packet sent
Return Value:
None
--*/
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
PMDL pMdl;
RCADEBUGP(RCA_INFO, ("RCACoSendComplete: enter. VC=%x, Packet=%x\n", ProtocolVcContext, pNdisPacket));
InterlockedDecrement(&((PRCA_VC)ProtocolVcContext)->PendingSends);
//
// Get the MDL out of the packet and give it back to the client.
//
pMdl = (PMDL) pNdisPacket->Private.Head;
ACQUIRE_SPIN_LOCK(&(((PRCA_VC)ProtocolVcContext)->SpinLock));
if (pProtocolContext->Handlers.SendCompleteCallback) {
pProtocolContext->Handlers.SendCompleteCallback((PVOID)ProtocolVcContext,
((PRCA_VC)ProtocolVcContext)->ClientSendContext,
PKT_RSVD_FROM_PKT(pNdisPacket)->PacketContext,
pMdl,
Status);
}
RELEASE_SPIN_LOCK(&(((PRCA_VC)ProtocolVcContext)->SpinLock));
#if PACKET_POOL_OPTIMIZATION
// SendPPOpt - Start
NdisAcquireSpinLock(&g_SendPPOptLock);
g_lSendPPOptOutstanding--;
NdisReleaseSpinLock(&g_SendPPOptLock);
// SendPPOpt - End
#endif
NdisFreePacket(pNdisPacket);
RCADEBUGP(RCA_LOUD, ("RCACoSendComplete: exit\n"));
}
PNDIS_PACKET
RCAAllocCopyPacket(
IN PRCA_VC pRcaVc,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Allocate and copy a received packet to a private packet.
Note: We set the returned packet's status to NDIS_STATUS_RESOURCES,
which lets us know later on that this packet belongs to us and
not to the miniport.
Arguments:
pRcaVc - Pointer to our Adapter structure
pNdisPacket - Packet to be copied.
Return Value:
The allocated copy of the given packet, if successful. NULL otherwise.
--*/
{
PUCHAR pBuffer;
NDIS_STATUS Status;
PNDIS_PACKET pNewPacket;
PNDIS_BUFFER pNdisBuffer, pNewBuffer;
ULONG TotalLength;
ULONG BytesCopied;
pBuffer = NULL;
pNewPacket = NULL;
pNewBuffer = NULL;
do
{
//
// Copy the received packet into this one. First get the
// length to copy.
//
NdisQueryPacket(pNdisPacket,
NULL,
NULL,
NULL,
&TotalLength);
RCAAllocMem(pBuffer, UCHAR, TotalLength);
if (pBuffer == NULL)
{
break;
}
//
// Get a new NDIS buffer.
//
NdisAllocateBuffer(&Status,
&pNewBuffer,
pRcaVc->pAdapter->RecvBufferPool,
pBuffer,
TotalLength);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
//
// Allocate a new packet.
//
#if PACKET_POOL_OPTIMIZATION
// RecvPPOpt - Start
NdisAcquireSpinLock(&g_RecvPPOptLock);
g_alRecvPPOptBuckets[g_lRecvPPOptOutstanding]++;
g_lRecvPPOptOutstanding++;
NdisReleaseSpinLock(&g_RecvPPOptLock);
// RecvPPOpt - End
#endif
NdisAllocatePacket(&Status,
&pNewPacket,
pRcaVc->pAdapter->RecvPacketPool);
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
NDIS_SET_PACKET_STATUS(pNewPacket, 0);
//
// Link the buffer to the packet.
//
NdisChainBufferAtFront(pNewPacket, pNewBuffer);
//copy the packet
NdisCopyFromPacketToPacket(pNewPacket,
0, // Destn offset
TotalLength,
pNdisPacket,
0, // Src offset
&BytesCopied);
RCAAssert(TotalLength == BytesCopied);
NdisAdjustBufferLength(pNewBuffer, TotalLength);
} while (FALSE);
if (pNewPacket != (PNDIS_PACKET)NULL)
{
NDIS_SET_PACKET_STATUS(pNewPacket, NDIS_STATUS_RESOURCES);
}
else
{
if (pNewBuffer != NULL)
{
NdisFreeBuffer(pNewBuffer);
}
if (pBuffer != NULL)
{
RCAFreeMem(pBuffer);
}
}
return(pNewPacket);
}
UINT
RCACoReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE ProtocolVcContext,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Called by NDIS when a packet is received on a VC owned
by RCA. If there's a 'streamto' device indicated in teh VC,
we get an IRP, point the IR at teh MDL, and send it to
the next streaming driver.
If there is no 'streamto' device, since this is 'live' data
we currently dump the packet.
Arguments:
ProtocolBindingContext - our ClientBind structure for this adapter
ProtocolVcContext - our VC structure
pNdisPacket - NDIS packet
Return Value:
Success, whether we dumped or not.
--*/
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
PFN_RCARECEIVE_CALLBACK pfnReceiveCallback;
NDIS_STATUS Status = 0;
PRCA_VC pRcaVc = (PRCA_VC) ProtocolVcContext;
PNDIS_PACKET pCopiedPacket, pPacket;
UINT PacketRefs = 0;
RCADEBUGP(RCA_INFO, ("RCACoReceivePacket: Enter\n"));
do {
ACQUIRE_SPIN_LOCK(&pRcaVc->SpinLock);
pfnReceiveCallback = pProtocolContext->Handlers.ReceiveCallback;
if (pfnReceiveCallback == NULL ||
pRcaVc->ClientReceiveContext == NULL) {
PacketRefs = 0;
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
break;
}
if (NDIS_GET_PACKET_STATUS (pNdisPacket) == NDIS_STATUS_RESOURCES) {
//
// Miniport's short on resources. Copy the packet.
//
RCADEBUGP(RCA_LOUD, ("RCACoReceivePacket: Miniport is low on resources, have to copy packet\n"));
pCopiedPacket = RCAAllocCopyPacket(pRcaVc, pNdisPacket);
PacketRefs = 0;
if (pCopiedPacket == NULL) {
RCADEBUGP(RCA_ERROR, ("RcaCoReceivePacket: Failed to copy packet\n"));
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
break;
}
pPacket = pCopiedPacket;
WORK_ITEM_FROM_PKT(pPacket)->bFreeThisPacket = TRUE;
} else {
PacketRefs = 1;
pPacket = pNdisPacket;
WORK_ITEM_FROM_PKT(pPacket)->bFreeThisPacket = FALSE;
}
pfnReceiveCallback((PVOID)pRcaVc,
pRcaVc->ClientReceiveContext,
pPacket);
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
} while (FALSE);
RCADEBUGP(RCA_INFO,("CoReceivePacket: Exit return %lu\n", PacketRefs));
return(PacketRefs);
}
VOID
RCAReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
{
RCADEBUGP(RCA_INFO, (" RCACoReceiveComplete: Enter\n"));
RCADEBUGP(RCA_INFO, (" RCACoReceiveComplete: Exit\n"));
}
NDIS_STATUS
RCACreateVc(
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE NdisVcHandle,
OUT PNDIS_HANDLE pProtocolVcContext
)
/*++
Routine Description:
Entry point called by NDIS when the Call Manager wants to create
a new endpoint (VC) for a new inbound call on our SAP.
We accept the VC and do the main part of the work in our RCAIncomingCall
function.
Arguments:
ProtocolAfContext - Actually a pointer to the client bind structure we specified on OpenAddressFamily
NdisVcHandle - Handle for this VC for all future references
pProtocolVcContext - Place where we (protocol) return our context for the VC
Return Value:
NDIS_STATUS_SUCCESS if we could create a VC
NDIS_STATUS_RESOURCES otherwise
--*/
{
PRCA_ADAPTER pAdapter;
PRCA_VC pRcaVc;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
RCADEBUGP(RCA_INFO, ("RCACreateVc - Enter\n"));
pAdapter = (PRCA_ADAPTER)ProtocolAfContext;
RCADEBUGP(RCA_LOUD, ("RCACreateVc: pAdapter is 0x%x\n", pAdapter));
do
{
//
// Allocate a new VC structure.
//
RCAAllocMem(pRcaVc, RCA_VC, sizeof(RCA_VC));
if(pRcaVc != (PRCA_VC)NULL)
{
RCADEBUGP(RCA_LOUD, ("RCACreateVc: Allocated Vc 0x%x\n", pRcaVc));
//
// Initialize the interesting fields.
//
RCAMemSet(pRcaVc, 0, sizeof(RCA_VC));
#if DBG
pRcaVc->rca_sig = rca_signature;
#endif
pRcaVc->pAdapter = pAdapter;
pRcaVc->RefCount = 1;
NdisAllocateSpinLock(&pRcaVc->SpinLock);
pRcaVc->NdisVcHandle = NdisVcHandle;
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
LinkDoubleAtHead(pAdapter->VcList, pRcaVc, NextVcOnAdapter, PrevVcOnAdapter);
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
} else {
RCADEBUGP(RCA_ERROR, ("RCACreateVc: Failed to allocate VC structure, "
"setting Status = NDIS_STATUS_RESOURCES\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
*pProtocolVcContext = (NDIS_HANDLE)pRcaVc;
} while (FALSE);
RCADEBUGP(RCA_INFO, ("RCACreateVc: Exit, returning Status 0x%x\n", Status));
return(Status);
}
NDIS_STATUS
RCADeleteVc(
IN NDIS_HANDLE ProtocolVcContext
)
/*++
Routine Description:
Handles requests from a call mgr to delete a VC.
We need to delete the VC pointer
At this time, this VC structure should be free of any calls, and we
simply free it.
Arguments:
ProtocolVcContext - pointer to our VC structure
Return Value:
NDIS_STATUS_SUCCESS always
--*/
{
PRCA_VC pRcaVc;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRCA_ADAPTER pAdapter;
RCADEBUGP(RCA_INFO, ("RCADeleteVc: Enter\n"));
pRcaVc = (PRCA_VC)ProtocolVcContext;
pAdapter = pRcaVc->pAdapter;
RCADEBUGP(RCA_INFO, ("RCADeleteVc: pRcaVc is 0x%x\n", pRcaVc));
ASSERT((pRcaVc->ClientReceiveContext == NULL) && (pRcaVc->ClientSendContext == NULL));
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
pRcaVc->ClosingState |= CLOSING_DELETE_VC;
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
RCADereferenceVc(pRcaVc);
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
if (pAdapter->VcList == NULL) {
RCADEBUGP(RCA_LOUD, ("RCADeleteVc: All VCs gone, unblocking RCADeactivateAdapter().\n"));
if (pAdapter->BlockedOnClose) {
RCASignal(&pAdapter->CloseBlock, Status);
}
} else {
RCADEBUGP(RCA_INFO, ("RCADeleteVc: There are still some VCs remaining.\n"));
}
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
return(NDIS_STATUS_SUCCESS);
}
NDIS_STATUS
RCAIncomingCall(
IN NDIS_HANDLE ProtocolSapContext,
IN NDIS_HANDLE ProtocolVcContext,
IN OUT PCO_CALL_PARAMETERS pCallParams
)
/*++
Routine Description:
This handler is called when there is an incoming call matching:
- a SAP we registered on behalf of a client
- our own SAP (systemwide RCA for this adapter/AF.
Arguments:
ProtocolSapContext - Pointer to our SAP structure
ProtocolVcContext - Pointer to our RCA_VC structure
pCallParameters - Call parameters
Return Value:
NDIS_STATUS_SUCCESS if we accept this call
NDIS_STATUS_FAILURE if we reject it.
--*/
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
PRCA_VC pRcaVc = (PRCA_VC)ProtocolVcContext;
ULONG HashIndex = HASH_VC((ULONG_PTR)pRcaVc);
RCADEBUGP(RCA_INFO, ("RCAIncomingCall: Adapter: 0x%x, RCAVC: 0x%x, pCallParams: 0x%x\n",
pRcaVc->pAdapter, pRcaVc, pCallParams));
ACQUIRE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCAIncomingCall: Acquired global protocol context lock\n"));
//
// Stick the RCA VC in the Hash Table at the hashed position.
//
LinkDoubleAtHead(pProtocolContext->VcHashTable[HashIndex], pRcaVc, NextVcOnHash, PrevVcOnHash);
RELEASE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCAIncomingCall: Release global protocol context lock\n"));
//
// Copy the call parameters for use later.
//
RtlCopyMemory(&pRcaVc->CallParameters, pCallParams, sizeof(CO_CALL_PARAMETERS));
//
// Accept the call
//
NdisClIncomingCallComplete(NDIS_STATUS_SUCCESS,
pRcaVc->NdisVcHandle,
pCallParams);
RCADEBUGP(RCA_INFO, ("RCAIncomingCall: Exit - Returning NDIS_STATUS_SUCCESS\n"));
return(NDIS_STATUS_SUCCESS);
}
VOID
RCAIncomingCloseCall(
IN NDIS_STATUS closeStatus,
IN NDIS_HANDLE ProtocolVcContext,
IN PVOID CloseData OPTIONAL,
IN UINT Size OPTIONAL
)
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
PRCA_VC pRcaVc;
NDIS_STATUS Status = NDIS_STATUS_PENDING;
RCADEBUGP(RCA_INFO, ("RCAIncomingCloseCall: Enter\n"));
//
// First close the call from our perspective, then let the KS client know that the
// call is closed by invoking the VC close callback.
//
pRcaVc = (PRCA_VC)ProtocolVcContext;
Status = RCACoNdisCloseCallOnVcNoWait((PVOID)pRcaVc);
//
// Call this callback only if we have either a send or a receive client
// context - if we don't have either, assume no-one cares that this
// VC is closing. The actual callback should check for NULL contexts.
//
ACQUIRE_SPIN_LOCK(&pRcaVc->SpinLock);
if ((pRcaVc->ClientReceiveContext || pRcaVc->ClientSendContext) &&
(pProtocolContext->Handlers.VcCloseCallback)) {
//
// Release the spin lock here because this callback will very likely
// call RCACoNdisReleaseXXxVcContext() etc which will want the lock.
//
// There is a teensy tiny race here - if someone releases the VC context
// between when we release the lock and when we call the callback, we
// could be in trouble.
//
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
pProtocolContext->Handlers.VcCloseCallback((PVOID)pRcaVc,
pRcaVc->ClientReceiveContext,
pRcaVc->ClientSendContext);
} else {
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
}
RCADEBUGP(RCA_INFO, ("RCAIncomingCloseCall: Exit\n"));
}
VOID
RCACloseCallComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolVcContext,
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL
)
/*++
Routine Description:
This routine handles completion of a previous NdisClCloseCall.
It is assumed that Status is always NDIS_STATUS_SUCCESS.
Arguments:
Status - Status of the Close Call.
ProtocolVcContext - Pointer to VC structure.
ProtocolPartyContext - Not used.
Return Value:
None
--*/
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
PRCA_VC pRcaVc = (PRCA_VC)ProtocolVcContext;
RCADEBUGP(RCA_INFO, ("RCACloseCallComplete: Enter\n"));
ACQUIRE_SPIN_LOCK(&(pRcaVc->pAdapter->SpinLock));
pRcaVc->ClosingState |= CLOSING_CLOSE_COMPLETE;
RELEASE_SPIN_LOCK(&(pRcaVc->pAdapter->SpinLock));
ACQUIRE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCACloseCallComplete: Acquired global protocol context lock\n"));
//
// Take VC out of hash table
//
UnlinkDouble(pRcaVc, NextVcOnHash, PrevVcOnHash);
RELEASE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCACloseCallComplete: Released global protocol context lock\n"));
RCASignal(&pRcaVc->CloseBlock, Status);
RCADEBUGP(RCA_INFO, ("RCACloseCallComplete: Exit\n"));
}
VOID
RCACallConnected(
IN NDIS_HANDLE ProtocolVcContext
)
/*++
Routine Description:
This is the final step of an incoming call. The call on this VC
is now fully set up.
Arguments:
ProtocolVcContext - Call Manager's VC
Return Value:
None
--*/
{
PRCA_VC pRcaVc = (PRCA_VC)ProtocolVcContext;
RCADEBUGP(RCA_INFO, ("RCACallConnected: Enter\n"));
ACQUIRE_SPIN_LOCK(&pRcaVc->pAdapter->SpinLock);
pRcaVc = (PRCA_VC)ProtocolVcContext;
pRcaVc->Flags |= VC_ACTIVE;
RELEASE_SPIN_LOCK(&pRcaVc->pAdapter->SpinLock);
RCADEBUGP(RCA_INFO, ("RCACallConnected: Exit\n"));
}
NDIS_STATUS
RCARequest(
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
IN OUT PNDIS_REQUEST NdisRequest
)
/*++
Routine Description:
This routine is called by NDIS when a call manager sends us an NDIS Request.
Arguments:
ProtocolAfContext - Our context for the client binding
ProtocolVcContext - Our context for a VC
ProtocolPartyContext - Our context for a Party; RCA VC's Party list.
pNdisRequest - Pointer to the NDIS Request.
Return Value:
NDIS_STATUS_SUCCESS
--*/
{
PRCA_ADAPTER pAdapter = (PRCA_ADAPTER)ProtocolAfContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
RCADEBUGP(RCA_INFO, ("RCARequest: Enter - pAdapter->NdisAfHandle = 0X%x\n", pAdapter->NdisAfHandle));
if (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_CO_AF_CLOSE)
{
RCADEBUGP(RCA_LOUD, ("RCARequest: received OID_CO_AF_CLOSE\n"));
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
if (!(pAdapter->AdapterFlags & RCA_ADAPTERFLAGS_DEACTIVATE_IN_PROGRESS)) {
pAdapter->AdapterFlags |= RCA_ADAPTERFLAGS_DEACTIVATE_IN_PROGRESS;
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
Status = NdisScheduleWorkItem(&pAdapter->DeactivateWorkItem);
if (Status != NDIS_STATUS_SUCCESS) {
RCADEBUGP(RCA_ERROR, ("RCARequest: NdisScheduleWorkItem failed with status 0x%x\n", Status));
}
} else {
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
}
}
RCADEBUGP(RCA_INFO, ("RCARequest: Exit - Returning NDIS_STATUS_SUCCESS\n"));
return Status;
}