/*++ 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 #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; }