/*************************************************************************** Copyright (c) 1999 Microsoft Corporation Module Name: COMINI.C Abstract: CO-NDIS Miniport driver entry points for the Remote NDIS miniport. Environment: kernel mode only Notes: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright (c) 1999 Microsoft Corporation. All Rights Reserved. Revision History: 12/16/99: Created Author: ArvindM ****************************************************************************/ #include "precomp.h" /****************************************************************************/ /* RndismpCoCreateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to create a VC. We allocate a local VC structure, and send */ /* off a CreateVc message to the device. */ /* */ /* Arguments: */ /* */ /* MiniportAdapterContext - pointer to our adapter structure */ /* NdisVcHandle - the NDIS wrapper's handle for this VC */ /* pMiniportVcContext - place to return our context for this VC */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS RndismpCoCreateVc(IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE NdisVcHandle, OUT PNDIS_HANDLE pMiniportVcContext) { PRNDISMP_ADAPTER pAdapter; PRNDISMP_VC pVc; PRNDISMP_MESSAGE_FRAME pMsgFrame; NDIS_STATUS Status; ULONG RefCount = 0; pVc = NULL; // get adapter context pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); do { if (pAdapter->Halting) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } pVc = AllocateVc(pAdapter); if (pVc == NULL) { Status = NDIS_STATUS_RESOURCES; break; } RNDISMP_REF_VC(pVc); // Creation ref // // Prepare a CreateVc message to send to the device. // pMsgFrame = BuildRndisMessageCoMiniport(pAdapter, pVc, REMOTE_CONDIS_MP_CREATE_VC_MSG, NULL); if (pMsgFrame == NULL) { Status = NDIS_STATUS_RESOURCES; break; } pVc->VcState = RNDISMP_VC_CREATING; RNDISMP_REF_VC(pVc); // Pending CreateVc response RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, TRUE, CompleteSendCoCreateVc); } while (FALSE); // // Clean up if failure. // if (Status != NDIS_STATUS_SUCCESS) { if (pVc != NULL) { RNDISMP_DEREF_VC(pVc, &RefCount); // Creation ref ASSERT(RefCount == 0); // the Vc should be dealloc'ed above. } } return (Status); } /****************************************************************************/ /* CompleteSendCoCreateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Callback routine called when microport completes sending a CreateVc */ /* message to the device. */ /* */ /* Arguments: */ /* */ /* pMsgFrame - Pointer to message frame */ /* SendStatus - status of the microport send. */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendCoCreateVc(IN PRNDISMP_MESSAGE_FRAME pMsgFrame, IN NDIS_STATUS SendStatus) { PRNDISMP_VC pVc; PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pTmpMsgFrame; ULONG RefCount = 0; if (SendStatus == NDIS_STATUS_SUCCESS) { // // The message was sent successfully. Do nothing until // we get a response from the device. // } else { pVc = pMsgFrame->pVc; pAdapter = pVc->pAdapter; TRACE1(("CompleteSendCoCreateVc: VC %x, Adapter %x, fail status %x\n", pVc, pAdapter, SendStatus)); // // Failed to send it to the device. Remove this message from // the pending list and free it. // RNDISMP_LOOKUP_PENDING_MESSAGE(pTmpMsgFrame, pAdapter, pMsgFrame->RequestId); ASSERT(pMsgFrame == pTmpMsgFrame); DereferenceMsgFrame(pMsgFrame); HandleCoCreateVcFailure(pVc, SendStatus); } } // CompleteSendCoCreateVc /****************************************************************************/ /* HandleCoCreateVcFailure */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Utility routine to handle failure of a CreateVc, either due to a local */ /* microport send failure, or via explicit rejection by the device. */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to VC on which this failure has occurred */ /* Status - NDIS status associated with this failure */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID HandleCoCreateVcFailure(IN PRNDISMP_VC pVc, IN NDIS_STATUS Status) { NDIS_HANDLE NdisVcHandle; BOOLEAN bFailActivateVc = FALSE; PCO_CALL_PARAMETERS pCallParameters; ULONG RefCount = 0; RNDISMP_ACQUIRE_VC_LOCK(pVc); NdisVcHandle = pVc->NdisVcHandle; switch (pVc->VcState) { case RNDISMP_VC_CREATING: pVc->VcState = RNDISMP_VC_CREATE_FAILURE; break; case RNDISMP_VC_CREATING_DELETE_PENDING: pVc->VcState = RNDISMP_VC_ALLOCATED; break; case RNDISMP_VC_CREATING_ACTIVATE_PENDING: bFailActivateVc = TRUE; pCallParameters = pVc->pCallParameters; pVc->VcState = RNDISMP_VC_CREATE_FAILURE; break; default: ASSERT(FALSE); break; } RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // Pending CreateVc response if (RefCount != 0) { RNDISMP_RELEASE_VC_LOCK(pVc); } if (bFailActivateVc) { NdisMCoActivateVcComplete(Status, NdisVcHandle, pCallParameters); } } // HandleCoCreateVcFailure /****************************************************************************/ /* RndismpCoDeleteVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to delete a VC. We send a DeleteVc message to the device. */ /* */ /* Arguments: */ /* */ /* MiniportVcContext - pointer to our VC structure */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS RndismpCoDeleteVc(IN NDIS_HANDLE MiniportVcContext) { PRNDISMP_VC pVc; NDIS_STATUS Status; pVc = PRNDISMP_VC_FROM_CONTEXT_HANDLE(MiniportVcContext); Status = StartVcDeletion(pVc); return (Status); } // RndismpCoDeleteVc /****************************************************************************/ /* StartVcDeletion */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Initiate a DeleteVc operation on the specified VC. */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to VC structure */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS StartVcDeletion(IN PRNDISMP_VC pVc) { PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pMsgFrame; NDIS_STATUS Status; ULONG RefCount = 0; BOOLEAN bSendDeleteVc; pAdapter = pVc->pAdapter; bSendDeleteVc = FALSE; pMsgFrame = NULL; do { // // Prepare a DeleteVc message to send to the device. // pMsgFrame = BuildRndisMessageCoMiniport(pAdapter, pVc, REMOTE_CONDIS_MP_DELETE_VC_MSG, NULL); Status = NDIS_STATUS_SUCCESS; TRACE2(("StartVcDeletion: VC %x, state %d, Msg %x\n", pVc, pVc->VcState, pMsgFrame)); RNDISMP_ACQUIRE_VC_LOCK(pVc); switch (pVc->VcState) { case RNDISMP_VC_CREATED: if (pMsgFrame != NULL) { pVc->VcState = RNDISMP_VC_DELETING; bSendDeleteVc = TRUE; } else { Status = NDIS_STATUS_RESOURCES; bSendDeleteVc = FALSE; } break; case RNDISMP_VC_CREATING: bSendDeleteVc = FALSE; pVc->VcState = RNDISMP_VC_CREATING_DELETE_PENDING; break; case RNDISMP_VC_CREATE_FAILURE: bSendDeleteVc = FALSE; pVc->VcState = RNDISMP_VC_ALLOCATED; break; default: bSendDeleteVc = FALSE; Status = NDIS_STATUS_NOT_ACCEPTED; break; } RNDISMP_RELEASE_VC_LOCK(pVc); if (Status != NDIS_STATUS_SUCCESS) { break; } if (bSendDeleteVc) { ASSERT(pMsgFrame != NULL); RNDISMP_REF_VC(pVc); // pending DeleteVc message RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, TRUE, CompleteSendCoDeleteVc); } RNDISMP_DEREF_VC(pVc, &RefCount); // successful DeleteVc } while (FALSE); if (!bSendDeleteVc) { if (pMsgFrame != NULL) { DereferenceMsgFrame(pMsgFrame); } } return (Status); } // StartVcDeletion /****************************************************************************/ /* CompleteSendCoDeleteVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Callback routine called when microport completes sending a DeleteVc */ /* message to the device. */ /* */ /* Arguments: */ /* */ /* pMsgFrame - Pointer to message frame */ /* SendStatus - status of the microport send. */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendCoDeleteVc(IN PRNDISMP_MESSAGE_FRAME pMsgFrame, IN NDIS_STATUS SendStatus) { PRNDISMP_VC pVc; PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pTmpMsgFrame; if (SendStatus == NDIS_STATUS_SUCCESS) { // // The message was sent successfully. Do nothing until // we get a response from the device. // } else { pVc = pMsgFrame->pVc; pAdapter = pVc->pAdapter; TRACE1(("CompleteSendCoDeleteVc: VC %x, Adapter %x, fail status %x\n", pVc, pAdapter, SendStatus)); // // Failed to send it to the device. Remove this message from // the pending list and free it. // RNDISMP_LOOKUP_PENDING_MESSAGE(pTmpMsgFrame, pAdapter, pMsgFrame->RequestId); ASSERT(pMsgFrame == pTmpMsgFrame); DereferenceMsgFrame(pMsgFrame); // // Take care of the VC now. // HandleCoDeleteVcFailure(pVc, SendStatus); } } // CompleteSendCoDeleteVc /****************************************************************************/ /* HandleCoDeleteVcFailure */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Utility routine to handle failure of a DeleteVc, either due to a local */ /* microport send failure, or via explicit rejection by the device. */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to VC on which this failure has occurred */ /* Status - NDIS status associated with this failure */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID HandleCoDeleteVcFailure(IN PRNDISMP_VC pVc, IN NDIS_STATUS Status) { ULONG RefCount = 0; RNDISMP_ACQUIRE_VC_LOCK(pVc); switch (pVc->VcState) { case RNDISMP_VC_DELETING: pVc->VcState = RNDISMP_VC_DELETE_FAIL; break; default: ASSERT(FALSE); break; } RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // Pending DeleteVc response if (RefCount != 0) { RNDISMP_RELEASE_VC_LOCK(pVc); } } // HandleCoDeleteVcFailure /****************************************************************************/ /* RndismpCoActivateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to activate a VC. We send an ActivateVc message to the */ /* device. */ /* */ /* Arguments: */ /* */ /* MiniportVcContext - pointer to our VC structure */ /* pCallParameters - CONDIS parameters for the VC */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS RndismpCoActivateVc(IN NDIS_HANDLE MiniportVcContext, IN PCO_CALL_PARAMETERS pCallParameters) { PRNDISMP_VC pVc; NDIS_STATUS Status; pVc = PRNDISMP_VC_FROM_CONTEXT_HANDLE(MiniportVcContext); pVc->pCallParameters = pCallParameters; Status = StartVcActivation(pVc); return (Status); } // RndismpCoActivateVc /****************************************************************************/ /* StartVcActivation */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Start an Activate-VC operation on the specified VC. */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to VC structure */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS StartVcActivation(IN PRNDISMP_VC pVc) { NDIS_STATUS Status; PRNDISMP_MESSAGE_FRAME pMsgFrame; PRNDISMP_ADAPTER pAdapter; BOOLEAN bSendActivateVc; NDIS_HANDLE NdisVcHandle; PCO_CALL_PARAMETERS pCallParameters; Status = NDIS_STATUS_PENDING; bSendActivateVc = FALSE; NdisVcHandle = pVc->NdisVcHandle; pCallParameters = pVc->pCallParameters; pAdapter = pVc->pAdapter; do { // // Prepare an ActivateVc message to send to the device. // pMsgFrame = BuildRndisMessageCoMiniport(pAdapter, pVc, REMOTE_CONDIS_MP_ACTIVATE_VC_MSG, pCallParameters); RNDISMP_ACQUIRE_VC_LOCK(pVc); switch (pVc->VcState) { case RNDISMP_VC_CREATING: pVc->VcState = RNDISMP_VC_CREATING_ACTIVATE_PENDING; break; case RNDISMP_VC_CREATED: if (pMsgFrame != NULL) { pVc->VcState = RNDISMP_VC_ACTIVATING; bSendActivateVc = TRUE; } else { TRACE1(("StartVcAct: VC %x, failed to build msg!\n", pVc)); Status = NDIS_STATUS_RESOURCES; } break; default: TRACE1(("StartVcAct: VC %x in invalid state %d\n", pVc, pVc->VcState)); Status = NDIS_STATUS_NOT_ACCEPTED; break; } RNDISMP_RELEASE_VC_LOCK(pVc); if (Status != NDIS_STATUS_PENDING) { break; } if (bSendActivateVc) { ASSERT(pMsgFrame != NULL); RNDISMP_REF_VC(pVc); // pending ActivateVc message RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, TRUE, CompleteSendCoActivateVc); } } while (FALSE); if (!bSendActivateVc) { if (pMsgFrame != NULL) { DereferenceMsgFrame(pMsgFrame); } } if (Status != NDIS_STATUS_PENDING) { NdisMCoActivateVcComplete( Status, NdisVcHandle, pCallParameters); Status = NDIS_STATUS_PENDING; } return (Status); } // StartVcActivation /****************************************************************************/ /* CompleteSendCoActivateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Callback routine to handle send-completion of an Activate VC message. */ /* */ /* Arguments: */ /* */ /* pMsgFrame - Pointer to message frame */ /* SendStatus - status of the microport send. */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendCoActivateVc(IN PRNDISMP_MESSAGE_FRAME pMsgFrame, IN NDIS_STATUS SendStatus) { PRNDISMP_VC pVc; PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pTmpMsgFrame; PCO_CALL_PARAMETERS pCallParameters; ULONG RefCount = 0; NDIS_HANDLE NdisVcHandle; if (SendStatus == NDIS_STATUS_SUCCESS) { // // The message was sent successfully. Do nothing until // we get a response from the device. // } else { pVc = pMsgFrame->pVc; pAdapter = pVc->pAdapter; TRACE1(("CompleteSendCoActivateVc: VC %x, Adapter %x, fail status %x\n", pVc, pAdapter, SendStatus)); ASSERT(SendStatus != NDIS_STATUS_PENDING); // // Failed to send it to the device. Remove this message from // the pending list and free it. // RNDISMP_LOOKUP_PENDING_MESSAGE(pTmpMsgFrame, pAdapter, pMsgFrame->RequestId); ASSERT(pMsgFrame == pTmpMsgFrame); DereferenceMsgFrame(pMsgFrame); // // Take care of the VC now. // RNDISMP_ACQUIRE_VC_LOCK(pVc); NdisVcHandle = pVc->NdisVcHandle; pCallParameters = pVc->pCallParameters; pVc->VcState = RNDISMP_VC_CREATED; RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending ActivateVc if (RefCount != 0) { RNDISMP_RELEASE_VC_LOCK(pVc); } NdisMCoActivateVcComplete( SendStatus, NdisVcHandle, pCallParameters); } } // CompleteSendCoActivateVc /****************************************************************************/ /* RndismpCoDeactivateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to de-activate a VC. We send an DeactivateVc message to the */ /* device. */ /* */ /* Arguments: */ /* */ /* MiniportVcContext - pointer to our VC structure */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS RndismpCoDeactivateVc(IN NDIS_HANDLE MiniportVcContext) { PRNDISMP_VC pVc; PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pMsgFrame; NDIS_STATUS Status; NDIS_HANDLE NdisVcHandle; BOOLEAN bVcLockAcquired = FALSE; BOOLEAN bSendDeactivateVc = FALSE; pMsgFrame = NULL; pVc = PRNDISMP_VC_FROM_CONTEXT_HANDLE(MiniportVcContext); pAdapter = pVc->pAdapter; Status = NDIS_STATUS_PENDING; do { // // Prepare a DeactivateVc message to send to the device. // pMsgFrame = BuildRndisMessageCoMiniport(pAdapter, pVc, REMOTE_CONDIS_MP_DEACTIVATE_VC_MSG, NULL); bVcLockAcquired = TRUE; RNDISMP_ACQUIRE_VC_LOCK(pVc); NdisVcHandle = pVc->NdisVcHandle; if (pVc->VcState != RNDISMP_VC_ACTIVATED) { Status = NDIS_STATUS_NOT_ACCEPTED; break; } switch (pVc->VcState) { case RNDISMP_VC_ACTIVATED: if (pMsgFrame != NULL) { bSendDeactivateVc = TRUE; pVc->VcState = RNDISMP_VC_DEACTIVATING; } else { bSendDeactivateVc = FALSE; Status = NDIS_STATUS_RESOURCES; } break; default: bSendDeactivateVc = FALSE; break; } if (bSendDeactivateVc) { RNDISMP_REF_VC(pVc); // pending Deactivate VC RNDISMP_SEND_TO_MICROPORT(pAdapter, pMsgFrame, TRUE, CompleteSendCoDeactivateVc); } } while (FALSE); if (!bSendDeactivateVc) { if (pMsgFrame != NULL) { DereferenceMsgFrame(pMsgFrame); } } if (Status != NDIS_STATUS_PENDING) { ASSERT(Status != NDIS_STATUS_SUCCESS); NdisMCoDeactivateVcComplete( Status, NdisVcHandle); Status = NDIS_STATUS_PENDING; } return (Status); } /****************************************************************************/ /* CompleteSendCoDeactivateVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Callback routine to handle send-completion of a deactivate VC message. */ /* */ /* Arguments: */ /* */ /* pMsgFrame - Pointer to message frame */ /* SendStatus - status of the microport send. */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendCoDeactivateVc(IN PRNDISMP_MESSAGE_FRAME pMsgFrame, IN NDIS_STATUS SendStatus) { PRNDISMP_VC pVc; PRNDISMP_ADAPTER pAdapter; PRNDISMP_MESSAGE_FRAME pTmpMsgFrame; PCO_CALL_PARAMETERS pCallParameters; ULONG RefCount = 0; NDIS_HANDLE NdisVcHandle; if (SendStatus == NDIS_STATUS_SUCCESS) { // // The message was sent successfully. Do nothing until // we get a response from the device. // } else { pVc = pMsgFrame->pVc; pAdapter = pVc->pAdapter; TRACE1(("CompleteSendCoDeactivateVc: VC %x, Adapter %x, fail status %x\n", pVc, pAdapter, SendStatus)); ASSERT(SendStatus != NDIS_STATUS_PENDING); // // Failed to send it to the device. Remove this message from // the pending list and free it. // RNDISMP_LOOKUP_PENDING_MESSAGE(pTmpMsgFrame, pAdapter, pMsgFrame->RequestId); ASSERT(pMsgFrame == pTmpMsgFrame); DereferenceMsgFrame(pMsgFrame); // // Take care of the VC now. // RNDISMP_ACQUIRE_VC_LOCK(pVc); NdisVcHandle = pVc->NdisVcHandle; pCallParameters = pVc->pCallParameters; pVc->VcState = RNDISMP_VC_ACTIVATED; RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending DeactivateVc if (RefCount != 0) { RNDISMP_RELEASE_VC_LOCK(pVc); } NdisMCoDeactivateVcComplete( SendStatus, NdisVcHandle); } } // CompleteSendCoDeactivateVc /****************************************************************************/ /* RndismpCoRequest */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to handle a CO-request. We send a MiniportCoRequest message */ /* to the device. */ /* */ /* Arguments: */ /* */ /* MiniportAdapterContext - pointer to our adapter structure */ /* MiniportVcContext - pointer to our VC structure */ /* pRequest - Pointer to NDIS request */ /* */ /* Return: */ /* */ /* NDIS_STATUS */ /* */ /****************************************************************************/ NDIS_STATUS RndismpCoRequest(IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE MiniportVcContext, IN OUT PNDIS_REQUEST pRequest) { PRNDISMP_ADAPTER pAdapter; PRNDISMP_VC pVc; NDIS_STATUS Status; NDIS_OID Oid; pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); pVc = PRNDISMP_VC_FROM_CONTEXT_HANDLE(MiniportVcContext); switch (pRequest->RequestType) { case NdisRequestQueryInformation: case NdisRequestQueryStatistics: Oid = pRequest->DATA.QUERY_INFORMATION.Oid; TRACE2(("CoReq: Adapter %x, Req %x, QueryInfo/Stat (%d) Oid %x\n", pAdapter, pRequest, pRequest->RequestType, Oid)); Status = ProcessQueryInformation(pAdapter, pVc, pRequest, Oid, pRequest->DATA.QUERY_INFORMATION.InformationBuffer, pRequest->DATA.QUERY_INFORMATION.InformationBufferLength, &pRequest->DATA.QUERY_INFORMATION.BytesWritten, &pRequest->DATA.QUERY_INFORMATION.BytesNeeded); break; case NdisRequestSetInformation: Oid = pRequest->DATA.SET_INFORMATION.Oid; TRACE1(("CoReq: Adapter %x, Req %x, SetInfo Oid %x\n", pAdapter, pRequest, Oid)); Status = ProcessSetInformation(pAdapter, pVc, pRequest, Oid, pRequest->DATA.SET_INFORMATION.InformationBuffer, pRequest->DATA.SET_INFORMATION.InformationBufferLength, &pRequest->DATA.SET_INFORMATION.BytesRead, &pRequest->DATA.SET_INFORMATION.BytesNeeded); break; default: TRACE1(("CoReq: Unsupported request type %d\n", pRequest->RequestType)); Status = NDIS_STATUS_NOT_SUPPORTED; break; } return (Status); } /****************************************************************************/ /* RndismpCoSendPackets */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Entry point to send one or more packets on a VC. */ /* */ /* Arguments: */ /* */ /* MiniportVcContext - pointer to our VC structure */ /* PacketArray - Array of packet pointers */ /* NumberOfPackets - number of packets in array above */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID RndismpCoSendPackets(IN NDIS_HANDLE MiniportVcContext, IN PNDIS_PACKET * PacketArray, IN UINT NumberOfPackets) { PRNDISMP_VC pVc; UINT i; pVc = PRNDISMP_VC_FROM_CONTEXT_HANDLE(MiniportVcContext); RNDISMP_ACQUIRE_VC_LOCK(pVc); pVc->RefCount += NumberOfPackets; if (pVc->VcState == RNDISMP_VC_ACTIVATED) { RNDISMP_RELEASE_VC_LOCK(pVc); DoMultipleSend(pVc->pAdapter, pVc, PacketArray, NumberOfPackets); } else { RNDISMP_RELEASE_VC_LOCK(pVc); for (i = 0; i < NumberOfPackets; i++) { CompleteSendDataOnVc(pVc, PacketArray[i], NDIS_STATUS_VC_NOT_ACTIVATED); } } } // RndismpCoSendPackets /****************************************************************************/ /* ReceiveCreateVcComplete */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Process a CONDIS CreateVcComplete message from the device */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceiveCreateVcComplete(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { BOOLEAN bDiscardPkt = TRUE; PRNDISMP_VC pVc; PRNDISMP_MESSAGE_FRAME pCreateVcMsgFrame; PRCONDIS_MP_CREATE_VC_COMPLETE pCreateVcComp; RNDISMP_VC_STATE VcState; BOOLEAN bVcLockAcquired = FALSE; ULONG RefCount = 0; NDIS_STATUS Status; pVc = NULL; do { pCreateVcComp = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage); // // TBD - Validate lengths? // // // Check the request Id. // RNDISMP_LOOKUP_PENDING_MESSAGE(pCreateVcMsgFrame, pAdapter, pCreateVcComp->RequestId); if (pCreateVcMsgFrame == NULL) { TRACE1(("CreateVcComp: Adapter %x, Invalid ReqId %d!\n", pAdapter, pCreateVcComp->RequestId)); break; } pVc = pCreateVcMsgFrame->pVc; Status = pCreateVcComp->Status; DereferenceMsgFrame(pCreateVcMsgFrame); if (Status != NDIS_STATUS_SUCCESS) { HandleCoCreateVcFailure(pVc, Status); break; } bVcLockAcquired = TRUE; RNDISMP_ACQUIRE_VC_LOCK(pVc); RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending CreateVc if (RefCount == 0) { bVcLockAcquired = FALSE; break; } pVc->DeviceVcContext = pCreateVcComp->DeviceVcHandle; VcState = pVc->VcState; switch (VcState) { case RNDISMP_VC_CREATING: pVc->VcState = RNDISMP_VC_CREATED; break; case RNDISMP_VC_CREATING_ACTIVATE_PENDING: pVc->VcState = RNDISMP_VC_CREATED; RNDISMP_RELEASE_VC_LOCK(pVc); bVcLockAcquired = FALSE; Status = StartVcActivation(pVc); ASSERT(Status == NDIS_STATUS_PENDING); break; case RNDISMP_VC_CREATING_DELETE_PENDING: pVc->VcState = RNDISMP_VC_CREATED; RNDISMP_RELEASE_VC_LOCK(pVc); bVcLockAcquired = FALSE; Status = StartVcDeletion(pVc); break; default: TRACE1(("CreateVcComp: VC %x, wrong state %d\n", pVc, VcState)); break; } } while (FALSE); if (bVcLockAcquired) { RNDISMP_RELEASE_VC_LOCK(pVc); } return (bDiscardPkt); } /****************************************************************************/ /* ReceiveActivateVcComplete */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Process a CONDIS ActivateVcComplete message from the device */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceiveActivateVcComplete(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { BOOLEAN bDiscardPkt = TRUE; PRNDISMP_VC pVc; PRNDISMP_MESSAGE_FRAME pActVcMsgFrame; PRCONDIS_MP_ACTIVATE_VC_COMPLETE pActVcComp; BOOLEAN bVcLockAcquired = FALSE; ULONG RefCount = 0; NDIS_STATUS Status; NDIS_HANDLE NdisVcHandle; PCO_CALL_PARAMETERS pCallParameters; pVc = NULL; do { pActVcComp = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage); // // TBD - Validate lengths? // // // Check the request Id. // RNDISMP_LOOKUP_PENDING_MESSAGE(pActVcMsgFrame, pAdapter, pActVcComp->RequestId); if (pActVcMsgFrame == NULL) { TRACE1(("ActVcComp: Adapter %x, Invalid ReqId %d!\n", pAdapter, pActVcComp->RequestId)); break; } pVc = pActVcMsgFrame->pVc; DereferenceMsgFrame(pActVcMsgFrame); bVcLockAcquired = TRUE; RNDISMP_ACQUIRE_VC_LOCK(pVc); RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending ActivateVc if (RefCount == 0) { bVcLockAcquired = FALSE; break; } if (pVc->VcState != RNDISMP_VC_ACTIVATING) { TRACE1(("ActVcComp: Adapter %x, VC %x: invalid state %d\n", pAdapter, pVc, pVc->VcState)); break; } Status = pActVcComp->Status; if (Status == NDIS_STATUS_SUCCESS) { pVc->VcState = RNDISMP_VC_ACTIVATED; } else { pVc->VcState = RNDISMP_VC_CREATED; } NdisVcHandle = pVc->NdisVcHandle; pCallParameters = pVc->pCallParameters; RNDISMP_RELEASE_VC_LOCK(pVc); bVcLockAcquired = FALSE; NdisMCoActivateVcComplete( pActVcComp->Status, NdisVcHandle, pCallParameters); } while (FALSE); if (bVcLockAcquired) { RNDISMP_RELEASE_VC_LOCK(pVc); } return (bDiscardPkt); } /****************************************************************************/ /* ReceiveDeleteVcComplete */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Process a CONDIS DeleteVcComplete message from the device */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceiveDeleteVcComplete(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { BOOLEAN bDiscardPkt = TRUE; PRNDISMP_VC pVc; PRCONDIS_MP_DELETE_VC_COMPLETE pDeleteVcComp; PRNDISMP_MESSAGE_FRAME pDeleteVcMsgFrame; RNDISMP_VC_STATE VcState; BOOLEAN bVcLockAcquired = FALSE; ULONG RefCount = 0; NDIS_STATUS Status; pVc = NULL; do { pDeleteVcComp = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage); // // TBD - Validate lengths? // // // Check the request Id. // RNDISMP_LOOKUP_PENDING_MESSAGE(pDeleteVcMsgFrame, pAdapter, pDeleteVcComp->RequestId); if (pDeleteVcMsgFrame == NULL) { TRACE1(("DeleteVcComp: Adapter %x, Invalid ReqId %d!\n", pAdapter, pDeleteVcComp->RequestId)); break; } pVc = pDeleteVcMsgFrame->pVc; Status = pDeleteVcComp->Status; DereferenceMsgFrame(pDeleteVcMsgFrame); if (Status != NDIS_STATUS_SUCCESS) { HandleCoDeleteVcFailure(pVc, Status); break; } bVcLockAcquired = TRUE; RNDISMP_ACQUIRE_VC_LOCK(pVc); RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending DeleteVc if (RefCount == 0) { bVcLockAcquired = FALSE; break; } if (pVc->VcState != RNDISMP_VC_DELETING) { TRACE1(("DeleteVcComp: Adapter %x, VC %x: invalid state %d\n", pAdapter, pVc, pVc->VcState)); break; } pVc->VcState = RNDISMP_VC_ALLOCATED; RNDISMP_DEREF_VC(pVc, &RefCount); // remove create ref if (RefCount == 0) { bVcLockAcquired = FALSE; } } while (FALSE); if (bVcLockAcquired) { RNDISMP_RELEASE_VC_LOCK(pVc); } return (bDiscardPkt); } /****************************************************************************/ /* ReceiveDeactivateVcComplete */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Process a CONDIS DeActivateVcComplete message from the device */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceiveDeactivateVcComplete(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { BOOLEAN bDiscardPkt = TRUE; PRNDISMP_VC pVc; RNDISMP_VC_STATE VcState; PRNDISMP_MESSAGE_FRAME pDeactivateVcMsgFrame; PRCONDIS_MP_DEACTIVATE_VC_COMPLETE pDeactivateVcComp; BOOLEAN bVcLockAcquired = FALSE; BOOLEAN bAddTempRef = FALSE; ULONG RefCount = 0; NDIS_STATUS Status; pVc = NULL; do { pDeactivateVcComp = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage); // // TBD - Validate lengths? // // // Check the request Id. // RNDISMP_LOOKUP_PENDING_MESSAGE(pDeactivateVcMsgFrame, pAdapter, pDeactivateVcComp->RequestId); if (pDeactivateVcMsgFrame == NULL) { TRACE1(("DeactivateVcComp: Adapter %x, Invalid ReqId %d!\n", pAdapter, pDeactivateVcComp->RequestId)); break; } pVc = pDeactivateVcMsgFrame->pVc; DereferenceMsgFrame(pDeactivateVcMsgFrame); bVcLockAcquired = TRUE; RNDISMP_ACQUIRE_VC_LOCK(pVc); RNDISMP_DEREF_VC_LOCKED(pVc, &RefCount); // pending DeactivateVc if (RefCount == 0) { bVcLockAcquired = FALSE; break; } if (pVc->VcState != RNDISMP_VC_DEACTIVATING) { TRACE1(("DeactVcComp: Adapter %x, VC %x: invalid state %d\n", pAdapter, pVc, pVc->VcState)); ASSERT(FALSE); break; } if (pDeactivateVcComp->Status == NDIS_STATUS_SUCCESS) { pVc->VcState = RNDISMP_VC_DEACTIVATED; // // We add a temp ref on the VC to help complete deactivate-VC // from a common place (see bAddTempRef below). // RNDISMP_REF_VC(pVc); // temp ref, deactivate vc complete OK bAddTempRef = TRUE; } else { pVc->VcState = RNDISMP_VC_ACTIVATED; } RNDISMP_RELEASE_VC_LOCK(pVc); bVcLockAcquired = FALSE; if (bAddTempRef) { // // The following deref will check and call NDIS' // deactivate vc complete API if we don't have any // outstanding sends or receives on this VC. // RNDISMP_DEREF_VC(pVc, &RefCount); // temp ref } } while (FALSE); if (bVcLockAcquired) { RNDISMP_RELEASE_VC_LOCK(pVc); } return (bDiscardPkt); } /****************************************************************************/ /* BuildRndisMessageCoMiniport */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Allocate resources for message and frame and build an RNDIS message */ /* for sending to a remote CONDIS Miniport device. */ /* */ /* Arguments: */ /* */ /* pAdapter - Pointer to adapter structure */ /* pVc - Pointer to VC structure */ /* NdisMessageType - RNDIS message type */ /* pCallParameters - optional pointer to call parameters, applicable to */ /* certain message types. */ /* */ /* Return: */ /* */ /* PRNDISMP_MESSAGE_FRAME */ /* */ /****************************************************************************/ PRNDISMP_MESSAGE_FRAME BuildRndisMessageCoMiniport(IN PRNDISMP_ADAPTER pAdapter, IN PRNDISMP_VC pVc, IN UINT NdisMessageType, IN PCO_CALL_PARAMETERS pCallParameters OPTIONAL) { PRNDIS_MESSAGE pMessage; UINT MessageSize; PRNDISMP_MESSAGE_FRAME pMsgFrame; switch (NdisMessageType) { case REMOTE_CONDIS_MP_CREATE_VC_MSG: { PRCONDIS_MP_CREATE_VC pCreateVc; MessageSize = RNDIS_MESSAGE_SIZE(RCONDIS_MP_CREATE_VC); pMsgFrame = AllocateMessageAndFrame(pAdapter, MessageSize); if (pMsgFrame == NULL) { break; } pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame); pMessage->NdisMessageType = NdisMessageType; pMsgFrame->NdisMessageType = NdisMessageType; pCreateVc = &pMessage->Message.CoMiniportCreateVc; pCreateVc->RequestId = pMsgFrame->RequestId; pCreateVc->NdisVcHandle = pVc->VcId; break; } case REMOTE_CONDIS_MP_DELETE_VC_MSG: { PRCONDIS_MP_DELETE_VC pDeleteVc; MessageSize = RNDIS_MESSAGE_SIZE(RCONDIS_MP_DELETE_VC); pMsgFrame = AllocateMessageAndFrame(pAdapter, MessageSize); if (pMsgFrame == NULL) { break; } pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame); pMessage->NdisMessageType = NdisMessageType; pMsgFrame->NdisMessageType = NdisMessageType; pDeleteVc = &pMessage->Message.CoMiniportDeleteVc; pDeleteVc->RequestId = pMsgFrame->RequestId; pDeleteVc->DeviceVcHandle = pVc->DeviceVcContext; break; } case REMOTE_CONDIS_MP_ACTIVATE_VC_MSG: { PRCONDIS_MP_ACTIVATE_VC_REQUEST pActivateVc; PRCONDIS_CALL_MANAGER_PARAMETERS pCallMgrParams; PRCONDIS_MEDIA_PARAMETERS pMediaParams; ULONG_PTR FillLocation; UINT FillOffset; ASSERT(pCallParameters != NULL); MessageSize = RNDIS_MESSAGE_SIZE(RCONDIS_MP_ACTIVATE_VC_REQUEST); if (pCallParameters->CallMgrParameters) { MessageSize += (sizeof(RCONDIS_CALL_MANAGER_PARAMETERS) + pCallParameters->CallMgrParameters->CallMgrSpecific.Length); } if (pCallParameters->MediaParameters) { MessageSize += (sizeof(RCONDIS_MEDIA_PARAMETERS) + pCallParameters->MediaParameters->MediaSpecific.Length); } pMsgFrame = AllocateMessageAndFrame(pAdapter, MessageSize); if (pMsgFrame == NULL) { break; } pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame); pMessage->NdisMessageType = NdisMessageType; pMsgFrame->NdisMessageType = NdisMessageType; pActivateVc = &pMessage->Message.CoMiniportActivateVc; pActivateVc->RequestId = pMsgFrame->RequestId; pActivateVc->DeviceVcHandle = pVc->DeviceVcContext; pActivateVc->Flags = pCallParameters->Flags; FillOffset = RNDIS_MESSAGE_SIZE(RCONDIS_MP_ACTIVATE_VC_REQUEST); FillLocation = ((ULONG_PTR)pMessage + FillOffset); // // Fill in Media parameters, if present. // if (pCallParameters->MediaParameters) { PCO_SPECIFIC_PARAMETERS pMediaSpecific; pMediaSpecific = &pCallParameters->MediaParameters->MediaSpecific; pMediaParams = (PRCONDIS_MEDIA_PARAMETERS)FillLocation; pActivateVc->MediaParamsOffset = (UINT32)(FillLocation - (ULONG_PTR)pActivateVc); pActivateVc->MediaParamsLength = sizeof(RCONDIS_MEDIA_PARAMETERS) + pMediaSpecific->Length; RNDISMP_MOVE_MEM(pMediaParams, pCallParameters->MediaParameters, FIELD_OFFSET(RCONDIS_MEDIA_PARAMETERS, MediaSpecific)); FillLocation += sizeof(RCONDIS_MEDIA_PARAMETERS); FillOffset += sizeof(RCONDIS_MEDIA_PARAMETERS); pMediaParams->MediaSpecific.ParameterOffset = sizeof(RCONDIS_SPECIFIC_PARAMETERS); pMediaParams->MediaSpecific.ParameterType = pMediaSpecific->ParamType; pMediaParams->MediaSpecific.ParameterLength = pMediaSpecific->Length; RNDISMP_MOVE_MEM((PVOID)FillLocation, &pMediaSpecific->Parameters[0], pMediaSpecific->Length); FillLocation += pMediaSpecific->Length; FillOffset += pMediaSpecific->Length; } else { pActivateVc->MediaParamsOffset = 0; pActivateVc->MediaParamsLength = 0; } // // Fill in Call manager parameters, if present. // if (pCallParameters->CallMgrParameters) { PCO_SPECIFIC_PARAMETERS pCallMgrSpecific; pCallMgrSpecific = &pCallParameters->CallMgrParameters->CallMgrSpecific; pCallMgrParams = (PRCONDIS_CALL_MANAGER_PARAMETERS)FillLocation; pActivateVc->CallMgrParamsOffset = (UINT32)(FillLocation - (ULONG_PTR)pActivateVc); pActivateVc->CallMgrParamsLength = sizeof(RCONDIS_CALL_MANAGER_PARAMETERS) + pCallMgrSpecific->Length; RNDISMP_MOVE_MEM(pCallMgrParams, pCallParameters->CallMgrParameters, FIELD_OFFSET(RCONDIS_CALL_MANAGER_PARAMETERS, CallMgrSpecific)); FillLocation += sizeof(RCONDIS_CALL_MANAGER_PARAMETERS); FillOffset += sizeof(RCONDIS_CALL_MANAGER_PARAMETERS); pCallMgrParams->CallMgrSpecific.ParameterOffset = sizeof(RCONDIS_SPECIFIC_PARAMETERS); pCallMgrParams->CallMgrSpecific.ParameterType = pCallMgrSpecific->ParamType; pCallMgrParams->CallMgrSpecific.ParameterLength = pCallMgrSpecific->Length; RNDISMP_MOVE_MEM((PVOID)FillLocation, &pCallMgrSpecific->Parameters[0], pCallMgrSpecific->Length); FillLocation += pCallMgrSpecific->Length; FillOffset += pCallMgrSpecific->Length; } else { pActivateVc->CallMgrParamsOffset = 0; pActivateVc->CallMgrParamsLength = 0; } break; } case REMOTE_CONDIS_MP_DEACTIVATE_VC_MSG: { PRCONDIS_MP_DEACTIVATE_VC_REQUEST pDeactivateVc; MessageSize = RNDIS_MESSAGE_SIZE(RCONDIS_MP_DEACTIVATE_VC_REQUEST); pMsgFrame = AllocateMessageAndFrame(pAdapter, MessageSize); if (pMsgFrame == NULL) { break; } pMessage = RNDISMP_GET_MSG_FROM_FRAME(pMsgFrame); pMessage->NdisMessageType = NdisMessageType; pMsgFrame->NdisMessageType = NdisMessageType; pDeactivateVc = &pMessage->Message.CoMiniportDeactivateVc; pDeactivateVc->RequestId = pMsgFrame->RequestId; pDeactivateVc->DeviceVcHandle = pVc->DeviceVcContext; break; } default: ASSERT(FALSE); pMsgFrame = NULL; break; } return (pMsgFrame); } // BuildRndisMessageCoMiniport /****************************************************************************/ /* CompleteSendDataOnVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Handle send-completion of CONDIS data */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to Vc */ /* pNdisPacket - Packet being completed */ /* Status - send completion status */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID CompleteSendDataOnVc(IN PRNDISMP_VC pVc, IN PNDIS_PACKET pNdisPacket, IN NDIS_STATUS Status) { ULONG RefCount; NdisMCoSendComplete(Status, pVc->NdisVcHandle, pNdisPacket); RNDISMP_DEREF_VC(pVc, &RefCount); } /****************************************************************************/ /* IndicateReceiveDataOnVc */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Handle reception of a bunch of CONDIS packets on a Vc. */ /* */ /* Arguments: */ /* */ /* pVc - Pointer to VC on which data arrived. */ /* PacketArray - Array of packets */ /* NumberOfPackets - size of above array */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID IndicateReceiveDataOnVc(IN PRNDISMP_VC pVc, IN PNDIS_PACKET * PacketArray, IN UINT NumberOfPackets) { UINT i; do { if (pVc->VcState != RNDISMP_VC_ACTIVATED) { TRACE1(("Rcv VC data: VC %x, invalid state %d\n", pVc, pVc->VcState)); break; } for (i = 0; i < NumberOfPackets; i++) { RNDISMP_REF_VC(pVc); } NdisMCoIndicateReceivePacket(pVc->NdisVcHandle, PacketArray, NumberOfPackets); } while (FALSE); } // IndicateReceiveDataOnVc