windows-nt/Source/XPSP1/NT/net/tapi/rca/rcaksndi.c
2020-09-26 16:20:57 +08:00

664 lines
15 KiB
C

/*++
Copyright (c) 1995-1998 Microsoft Corporation
Module Name:
RCAKsNdi.c
Abstract:
The module implements the Co-NDIS wrapper functions that the KS parts of
RCA use to avoid having to deal with Co-NDIS directly.
Author:
Shyam Pather (SPATHER)
Revision History:
Who When What
-------- -------- ----------------------------------------------
SPATHER 04-20-99 Created
--*/
#include <precomp.h>
#define MODULE_NUMBER MODULE_KSNDIS
#define _FILENUMBER 'DNSK'
#if PACKET_POOL_OPTIMIZATION
// SendPPOpt - Start
LONG g_alSendPPOptBuckets[SENDPPOPT_NUM_BUCKETS];
LONG g_lSendPPOptOutstanding;
NDIS_SPIN_LOCK g_SendPPOptLock;
// SendPPOpt - End
#endif
PRCA_VC
RCARefVcFromHashTable(
IN PRCA_VC VcContext
)
/*++
Routine Description:
Searches for an RCA_VC structure in the hash table. If found, the structure is referenced.
Arguments:
VcContext -- The RCA_VC structure to look for.
Return Value:
RCA VC structure, or NULL if there's no entry. (Caller should assert this is never
NULL, since both RCA and NDIS think their respective pointers should still be valid...)
--*/
{
PRCA_PROTOCOL_CONTEXT pProtocolContext = &GlobalContext;
ULONG HashIndex = HASH_VC((ULONG_PTR)VcContext);
PRCA_VC pRcaVc;
RCADEBUGP(RCA_INFO, ("RCARefVcFromHashTable: enter\n" ));
ACQUIRE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCARefVcFromHashTable: Acquired global protocol context lock\n"));
for (pRcaVc = pProtocolContext->VcHashTable[HashIndex];
pRcaVc != NULL;
pRcaVc = pRcaVc->NextVcOnHash)
{
PRCA_ADAPTER pAdapter;
if (pRcaVc == VcContext)
{
pAdapter = pRcaVc->pAdapter;
DPR_ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
if (pRcaVc->Flags & VC_CLOSING)
{
pRcaVc = NULL;
}
else
{
pRcaVc->RefCount++;
}
DPR_RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
break;
}
}
RELEASE_SPIN_LOCK(&pProtocolContext->SpinLock);
RCADEBUGP(RCA_LOUD, ("RCARefVcFromHashTable: Released global protocol context lock\n"));
RCADEBUGP(RCA_INFO, ("RCARefVcFromHashTable: Exit - Returning VC %x\n", pRcaVc));
return(pRcaVc);
}
NDIS_STATUS
RCACoNdisGetVcContext(
IN UNICODE_STRING VcHandle,
IN PVOID ClientContext,
IN BOOL bRefForReceive,
OUT PVOID *VcContext
)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRCA_VC pRcaVc;
RCADEBUGP(RCA_INFO, ("RCACoNdisGetVcContext: Enter\n"));
do {
//
// Convert the unicode string to a pointer (this is
// equivalent to turning it into an NDIS_HANDLE).
//
Status = NdisClGetProtocolVcContextFromTapiCallId(VcHandle, (PNDIS_HANDLE)&pRcaVc);
if (Status != STATUS_SUCCESS) {
RCADEBUGP(RCA_ERROR, ("RCACoNdisGetVcContext: "
"Failed to get vc context from string, Status == 0x%x \n", Status));
break;
}
//
// Validate the VC by looking for it in our hash table. This increments the ref count on the VC.
//
pRcaVc = RCARefVcFromHashTable(pRcaVc);
if (pRcaVc == NULL) {
RCADEBUGP(RCA_ERROR, ("RCACoNdisGetVcContext: Could not find VC in hash table\n"));
Status = STATUS_NOT_FOUND;
break;
}
//
// Store away the client context, and give back the VC structure address as the
// VcContext to the client.
//
ACQUIRE_SPIN_LOCK(&pRcaVc->SpinLock);
if (bRefForReceive)
pRcaVc->ClientReceiveContext = ClientContext;
else
pRcaVc->ClientSendContext = ClientContext;
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
*VcContext = pRcaVc;
} while (FALSE);
RCADEBUGP(RCA_INFO, ("RCACoNdisGetVcContext: Exit - Returning Status 0x%x\n", Status));
return Status;
}
NDIS_STATUS
RCACoNdisGetVcContextForReceive(
IN UNICODE_STRING VcHandle,
IN PVOID ClientReceiveContext,
OUT PVOID *VcContext
)
/*++
Routine Description:
Retrieves VC context for a VC handle that will be used to receive packets.
Arguments:
VcHandle - The Unicode string representation of the VC Handle.
ClientReceiveContext - Caller-supplied context to be passed to the receive handler
when packets are received on this VC
VcContext - Address of a pointer in which the Co-NDIS VC Context will be
returned.
Return value:
NDIS_STATUS_SUCCESS in the case of success, STATUS_NOT_FOUND in the case of an invalid
VC handle, or some other relevant error code otherwise.
--*/
{
return RCACoNdisGetVcContext(VcHandle, ClientReceiveContext, TRUE, VcContext);
}
NDIS_STATUS
RCACoNdisGetVcContextForSend(
IN UNICODE_STRING VcHandle,
IN PVOID ClientSendContext,
OUT PVOID *VcContext
)
/*++
Routine Description:
Retrieves VC context for a VC handle that will be used to send packets.
Arguments:
VcHandle - The Unicode string representation of the VC Handle.
ClientSendContext - Caller-supplied context to be passed to the send complete handler
when packets sends are completed on this VC
VcContext - Address of a pointer in which the Co-NDIS VC Context will be
returned.
Return value:
NDIS_STATUS_SUCCESS in the case of success, STATUS_NOT_FOUND in the case of an invalid
VC handle, or some other relevant error code otherwise.
--*/
{
return RCACoNdisGetVcContext(VcHandle, ClientSendContext, FALSE, VcContext);
}
NDIS_STATUS
RCACoNdisReleaseSendVcContext(
IN PVOID VcContext
)
/*++
Routine Description:
This routine should be called when a client has finished using a VC Context
returned by RCACoNdisGetVcContextForSend().
Failure to do so will prevent the resources used by the VC from being freed.
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForSend()).
Return value:
NDIS_STATUS_SUCCESS
--*/
{
PRCA_VC pRcaVc = (PRCA_VC) VcContext;
RCADEBUGP(RCA_INFO, ("RCACoNdisReleaseSendVcContext: Enter\n"));
ACQUIRE_SPIN_LOCK(&pRcaVc->SpinLock);
pRcaVc->ClientSendContext = NULL;
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
RCADereferenceVc(pRcaVc);
RCADEBUGP(RCA_INFO, ("RCACoNdisReleaseSendVcContext: Exit, Returning NDIS_STATUS_SUCCESS\n"));
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
RCACoNdisReleaseReceiveVcContext(
IN PVOID VcContext
)
/*++
Routine Description:
This routine should be called when a client has finished using a VC Context
returned by RCACoNdisGetVcContextForReceive().
Failure to do so will prevent the resources used by the VC from being freed.
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForReceive()).
Return value:
NDIS_STATUS_SUCCESS
--*/
{
PRCA_VC pRcaVc = (PRCA_VC) VcContext;
RCADEBUGP(RCA_INFO, ("RCACoNdisReleaseReceiveVcContext: Enter\n"));
ACQUIRE_SPIN_LOCK(&pRcaVc->SpinLock);
pRcaVc->ClientReceiveContext = NULL;
RELEASE_SPIN_LOCK(&pRcaVc->SpinLock);
RCADereferenceVc(pRcaVc);
RCADEBUGP(RCA_INFO, ("RCACoNdisReleaseReceiveVcContext: Exit, Returning NDIS_STATUS_SUCCESS\n"));
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
RCACoNdisCloseCallOnVc(
IN PVOID VcContext
)
/*++
Routine Description:
Closes the call (if any) that is active on a particular VC
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForXXXX()).
Return value:
NDIS_STATUS_SUCCESS for a successful close, NDIS_STATUS_PENDING for a close that is still
proceeding, or a relevant error code otherwise.
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRCA_VC pRcaVc = (PRCA_VC)VcContext;
PRCA_ADAPTER pAdapter = pRcaVc->pAdapter;
BOOL bNeedToClose = FALSE;
RCADEBUGP(RCA_INFO, ("RCACoNdisCloseCallOnVc: Enter\n"));
RCAInitBlockStruc(&pRcaVc->CloseBlock);
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
pRcaVc->Flags &= ~VC_ACTIVE;
pRcaVc->Flags |= VC_CLOSING;
if (!(pRcaVc->ClosingState & CLOSING_INCOMING_CLOSE)) {
pRcaVc->ClosingState |= CLOSING_INCOMING_CLOSE;
bNeedToClose = TRUE;
}
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
if (bNeedToClose) {
Status = NdisClCloseCall(pRcaVc->NdisVcHandle, NULL, NULL, 0);
if (Status != NDIS_STATUS_PENDING) {
RCADEBUGP(RCA_LOUD, ("RCACoNdisCloseCallOnVc: "
"NdisClClose call returned status 0x%x, manually calling RCACloseCallComplete\n",
Status));
RCACloseCallComplete(Status, (NDIS_HANDLE)pRcaVc, NULL);
} else {
RCABlock(&pRcaVc->CloseBlock, &Status);
}
}
RCADEBUGP(RCA_INFO, ("RCACoNdisCloseCallOnVc: Exit - Returning Status 0x%x\n", Status));
return Status;
}
NDIS_STATUS
RCACoNdisCloseCallOnVcNoWait(
IN PVOID VcContext
)
/*++
Routine Description:
Closes the call (if any) that is active on a particular VC without waiting for the close
call operation to complete.
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForXXXX()).
Return value:
NDIS_STATUS_SUCCESS for a successful close, NDIS_STATUS_PENDING for a close that is still
proceeding, or a relevant error code otherwise.
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRCA_VC pRcaVc = (PRCA_VC)VcContext;
PRCA_ADAPTER pAdapter = pRcaVc->pAdapter;
BOOL bNeedToClose = FALSE;
RCADEBUGP(RCA_INFO, ("RCACoNdisCloseCallOnVc: Enter\n"));
//
// Though we aren't going to block, I have to init this here
// because the completion routine will signal it whether we're
// blocking or not.
//
RCAInitBlockStruc(&pRcaVc->CloseBlock);
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
pRcaVc->Flags &= ~VC_ACTIVE;
pRcaVc->Flags |= VC_CLOSING;
if (!(pRcaVc->ClosingState & CLOSING_INCOMING_CLOSE)) {
pRcaVc->ClosingState |= CLOSING_INCOMING_CLOSE;
bNeedToClose = TRUE;
}
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
if (bNeedToClose) {
Status = NdisClCloseCall(pRcaVc->NdisVcHandle, NULL, NULL, 0);
if (Status != NDIS_STATUS_PENDING) {
RCADEBUGP(RCA_LOUD, ("RCACoNdisCloseCallOnVc: "
"NdisClClose call returned status 0x%x, manually calling RCACloseCallComplete\n",
Status));
RCACloseCallComplete(Status, (NDIS_HANDLE)pRcaVc, NULL);
}
}
RCADEBUGP(RCA_INFO, ("RCACoNdisCloseCallOnVc: Exit - Returning Status 0x%x\n", Status));
return Status;
}
NDIS_STATUS
RCACoNdisSendFrame(
IN PVOID VcContext,
IN PMDL pMdl,
IN PVOID PacketContext
)
/*++
Routine Description:
Sends a frame of data out on a VC.
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForXXXX()).
pMdl - Pointer to the MDL containing the data to send
PacketContext - Caller-supplied context for this packet that will be passed
to the send complete handler when this packet has been sent.
Return value:
NDIS_STATUS_PENDING if the packet has been sent and is waiting to be completed,
or an error code otherwise.
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PRCA_VC pRcaVc = (PRCA_VC)VcContext;
PRCA_ADAPTER pAdapter;
PNDIS_PACKET pPacket;
RCADEBUGP(RCA_INFO, ("RCACoNdisSendFrame: Enter\n"));
do {
BOOL bVcIsClosing = FALSE;
if (pRcaVc == NULL) {
RCADEBUGP(RCA_ERROR,
("RCACoNdisSendFrame: VcContext was null, returing NDIS_STATUS_FAILURE\n"));
Status = NDIS_STATUS_FAILURE;
break;
}
pAdapter = pRcaVc->pAdapter;
//
// Check if the VC is closing. If it is, we
// won't try to send a packet.
//
ACQUIRE_SPIN_LOCK(&pAdapter->SpinLock);
if (pRcaVc->ClosingState & CLOSING_INCOMING_CLOSE) {
bVcIsClosing = TRUE;
}
RELEASE_SPIN_LOCK(&pAdapter->SpinLock);
if (bVcIsClosing) {
RCADEBUGP(RCA_ERROR, ("RCACoNdisSendFrame: Can't send frame, VC is closing\n"));
Status = STATUS_PORT_DISCONNECTED;
break;
}
//
// Allocate a packet from our sending pool.
//
#if PACKET_POOL_OPTIMIZATION
// SendPPOpt - Start
NdisAcquireSpinLock(&g_SendPPOptLock);
g_alSendPPOptBuckets[g_lSendPPOptOutstanding]++;
g_lSendPPOptOutstanding++;
NdisReleaseSpinLock(&g_SendPPOptLock);
// SendPPOpt - End
#endif
NdisAllocatePacket(&Status, &pPacket, pAdapter->SendPacketPool);
if (Status != NDIS_STATUS_SUCCESS) {
RCADEBUGP(RCA_ERROR, ("RCACoNdisSendFrame: "
"Failed to allocate packet, Status == 0x%x\n", Status));
break;
}
//
// Initialize the packet and put the buffer into it.
//
NdisReinitializePacket(pPacket);
NdisChainBufferAtFront(pPacket, (PNDIS_BUFFER)pMdl);
//
// Put the packet context in the protocol reserved field.
//
PKT_RSVD_FROM_PKT(pPacket)->PacketContext = PacketContext;
//
// Send it on it's way!
//
InterlockedIncrement(&pRcaVc->PendingSends);
NdisCoSendPackets(pRcaVc->NdisVcHandle, &pPacket, 1);
Status = NDIS_STATUS_PENDING;
} while (FALSE);
RCADEBUGP(RCA_INFO, ("RCACoNdisSendFrame: Exit - Returning Status == 0x%x\n", Status));
return Status;
}
NDIS_STATUS
RCACoNdisGetMdlFromPacket(
IN PNDIS_PACKET pPacket,
OUT PMDL *ppMdl
)
/*++
Routine Description:
Utility function that retrieves the data MDL from an NDIS packet.
Arguments:
pPacket - Pointer to an NDIS packet
ppMdl - Address of an MDL pointer in which the address of the MDL will be returned.
Return value:
NDIS_STATUS_SUCCESS
--*/
{
RCADEBUGP(RCA_INFO, ("RCACoNdisGetMdlFromPacket: Enter\n"));
*ppMdl = (PMDL) pPacket->Private.Head;
RCADEBUGP(RCA_INFO, ("RCACoNdisGetMdlFromPacket: Exit - Returning NDIS_STATUS_SUCCESS\n"));
return NDIS_STATUS_SUCCESS;
}
VOID
RCACoNdisReturnPacket(
IN PNDIS_PACKET pPacket
)
/*++
Routine Description:
This routine should be called to return a packet to NDIS. Failure
to call this routine when finished with a packet will cause a resource
leak that will result in packets being dropped on the network.
Arguments:
pPacket - Pointer to the NDIS packet to return
Return value:
(None)
--*/
{
RCADEBUGP(RCA_INFO, ("RCACoNdisReturnPacket: Enter\n"));
if (WORK_ITEM_FROM_PKT(pPacket)->bFreeThisPacket) {
//
// This is our packet - free it.
//
RCADEBUGP(RCA_LOUD, ("RCACoNdisReturnPacket: Freeing locally allocated packet\n"));
#if PACKET_POOL_OPTIMIZATION
// RecvPPOpt - Start
NdisAcquireSpinLock(&g_RecvPPOptLock);
g_lRecvPPOptOutstanding--;
NdisReleaseSpinLock(&g_RecvPPOptLock);
// RecvPPOpt - End
#endif
RCAFreeCopyPacket(pPacket);
} else {
//
// This is the miniport's packet - return it.
//
RCADEBUGP(RCA_LOUD, ("RCACoNdisReturnPacket: Returning packet to the miniport\n"));
NdisReturnPackets(&pPacket, 1);
}
RCADEBUGP(RCA_INFO, ("RCACoNdisReturnPacket: Exit\n"));
}
NDIS_STATUS
RCACoNdisGetMaxSduSizes(
IN PVOID VcContext,
OUT ULONG *RxMaxSduSize,
OUT ULONG *TxMaxSduSize
)
/*++
Routine Description:
Utility function that retrieves the largest SDU sizes that a VC
can support.
Arguments:
VcContext - The VC Context (returned by RCACoNdisGetVcContextForXXXX()).
RxMaxSduSize - Pointer to ULONG variable in which to place the max receive
SDU size.
TxMaxSduSize - Pointer to ULONG variable in which to place the max transmit
SDU size.
Return value:
(None)
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
RCADEBUGP(RCA_INFO, ("RCACoNdisGetMaxSduSizes: Enter\n"));
do {
PRCA_VC pRcaVc = (PRCA_VC)VcContext;
if (RxMaxSduSize) {
*RxMaxSduSize = pRcaVc->CallParameters.CallMgrParameters->Receive.MaxSduSize;
}
if (TxMaxSduSize) {
*TxMaxSduSize = pRcaVc->CallParameters.CallMgrParameters->Transmit.MaxSduSize;
}
} while (FALSE);
RCADEBUGP(RCA_INFO, ("RCACoNdisGetMaxSduSizes: Exit - Returning Status 0x%x\n", Status));
return Status;
}