5385 lines
136 KiB
C
5385 lines
136 KiB
C
/*++
|
|
|
|
Copyright(c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
protocol.c
|
|
|
|
Abstract:
|
|
|
|
ATM Ethernet PVC driver.
|
|
|
|
Author:
|
|
ADube - created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
const WCHAR c_szIMMiniportList[] = L"IMMiniportList";
|
|
const WCHAR c_szUpperBindings[] = L"UpperBindings";
|
|
|
|
|
|
#define MAX_PACKET_POOL_SIZE 0x0000FFFF
|
|
#define MIN_PACKET_POOL_SIZE 0x000000FF
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
EpvcResetComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion for the reset.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
Status Completion status
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
|
|
|
|
//
|
|
// We never issue a reset, so we should not be here.
|
|
//
|
|
ASSERT(0);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
EpvcRequestComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_REQUEST pNdisRequest,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion handler for the previously posted request. All OIDS are completed by and sent to
|
|
the same miniport that they were requested for.
|
|
If Oid == OID_PNP_QUERY_POWER then the data structure needs to returned with all entries =
|
|
NdisDeviceStateUnspecified
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
NdisRequest The posted request
|
|
Status Completion status
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ENTER("EpvcRequestComplete", 0x44a78b21)
|
|
|
|
PEPVC_ADAPTER pAdapter =(PEPVC_ADAPTER)ProtocolBindingContext;
|
|
PEPVC_NDIS_REQUEST pEpvcRequest = (PEPVC_NDIS_REQUEST )pNdisRequest;
|
|
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
pEpvcRequest = CONTAINING_RECORD(pNdisRequest, EPVC_NDIS_REQUEST, Request);
|
|
pEpvcRequest->Status = Status;
|
|
|
|
if (pEpvcRequest->pFunc == NULL)
|
|
{
|
|
//
|
|
// Unblock the calling thread
|
|
//
|
|
NdisSetEvent(&pEpvcRequest ->Event);
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Invoke the REquest completion handler
|
|
//
|
|
(pEpvcRequest->pFunc) (pEpvcRequest, Status);
|
|
|
|
}
|
|
|
|
EXIT()
|
|
RM_ASSERT_CLEAR(&sr);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PtStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Status handler for the lower-edge(protocol).
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
GeneralStatus Status code
|
|
StatusBuffer Status buffer
|
|
StatusBufferSize Size of the status buffer
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PEPVC_ADAPTER pAdapter =(PEPVC_ADAPTER)ProtocolBindingContext;
|
|
TRACE (TL_T, TM_Pt, ("== PtStatus Status %x", GeneralStatus));
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
EpvcStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Status handler for the lower-edge(protocol).
|
|
|
|
Call the Status indication function of all the miniports
|
|
associated with this adapter
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
GeneralStatus Status code
|
|
StatusBuffer Status buffer
|
|
StatusBufferSize Size of the status buffer
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
ENTER ("EpvcStatus",0x733e2f9e)
|
|
PEPVC_ADAPTER pAdapter =(PEPVC_ADAPTER)ProtocolBindingContext;
|
|
PEPVC_WORKITEM pWorkItem = NULL;
|
|
STATUS_INDICATION_CONTEXT Context;
|
|
BOOLEAN bDoNotProcess = FALSE;
|
|
BOOLEAN bIsMediaEvent = FALSE;
|
|
NDIS_MEDIA_STATE NewMediaState;
|
|
|
|
RM_DECLARE_STACK_RECORD(SR);
|
|
|
|
//
|
|
// Store the parameter, these will be passed to the miniports
|
|
//
|
|
Context.StatusBuffer = StatusBuffer ;
|
|
Context.StatusBufferSize = StatusBufferSize;
|
|
Context.GeneralStatus = GeneralStatus;
|
|
|
|
do
|
|
{
|
|
LOCKOBJ(pAdapter, &SR);
|
|
|
|
//
|
|
// Check for 2 conditions i Is it a Media event and
|
|
// 2) if it is a repeat indication
|
|
//
|
|
bIsMediaEvent = (GeneralStatus == NDIS_STATUS_MEDIA_CONNECT ||
|
|
GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT );
|
|
|
|
//
|
|
// Check for repitions next
|
|
//
|
|
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_CONNECT &&
|
|
pAdapter->info.MediaState == NdisMediaStateConnected)
|
|
{
|
|
bDoNotProcess = TRUE;
|
|
}
|
|
|
|
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT &&
|
|
pAdapter->info.MediaState == NdisMediaStateDisconnected)
|
|
{
|
|
bDoNotProcess = TRUE;
|
|
}
|
|
|
|
//
|
|
// Convert the Media Status into an NdisMediaState
|
|
//
|
|
if (bIsMediaEvent == TRUE && bDoNotProcess == FALSE)
|
|
{
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT )
|
|
{
|
|
pAdapter->info.MediaState = NdisMediaStateDisconnected;
|
|
}
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_CONNECT)
|
|
{
|
|
pAdapter->info.MediaState = NdisMediaStateConnected;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Update the Media state, if we have a new state
|
|
//
|
|
|
|
UNLOCKOBJ(pAdapter, &SR);
|
|
|
|
|
|
if (bDoNotProcess == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
epvcEnumerateObjectsInGroup(&pAdapter->MiniportsGroup,
|
|
epvcProcessStatusIndication ,
|
|
(PVOID)&Context,
|
|
&SR);
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
EXIT()
|
|
return;
|
|
}
|
|
|
|
|
|
INT
|
|
epvcProcessStatusIndication (
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Status handler for the lower-edge(protocol).
|
|
|
|
If we get a media connect, we queue a task to do the Vc Setup
|
|
|
|
If we get a media disconnect, we queue a task to tear the VC down
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
GeneralStatus Status code
|
|
StatusBuffer Status buffer
|
|
StatusBufferSize Size of the status buffer
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)pHdr;
|
|
PEPVC_ADAPTER pAdapter = pMiniport->pAdapter;
|
|
BOOLEAN fIsMiniportActive = FALSE;
|
|
PSTATUS_INDICATION_CONTEXT pContext = (PSTATUS_INDICATION_CONTEXT)pvContext ;
|
|
NDIS_STATUS GeneralStatus = pContext->GeneralStatus;
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// if this is not a media indication pass it up to ndis.
|
|
//
|
|
|
|
fIsMiniportActive = MiniportTestFlag(pMiniport, fMP_MiniportInitialized);
|
|
|
|
|
|
if (fIsMiniportActive == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Only pass up an indication if the miniport has been initialized
|
|
//
|
|
|
|
|
|
//
|
|
// Filter out a duplicate Indication
|
|
//
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT &&
|
|
pMiniport->info.MediaState == NdisMediaStateDisconnected)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT &&
|
|
pMiniport->info.MediaState == NdisMediaStateDisconnected)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Record the status and indicate it up to the protocols
|
|
//
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_CONNECT)
|
|
{
|
|
pMiniport->info.MediaState = NdisMediaStateConnected;
|
|
}
|
|
|
|
if (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT )
|
|
{
|
|
pMiniport->info.MediaState = NdisMediaStateDisconnected;
|
|
}
|
|
|
|
epvcMIndicateStatus(pMiniport,
|
|
GeneralStatus,
|
|
pContext->StatusBuffer,
|
|
pContext->StatusBufferSize
|
|
);
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// As we continue the iteration, return TRUE
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
epvcMediaWorkItem(
|
|
PNDIS_WORK_ITEM pWorkItem,
|
|
PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Status handler for the lower-edge(protocol).
|
|
|
|
If we get a media connect, we queue a task to do the Vc Setup
|
|
|
|
If we get a media disconnect, we queue a task to tear the VC down
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the adapter structure
|
|
GeneralStatus Status code
|
|
StatusBuffer Status buffer
|
|
StatusBufferSize Size of the status buffer
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
ASSERT (0);
|
|
}
|
|
|
|
|
|
|
|
|
|
INT
|
|
epvcMiniportIndicateStatusComplete(
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicate the status upto the protocols
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT) pHdr;
|
|
|
|
BOOLEAN fIsMiniportActive = MiniportTestFlag(pMiniport, fMP_MiniportInitialized);
|
|
|
|
//
|
|
// Only pass up an indication if the miniport has been initialized
|
|
//
|
|
|
|
if (fIsMiniportActive == TRUE )
|
|
{
|
|
NdisMIndicateStatusComplete(pMiniport->ndis.MiniportAdapterHandle);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
PtStatusComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ENTER("PtStatusComplete", 0x5729d194)
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) ProtocolBindingContext;
|
|
RM_DECLARE_STACK_RECORD(SR);
|
|
|
|
//
|
|
// Iterate through all the miniports and stop them
|
|
//
|
|
|
|
epvcEnumerateObjectsInGroup (&pAdapter->MiniportsGroup,
|
|
epvcMiniportIndicateStatusComplete,
|
|
NULL,
|
|
&SR );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
PtTransferDataComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET Packet,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PEPVC_I_MINIPORT pMiniport =(PEPVC_I_MINIPORT )ProtocolBindingContext;
|
|
|
|
|
|
if(pMiniport->ndis.MiniportAdapterHandle)
|
|
{
|
|
NdisMTransferDataComplete(pMiniport->ndis.MiniportAdapterHandle,
|
|
Packet,
|
|
Status,
|
|
BytesTransferred);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
PtReceive(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID LookAheadBuffer,
|
|
IN UINT LookAheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
LBFO - need to use primary for all receives
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
|
|
PNDIS_PACKET MyPacket, Packet;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
|
|
if(!pAdapt->ndis.MiniportAdapterHandle)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
PtReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the adapter below us when it is done indicating a batch of received buffers.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
|
|
|
|
}
|
|
|
|
|
|
INT
|
|
PtReceivePacket(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
ReceivePacket handler. Called up by the miniport below when it supports NDIS 4.0 style receives.
|
|
Re-package the packet and hand it back to NDIS for protocols above us. The re-package part is
|
|
important since NDIS uses the WrapperReserved part of the packet for its own book-keeping. Also
|
|
the re-packaging works differently when packets flow-up or down. In the up-path(here) the protocol
|
|
reserved is owned by the protocol above. We need to use the miniport reserved here.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
Packet - Pointer to the packet
|
|
|
|
Return Value:
|
|
|
|
== 0 -> We are done with the packet
|
|
!= 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
|
|
--*/
|
|
{
|
|
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET MyPacket;
|
|
PEPVC_PKT_CONTEXT Resvd;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// //
|
|
// Address Family - Entry points and Tasks //
|
|
// //
|
|
// //
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
VOID
|
|
EpvcAfRegisterNotify(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PCO_ADDRESS_FAMILY pAddressFamily
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This informs us that the Call manager is bound to a NIC. and that the call
|
|
manager is telling us that it is ready to accepts calls.
|
|
|
|
We expect there to be one interesting Address Family per underlying adapter
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : UnbindContext
|
|
|
|
--*/
|
|
{
|
|
ENTER("EpvcAfRegisterNotify", 0xaea79b12)
|
|
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) ProtocolBindingContext;
|
|
|
|
RM_DECLARE_STACK_RECORD(SR);
|
|
|
|
TRACE (TL_T, TM_Pt,("==>EpvcAfRegisterNotify\n"));
|
|
|
|
|
|
do
|
|
{
|
|
|
|
if (pAddressFamily->AddressFamily != CO_ADDRESS_FAMILY_Q2931)
|
|
{
|
|
//
|
|
// The call manager is not indicating the address family for an atm
|
|
// miniport. We are not interested
|
|
//
|
|
break;
|
|
}
|
|
|
|
LOCKOBJ(pAdapter, &SR);
|
|
|
|
RmTmpReferenceObject(&pAdapter->Hdr, &SR);
|
|
|
|
|
|
pAdapter->af.AddressFamily = *pAddressFamily;
|
|
|
|
//
|
|
//Begin a task that will call NdisClOpenAddressFamily asynchronously
|
|
//
|
|
UNLOCKOBJ(pAdapter, &SR);
|
|
|
|
epvcEnumerateObjectsInGroup(&pAdapter->MiniportsGroup,
|
|
epvcAfInitEnumerate,
|
|
NULL, // Context
|
|
&SR );
|
|
|
|
LOCKOBJ(pAdapter, &SR);
|
|
|
|
RmTmpDereferenceObject(&pAdapter->Hdr, &SR);
|
|
|
|
UNLOCKOBJ(pAdapter, &SR);
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
TRACE (TL_T, TM_Pt, ("<==EpvcAfRegisterNotify\n"));
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
|
|
EXIT()
|
|
|
|
}
|
|
|
|
|
|
// Enum function
|
|
//
|
|
INT
|
|
epvcAfInitEnumerate(
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext, // Unused
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
We have been notified of an acceptable address family
|
|
|
|
Iterate through all the miniort structures and open the address family
|
|
and InitDeviceInstance on each of the miniports
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ENTER("epvcAfInitEnumerate ",0x72eb5b98 )
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT) pHdr;
|
|
//
|
|
// Get miniport lock and tmpref it.
|
|
//
|
|
LOCKOBJ(pMiniport, pSR);
|
|
RmTmpReferenceObject(&pMiniport->Hdr, pSR);
|
|
|
|
|
|
do
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PRM_TASK pTask= NULL;
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->Hdr.pParentObject;
|
|
|
|
ASSERT (pAdapter->Hdr.Sig == TAG_ADAPTER);
|
|
|
|
//
|
|
// Allocate task to complete the unbind.
|
|
//
|
|
Status = epvcAllocateTask(
|
|
&pMiniport->Hdr, // pParentObject,
|
|
epvcTaskStartIMiniport, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Open address Family", // szDescription
|
|
&pTask,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
// Ugly situation. We'll just leave things as they are...
|
|
//
|
|
pTask = NULL;
|
|
TR_WARN(("FATAL: couldn't allocate unbind task!\n"));
|
|
break;
|
|
}
|
|
|
|
// Start the task to complete the Open Address Family.
|
|
// No locks must be held. RmStartTask uses up the tmpref on the task
|
|
// which was added by epvcAllocateTask.
|
|
//
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
|
|
((PTASK_AF) pTask)->pAf= &pAdapter->af.AddressFamily ;
|
|
((PTASK_AF) pTask)->Cause = TaskCause_AfNotify;
|
|
RmStartTask(pTask, 0, pSR);
|
|
|
|
LOCKOBJ(pMiniport, pSR);
|
|
|
|
} while(FALSE);
|
|
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
RmTmpDereferenceObject(&pMiniport->Hdr, pSR);
|
|
EXIT()
|
|
|
|
//
|
|
// As we want the enumeration to cotinue
|
|
//
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskStartIMiniport(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler for opening address families on an underlying adapters.
|
|
The number of address families instantiated is determined by the
|
|
configuration read in the registry
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : UnbindContext
|
|
|
|
--*/
|
|
{
|
|
|
|
ENTER("epvcTaskStartIMiniport", 0xaac34d81)
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
|
|
NDIS_STATUS InitStatus = NDIS_STATUS_SUCCESS;
|
|
PTASK_AF pAfTask = (PTASK_AF) pTask;
|
|
NDIS_HANDLE NdisAfHandle = NULL;
|
|
PEPVC_ADAPTER pAdapter = pMiniport->pAdapter;
|
|
ULONG State = pTask->Hdr.State;
|
|
|
|
enum
|
|
{
|
|
Stage_Start =0, // default
|
|
Stage_OpenAfComplete,
|
|
Stage_CloseAfComplete, // In case of failure
|
|
Stage_TaskCompleted,
|
|
Stage_End
|
|
|
|
}; // To be used in pTask->Hdr.State to indicate the state of the Task
|
|
|
|
|
|
TRACE ( TL_T, TM_Pt, ("==>epvcTaskStartIMiniport Code %x", Code) );
|
|
|
|
TRACE (TL_V, TM_Pt, ("epvcTaskStartIMiniport Task %p Task is in state %x\n", pTask, pTask->Hdr.State));
|
|
|
|
|
|
switch(pTask->Hdr.State)
|
|
{
|
|
|
|
case Stage_Start:
|
|
{
|
|
//
|
|
// is there another open address family task active
|
|
//
|
|
LOCKOBJ (pMiniport, pSR);
|
|
|
|
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->af.pAfTask)) == FALSE)
|
|
{
|
|
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->af.pAfTask);
|
|
|
|
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
|
|
|
|
//
|
|
// Set The state so we restart this code after main task completes
|
|
//
|
|
|
|
pTask->Hdr.State = Stage_Start;
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
|
|
|
|
|
|
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
|
|
|
|
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We are the primary task
|
|
//
|
|
ASSERT (pMiniport->af.pAfTask == pAfTask);
|
|
|
|
//
|
|
// make sure we are bound to the adapter below. If not exit
|
|
//
|
|
if (CHECK_AD_PRIMARY_STATE (pAdapter, EPVC_AD_PS_INITED) == FALSE &&
|
|
pAdapter->bind.BindingHandle == NULL)
|
|
{
|
|
//
|
|
// quietly exit as the protocol is not bound to the adapter below
|
|
//
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
pTask->Hdr.State = Stage_TaskCompleted; // we're finished.
|
|
Status = NDIS_STATUS_SUCCESS; // Exit
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check to see if our work is already done
|
|
//
|
|
|
|
|
|
if (MiniportTestFlag (pMiniport, fMP_AddressFamilyOpened) == TRUE)
|
|
{
|
|
//
|
|
// quietly exit as the address family is already Opened
|
|
//
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
pTask->Hdr.State = Stage_TaskCompleted; // we're finished.
|
|
Status = NDIS_STATUS_SUCCESS; // Exit
|
|
break;
|
|
}
|
|
|
|
|
|
UNLOCKOBJ(pMiniport,pSR);
|
|
|
|
//
|
|
// Get Ready to suspend the task.
|
|
// First update the state so that the resume
|
|
// will take it to the correct place
|
|
//
|
|
pTask->Hdr.State = Stage_OpenAfComplete;
|
|
RmSuspendTask( pTask, 0 ,pSR);
|
|
|
|
//
|
|
// Call Ndis to open address family
|
|
//
|
|
Status = epvcClOpenAddressFamily(pAdapter->bind.BindingHandle,
|
|
&pAdapter->af.AddressFamily,
|
|
(NDIS_HANDLE)pMiniport,
|
|
&EpvcGlobals.ndis.CC,
|
|
sizeof (EpvcGlobals.ndis.CC),
|
|
&NdisAfHandle
|
|
);
|
|
|
|
if (PEND(Status)== FALSE)
|
|
{
|
|
//
|
|
// Call the completion handler
|
|
//
|
|
EpvcCoOpenAfComplete(Status,
|
|
pMiniport,
|
|
NdisAfHandle );
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
//
|
|
// Now let this thread exit. Make the Async
|
|
// Completion handler complete the task
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case Stage_OpenAfComplete:
|
|
{
|
|
InitStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
//
|
|
// If the status is success then initialize the miniport
|
|
//
|
|
|
|
do
|
|
{
|
|
|
|
if (pAfTask->ReturnStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Success, so Now initialize the miniport
|
|
//
|
|
|
|
LOCKOBJ (pMiniport, pSR);
|
|
|
|
//
|
|
// Set the appropriate flag
|
|
//
|
|
MiniportSetFlag(pMiniport, fMP_DevInstanceInitialized);
|
|
|
|
UNLOCKOBJ (pMiniport, pSR);
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
InitStatus = NdisIMInitializeDeviceInstanceEx( EpvcGlobals.driver.DriverHandle,
|
|
&pMiniport->ndis.DeviceName,
|
|
pMiniport);
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Handle Failure
|
|
//
|
|
|
|
if (FAIL(InitStatus) || FAIL(pAfTask->ReturnStatus))
|
|
{
|
|
|
|
TRACE (TL_V, TM_Mp, ("epvcStartImMiniport Failed Status %x, InitStatus %x",Status, InitStatus));
|
|
|
|
LOCKOBJ (pMiniport, pSR);
|
|
|
|
//
|
|
// Clear the appropriate flags
|
|
//
|
|
|
|
|
|
if (MiniportTestFlag(pMiniport, fMP_AddressFamilyOpened)== TRUE)
|
|
{
|
|
MiniportClearFlag (pMiniport, fMP_AddressFamilyOpened);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (pMiniport->af.AfHandle == NULL);
|
|
}
|
|
|
|
UNLOCKOBJ (pMiniport, pSR);
|
|
|
|
//
|
|
// Close the Af if there was one.
|
|
//
|
|
|
|
if (pMiniport->af.AfHandle != NULL)
|
|
{
|
|
pTask->Hdr.State = Stage_CloseAfComplete;
|
|
//
|
|
// Prepare to so an Async Close Af
|
|
//
|
|
RmSuspendTask (pTask, 0, pSR);
|
|
//
|
|
// Close Address Family
|
|
//
|
|
|
|
Status = epvcClCloseAddressFamily(pMiniport->af.AfHandle);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
|
|
EpvcCoCloseAfComplete(Status,pMiniport );
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// We've finished task;
|
|
//
|
|
|
|
|
|
//
|
|
// Fall through
|
|
//
|
|
}
|
|
case Stage_CloseAfComplete:
|
|
{
|
|
pTask->Hdr.State = Stage_TaskCompleted;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
}
|
|
case Stage_End:
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
if (pTask->Hdr.State == Stage_TaskCompleted)
|
|
{
|
|
pTask->Hdr.State = Stage_End;
|
|
|
|
|
|
LOCKOBJ(pMiniport, pSR);
|
|
|
|
pMiniport->af.pAfTask = NULL;
|
|
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
TRACE ( TL_T, TM_Pt, ("<==epvcTaskStartIMiniport Status %x", Status) );
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskCloseIMiniport(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the task that Closes the miniport, the Device Instance and
|
|
the Address Family/
|
|
|
|
There are three reason that the task could be called.
|
|
1) Miniport Halt -MiniportInstance functions need not be called
|
|
2) Protocol Unbind- MiniportInstance functions HAVE to be called
|
|
3) CloseAddress Family - Miniport function are already called
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : UnbindContext
|
|
|
|
--*/
|
|
|
|
{
|
|
ENTER ("epvcTaskCloseIMiniport", 0x83342651)
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT ) RM_PARENT_OBJECT(pTask);
|
|
PTASK_AF pAfTask = (PTASK_AF) pTask;
|
|
BOOLEAN fNeedToHalt = FALSE;
|
|
BOOLEAN fNeedToCancel = FALSE;
|
|
ULONG State;
|
|
BOOLEAN fAddressFamilyOpened = FALSE;
|
|
BOOLEAN fIsDevInstanceInitialized = FALSE;
|
|
BOOLEAN fIsMiniportHalting = FALSE;
|
|
|
|
enum
|
|
{
|
|
Stage_Start =0, // default
|
|
Stage_CloseAddressFamilyCompleted,
|
|
Stage_TaskCompleted,
|
|
Stage_End
|
|
|
|
}; // To be used in pTask->Hdr.State to indicate the state of the Task
|
|
|
|
TRACE ( TL_T, TM_Pt, ("==> epvcTaskCloseIMiniport State %x", pTask->Hdr.State) );
|
|
|
|
State = pTask->Hdr.State;
|
|
|
|
switch(pTask->Hdr.State)
|
|
{
|
|
case Stage_Start:
|
|
{
|
|
//
|
|
// Check to see if the miniport has already opened an address family.
|
|
// If so exit
|
|
//
|
|
LOCKOBJ (pMiniport, pSR );
|
|
|
|
|
|
if (epvcIsThisTaskPrimary ( pTask, &(PRM_TASK)(pMiniport->af.pAfTask)) == FALSE)
|
|
{
|
|
PRM_TASK pOtherTask = (PRM_TASK)(pMiniport->af.pAfTask);
|
|
|
|
|
|
RmTmpReferenceObject (&pOtherTask->Hdr, pSR);
|
|
|
|
|
|
//
|
|
// Set The state so we restart this code after main task completes
|
|
//
|
|
|
|
pTask->Hdr.State = Stage_Start;
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
|
|
|
|
|
|
RmPendTaskOnOtherTask (pTask, 0, pOtherTask, pSR);
|
|
|
|
RmTmpDereferenceObject(&pOtherTask->Hdr,pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We are the primary task
|
|
//
|
|
ASSERT (pMiniport->af.pAfTask == pAfTask);
|
|
//
|
|
// Check to see if our work is already done
|
|
//
|
|
|
|
|
|
if (MiniportTestFlag (pMiniport, fMP_AddressFamilyOpened) == FALSE)
|
|
{
|
|
//
|
|
// quietly exit as the address family is already closed
|
|
//
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
State = Stage_TaskCompleted; // we're finished.
|
|
Status = NDIS_STATUS_FAILURE; // Exit
|
|
break;
|
|
}
|
|
|
|
fIsDevInstanceInitialized = MiniportTestFlag (pMiniport, fMP_DevInstanceInitialized);
|
|
|
|
fIsMiniportHalting = (pAfTask->Cause == TaskCause_MiniportHalt );
|
|
|
|
//
|
|
// Now do we need to halt the miniport. -
|
|
// Q1. Are we are in the middle of a Halt
|
|
// Q2. Has Our Miniport Instance been initialized -
|
|
// Has miniportInitialize been called - then DeInit the miniport
|
|
// If not then - cancel the Device Instance
|
|
//
|
|
if ((TRUE == fIsDevInstanceInitialized ) &&
|
|
( FALSE ==fIsMiniportHalting) )
|
|
{
|
|
if (MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == TRUE)
|
|
{
|
|
//
|
|
// Our Halt Handler has not been called,
|
|
//
|
|
fNeedToHalt = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Our miniport's initalized handler has not been called
|
|
//
|
|
//
|
|
// We are not in the middle of a halt, so this probably
|
|
// an unbind .
|
|
//
|
|
fNeedToCancel = TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Clear the Device Instance flag.
|
|
//
|
|
MiniportClearFlag (pMiniport, fMP_DevInstanceInitialized);
|
|
|
|
}
|
|
|
|
//
|
|
// Mark the address family as closed ,because this task will close it.
|
|
//
|
|
|
|
fAddressFamilyOpened = MiniportTestFlag (pMiniport, fMP_AddressFamilyOpened);
|
|
|
|
MiniportClearFlag (pMiniport, fMP_AddressFamilyOpened);
|
|
|
|
|
|
UNLOCKOBJ(pMiniport,pSR);
|
|
|
|
|
|
//
|
|
// Call Ndis to Deinitialize the miniport, The miniport is already Refed
|
|
//
|
|
TRACE ( TL_T, TM_Pt, ("epvcTaskCloseIMiniport ----") );
|
|
|
|
if (TRUE == fNeedToHalt )
|
|
{
|
|
epvcIMDeInitializeDeviceInstance(pMiniport);
|
|
}
|
|
|
|
if (TRUE== fNeedToCancel)
|
|
{
|
|
ASSERT (!" Need To cancel in Task close Miniport");
|
|
epvcCancelDeviceInstance(pMiniport, pSR);
|
|
}
|
|
|
|
//
|
|
// Now close the address family asynchronously.
|
|
// First suspend this task
|
|
//
|
|
pTask->Hdr.State = Stage_CloseAddressFamilyCompleted;
|
|
RmSuspendTask (pTask, 0 , pSR);
|
|
|
|
if (fAddressFamilyOpened == TRUE)
|
|
{
|
|
|
|
//
|
|
// We need to start a task to complete the Close Call And DeleteVC
|
|
//
|
|
|
|
Status = epvcClCloseAddressFamily(pMiniport->af.AfHandle);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
EpvcCoCloseAfComplete(Status, pMiniport);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
State = Stage_TaskCompleted; // we're finished.
|
|
Status = NDIS_STATUS_SUCCESS; // Exit
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// End this thread. If this thread is closing the addres family
|
|
// then we exit. If not, then we do the cleanup below
|
|
//
|
|
break;
|
|
|
|
}
|
|
case Stage_CloseAddressFamilyCompleted:
|
|
{
|
|
Status = pAfTask->ReturnStatus;
|
|
|
|
State = Stage_TaskCompleted ;
|
|
break;
|
|
|
|
}
|
|
|
|
case Stage_End:
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (Stage_TaskCompleted == State )
|
|
{
|
|
pTask->Hdr.State = Stage_End;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
//
|
|
// Clear the task here
|
|
//
|
|
|
|
LOCKOBJ (pMiniport, pSR);
|
|
|
|
pMiniport->af.pAfTask = NULL;
|
|
|
|
UNLOCKOBJ (pMiniport, pSR);
|
|
|
|
|
|
//
|
|
// Set the complete event here
|
|
//
|
|
|
|
if (pAfTask->Cause == TaskCause_ProtocolUnbind)
|
|
{
|
|
epvcSetEvent (&pAfTask->CompleteEvent);
|
|
|
|
}
|
|
|
|
if (pAfTask->Cause == TaskCause_AfCloseRequest)
|
|
{
|
|
//
|
|
// Nothing to do
|
|
//
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
TRACE ( TL_T, TM_Pt, ("<== epvcTaskCloseIMiniport Status %x", Status) );
|
|
|
|
EXIT();
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
epvcInstantiateMiniport(
|
|
IN PEPVC_ADAPTER pAdapter,
|
|
NDIS_HANDLE MIniportConfigHandle,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine goes to the registry and reads the device name for the IM miniport.
|
|
It then allocates a structure for it.
|
|
|
|
If the allocation fails, it quietly returns as there is no more work to be done.
|
|
(Maybe we should deregister the protocol)
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
PEPVC_I_MINIPORT pMiniport = NULL;
|
|
NDIS_STRING UpperBindings;
|
|
PNDIS_CONFIGURATION_PARAMETER pParameterValue = NULL;
|
|
EPVC_I_MINIPORT_PARAMS Params;
|
|
|
|
TRACE (TL_T, TM_Mp, ("==> epvcInstantiateMiniport pAdapter %p KeyName %p \n", pAdapter));
|
|
|
|
do
|
|
{
|
|
|
|
|
|
|
|
|
|
//
|
|
// Now read the upper bindings
|
|
//
|
|
|
|
NdisInitUnicodeString(&UpperBindings, c_szUpperBindings);
|
|
|
|
NdisReadConfiguration(
|
|
&NdisStatus,
|
|
&pParameterValue,
|
|
MIniportConfigHandle,
|
|
&UpperBindings,
|
|
NdisParameterString);
|
|
|
|
|
|
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus)
|
|
{
|
|
TRACE (TL_T, TM_Mp, (" epvcInstantiateMiniport NdisReadConfiguration Failed"));
|
|
break;
|
|
|
|
}
|
|
|
|
TRACE (TL_I, TM_Pt, ("Creating Miniport Adapter %x, KeyName: len %d, max %d, name: [%ws]\n",
|
|
pAdapter,
|
|
pParameterValue->ParameterData.StringData.Length,
|
|
pParameterValue->ParameterData.StringData.MaximumLength,
|
|
(unsigned char*)pParameterValue->ParameterData.StringData.Buffer));
|
|
|
|
//
|
|
// Check and see if we already have a miniport
|
|
//
|
|
|
|
RmLookupObjectInGroup( &pAdapter->MiniportsGroup,
|
|
0 , // no flags (not locked)
|
|
&pParameterValue->ParameterData.StringData,
|
|
NULL,
|
|
&(PRM_OBJECT_HEADER)pMiniport,
|
|
NULL,
|
|
pSR
|
|
);
|
|
if (pMiniport!= NULL)
|
|
{
|
|
//
|
|
// we already have a miniport, therefore exit.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Create and Initialize the miniport here
|
|
//
|
|
|
|
|
|
Params.pDeviceName = &pParameterValue->ParameterData.StringData;
|
|
Params.pAdapter = pAdapter;
|
|
Params.CurLookAhead = pAdapter->info.MaxAAL5PacketSize;
|
|
Params.NumberOfMiniports = (NdisInterlockedIncrement (&pAdapter->info.NumberOfMiniports) - 1);
|
|
Params.LinkSpeed = pAdapter->info.LinkSpeed;
|
|
Params.MacAddress = pAdapter->info.MacAddress;
|
|
Params.MediaState = pAdapter->info.MediaState;
|
|
|
|
NdisStatus = RM_CREATE_AND_LOCK_OBJECT_IN_GROUP(
|
|
&pAdapter->MiniportsGroup,
|
|
Params.pDeviceName, // Key
|
|
&Params, // Init params
|
|
&((PRM_OBJECT_HEADER)pMiniport),
|
|
NULL, // pfCreated
|
|
pSR
|
|
);
|
|
|
|
|
|
if (FAIL(NdisStatus))
|
|
{
|
|
TR_WARN(("FATAL: Couldn't create adapter object\n"));
|
|
pMiniport = NULL;
|
|
break;
|
|
}
|
|
|
|
UNLOCKOBJ(pMiniport,pSR);
|
|
|
|
//
|
|
// Initalize new miniport specific events here
|
|
//
|
|
epvcInitializeEvent (&pMiniport->pnp.HaltCompleteEvent);
|
|
epvcInitializeEvent (&pMiniport->pnp.DeInitEvent);
|
|
|
|
} while (FALSE);
|
|
|
|
if (FAIL(NdisStatus ) == TRUE)
|
|
{
|
|
//
|
|
// Do nothing
|
|
//
|
|
ASSERT (FAIL(NdisStatus ) == FALSE);
|
|
|
|
}
|
|
else
|
|
{
|
|
RmTmpDereferenceObject(&pMiniport->Hdr, pSR);
|
|
}
|
|
|
|
TRACE (TL_T, TM_Mp, ("<== epvcInstantiateMiniport pMiniport %p \n", pMiniport));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// //
|
|
// Adapter RM Object - Create, Delete, Hash and Compare functions //
|
|
// //
|
|
// //
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
PRM_OBJECT_HEADER
|
|
epvcAdapterCreate(
|
|
PRM_OBJECT_HEADER pParentObject,
|
|
PVOID pCreateParams,
|
|
PRM_STACK_RECORD psr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate and initialize an object of type EPVC_ADAPTER.
|
|
|
|
Arguments:
|
|
|
|
pParentObject - Object that is to be the parent of the adapter.
|
|
pCreateParams - Actually a pointer to a EPVC_ADAPTER_PARAMS structure,
|
|
which contains information required to create the adapter.
|
|
|
|
Return Value:
|
|
|
|
Pointer to the allocated and initialized object on success.
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PEPVC_ADAPTER pA;
|
|
PEPVC_ADAPTER_PARAMS pBindParams = (PEPVC_ADAPTER_PARAMS)pCreateParams;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
extern RM_STATIC_OBJECT_INFO EpvcGlobals_AdapterStaticInfo;
|
|
extern RM_STATIC_OBJECT_INFO EpvcGlobals_I_MiniportStaticInfo ;
|
|
|
|
ENTER("AdapterCreate", 0x9cb433f4);
|
|
|
|
|
|
TRACE (TL_V, TM_Pt, ("--> epvcAdapterCreate") );
|
|
|
|
EPVC_ALLOCSTRUCT(pA, TAG_PROTOCOL);
|
|
do
|
|
{
|
|
|
|
|
|
if (pA == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
EPVC_ZEROSTRUCT(pA);
|
|
|
|
//
|
|
// Do all the initialization work here
|
|
//
|
|
|
|
pA->Hdr.Sig = TAG_ADAPTER;
|
|
|
|
RmInitializeLock(
|
|
&pA->Lock,
|
|
LOCKLEVEL_ADAPTER
|
|
);
|
|
|
|
RmInitializeHeader(
|
|
pParentObject,
|
|
&pA->Hdr,
|
|
TAG_ADAPTER,
|
|
&pA->Lock,
|
|
&EpvcGlobals_AdapterStaticInfo,
|
|
NULL,
|
|
psr
|
|
);
|
|
|
|
//
|
|
// Now initialize the adapter structure with the parameters
|
|
// that were passed in.
|
|
//
|
|
|
|
// Create up-cased version of the DeviceName and save it.
|
|
//
|
|
//
|
|
Status = epvcCopyUnicodeString(
|
|
&(pA->bind.DeviceName),
|
|
pBindParams->pDeviceName,
|
|
TRUE // Upcase
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pA->bind.DeviceName.Buffer=NULL; // so we don't try to free it later
|
|
break;
|
|
}
|
|
|
|
pA->bind.pEpvcConfigName = pBindParams->pEpvcConfigName;
|
|
|
|
Status = epvcCopyUnicodeString(
|
|
&(pA->bind.EpvcConfigName),
|
|
pBindParams->pEpvcConfigName,
|
|
FALSE
|
|
);
|
|
|
|
pA->bind.BindContext = pBindParams->BindContext;
|
|
|
|
//
|
|
// Initialize and allocate a group for all the intermediate miniports that
|
|
// will be instantiated over this physical adapter
|
|
//
|
|
|
|
|
|
RmInitializeGroup(
|
|
&pA->Hdr, // pOwningObject
|
|
&EpvcGlobals_I_MiniportStaticInfo ,
|
|
&(pA->MiniportsGroup),
|
|
"Intermediate miniports", // szDescription
|
|
psr
|
|
);
|
|
|
|
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
while(FALSE);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
if (pA != NULL)
|
|
{
|
|
epvcAdapterDelete ((PRM_OBJECT_HEADER) pA, psr);
|
|
pA = NULL;
|
|
}
|
|
}
|
|
|
|
TRACE (TL_V, TM_Pt, ("<-- epvcAdapterCreate pAdpater. %p",pA) );
|
|
|
|
return (PRM_OBJECT_HEADER) pA;
|
|
}
|
|
|
|
|
|
VOID
|
|
epvcAdapterDelete (
|
|
PRM_OBJECT_HEADER pObj,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free an object of type EPVC_ADAPTER.
|
|
|
|
Arguments:
|
|
|
|
pHdr - Actually a pointer to the EPVC_ADAPTER to be deleted.
|
|
|
|
--*/
|
|
{
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) pObj;
|
|
|
|
TRACE (TL_V, TM_Pt, ("-- epvcAdapterDelete pAdapter %p",pAdapter) );
|
|
|
|
pAdapter->Hdr.Sig = TAG_FREED;
|
|
|
|
|
|
EPVC_FREE (pAdapter);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
epvcAdapterCompareKey(
|
|
PVOID pKey,
|
|
PRM_HASH_LINK pItem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Hash comparison function for EPVC_ADAPTER.
|
|
|
|
Arguments:
|
|
|
|
pKey - Points to a Epvc Protocol object.
|
|
pItem - Points to EPVC_ADAPTER.Hdr.HashLink.
|
|
|
|
Return Value:
|
|
|
|
TRUE IFF the key (adapter name) exactly matches the key of the specified
|
|
adapter object.
|
|
|
|
--*/
|
|
{
|
|
PEPVC_ADAPTER pA = NULL;
|
|
PNDIS_STRING pName = (PNDIS_STRING) pKey;
|
|
BOOLEAN fCompare;
|
|
|
|
pA = CONTAINING_RECORD(pItem, EPVC_ADAPTER, Hdr.HashLink);
|
|
|
|
//
|
|
// TODO: maybe case-insensitive compare?
|
|
//
|
|
|
|
if ( (pA->bind.DeviceName.Length == pName->Length)
|
|
&& NdisEqualMemory(pA->bind.DeviceName.Buffer, pName->Buffer, pName->Length))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
TRACE (TL_V, TM_Pt, ("-- epvcProtocolCompareKey pAdapter %p, pKey, return %x",pA, pKey, fCompare ) );
|
|
|
|
return fCompare;
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
epvcAdapterHash(
|
|
PVOID pKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Hash function responsible for returning a hash of pKey, which
|
|
we expect to be a pointer to an Epvc Protocol block.
|
|
|
|
Return Value:
|
|
|
|
ULONG-sized hash of the string.
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
|
|
PNDIS_STRING pName = (PNDIS_STRING) pKey;
|
|
WCHAR *pwch = pName->Buffer;
|
|
WCHAR *pwchEnd = pName->Buffer + pName->Length/sizeof(*pwch);
|
|
ULONG Hash = 0;
|
|
|
|
for (;pwch < pwchEnd; pwch++)
|
|
{
|
|
Hash ^= (Hash<<1) ^ *pwch;
|
|
}
|
|
|
|
return Hash;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
// //
|
|
// Bind Adapter - Entry Points and Tasks //
|
|
// //
|
|
// //
|
|
//--------------------------------------------------------------------------------
|
|
|
|
VOID
|
|
EpvcBindAdapter(
|
|
OUT PNDIS_STATUS pStatus,
|
|
IN NDIS_HANDLE BindContext,
|
|
IN PNDIS_STRING pDeviceName,
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID SystemSpecific2
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called by NDIS when it has an adapter for which there is a
|
|
binding to the Epvc Protocol.
|
|
|
|
We first allocate an Adapter structure. Then we open our configuration
|
|
section for this adapter and save the handle in the Adapter structure.
|
|
Finally, we open the adapter.
|
|
|
|
We then read the registry and find out how many intermediate Miniports are
|
|
sitting on top of this adapter. Data structures are initialized for these Miniports
|
|
|
|
We don't do anything more for this adapter until NDIS notifies us of
|
|
the presence of a Call manager (via our AfRegisterNotify handler).
|
|
|
|
Arguments:
|
|
|
|
pStatus - Place to return status of this call
|
|
BindContext - Not used, because we don't pend this call
|
|
pDeviceName - The name of the adapter we are requested to bind to
|
|
SystemSpecific1 - Opaque to us; to be used to access configuration info
|
|
SystemSpecific2 - Opaque to us; not used.
|
|
|
|
Return Value:
|
|
|
|
Always TRUE. We set *pStatus to an error code if something goes wrong before
|
|
we
|
|
call NdisOpenAdapter, otherwise NDIS_STATUS_PENDING.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
EPVC_ADAPTER *pAdapter;
|
|
#if DBG
|
|
KIRQL EntryIrql = KeGetCurrentIrql();
|
|
#endif // DBG
|
|
|
|
ENTER("BindAdapter", 0xa830f919)
|
|
RM_DECLARE_STACK_RECORD(SR)
|
|
TIMESTAMP("==>BindAdapter");
|
|
|
|
|
|
|
|
do
|
|
{
|
|
PRM_TASK pTask;
|
|
EPVC_ADAPTER_PARAMS BindParams;
|
|
|
|
// Setup initialization parameters
|
|
//
|
|
BindParams.pDeviceName = pDeviceName;
|
|
BindParams.pEpvcConfigName = (PNDIS_STRING) SystemSpecific1;
|
|
BindParams.BindContext = BindContext;
|
|
|
|
|
|
// Allocate and initialize adapter object.
|
|
// This also sets up ref counts for all linkages, plus one
|
|
// tempref for us, which we must deref when done.
|
|
//
|
|
Status = RM_CREATE_AND_LOCK_OBJECT_IN_GROUP(
|
|
&EpvcGlobals.adapters.Group,
|
|
pDeviceName, // Key
|
|
&BindParams, // Init params
|
|
&((PRM_OBJECT_HEADER)pAdapter),
|
|
NULL, // pfCreated
|
|
&SR
|
|
);
|
|
if (FAIL(Status))
|
|
{
|
|
TR_WARN(("FATAL: Couldn't create adapter object\n"));
|
|
pAdapter = NULL;
|
|
break;
|
|
}
|
|
|
|
// Allocate task to complete the initialization.
|
|
// The task is tmp ref'd for us, and we must deref it when we're done here.
|
|
// We implicitly do this by calling RmStartTask below.
|
|
//
|
|
Status = epvcAllocateTask(
|
|
&pAdapter->Hdr, // pParentObject,
|
|
epvcTaskInitializeAdapter, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Initialize Adapter", // szDescription
|
|
&pTask,
|
|
&SR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pTask = NULL;
|
|
break;
|
|
}
|
|
|
|
UNLOCKOBJ(pAdapter, &SR);
|
|
|
|
// Start the task to complete this initialization.
|
|
// NO locks must be held at this time.
|
|
// RmStartTask expect's a tempref on the task, which it deref's when done.
|
|
// RmStartTask will free the task automatically, whether it completes
|
|
// synchronously or asynchronously.
|
|
//
|
|
RmStartTask(pTask, 0, &SR);
|
|
|
|
TRACE (TL_V, TM_Pt, ("Task InitializeAdapter - Start Task returned %x", Status));
|
|
LOCKOBJ(pAdapter, &SR);
|
|
|
|
} while(FALSE);
|
|
|
|
if (pAdapter)
|
|
{
|
|
UNLOCKOBJ(pAdapter, &SR);
|
|
|
|
if (!PEND(Status) && FAIL(Status))
|
|
{
|
|
// At this point the adapter should be a "zombie object."
|
|
//
|
|
ASSERTEX(RM_IS_ZOMBIE(pAdapter), pAdapter);
|
|
}
|
|
|
|
RmTmpDereferenceObject(&pAdapter->Hdr, &SR);
|
|
|
|
*pStatus = NDIS_STATUS_PENDING;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Fail the bind as the adapter was not allocated
|
|
//
|
|
*pStatus = NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DBG
|
|
{
|
|
KIRQL ExitIrql = KeGetCurrentIrql();
|
|
TR_INFO(("Exiting. EntryIrql=%lu, ExitIrql = %lu\n", EntryIrql, ExitIrql));
|
|
}
|
|
#endif //DBG
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
EXIT()
|
|
TIMESTAMP("<==BindAdapter");
|
|
TRACE (TL_T, TM_Pt, ("<==BindAdapter %x", *pStatus));
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskInitializeAdapter(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler responsible for initializing an adapter.
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : unused
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) RM_PARENT_OBJECT(pTask);
|
|
PTASK_ADAPTERINIT pAdapterInitTask;
|
|
|
|
enum
|
|
{
|
|
STAGE_BecomePrimaryTask,
|
|
STAGE_ActivateAdapterComplete,
|
|
STAGE_DeactivateAdapterComplete,
|
|
STAGE_End
|
|
|
|
} Stage;
|
|
|
|
ENTER("TaskInitializeAdapter", 0x18f9277a)
|
|
|
|
pAdapterInitTask = (PTASK_ADAPTERINIT) pTask;
|
|
|
|
TRACE (TL_T, TM_Pt, ("==>epvcTaskInitializeAdapter Code %x \n", Code));
|
|
|
|
//
|
|
// Message normalizing code
|
|
//
|
|
switch(Code)
|
|
{
|
|
|
|
case RM_TASKOP_START:
|
|
Stage = STAGE_BecomePrimaryTask;
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
Status = (NDIS_STATUS) UserParam;
|
|
ASSERT(!PEND(Status));
|
|
Stage = RM_PEND_CODE(pTask);
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
Status = (NDIS_STATUS) UserParam;
|
|
Stage= STAGE_End;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
|
|
|
|
}
|
|
|
|
ASSERTEX(!PEND(Status), pTask);
|
|
|
|
switch(Stage)
|
|
{
|
|
|
|
case STAGE_BecomePrimaryTask:
|
|
{
|
|
// If there is a primary task, pend on it, else make ourselves
|
|
// the primary task.
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
if (pAdapter->bind.pPrimaryTask == NULL)
|
|
{
|
|
epvcSetPrimaryAdapterTask(pAdapter, pTask, EPVC_AD_PS_INITING, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
}
|
|
else
|
|
{
|
|
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
|
|
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
STAGE_BecomePrimaryTask, // we'll try again...
|
|
pOtherTask,
|
|
pSR
|
|
);
|
|
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We're now the primary task. Since we're starting out,
|
|
// there should be NO activate/deactivate task.
|
|
// (Note: we don't bother getting the adapter lock for these asserts).
|
|
//
|
|
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
|
|
ASSERT(pAdapter->bind.pSecondaryTask == NULL);
|
|
|
|
//
|
|
// Allocate and start the activate adapter task.
|
|
//
|
|
{
|
|
PRM_TASK pActivateTask;
|
|
|
|
Status = epvcAllocateTask(
|
|
&pAdapter->Hdr, // pParentObject,
|
|
epvcTaskActivateAdapter, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Activate Adapter(init)", // szDescription
|
|
&pActivateTask,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pActivateTask = NULL;
|
|
TR_WARN(("FATAL: couldn't alloc activate task!\n"));
|
|
}
|
|
else
|
|
{
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
STAGE_ActivateAdapterComplete,
|
|
pActivateTask, // task to pend on
|
|
pSR
|
|
);
|
|
|
|
// RmStartTask uses up the tmpref on the task
|
|
// which was added by arpAllocateTask.
|
|
//
|
|
Status = RmStartTask(
|
|
pActivateTask,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (PEND(Status)) break;
|
|
|
|
// FALL THROUGH TO NEXT STAGE
|
|
|
|
case STAGE_ActivateAdapterComplete:
|
|
{
|
|
//
|
|
// We've run the active-adapter task. On failure, we need to
|
|
// cleanup state by calling the deactivate-adapter task.
|
|
//
|
|
|
|
// Save away the failure code for later...
|
|
//
|
|
pAdapterInitTask->ReturnStatus = Status;
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
PRM_TASK pDeactivateTask;
|
|
|
|
Status = epvcAllocateTask(
|
|
&pAdapter->Hdr, // pParentObject,
|
|
epvcTaskDeactivateAdapter, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Deactivate Adapter(init)", // szDescription
|
|
&pDeactivateTask,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pDeactivateTask = NULL;
|
|
ASSERT(FALSE); // TODO: use special dealloc task pool for this.
|
|
TR_WARN(("FATAL: couldn't alloc deactivate task!\n"));
|
|
}
|
|
else
|
|
{
|
|
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
STAGE_DeactivateAdapterComplete,
|
|
pDeactivateTask, // task to pend on
|
|
pSR
|
|
);
|
|
|
|
//
|
|
// RmStartTask uses up the tmpref on the task
|
|
// which was added by arpAllocateTask.
|
|
//
|
|
Status = RmStartTask(
|
|
pDeactivateTask,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STAGE_DeactivateAdapterComplete:
|
|
{
|
|
|
|
//
|
|
// We've completed the deactivate adapter task which we started
|
|
// because of some init-adapter failure.
|
|
//
|
|
|
|
// In general, we don't expect the deactivate task to return failure.
|
|
//
|
|
ASSERT(!FAIL(Status));
|
|
|
|
// We expect the original status of the init to be a failure (that's
|
|
// why we started the deinit in the first place!
|
|
//
|
|
ASSERT(FAIL(pAdapterInitTask->ReturnStatus));
|
|
Status = pAdapterInitTask->ReturnStatus;
|
|
|
|
}
|
|
break;
|
|
|
|
case STAGE_End:
|
|
{
|
|
NDIS_HANDLE BindContext;
|
|
|
|
//
|
|
// We HAVE to be the primary task at this point, becase we simply
|
|
// wait and retry until we become one.
|
|
//
|
|
|
|
// Clear the primary task in the adapter object.
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
{
|
|
ULONG InitState;
|
|
InitState = FAIL(Status) ? EPVC_AD_PS_FAILEDINIT : EPVC_AD_PS_INITED;
|
|
epvcClearPrimaryAdapterTask(pAdapter, pTask, InitState, pSR);
|
|
}
|
|
BindContext = pAdapter->bind.BindContext;
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
|
|
|
|
// On failure, pAdapter should be deallocated.
|
|
//
|
|
if (FAIL(Status))
|
|
{
|
|
if(RM_IS_ZOMBIE(pAdapter))
|
|
{
|
|
TR_WARN(("END: pAdapter is already deallocated.\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// On failure, free the adapter here itself, because we're
|
|
// not going to call the shutdown task.
|
|
//
|
|
RmFreeObjectInGroup(
|
|
&EpvcGlobals.adapters.Group,
|
|
&(pAdapter->Hdr),
|
|
NULL, // NULL pTask == synchronous.
|
|
pSR
|
|
);
|
|
|
|
pAdapter = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clear out the variables that are valid only
|
|
// during the BindAdapter Call
|
|
//
|
|
if (pAdapter != NULL)
|
|
{
|
|
pAdapter->bind.pEpvcConfigName = NULL;
|
|
}
|
|
// Signal Ndis that the bind is complete.
|
|
//
|
|
NdisCompleteBindAdapter(BindContext ,
|
|
Status,
|
|
NDIS_STATUS_PENDING);
|
|
TIMESTAMP("== Completing the Adapter Bind");
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
TRACE (TL_T, TM_Pt, ("<==epvcTaskInitializeAdapter Status %x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskActivateAdapter(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler responsible for initializing an adapter.
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : unused
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) RM_PARENT_OBJECT(pTask);
|
|
|
|
enum
|
|
{
|
|
PEND_OpenAdapter,
|
|
PEND_GetAdapterInfo
|
|
};
|
|
ENTER("TaskInitializeAdapter", 0xb6ada31d)
|
|
TRACE (TL_T, TM_Pt, ("==>epvcTaskActivateAdapter pAdapter %p Code %x",pAdapter, Code ));
|
|
|
|
switch(Code)
|
|
{
|
|
|
|
case RM_TASKOP_START:
|
|
{
|
|
|
|
NDIS_MEDIUM Medium = NdisMediumAtm;
|
|
|
|
|
|
UINT SelMediumIndex = 0;
|
|
NDIS_STATUS OpenStatus;
|
|
|
|
TRACE (TL_T, TM_Pt, (" epvcTaskActivateAdapter RM_TASKOP_START "));
|
|
|
|
|
|
// Set ourselves as the secondary task.
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
epvcSetSecondaryAdapterTask(pAdapter, pTask, EPVC_AD_AS_ACTIVATING, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
|
|
//
|
|
// Suspend task and call NdisOpenAdapter...
|
|
//
|
|
|
|
RmSuspendTask(pTask, PEND_OpenAdapter, pSR);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
epvcOpenAdapter(
|
|
&Status,
|
|
&OpenStatus,
|
|
&pAdapter->bind.BindingHandle,
|
|
&SelMediumIndex, // selected medium index
|
|
&Medium, // Array of medium types
|
|
1, // Size of Media list
|
|
EpvcGlobals.driver.ProtocolHandle,
|
|
(NDIS_HANDLE)pAdapter, // our adapter bind context
|
|
&pAdapter->bind.DeviceName, // pDeviceName
|
|
0, // Open options
|
|
(PSTRING)NULL, // Addressing Info...
|
|
pSR);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
EpvcOpenAdapterComplete(
|
|
(NDIS_HANDLE)pAdapter,
|
|
Status,
|
|
OpenStatus
|
|
);
|
|
}
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
{
|
|
PTASK_ADAPTERACTIVATE pAdapterInitTask;
|
|
pAdapterInitTask = (PTASK_ADAPTERACTIVATE) pTask;
|
|
Status = (NDIS_STATUS) UserParam;
|
|
ASSERT(!PEND(Status));
|
|
ASSERT(sizeof(TASK_ADAPTERACTIVATE) <= sizeof(EPVC_TASK));
|
|
|
|
|
|
switch(RM_PEND_CODE(pTask))
|
|
{
|
|
case PEND_OpenAdapter:
|
|
|
|
//
|
|
// The open adapter operation is complete. Get adapter
|
|
// information and notify IP on success. On failure,
|
|
// shutdown the adapter if required, and notify IP of
|
|
// the failure.
|
|
//
|
|
|
|
TRACE (TL_T, TM_Pt, (" epvcTaskActivateAdapter RM_TASKOP_PENDCOMPLETE - PEND_OpenAdapter "));
|
|
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
// Set adapter handle to null -- it may not be hull.
|
|
// even though the open adapter has succeeded.
|
|
//
|
|
pAdapter->bind.BindingHandle = NULL;
|
|
break;
|
|
}
|
|
|
|
ASSERT (pAdapter->bind.BindingHandle != NULL);
|
|
|
|
// FALL THROUGH on synchronous completion of arpGetAdapterInfo...
|
|
|
|
case PEND_GetAdapterInfo:
|
|
|
|
//
|
|
// Done with getting adapter info.
|
|
// We need to switch to passive before going further
|
|
//
|
|
TRACE (TL_T, TM_Pt, (" epvcTaskActivateAdapter RM_TASKOP_PENDCOMPLETE - PEND_GetAdapterInfo "));
|
|
|
|
ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
if (!EPVC_ATPASSIVE())
|
|
{
|
|
ASSERT (!"Should not be here");
|
|
|
|
// We're not at passive level, but we need to be when we
|
|
// call IP's add interface. So we switch to passive...
|
|
// NOTE: we specify completion code PEND_GetAdapterInfo
|
|
// because we want to get back here (except
|
|
// we'll be at passive).
|
|
//
|
|
/*RmSuspendTask(pTask, PEND_GetAdapterInfo, pSR);
|
|
RmResumeTaskAsync(
|
|
pTask,
|
|
Status,
|
|
&pAdapterInitTask->WorkItem,
|
|
pSR
|
|
);
|
|
Status = NDIS_STATUS_PENDING;*/
|
|
break;
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Copy over adapter info into pAdapter->info...
|
|
// Then read configuration information.
|
|
//
|
|
|
|
//
|
|
// Query the ATM adapter for HW specific Info
|
|
//
|
|
epvcGetAdapterInfo(pAdapter, pSR, NULL);
|
|
|
|
// Read Adapter Configuration Information
|
|
//
|
|
Status = epvcReadAdapterConfiguration(pAdapter, pSR);
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// NOTE: if we fail, a higher level task is responsible
|
|
// for "running the compensating transaction", i.e., running
|
|
// epvcTaskDeactivateAdapter.
|
|
//
|
|
|
|
// end case PEND_OpenAdapter, PEND_GetAdapterInfo
|
|
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown pend op", pTask);
|
|
}
|
|
break;
|
|
|
|
|
|
} // end switch(RM_PEND_CODE(pTask))
|
|
|
|
|
|
} // case RM_TASKOP_PENDCOMPLETE
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
{
|
|
|
|
TRACE (TL_T, TM_Pt, (" epvcTaskActivateAdapter RM_TASKOP_END"));
|
|
Status = (NDIS_STATUS) UserParam;
|
|
|
|
// We're done -- the status had better not be pending!
|
|
//
|
|
ASSERTEX(!PEND(Status), pTask);
|
|
|
|
// Clear ourselves as the secondary task in the adapter object.
|
|
//
|
|
{
|
|
ULONG InitState;
|
|
LOCKOBJ(pAdapter, pSR);
|
|
InitState = FAIL(Status)
|
|
? EPVC_AD_AS_FAILEDACTIVATE
|
|
: EPVC_AD_AS_ACTIVATED;
|
|
epvcClearSecondaryAdapterTask(pAdapter, pTask, InitState, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
}
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
TRACE (TL_T, TM_Pt, ("<==epvcTaskActivateAdapter Status %x", Status ));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
EpvcOpenAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called by NDIS when a previous call to NdisOpenAdapter
|
|
that had pended has completed. We now complete the BindAdapter
|
|
that lead to this.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - Our context for this adapter binding, which
|
|
is a pointer to an EPVC_ADAPTER structure.
|
|
Status - Status of OpenAdapter
|
|
OpenErrorStatus - Error code in case of failure.
|
|
|
|
--*/
|
|
{
|
|
ENTER("OpenAdapterComplete", 0x06d9342c)
|
|
|
|
|
|
EPVC_ADAPTER * pAdapter = (EPVC_ADAPTER*) ProtocolBindingContext;
|
|
RM_DECLARE_STACK_RECORD(SR)
|
|
|
|
|
|
TIMESTAMP("==>OpenAdapterComplete");
|
|
TRACE ( TL_T, TM_Mp, ("==>OpenAdapterComplete"));
|
|
|
|
// We expect a nonzero task here (the bind task), which we unpend.
|
|
// No need to grab locks or anything at this stage.
|
|
//
|
|
{
|
|
TR_INFO((
|
|
"BindCtxt=0x%p, status=0x%p, OpenErrStatus=0x%p",
|
|
ProtocolBindingContext,
|
|
Status,
|
|
OpenErrorStatus
|
|
));
|
|
|
|
// We don't pass on OpenErrorStatus, so we have just the status
|
|
// to pass on, which we do directly as the UINT_PTR "Param".
|
|
//
|
|
RmResumeTask(pAdapter->bind.pSecondaryTask, (UINT_PTR) Status, &SR);
|
|
}
|
|
|
|
RM_ASSERT_CLEAR(&SR)
|
|
EXIT()
|
|
TRACE ( TL_T, TM_Mp, ("<==OpenAdapterComplete"));
|
|
TIMESTAMP("<==OpenAdapterComplete");
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskDeactivateAdapter(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler responsible for shutting down an IP interface.
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : UnbindContext
|
|
|
|
--*/
|
|
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
EPVC_ADAPTER * pAdapter = (EPVC_ADAPTER*) RM_PARENT_OBJECT(pTask);
|
|
BOOLEAN fContinueShutdown = FALSE;
|
|
enum
|
|
{
|
|
PEND_CloseAdapter
|
|
};
|
|
ENTER("TaskShutdownAdapter", 0xe262e828)
|
|
TRACE ( TL_T, TM_Pt, ("==>epvcTaskDeactivateAdapter Code %x", Code) );
|
|
|
|
switch(Code)
|
|
{
|
|
|
|
case RM_TASKOP_START:
|
|
{
|
|
NDIS_HANDLE NdisAdapterHandle;
|
|
|
|
LOCKOBJ(pAdapter, pSR);
|
|
epvcSetSecondaryAdapterTask(pAdapter, pTask, EPVC_AD_AS_DEACTIVATING, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
fContinueShutdown = TRUE;
|
|
|
|
//
|
|
// Iterate through all the miniports and stop them
|
|
//
|
|
|
|
epvcEnumerateObjectsInGroup (&pAdapter->MiniportsGroup,
|
|
epvcMiniportDoUnbind,
|
|
NULL,
|
|
pSR );
|
|
|
|
|
|
//
|
|
// Close the adapter below
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
|
|
|
|
NdisAdapterHandle = pAdapter->bind.BindingHandle;
|
|
pAdapter->bind.BindingHandle = NULL;
|
|
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
|
|
if (NdisAdapterHandle != NULL)
|
|
{
|
|
//
|
|
// Suspend task and call NdisCloseAdapter...
|
|
//
|
|
|
|
RmSuspendTask(pTask, PEND_CloseAdapter, pSR);
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
|
|
epvcCloseAdapter(
|
|
&Status,
|
|
NdisAdapterHandle,
|
|
pSR
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
EpvcCloseAdapterComplete(
|
|
(NDIS_HANDLE)pAdapter,
|
|
Status
|
|
);
|
|
}
|
|
Status = NDIS_STATUS_PENDING;
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
{
|
|
|
|
switch(RM_PEND_CODE(pTask))
|
|
{
|
|
case PEND_CloseAdapter:
|
|
{
|
|
|
|
//
|
|
// The close adapter operation is complete. Free the the
|
|
// adapter and if there is an unbind context, notify NDIS
|
|
// of unbind completion.
|
|
//
|
|
|
|
ASSERTEX(pAdapter->bind.BindingHandle == NULL, pAdapter);
|
|
|
|
|
|
Status = (NDIS_STATUS) UserParam;
|
|
|
|
// Status of the completed operation can't itself be pending!
|
|
//
|
|
ASSERT(Status != NDIS_STATUS_PENDING);
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case RM_TASKOP_END:
|
|
{
|
|
Status = (NDIS_STATUS) UserParam;
|
|
|
|
// Clear the secondary task in the adapter object.
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
epvcClearSecondaryAdapterTask(pAdapter, pTask, EPVC_AD_AS_DEACTIVATED, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
TRACE ( TL_T, TM_Pt, ("<==epvcTaskDeactivateAdapter Status %x", Status) );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
EpvcCloseAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called by NDIS when a previous call to NdisCloseAdapter
|
|
that had pended has completed. The task that called NdisCloseAdapter
|
|
would have suspended itself, so we simply resume it now.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - Our context for this adapter binding, which
|
|
is a pointer to an EPVC_ADAPTER structure.
|
|
Status - Status of CloseAdapter
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ENTER("CloseAdapterComplete", 0xe23bfba7)
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) ProtocolBindingContext;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TIMESTAMP("==>CloseAdapterComplete");
|
|
TRACE (TL_T, TM_Pt, ("== EpvcCloseAdapterComplete"));
|
|
|
|
LOCKOBJ (pAdapter, &sr);
|
|
|
|
AdapterSetFlag (pAdapter,EPVC_AD_INFO_AD_CLOSED);
|
|
|
|
UNLOCKOBJ (pAdapter, &sr);
|
|
// We expect a nonzero task here (UNbind task), which we unpend.
|
|
// No need to grab locks or anything at this stage.
|
|
//
|
|
RmResumeTask(pAdapter->bind.pSecondaryTask, (UINT_PTR) Status, &sr);
|
|
|
|
TIMESTAMP("<==CloseAdapterComplete");
|
|
|
|
RM_ASSERT_CLEAR(&sr)
|
|
EXIT()
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcReadAdapterConfiguration(
|
|
PEPVC_ADAPTER pAdapter,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function can only be called from the BindAdapter function
|
|
|
|
Arguments:
|
|
pAdapter - Underlying adapter whose configuration is being read/
|
|
pSR - Stack Record
|
|
|
|
Return Value:
|
|
|
|
None
|
|
++*/
|
|
{
|
|
NDIS_HANDLE AdaptersConfigHandle = NULL;
|
|
NDIS_HANDLE MiniportListConfigHandle = NULL;
|
|
NDIS_STRING MiniportListKeyName;
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
ENTER("ReadAdapterConfiguration", 0x83c48ad8)
|
|
|
|
TRACE(TL_T, TM_Pt, ("==> epvcReadAdapterConfigurationpAdapter %p", pAdapter));
|
|
|
|
|
|
do
|
|
{
|
|
//
|
|
// Start off by opening the config section and reading our instance which we want
|
|
// to export for this binding
|
|
//
|
|
epvcOpenProtocolConfiguration(&NdisStatus,
|
|
&AdaptersConfigHandle ,
|
|
&pAdapter->bind.EpvcConfigName,
|
|
pSR);
|
|
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus )
|
|
{
|
|
AdaptersConfigHandle = NULL;
|
|
TRACE_BREAK(TM_Pt, ("epvcOpenProtocolConfiguration failed " ) );
|
|
}
|
|
|
|
|
|
//
|
|
// this should get us to the protocol\paramters\adapters\guid section in the registry
|
|
//
|
|
|
|
//
|
|
// Open the Elan List configuration key.
|
|
//
|
|
NdisInitUnicodeString(&MiniportListKeyName, c_szIMMiniportList);
|
|
|
|
epvcOpenConfigurationKeyByName(
|
|
&NdisStatus,
|
|
AdaptersConfigHandle ,
|
|
&MiniportListKeyName,
|
|
&MiniportListConfigHandle,
|
|
pSR);
|
|
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus)
|
|
{
|
|
MiniportListConfigHandle = NULL;
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE_BREAK(TM_Pt, ("NdisOpenConfigurationKeyByName failed " ) );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Allocate and initialize all IM miniport instances that are present
|
|
// in the registry under this adapter
|
|
//
|
|
(VOID)epvcReadIntermediateMiniportConfiguration( pAdapter,
|
|
MiniportListConfigHandle,
|
|
pSR);
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
if (MiniportListConfigHandle!= NULL)
|
|
{
|
|
NdisCloseConfiguration(MiniportListConfigHandle);
|
|
MiniportListConfigHandle = NULL;
|
|
}
|
|
|
|
if (AdaptersConfigHandle != NULL)
|
|
{
|
|
NdisCloseConfiguration(AdaptersConfigHandle );
|
|
AdaptersConfigHandle = NULL;
|
|
}
|
|
|
|
if (STATUS_NO_MORE_ENTRIES == NdisStatus )
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
TRACE(TL_T, TM_Pt, ("<== epvcReadAdapterConfiguration Status %x", NdisStatus));
|
|
EXIT()
|
|
return NdisStatus;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcReadIntermediateMiniportConfiguration(
|
|
IN PEPVC_ADAPTER pAdapter,
|
|
IN NDIS_HANDLE MiniportListConfigHandle,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE;
|
|
|
|
ENTER ("ReadMiniportConfiguration", 0xb974a6fa)
|
|
|
|
TRACE(TL_T, TM_Pt, ("==> epvcReadIntermediateMiniportConfiguration pAdapter %p", pAdapter));
|
|
|
|
|
|
{
|
|
NDIS_HANDLE MiniportConfigHandle;
|
|
NDIS_STRING MiniportKeyName;
|
|
PEPVC_I_MINIPORT pMiniport = NULL;
|
|
|
|
UINT Index = 0;
|
|
//
|
|
// Iterate thru the configured Miniport
|
|
//
|
|
for (Index = 0;
|
|
; // Stop only on error or no more Elans
|
|
Index++)
|
|
{
|
|
EPVC_I_MINIPORT_PARAMS Params;
|
|
//
|
|
// Open the "next" Miniport key
|
|
//
|
|
epvcOpenConfigurationKeyByIndex(
|
|
&NdisStatus,
|
|
MiniportListConfigHandle,
|
|
Index,
|
|
&MiniportKeyName,
|
|
&MiniportConfigHandle,
|
|
pSR
|
|
);
|
|
|
|
if (NDIS_STATUS_SUCCESS != NdisStatus)
|
|
{
|
|
MiniportConfigHandle = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// If NULL handle, assume no more Miniports.
|
|
//
|
|
if (MiniportConfigHandle == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Creating this Miniport
|
|
//
|
|
epvcInstantiateMiniport (pAdapter,
|
|
MiniportConfigHandle,
|
|
pSR);
|
|
|
|
|
|
|
|
NdisCloseConfiguration(MiniportConfigHandle);
|
|
MiniportConfigHandle = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Close config handles
|
|
//
|
|
if (NULL != MiniportConfigHandle)
|
|
{
|
|
NdisCloseConfiguration(MiniportConfigHandle);
|
|
MiniportConfigHandle = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if (STATUS_NO_MORE_ENTRIES == NdisStatus )
|
|
{
|
|
NdisStatus = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
TRACE(TL_T, TM_Pt, ("<== epvcReadIntermediateMiniportConfiguration NdisStatus %x", NdisStatus));
|
|
EXIT()
|
|
return NdisStatus;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
EpvcUnbindAdapter(
|
|
OUT PNDIS_STATUS pStatus,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE UnbindContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS when it wants us to unbind
|
|
from an adapter. Or, this may be called from within our Unload
|
|
handler. We undo the sequence of operations we performed
|
|
in our BindAdapter handler.
|
|
|
|
Arguments:
|
|
|
|
pStatus - Place to return status of this operation
|
|
ProtocolBindingContext - Our context for this adapter binding, which
|
|
is a pointer to an ATMEPVC Adapter structure.
|
|
UnbindContext - This is NULL if this routine is called from
|
|
within our Unload handler. Otherwise (i.e.
|
|
NDIS called us), we retain this for later use
|
|
when calling NdisCompleteUnbindAdapter.
|
|
|
|
Return Value:
|
|
|
|
None. We set *pStatus to NDIS_STATUS_PENDING always.
|
|
|
|
--*/
|
|
{
|
|
ENTER("UnbindAdapter", 0x3f25396e)
|
|
EPVC_ADAPTER * pAdapter = (EPVC_ADAPTER*) ProtocolBindingContext;
|
|
RM_DECLARE_STACK_RECORD(sr)
|
|
|
|
TIMESTAMP("==>UnbindAdapter");
|
|
|
|
TRACE ( TL_T, TM_Pt, ("==>UnbindAdapter ProtocolBindingContext %x\n", ProtocolBindingContext) );
|
|
|
|
//
|
|
// Get adapter lock and tmpref it.
|
|
//
|
|
LOCKOBJ(pAdapter, &sr);
|
|
RmTmpReferenceObject(&pAdapter->Hdr, &sr);
|
|
|
|
|
|
do
|
|
{
|
|
NDIS_STATUS Status;
|
|
PRM_TASK pTask;
|
|
|
|
// Allocate task to complete the unbind.
|
|
//
|
|
Status = epvcAllocateTask(
|
|
&pAdapter->Hdr, // pParentObject,
|
|
epvcTaskShutdownAdapter, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Shutdown Adapter", // szDescription
|
|
&pTask,
|
|
&sr
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
// Ugly situation. We'll just leave things as they are...
|
|
//
|
|
pTask = NULL;
|
|
TR_WARN(("FATAL: couldn't allocate unbind task!\n"));
|
|
break;
|
|
}
|
|
|
|
// Start the task to complete the unbind.
|
|
// No locks must be held. RmStartTask uses up the tmpref on the task
|
|
// which was added by arpAllocateTask.
|
|
//
|
|
UNLOCKOBJ(pAdapter, &sr);
|
|
|
|
((PTASK_ADAPTERSHUTDOWN) pTask)->pUnbindContext = UnbindContext;
|
|
RmStartTask(pTask, (UINT_PTR) UnbindContext, &sr);
|
|
|
|
LOCKOBJ(pAdapter, &sr);
|
|
|
|
} while(FALSE);
|
|
|
|
UNLOCKOBJ(pAdapter, &sr);
|
|
RmTmpDereferenceObject(&pAdapter->Hdr, &sr);
|
|
*pStatus = NDIS_STATUS_PENDING;
|
|
|
|
RM_ASSERT_CLEAR(&sr);
|
|
TIMESTAMP("<==UnbindAdapter");
|
|
EXIT()
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcTaskShutdownAdapter(
|
|
IN struct _RM_TASK * pTask,
|
|
IN RM_TASK_OPERATION Code,
|
|
IN UINT_PTR UserParam,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Task handler responsible for shutting down an ATMEPVC adapter.
|
|
|
|
Arguments:
|
|
|
|
UserParam for (Code == RM_TASKOP_START) : UnbindContext
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
EPVC_ADAPTER * pAdapter = (EPVC_ADAPTER*) RM_PARENT_OBJECT(pTask);
|
|
TASK_ADAPTERSHUTDOWN *pMyTask = (TASK_ADAPTERSHUTDOWN*) pTask;
|
|
enum
|
|
{
|
|
STAGE_BecomePrimaryTask,
|
|
STAGE_DeactivateAdapterComplete,
|
|
STAGE_End
|
|
} Stage;
|
|
|
|
ENTER("TaskShutdownAdapter", 0x3f25396e)
|
|
|
|
TRACE (TL_T, TM_Pt, ("==>epvcTaskShutdownAdapter Code %x", Code));
|
|
|
|
//
|
|
// Message normalizing code
|
|
//
|
|
switch(Code)
|
|
{
|
|
|
|
case RM_TASKOP_START:
|
|
Stage = STAGE_BecomePrimaryTask;
|
|
|
|
// Save away the UnbindContext (which we get as UserParam) in
|
|
// the task's private context, for use later.
|
|
//
|
|
pMyTask->pUnbindContext = (NDIS_HANDLE) UserParam;
|
|
|
|
break;
|
|
|
|
case RM_TASKOP_PENDCOMPLETE:
|
|
Status = (NDIS_STATUS) UserParam;
|
|
ASSERT(!PEND(Status));
|
|
Stage = RM_PEND_CODE(pTask);
|
|
break;
|
|
|
|
case RM_TASKOP_END:
|
|
Status = (NDIS_STATUS) UserParam;
|
|
Stage= STAGE_End;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
|
|
}
|
|
|
|
ASSERTEX(!PEND(Status), pTask);
|
|
|
|
switch(Stage)
|
|
{
|
|
|
|
case STAGE_BecomePrimaryTask:
|
|
{
|
|
// If there is a primary task, pend on it, else make ourselves
|
|
// the primary task.
|
|
// We could get in this situation if someone does a
|
|
// "net stop arp1394" while we're in the middle of initializing or
|
|
// shutting down the adapter.
|
|
//
|
|
//
|
|
TRACE (TL_V, TM_Pt, (" epvcTaskShutdownAdapter STAGE_BecomePrimaryTask" ));
|
|
|
|
LOCKOBJ(pAdapter, pSR);
|
|
if (pAdapter->bind.pPrimaryTask == NULL)
|
|
{
|
|
epvcSetPrimaryAdapterTask(pAdapter, pTask, EPVC_AD_PS_DEINITING, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
}
|
|
else
|
|
{
|
|
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
|
|
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
STAGE_BecomePrimaryTask, // we'll try again...
|
|
pOtherTask,
|
|
pSR
|
|
);
|
|
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We're now the primary task. Since we're starting out,
|
|
// there should be NO activate/deactivate task.
|
|
// (Note: we don't bother getting the adapter lock for these asserts).
|
|
//
|
|
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
|
|
ASSERT(pAdapter->bind.pSecondaryTask == NULL);
|
|
|
|
//
|
|
// Allocate and start the deactivate adapter task.
|
|
//
|
|
{
|
|
PRM_TASK pDeactivateTask;
|
|
|
|
Status = epvcAllocateTask(
|
|
&pAdapter->Hdr, // pParentObject,
|
|
epvcTaskDeactivateAdapter, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Deactivate Adapter(shutdown)", // szDescription
|
|
&pDeactivateTask,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pDeactivateTask = NULL;
|
|
TR_WARN(("FATAL: couldn't alloc deactivate task!\n"));
|
|
}
|
|
else
|
|
{
|
|
RmPendTaskOnOtherTask(
|
|
pTask,
|
|
STAGE_DeactivateAdapterComplete,
|
|
pDeactivateTask, // task to pend on
|
|
pSR
|
|
);
|
|
|
|
// RmStartTask uses up the tmpref on the task
|
|
// which was added by arpAllocateTask.
|
|
//
|
|
Status = RmStartTask(
|
|
pDeactivateTask,
|
|
0, // UserParam (unused)
|
|
pSR
|
|
);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case STAGE_DeactivateAdapterComplete:
|
|
{
|
|
TRACE (TL_V, TM_Pt,( " epvcTaskShutdownAdapter STAGE_DeactivateAdapterComplete" ));
|
|
|
|
// Nothing to do here -- we clean up in STAGE_End.
|
|
//
|
|
break;
|
|
}
|
|
|
|
case STAGE_End:
|
|
{
|
|
TRACE (TL_V, TM_Pt, (" epvcTaskShutdownAdapter STAGE_End" ));
|
|
|
|
//
|
|
// We HAVE to be the primary task at this point, becase we simply
|
|
// wait and retry until we become one.
|
|
//
|
|
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
|
|
|
|
// Clear the primary task in the adapter object.
|
|
//
|
|
LOCKOBJ(pAdapter, pSR);
|
|
epvcClearPrimaryAdapterTask(pAdapter, pTask, EPVC_AD_PS_DEINITED, pSR);
|
|
UNLOCKOBJ(pAdapter, pSR);
|
|
|
|
if(RM_IS_ZOMBIE(pAdapter))
|
|
{
|
|
TR_WARN(("END: pAdapter is already deallocated.\n"));
|
|
}
|
|
else
|
|
{
|
|
// Free the adapter.
|
|
// (pAdapter will be allocated, but it will be in a "zombie" state).
|
|
//
|
|
RmDeinitializeGroup(&(pAdapter->MiniportsGroup), pSR);
|
|
|
|
RmFreeObjectInGroup(
|
|
&EpvcGlobals.adapters.Group,
|
|
&(pAdapter->Hdr),
|
|
NULL, // NULL pTask == synchronous.
|
|
pSR
|
|
);
|
|
}
|
|
// If there is an unbind-context, signal NDIS that the unbind is
|
|
// complete.
|
|
//
|
|
if (pMyTask->pUnbindContext)
|
|
{
|
|
TR_WARN(("END: Calling NdisCompleteUnbindAdapter. Status= 0x%lx\n",
|
|
Status));
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
TIMESTAMP("===Calling NdisCompleteUnbindAdapter");
|
|
NdisCompleteUnbindAdapter(
|
|
pMyTask->pUnbindContext,
|
|
Status
|
|
);
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
ASSERTEX(!"Unknown task op", pTask);
|
|
}
|
|
break;
|
|
|
|
} // switch (Code)
|
|
|
|
RM_ASSERT_NOLOCKS(pSR);
|
|
EXIT()
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
epvcGetAdapterInfo(
|
|
IN PEPVC_ADAPTER pAdapter,
|
|
IN PRM_STACK_RECORD pSR,
|
|
IN PRM_TASK pTask // OPTIONAL
|
|
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query an adapter for hardware-specific information that we need:
|
|
- burnt in hardware address (ESI part)
|
|
- Max packet size
|
|
- line rate
|
|
|
|
Arguments:
|
|
|
|
pAdapter - Pointer to EPVC adapter structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
EPVC_NDIS_REQUEST Request;
|
|
NDIS_MEDIA_STATE MediaState= NdisMediaStateDisconnected;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Initialize.
|
|
//
|
|
NdisZeroMemory(&pAdapter->info.MacAddress, sizeof(MAC_ADDRESS));
|
|
pAdapter->info.MediaState = MediaState;
|
|
pAdapter->info.MaxAAL5PacketSize = ATMEPVC_DEF_MAX_AAL5_PDU_SIZE;
|
|
pAdapter->info.LinkSpeed.Outbound = pAdapter->info.LinkSpeed.Inbound = ATM_USER_DATA_RATE_SONET_155;
|
|
|
|
//
|
|
// MAC Address:
|
|
//
|
|
Status = epvcPrepareAndSendNdisRequest (pAdapter,
|
|
&Request,
|
|
NULL, // OPTIONAL
|
|
OID_ATM_HW_CURRENT_ADDRESS,
|
|
(PVOID)(&pAdapter->info.MacAddress),
|
|
sizeof (pAdapter->info.MacAddress),
|
|
NdisRequestQueryInformation,
|
|
NULL, // No miniport
|
|
FALSE, // No request was pended
|
|
FALSE, // Pended Request info
|
|
pSR);
|
|
|
|
ASSERT (PEND(Status) == FALSE);
|
|
|
|
if (FAIL(Status)== TRUE)
|
|
{
|
|
//
|
|
// Don't break .continue on
|
|
//
|
|
TRACE (TL_I, TM_Pt, ("Oid - Atm Hw Address failed %x", Status));
|
|
|
|
}
|
|
|
|
Status = epvcPrepareAndSendNdisRequest(
|
|
pAdapter,
|
|
&Request,
|
|
NULL, // OPTIONAL
|
|
OID_ATM_MAX_AAL5_PACKET_SIZE,
|
|
(PVOID)(&pAdapter->info.MaxAAL5PacketSize),
|
|
sizeof(pAdapter->info.MaxAAL5PacketSize),
|
|
NdisRequestQueryInformation,
|
|
NULL, // No miniport
|
|
FALSE, // No request was pended
|
|
FALSE, // Pended Request info
|
|
pSR);
|
|
|
|
if (FAIL(Status)== TRUE)
|
|
{
|
|
TRACE (TL_I, TM_Pt, ("Oid - Atm Max AAL5 Packet Size failed %x", Status));
|
|
|
|
|
|
}
|
|
|
|
if (pAdapter->info.MaxAAL5PacketSize > ATMEPVC_DEF_MAX_AAL5_PDU_SIZE)
|
|
{
|
|
pAdapter->info.MaxAAL5PacketSize = ATMEPVC_DEF_MAX_AAL5_PDU_SIZE;
|
|
}
|
|
|
|
//
|
|
// Link speed:
|
|
//
|
|
Status = epvcPrepareAndSendNdisRequest(
|
|
pAdapter,
|
|
&Request,
|
|
NULL, // OPTIONAL
|
|
OID_GEN_CO_LINK_SPEED,
|
|
&pAdapter->info.LinkSpeed,
|
|
sizeof(pAdapter->info.LinkSpeed),
|
|
NdisRequestQueryInformation,
|
|
NULL, // No miniport
|
|
FALSE, // No request was pended
|
|
FALSE, // Pended Request info
|
|
pSR);
|
|
|
|
TRACE (TL_V, TM_Mp, ("Outbound %x Inbound %x",
|
|
pAdapter->info.LinkSpeed.Outbound,
|
|
pAdapter->info.LinkSpeed.Inbound));
|
|
|
|
|
|
if ((NDIS_STATUS_SUCCESS != Status) ||
|
|
(0 == pAdapter->info.LinkSpeed.Inbound) ||
|
|
(0 == pAdapter->info.LinkSpeed.Outbound))
|
|
{
|
|
TRACE (TL_I, TM_Pt, ( "GetAdapterInfo: OID_GEN_CO_LINK_SPEED failed\n"));
|
|
|
|
//
|
|
// Default and assume data rate for 155.52Mbps SONET
|
|
//
|
|
pAdapter->info.LinkSpeed.Outbound = pAdapter->info.LinkSpeed.Inbound = ATM_USER_DATA_RATE_SONET_155;
|
|
}
|
|
|
|
//
|
|
// Link speed:
|
|
//
|
|
Status = epvcPrepareAndSendNdisRequest(
|
|
pAdapter,
|
|
&Request,
|
|
NULL, // OPTIONAL
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
&MediaState,
|
|
sizeof(MediaState),
|
|
NdisRequestQueryInformation,
|
|
NULL, // No miniport
|
|
FALSE, // No request was pended
|
|
FALSE, // Pended Request info
|
|
pSR);
|
|
|
|
TRACE (TL_V, TM_Mp, ("MediaConnectivity %x ",MediaState));
|
|
|
|
|
|
if (NDIS_STATUS_SUCCESS != Status )
|
|
{
|
|
TRACE (TL_I, TM_Pt, ( "GetAdapterInfo: OID_GEN_CO_LINK_SPEED failed\n"));
|
|
|
|
//
|
|
// Default and assume data rate for 155.52Mbps SONET
|
|
//
|
|
MediaState = NdisMediaStateDisconnected;
|
|
}
|
|
|
|
pAdapter->info.MediaState = MediaState ;
|
|
|
|
TRACE( TL_V, TM_Pt,("GetAdapterInfo: Outbound Linkspeed %d", pAdapter->info.LinkSpeed.Outbound));
|
|
TRACE( TL_V, TM_Pt,("GetAdapterInfo: Inbound Linkspeed %d\n", pAdapter->info.LinkSpeed.Inbound));
|
|
|
|
}while (FALSE);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
EpvcPtPNPHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNET_PNP_EVENT pNetPnPEvent
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This is the Protocol PNP handlers.
|
|
All PNP Related OIDS(requests) are routed to this function
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
pNetPnPEvent Pointer to a Net_PnP_Event
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS: as we do not do much here
|
|
|
|
--*/
|
|
{
|
|
ENTER("EpvcPtPnPHandler", 0xacded1ce)
|
|
PEPVC_ADAPTER pAdapter =(PEPVC_ADAPTER)ProtocolBindingContext;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
RM_DECLARE_STACK_RECORD (SR);
|
|
|
|
TRACE (TL_T, TM_Pt, ("==> EpvcPtPNPHandler Adapter %p, pNetPnpEvent %x", pAdapter, pNetPnPEvent));
|
|
|
|
|
|
//
|
|
// This will happen when all entities in the system need to be notified
|
|
//
|
|
|
|
switch(pNetPnPEvent->NetEvent)
|
|
{
|
|
|
|
case NetEventReconfigure :
|
|
Status = epvcPtNetEventReconfigure(pAdapter, pNetPnPEvent->Buffer, &SR);
|
|
break;
|
|
|
|
default :
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
TRACE (TL_T, TM_Pt, ("<== EpvcPtPNPHandler Status %x", Status));
|
|
RM_ASSERT_NOLOCKS(&SR)
|
|
EXIT();
|
|
return Status;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
epvcPtNetEventReconfigure(
|
|
IN PEPVC_ADAPTER pAdapter,
|
|
IN PVOID pBuffer,
|
|
IN PRM_STACK_RECORD pSR
|
|
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This is the function that will be called by the PNP handler
|
|
whenever a PNPNetEventReconfigure happens
|
|
|
|
THis will happen if a new physical adapter has come in or the user
|
|
has re-enabled a virtual miniport.
|
|
|
|
To process:
|
|
Iterate through all the adapter. If adapters are bound, then make sure that
|
|
all of its miniport's are initialized.
|
|
|
|
If not, then leave it and call NdisReenumerate to connect all our protocol
|
|
instances with valid adapters
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS: as we do not do much here
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE (TL_T, TM_Pt, ("==> epvcPtNetEventReconfigure Adapter %p, pBuffer %x", pAdapter, pBuffer));
|
|
|
|
|
|
do
|
|
{
|
|
|
|
|
|
|
|
//
|
|
// The notify object sets the REconfig buffer.
|
|
//
|
|
if (pBuffer != NULL)
|
|
{
|
|
|
|
ASSERT (!"PnPBuffer != NULL - not implemented yet");
|
|
break;
|
|
}
|
|
|
|
if (pAdapter == NULL)
|
|
{
|
|
//
|
|
// Iterate through all the adapters and initialize
|
|
// uninitialized miniports
|
|
//
|
|
|
|
epvcEnumerateObjectsInGroup ( &EpvcGlobals.adapters.Group,
|
|
epvcReconfigureAdapter,
|
|
pBuffer,
|
|
pSR);
|
|
|
|
|
|
|
|
//
|
|
// Re-enumerate the protocol bindings, this will cause us to get
|
|
// a BindAdapter on all our unbound adapters, and then we
|
|
// will InitDeviceInstance.
|
|
// This is called when the protcol is not bound to the physical adapter
|
|
//
|
|
NdisReEnumerateProtocolBindings(EpvcGlobals.driver.ProtocolHandle);
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
TRACE (TL_T, TM_Pt, ("<== epvcPtNetEventReconfigure " ));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
INT
|
|
epvcReconfigureAdapter(
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
When the Protocol's Reconfigure handler is called, this adapter will be in one
|
|
of two condtions - Its binding to the adapter below is open or the binding is
|
|
closed.
|
|
|
|
if the blinding is closed, then the protocol will call NdisReEnumerate Bindings
|
|
and this will restart the Binding and re-instantiate the miniports.
|
|
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE: so that iteration continues
|
|
|
|
--*/
|
|
{
|
|
ENTER("epvcReconfigureAdapter", 0x2906a037)
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER )pHdr;
|
|
|
|
do
|
|
{
|
|
if (CHECK_AD_PRIMARY_STATE(pAdapter, EPVC_AD_PS_INITED)== FALSE)
|
|
{
|
|
//
|
|
// no more work to be done on this adapter,
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// TODO: Go through the registry and initialize
|
|
// all the IM miniports present
|
|
//
|
|
epvcReadAdapterConfiguration(pAdapter, pSR);
|
|
//
|
|
// Now go through all the miniports on this group and
|
|
// initialize them
|
|
//
|
|
epvcEnumerateObjectsInGroup ( &pAdapter->MiniportsGroup,
|
|
epvcReconfigureMiniport,
|
|
NULL,
|
|
pSR);
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
EXIT()
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
INT
|
|
epvcReconfigureMiniport (
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This should check to see if the InitDev instance has been
|
|
called on this miniport. IF not, then queue the task to
|
|
do it.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE: so that iteration continues
|
|
|
|
--*/
|
|
{
|
|
ENTER( "epvcReconfigureMiniport" ,0xdd9ecb01)
|
|
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)pHdr;
|
|
PTASK_AF pTask = NULL;
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)pMiniport->Hdr.pParentObject;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
|
|
LOCKOBJ(pMiniport, pSR);
|
|
|
|
//
|
|
// If the device instance is not initialized (i.e it has been halted)
|
|
// then this thread reinitializes the device instance
|
|
//
|
|
do
|
|
{
|
|
|
|
|
|
//
|
|
// If the device is already Initialized then exit.
|
|
//
|
|
if (MiniportTestFlag (pMiniport, fMP_DevInstanceInitialized ) == TRUE)
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
// Allocate task to Initialize the Device Instance.
|
|
//
|
|
Status = epvcAllocateTask(
|
|
&pMiniport->Hdr, // pParentObject,
|
|
epvcTaskStartIMiniport, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: Open address Family", // szDescription
|
|
&((PRM_TASK)pTask),
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
// Ugly situation. We'll just leave things as they are...
|
|
//
|
|
pTask = NULL;
|
|
TR_WARN(("FATAL: couldn't allocate unbind task!\n"));
|
|
break;
|
|
}
|
|
|
|
// Start the task to complete the Open Address Family.
|
|
// No locks must be held. RmStartTask uses up the tmpref on the task
|
|
// which was added by epvcAllocateTask.
|
|
//
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
|
|
pTask->pAf= &pAdapter->af.AddressFamily ;
|
|
pTask->Cause = TaskCause_ProtocolBind;
|
|
RmStartTask((PRM_TASK)pTask, 0, pSR);
|
|
|
|
LOCKOBJ(pMiniport, pSR);
|
|
|
|
} while(FALSE);
|
|
|
|
UNLOCKOBJ(pMiniport, pSR);
|
|
EXIT()
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
epvcExtractSendCompleteInfo (
|
|
OUT PEPVC_SEND_COMPLETE pStruct,
|
|
PEPVC_I_MINIPORT pMiniport,
|
|
PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_HANDLE PoolHandle = NULL;
|
|
|
|
pStruct->pPacket = pPacket;
|
|
|
|
|
|
PoolHandle = NdisGetPoolFromPacket(pPacket);
|
|
|
|
if (PoolHandle != pMiniport->PktPool.Send.Handle)
|
|
{
|
|
//
|
|
// We had passed down a packet belonging to the protocol above us.
|
|
//
|
|
|
|
pStruct->fUsedPktStack = TRUE;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
pStruct->fUsedPktStack = FALSE;
|
|
|
|
}
|
|
|
|
epvcSendCompleteStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
EpvcPtSendComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The Vc Context is the miniport block, Use it to complete the send
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
ENTER("EpvcPtSendComplete", 0x76beac72)
|
|
PEPVC_I_MINIPORT pMiniport =(PEPVC_I_MINIPORT)ProtocolVcContext;
|
|
EPVC_SEND_COMPLETE Struct;
|
|
RM_DECLARE_STACK_RECORD (SR);
|
|
|
|
|
|
TRACE (TL_T, TM_Send, ("EpvcPtSendComplete"));
|
|
|
|
EPVC_ZEROSTRUCT (&Struct);
|
|
|
|
#define OUR_EXTERNAL_ENTITY ((UINT_PTR) Packet)
|
|
#define szEPVCASSOC_EXTLINK_DEST_TO_PKT_FORMAT " send pkt 0x%p\n"
|
|
|
|
do
|
|
{
|
|
epvcExtractSendCompleteInfo (&Struct, pMiniport, Packet);
|
|
|
|
//
|
|
// If we are using the Packetstacking, then this packet is the
|
|
// original packet
|
|
//
|
|
if (Struct.fUsedPktStack == TRUE)
|
|
{
|
|
BOOLEAN Remaining = FALSE;
|
|
|
|
Struct.pOrigPkt = Packet;
|
|
|
|
Struct.pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
|
|
|
|
Struct.pContext = (PEPVC_STACK_CONTEXT)(&Struct.pStack->IMReserved[0]) ;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
Struct.pPktContext =(PEPVC_PKT_CONTEXT)(Packet->ProtocolReserved);
|
|
|
|
Struct.pContext = &Struct.pPktContext->Stack;
|
|
|
|
Struct.pOrigPkt = Struct.pPktContext->pOriginalPacket;
|
|
|
|
NdisIMCopySendCompletePerPacketInfo (Struct.pOrigPkt , Packet);
|
|
}
|
|
|
|
|
|
LOCKOBJ (pMiniport, &SR);
|
|
|
|
epvcDerefSendPkt(Packet, &pMiniport->Hdr);
|
|
|
|
UNLOCKOBJ (pMiniport, &SR);
|
|
|
|
|
|
//
|
|
// Make sure the original packet is in the same state
|
|
// when it was sent to the miniport
|
|
//
|
|
Struct.pPacket = Packet;
|
|
|
|
//
|
|
// Remove the ethernet padding - if necessary
|
|
//
|
|
epvcRemoveEthernetPad (pMiniport, Packet);
|
|
|
|
//
|
|
// Remove the ethernet padding buffer - if necessary
|
|
//
|
|
epvcRemoveEthernetTail (pMiniport, Packet, Struct.pPktContext);
|
|
|
|
//
|
|
// Remove the LLC Snap headers - if necessary
|
|
//
|
|
epvcRemoveExtraNdisBuffers (pMiniport, &Struct);
|
|
|
|
|
|
|
|
if (Struct.fUsedPktStack == FALSE)
|
|
{
|
|
epvcDprFreePacket(Packet,
|
|
&pMiniport->PktPool.Send);
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pMiniport->count.FramesXmitOk ++;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Complete the send
|
|
//
|
|
epvcMSendComplete(pMiniport,
|
|
Struct.pOrigPkt,
|
|
Status);
|
|
|
|
EXIT();
|
|
RM_ASSERT_CLEAR(&SR);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
epvcRemoveExtraNdisBuffers (
|
|
IN PEPVC_I_MINIPORT pMiniport,
|
|
IN PEPVC_SEND_COMPLETE pStruct
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
In the case of IP encapsulation, there will be an extra ndis buffer
|
|
that has been made the head of the Ndispacket. Remove it and
|
|
reattach the old one.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PNDIS_BUFFER pOldHead = NULL;
|
|
UINT OldHeadLength = 0;
|
|
|
|
do
|
|
{
|
|
//
|
|
// if an LLC header was used, remove it and free the MDL
|
|
// use the packet that was completed
|
|
//
|
|
|
|
if (pMiniport->fAddLLCHeader== TRUE)
|
|
{
|
|
PNDIS_PACKET_PRIVATE pPrivate = &pStruct->pPacket->Private;
|
|
PNDIS_BUFFER pHead = pPrivate->Head;
|
|
|
|
//
|
|
// Move the head of the packet past the LLC Header
|
|
//
|
|
pPrivate->Head = pHead->Next;
|
|
|
|
//
|
|
// Free the Head MDL
|
|
//
|
|
epvcFreeBuffer(pHead);
|
|
|
|
}
|
|
|
|
//
|
|
// if we are not doing IP encapsulation, then we are done.
|
|
//
|
|
if (pMiniport->fDoIpEncapsulation== FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// if the Ethernet header was stripped off, then put it back
|
|
//
|
|
pOldHead = pStruct->pContext->ipv4Send.pOldHeadNdisBuffer;
|
|
|
|
ASSERT (pOldHead != NULL);
|
|
|
|
OldHeadLength = NdisBufferLength(pOldHead);
|
|
|
|
//
|
|
// two ways this can happen
|
|
// 1) if the ethernet header was in a seperate MDL
|
|
// then simply take the old Head and make it the Head again
|
|
//
|
|
if (OldHeadLength == sizeof (EPVC_ETH_HEADER))
|
|
{
|
|
PNDIS_PACKET_PRIVATE pPrivate = &pStruct->pPacket->Private;
|
|
PNDIS_BUFFER pHead = pPrivate->Head;
|
|
|
|
ASSERT (pOldHead->Next == pPrivate->Head);
|
|
|
|
|
|
pOldHead->Next = pPrivate->Head;
|
|
|
|
pPrivate->Head = pOldHead ;
|
|
|
|
|
|
|
|
break; // we are done
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// 2nd Way 2) A new MDL had been allocated which just points to the
|
|
// IP part of the header.
|
|
// For this - free the Head in Packet, Take the old Head and put it back
|
|
// in the packet as the New Head
|
|
//
|
|
|
|
if (OldHeadLength > sizeof (EPVC_ETH_HEADER))
|
|
{
|
|
|
|
PNDIS_PACKET_PRIVATE pPrivate = &pStruct->pPacket->Private;
|
|
|
|
ASSERT (pOldHead->Next == pPrivate->Head->Next);
|
|
|
|
if (pPrivate->Head == pPrivate->Tail)
|
|
{
|
|
pPrivate->Tail = pOldHead;
|
|
pOldHead->Next = NULL;
|
|
}
|
|
else
|
|
{
|
|
pOldHead->Next = pPrivate->Head->Next;
|
|
}
|
|
|
|
epvcFreeBuffer(pPrivate->Head );
|
|
|
|
pPrivate->Head = pOldHead;
|
|
|
|
|
|
break; // we are done
|
|
|
|
}
|
|
} while (FALSE);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
EpvcPtReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the adapter below us when it is done indicating a batch of
|
|
received packets.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to our adapter structure.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER)ProtocolBindingContext;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
INT
|
|
epvcMiniportDoUnbind(
|
|
PRM_OBJECT_HEADER pHdr,
|
|
PVOID pvContext,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
{
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the Protocl Unbind code path
|
|
|
|
This should halt the current miniport and close the address
|
|
family. This is all done in the CloseMiniportTask, so we
|
|
will simply start the task and wait for it to complete
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - as we want to iterate to the very end
|
|
|
|
--*/
|
|
|
|
ENTER ("epvcMiniportDoUnbind", 0x26dc5d35)
|
|
|
|
PRM_TASK pRmTask = NULL;
|
|
PTASK_AF pAfTask = NULL;
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)pHdr;
|
|
PEPVC_ADAPTER pAdapter = (PEPVC_ADAPTER) pMiniport->Hdr.pParentObject;
|
|
BOOLEAN fHaltNotCompleted = FALSE;
|
|
|
|
TRACE (TL_T, TM_Mp, ("==>epvcMiniportDoUnbind pMiniport %x", pMiniport) );
|
|
|
|
do
|
|
{
|
|
|
|
if (MiniportTestFlag (pMiniport, fMP_AddressFamilyOpened) == TRUE)
|
|
{
|
|
|
|
//
|
|
// allocate a close Miniport Task
|
|
//
|
|
|
|
Status = epvcAllocateTask(
|
|
&pMiniport->Hdr, // pParentObject,
|
|
epvcTaskCloseIMiniport, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: CloseIMiniport- Unbind", // szDescription
|
|
&pRmTask,
|
|
pSR
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
pAfTask = NULL;
|
|
break;
|
|
}
|
|
|
|
pAfTask= (PTASK_AF)pRmTask ;
|
|
|
|
pAfTask->Cause = TaskCause_ProtocolUnbind;
|
|
|
|
//
|
|
// Reference the task so it is around until our Wait for completion
|
|
// is complete
|
|
//
|
|
RmTmpReferenceObject (&pAfTask->TskHdr.Hdr, pSR);
|
|
|
|
|
|
|
|
epvcInitializeEvent (&pAfTask->CompleteEvent);
|
|
|
|
RmStartTask (pRmTask, 0, pSR);
|
|
|
|
|
|
epvcWaitEvent(&pAfTask->CompleteEvent, WAIT_INFINITE);
|
|
|
|
RmTmpDereferenceObject (&pAfTask->TskHdr.Hdr, pSR);
|
|
|
|
|
|
}
|
|
|
|
LOCKOBJ (pMiniport, pSR);
|
|
|
|
//
|
|
// If the Halt has not already completed then, we should wait for it
|
|
//
|
|
if (MiniportTestFlag(pMiniport ,fMP_MiniportInitialized) == TRUE )
|
|
{
|
|
//
|
|
// prepare to wait for halt
|
|
//
|
|
epvcResetEvent (&pMiniport->pnp.HaltCompleteEvent);
|
|
|
|
//
|
|
// Set the flag to mark it as waiting for halt
|
|
//
|
|
MiniportSetFlag (pMiniport, fMP_WaitingForHalt);
|
|
|
|
fHaltNotCompleted = TRUE;
|
|
}
|
|
|
|
UNLOCKOBJ (pMiniport, pSR);
|
|
|
|
if (fHaltNotCompleted == TRUE)
|
|
{
|
|
BOOLEAN bWaitSuccessful;
|
|
|
|
|
|
bWaitSuccessful = epvcWaitEvent (&pMiniport->pnp.HaltCompleteEvent,WAIT_INFINITE);
|
|
|
|
|
|
if (bWaitSuccessful == FALSE)
|
|
{
|
|
ASSERT (bWaitSuccessful == TRUE);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Free the miniport object because there should be no more tasks on it.
|
|
// this Thread will have either caused the Miniport to Halt and waited
|
|
// for its completion (above) or the miniport will already have been halted
|
|
//
|
|
|
|
TRACE ( TL_I, TM_Mp, ("epvcMiniportDoUnbind Freeing miniport %p", pMiniport) );
|
|
|
|
RmFreeObjectInGroup (&pAdapter->MiniportsGroup,&pMiniport->Hdr, NULL, pSR);
|
|
|
|
} while (FALSE);
|
|
|
|
TRACE (TL_T, TM_Mp, ("<==epvcMiniportDoUnbind pMiniport %x", pMiniport) );
|
|
EXIT();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcProcessOidCloseAf(
|
|
PEPVC_I_MINIPORT pMiniport,
|
|
PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the Af Close Request Code path
|
|
|
|
This simply starts a worktitem to close the Af, if the
|
|
Af is open
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PTASK_AF pTaskAf = NULL;
|
|
PEPVC_WORK_ITEM pCloseAfWorkItem = NULL;
|
|
|
|
TRACE (TL_T, TM_Mp, ("==> epvcProcessOidCloseAf pMiniport %x", pMiniport) );
|
|
|
|
|
|
|
|
//
|
|
// reference the adapter as it is going to passed to a workiter.
|
|
// decremented in the workitem
|
|
//
|
|
|
|
do
|
|
{
|
|
if (MiniportTestFlag( pMiniport, fMP_AddressFamilyOpened) == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
Status = epvcAllocateMemoryWithTag (&pCloseAfWorkItem,
|
|
sizeof(*pCloseAfWorkItem) ,
|
|
TAG_WORKITEM);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pCloseAfWorkItem= NULL;
|
|
break;
|
|
}
|
|
|
|
epvcMiniportQueueWorkItem (pCloseAfWorkItem,
|
|
pMiniport,
|
|
epvcOidCloseAfWorkItem,
|
|
Status, // Ignored
|
|
pSR
|
|
);
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// free locally allocated memory
|
|
//
|
|
if (pCloseAfWorkItem != NULL)
|
|
{
|
|
epvcFreeMemory(pCloseAfWorkItem, sizeof (*pCloseAfWorkItem), 0);
|
|
}
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
epvcOidCloseAfWorkItem(
|
|
IN PRM_OBJECT_HEADER pObj,
|
|
IN NDIS_STATUS Status,
|
|
IN PRM_STACK_RECORD pSR
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called from the Af Close Request Code path
|
|
|
|
This simply starts a worktitem to close the Af, if the
|
|
Af is open
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
PTASK_AF pTaskAf = NULL;
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)pObj;
|
|
|
|
TRACE (TL_T, TM_Mp, ("==> epvcProcessOidCloseAf pMiniport %x", pMiniport) );
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
|
|
//
|
|
// reference the adapter as it is going to passed to a workiter.
|
|
// decremented in the workitem
|
|
//
|
|
|
|
do
|
|
{
|
|
if (MiniportTestFlag( pMiniport, fMP_AddressFamilyOpened) == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
Status = epvcAllocateTask(
|
|
&pMiniport->Hdr, // pParentObject,
|
|
epvcTaskCloseIMiniport, // pfnHandler,
|
|
0, // Timeout,
|
|
"Task: CloseIMiniport - OID CloseAf", // szDescription
|
|
&(PRM_TASK)pTaskAf,
|
|
pSR
|
|
);
|
|
|
|
if (FAIL(Status))
|
|
{
|
|
pTaskAf = NULL;
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
break;
|
|
}
|
|
|
|
|
|
pTaskAf->Cause = TaskCause_AfCloseRequest;
|
|
|
|
pTaskAf->pRequest = NULL;
|
|
|
|
|
|
RmStartTask ((PRM_TASK)pTaskAf , 0, pSR);
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
UINT
|
|
EpvcCoReceive(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ENTER ("EpvcPtCoReceive", 0x1bfc168e)
|
|
PEPVC_ADAPTER pAdapter =(PEPVC_ADAPTER)ProtocolBindingContext;
|
|
PEPVC_I_MINIPORT pMiniport = (PEPVC_I_MINIPORT)ProtocolVcContext;
|
|
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
EPVC_RCV_STRUCT RcvStruct;
|
|
|
|
|
|
RM_DECLARE_STACK_RECORD (SR);
|
|
|
|
TRACE (TL_T, TM_Pt, ("==> EpvcCoReceive Pkt %x", Packet));
|
|
|
|
EPVC_ZEROSTRUCT (&RcvStruct);
|
|
|
|
TRACE (TL_T, TM_Recv, ("EpvcPtCoReceive pAd %p, pMp %p, pPkt %p", pAdapter, pMiniport, Packet));
|
|
|
|
do
|
|
{
|
|
if (MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
Status = epvcGetRecvPkt (&RcvStruct,pMiniport, Packet);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT (RcvStruct.pNewPacket != NULL);
|
|
|
|
Status = epvcStripHeaderFromNewPacket (&RcvStruct, pMiniport);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Status = epvcAddEthHeaderToNewPacket (&RcvStruct, pMiniport);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now indicate the packet up
|
|
//
|
|
NDIS_SET_PACKET_HEADER_SIZE(RcvStruct.pNewPacket,
|
|
sizeof (EPVC_ETH_HEADER)) ;
|
|
|
|
ASSERT (NDIS_GET_PACKET_HEADER_SIZE(RcvStruct.pNewPacket) == 14);
|
|
|
|
//
|
|
// Force protocols above to make a copy if they want to hang
|
|
// on to data in this packet. This is because we are in our
|
|
// Receive handler (not ReceivePacket) and we can't return a
|
|
// ref count from here.
|
|
//
|
|
|
|
RcvStruct.OldPacketStatus = NDIS_GET_PACKET_STATUS(Packet);
|
|
|
|
|
|
NDIS_SET_PACKET_STATUS(RcvStruct.pNewPacket,
|
|
RcvStruct.OldPacketStatus );
|
|
|
|
epvcDumpPkt (RcvStruct.pNewPacket);
|
|
|
|
epvcValidatePacket (RcvStruct.pNewPacket);
|
|
|
|
NdisMIndicateReceivePacket(pMiniport->ndis.MiniportAdapterHandle,
|
|
&RcvStruct.pNewPacket,
|
|
1);
|
|
|
|
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
//
|
|
// Check if we had indicated up the packet with NDIS_STATUS_RESOURCES
|
|
// NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket) for this since
|
|
// it might have changed! Use the value saved in the local variable.
|
|
//
|
|
if (RcvStruct.OldPacketStatus == NDIS_STATUS_RESOURCES)
|
|
{
|
|
epvcProcessReturnPacket (pMiniport, RcvStruct.pNewPacket,NULL, &SR);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
|
|
}
|
|
else if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
epvcProcessReturnPacket (pMiniport, RcvStruct.pNewPacket,NULL, &SR);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
pMiniport->count.RecvDropped ++;
|
|
}
|
|
|
|
|
|
|
|
RM_ASSERT_CLEAR(&SR);
|
|
|
|
TRACE (TL_T, TM_Pt, ("<== EpvcCoReceive Pkt %x", Packet))
|
|
|
|
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcGetRecvPkt (
|
|
IN PEPVC_RCV_STRUCT pRcvStruct,
|
|
IN PEPVC_I_MINIPORT pMiniport,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
|
|
TRACE (TL_T, TM_Pt, ("==>epvcGetRecvPkt "))
|
|
|
|
do
|
|
{
|
|
if (MiniportTestFlag (pMiniport, fMP_MiniportInitialized) == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
epvcValidatePacket (Packet);
|
|
|
|
//
|
|
// See if the packet is large enough
|
|
//
|
|
if (epvcIsPacketLengthAcceptable (Packet, pMiniport)== FALSE)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pRcvStruct->pPacket = Packet;
|
|
//
|
|
// Check if we can reuse the same packet for indicating up.
|
|
//
|
|
pRcvStruct->pStack = NdisIMGetCurrentPacketStack(Packet, &pRcvStruct->fRemaining);
|
|
|
|
if (pRcvStruct->fRemaining)
|
|
{
|
|
//
|
|
// We can reuse "Packet".
|
|
//
|
|
// NOTE: if we needed to keep per-packet information in packets
|
|
// indicated up, we can use pStack->IMReserved[].
|
|
//
|
|
|
|
pRcvStruct->pNewPacket = Packet;
|
|
|
|
pRcvStruct->fUsedPktStacks = TRUE;
|
|
|
|
pRcvStruct->pPktContext = (PEPVC_PKT_CONTEXT)pRcvStruct->pStack;
|
|
|
|
// Zero out our context
|
|
NdisZeroMemory (&pRcvStruct->pPktContext->Stack, sizeof(EPVC_STACK_CONTEXT));
|
|
|
|
NDIS_SET_PACKET_HEADER_SIZE(Packet, 14);
|
|
|
|
Status = NDIS_STATUS_SUCCESS; // We are done
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Get a packet off the pool and indicate that up
|
|
//
|
|
epvcDprAllocatePacket(&Status,
|
|
&pRcvStruct->pNewPacket,
|
|
&pMiniport->PktPool.Recv);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pRcvStruct->pNewPacket = NULL;
|
|
break;
|
|
}
|
|
|
|
{
|
|
//
|
|
// set up the new packet to look exactly like the old one
|
|
//
|
|
|
|
PNDIS_PACKET MyPacket = pRcvStruct->pNewPacket;
|
|
|
|
MyPacket->Private.Head = Packet->Private.Head;
|
|
MyPacket->Private.Tail = Packet->Private.Tail;
|
|
|
|
//
|
|
// Set the standard Ethernet header size
|
|
//
|
|
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, 14);
|
|
|
|
//
|
|
// Copy packet flags.
|
|
//
|
|
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
|
|
|
|
//
|
|
// Set up the context pointers
|
|
//
|
|
pRcvStruct->pPktContext = (PEPVC_PKT_CONTEXT)&MyPacket->MiniportReservedEx[0];
|
|
NdisZeroMemory (pRcvStruct->pPktContext, sizeof (*pRcvStruct->pPktContext));
|
|
pRcvStruct->pPktContext->pOriginalPacket = Packet;
|
|
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS; // We are done
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
TRACE (TL_T, TM_Pt, ("<==epvcGetRecvPkt Old %p, New %p ",
|
|
pRcvStruct->pPacket, pRcvStruct->pNewPacket))
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcStripLLCHeaderFromNewPacket (
|
|
IN PEPVC_RCV_STRUCT pRcvStruct,
|
|
IN PEPVC_I_MINIPORT pMiniport
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PNDIS_PACKET pPacket = NULL;
|
|
PNDIS_BUFFER pHead, pNewHead =NULL;
|
|
ULONG CurLength = 0;
|
|
PUCHAR pCurVa = NULL;
|
|
ULONG LlcHeaderLength = 0;
|
|
BOOLEAN fIsCorrectHeader ;
|
|
do
|
|
{
|
|
|
|
if (pMiniport->fAddLLCHeader == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
pPacket = pRcvStruct->pNewPacket;
|
|
pHead = pPacket->Private.Head;
|
|
LlcHeaderLength = pMiniport->LlcHeaderLength;
|
|
//
|
|
// Move the Head past the LLC Header
|
|
//
|
|
ASSERT (NdisBufferLength (pHead) > LlcHeaderLength);
|
|
|
|
//
|
|
// Adjust the length and start VA of the MDL
|
|
//
|
|
CurLength = NdisBufferLength(pHead);
|
|
|
|
pCurVa = NdisBufferVirtualAddress(pHead);
|
|
|
|
|
|
//
|
|
// Check arguments
|
|
//
|
|
if (pCurVa == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (CurLength <= LlcHeaderLength)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Compare and make sure that it is the right header
|
|
//
|
|
|
|
fIsCorrectHeader = NdisEqualMemory (pCurVa ,
|
|
pMiniport->pLllcHeader,
|
|
pMiniport->LlcHeaderLength) ;
|
|
|
|
|
|
// If the IsCorrectheader is still false, then there is more to do
|
|
if (fIsCorrectHeader == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
if (pMiniport->fDoIpEncapsulation == TRUE)
|
|
{
|
|
//
|
|
// In the case of IPEncap + LLC Header, the function
|
|
// which adds the Mac Header will strip the LLC Header
|
|
//
|
|
Status= NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Strip the LLC Header Length
|
|
//
|
|
CurLength -= pMiniport->LlcHeaderLength;
|
|
pCurVa += pMiniport->LlcHeaderLength;
|
|
|
|
epvcAllocateBuffer(&Status ,
|
|
&pNewHead,
|
|
NULL,
|
|
pCurVa,
|
|
CurLength
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pNewHead = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set up the Packet context
|
|
//
|
|
|
|
pPacket->Private.ValidCounts= FALSE;
|
|
|
|
pRcvStruct->pPktContext->Stack.EthLLC.pOldHead = pHead;
|
|
pRcvStruct->pPktContext->Stack.EthLLC.pOldTail = pPacket->Private.Tail;
|
|
|
|
//
|
|
// Set the New Ndis buffer in the Packet
|
|
//
|
|
pNewHead->Next = pHead->Next;
|
|
|
|
pPacket->Private.Head = pNewHead;
|
|
|
|
if (pPacket->Private.Tail == pHead)
|
|
{
|
|
//
|
|
// Update the Tail of the packet as well
|
|
//
|
|
pPacket->Private.Tail = pNewHead;
|
|
}
|
|
|
|
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcAddEthHeaderToNewPacket (
|
|
IN PEPVC_RCV_STRUCT pRcvStruct,
|
|
IN PEPVC_I_MINIPORT pMiniport
|
|
)
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE ;
|
|
PNDIS_BUFFER pOldHead = NULL;
|
|
PNDIS_BUFFER pNewBuffer = NULL;
|
|
PNDIS_PACKET pNewPacket = NULL;
|
|
PUCHAR pStartOfValidData = NULL;
|
|
PUCHAR pCurrOffset = NULL;
|
|
|
|
PEPVC_IP_RCV_BUFFER pIpBuffer = NULL;
|
|
|
|
extern UCHAR LLCSnapIpv4[8] ;
|
|
|
|
|
|
|
|
|
|
TRACE (TL_T, TM_Pt, ("==>epvcAddEthHeaderToNewPacket pRcvStruct %p ", pRcvStruct))
|
|
do
|
|
{
|
|
if (pMiniport->fDoIpEncapsulation == FALSE)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the data into a new buffer. The start of the data is adjusted
|
|
// to account for the LLC header and ethernet header
|
|
//
|
|
pNewPacket = pRcvStruct->pNewPacket;
|
|
|
|
pOldHead = pNewPacket->Private.Head;
|
|
|
|
pStartOfValidData = NdisBufferVirtualAddress (pOldHead );
|
|
|
|
if (pStartOfValidData == NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (pMiniport->fAddLLCHeader == TRUE)
|
|
{
|
|
pStartOfValidData += sizeof (LLCSnapIpv4);
|
|
pRcvStruct->fLLCHeader = TRUE;
|
|
}
|
|
|
|
pRcvStruct->pStartOfValidData = pStartOfValidData ;
|
|
|
|
|
|
//
|
|
// Get a locally allocated buffer to copy the packet into
|
|
//
|
|
|
|
|
|
pIpBuffer = epvcGetLookasideBuffer (&pMiniport->rcv.LookasideList);
|
|
|
|
if (pIpBuffer == NULL)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Start of the data
|
|
//
|
|
pCurrOffset = pRcvStruct->pLocalMemory = (PUCHAR)(&pIpBuffer->u.Pkt.Eth);
|
|
|
|
|
|
|
|
//
|
|
// First copy the Ethernet Header into the LocalMemory
|
|
//
|
|
NdisMoveMemory (pCurrOffset ,
|
|
&pMiniport->RcvEnetHeader,
|
|
sizeof(pMiniport->RcvEnetHeader));
|
|
|
|
pCurrOffset += sizeof(pMiniport->RcvEnetHeader);
|
|
|
|
pRcvStruct->BytesCopied += sizeof(pMiniport->RcvEnetHeader);
|
|
|
|
|
|
//
|
|
// Now copy the NdisBufferChain into the Locally allocated memory
|
|
//
|
|
Status = epvcCopyNdisBufferChain (pRcvStruct,
|
|
pOldHead ,
|
|
pCurrOffset
|
|
);
|
|
|
|
//
|
|
// We have to add an Ethernet Header for this packet.
|
|
//
|
|
|
|
|
|
|
|
epvcAllocateBuffer (&Status,
|
|
&pNewBuffer,
|
|
NULL,
|
|
pRcvStruct->pLocalMemory,
|
|
pRcvStruct->BytesCopied);
|
|
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pNewBuffer = NULL;
|
|
ASSERTAndBreak(Status == NDIS_STATUS_SUCCESS);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make the new Ndis Buffer the head
|
|
//
|
|
{
|
|
PNDIS_PACKET_PRIVATE pPrivate = &pRcvStruct->pNewPacket->Private;
|
|
|
|
//
|
|
// Save the head and tail of the old packet
|
|
//
|
|
pIpBuffer->pOldHead = pPrivate->Head ;
|
|
pIpBuffer->pOldTail = pPrivate->Tail ;
|
|
|
|
|
|
//
|
|
// Now set up the new packet
|
|
//
|
|
pNewBuffer->Next = NULL;
|
|
pPrivate->Head = pNewBuffer;
|
|
pPrivate->Tail = pNewBuffer;
|
|
|
|
|
|
pPrivate->ValidCounts= FALSE;
|
|
|
|
pRcvStruct->pPktContext->Stack.ipv4Recv.pIpBuffer = pIpBuffer;
|
|
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pRcvStruct->pNewBuffer = pNewBuffer;
|
|
pRcvStruct->pIpBuffer = pIpBuffer;
|
|
}
|
|
else
|
|
{
|
|
pRcvStruct->pNewBuffer = NULL;
|
|
pRcvStruct->pIpBuffer = NULL;
|
|
if (pIpBuffer != NULL)
|
|
{
|
|
epvcFreeToNPagedLookasideList (&pMiniport->rcv.LookasideList,
|
|
(PVOID)pIpBuffer);
|
|
|
|
}
|
|
}
|
|
|
|
TRACE (TL_T, TM_Pt, ("<==epvcAddEthHeaderToNewPacket Status %x ", Status))
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcCopyNdisBufferChain (
|
|
IN PEPVC_RCV_STRUCT pRcvStruct,
|
|
IN PNDIS_BUFFER pInBuffer,
|
|
IN PUCHAR pCurrOffset
|
|
)
|
|
{
|
|
|
|
//
|
|
// This function copies the data the belongs to the
|
|
// pInMdl chain to the local Buffer.
|
|
// BufferLength is used for validation purposes only
|
|
// Fragmentation and insertion of headers will take place here
|
|
//
|
|
|
|
|
|
UINT BufferLength = MAX_ETHERNET_FRAME- sizeof (EPVC_ETH_HEADER);
|
|
|
|
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
|
|
|
|
UINT LocalBufferIndex = 0; // Used as an index to the LocalBuffer, used for validation
|
|
|
|
UINT MdlLength = 0;
|
|
|
|
PUCHAR MdlAddress = NULL;
|
|
|
|
PNDIS_BUFFER pCurrBuffer = pInBuffer;
|
|
|
|
PUCHAR pLocalBuffer = pCurrOffset;
|
|
|
|
extern UCHAR LLCSnapIpv4[8];
|
|
|
|
//
|
|
// Use the pStartOfValidData for the first MDL
|
|
//
|
|
|
|
MdlLength = NdisBufferLength(pCurrBuffer);
|
|
MdlAddress= NdisBufferVirtualAddress(pCurrBuffer);
|
|
|
|
//
|
|
// Adjust for the LLC Header if any
|
|
//
|
|
|
|
|
|
if (pRcvStruct->fLLCHeader == TRUE)
|
|
{
|
|
//
|
|
// We have an LLC encapsulation
|
|
//
|
|
MdlLength -= sizeof (LLCSnapIpv4);
|
|
ASSERT (pRcvStruct->pStartOfValidData - MdlAddress == sizeof (LLCSnapIpv4));
|
|
|
|
MdlAddress = pRcvStruct->pStartOfValidData;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the first buffer Data to local memory.
|
|
//
|
|
|
|
|
|
NdisMoveMemory((PVOID)((ULONG_PTR)pLocalBuffer),
|
|
MdlAddress,
|
|
MdlLength);
|
|
|
|
LocalBufferIndex += MdlLength;
|
|
|
|
pCurrBuffer = pCurrBuffer->Next;
|
|
|
|
//
|
|
// now walk through the ndis buffer chain
|
|
//
|
|
|
|
while (pCurrBuffer!= NULL)
|
|
{
|
|
|
|
|
|
MdlLength = NdisBufferLength(pCurrBuffer);
|
|
MdlAddress= NdisBufferVirtualAddress(pCurrBuffer);
|
|
|
|
|
|
if (MdlLength != 0)
|
|
{
|
|
if (MdlAddress == NULL)
|
|
{
|
|
NdisStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if ( LocalBufferIndex + MdlLength > BufferLength)
|
|
{
|
|
|
|
ASSERT(LocalBufferIndex + MdlLength <= BufferLength);
|
|
|
|
NdisStatus = NDIS_STATUS_BUFFER_TOO_SHORT;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy the Data to local memory.
|
|
//
|
|
|
|
|
|
NdisMoveMemory((PVOID)((ULONG_PTR)pLocalBuffer+LocalBufferIndex),
|
|
MdlAddress,
|
|
MdlLength);
|
|
|
|
LocalBufferIndex += MdlLength;
|
|
}
|
|
|
|
pCurrBuffer = pCurrBuffer->Next;
|
|
|
|
}
|
|
pRcvStruct->BytesCopied += LocalBufferIndex;
|
|
|
|
return NdisStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
epvcValidatePacket (
|
|
IN PNDIS_PACKET pPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Takes a packet and makes sure that the MDL chain is valid
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG TotalLength = 0;
|
|
//ASSERT (pPacket->Private.Tail->Next == NULL);
|
|
|
|
|
|
if (pPacket->Private.Head != pPacket->Private.Tail)
|
|
{
|
|
PNDIS_BUFFER pTemp = pPacket->Private.Head;
|
|
|
|
while (pTemp != NULL)
|
|
{
|
|
TotalLength += NdisBufferLength(pTemp);
|
|
pTemp = pTemp->Next;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
TotalLength += NdisBufferLength(pPacket->Private.Head);
|
|
|
|
}
|
|
|
|
if (TotalLength != pPacket->Private.TotalLength)
|
|
{
|
|
ASSERT (pPacket->Private.ValidCounts == FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
epvcIsPacketLengthAcceptable (
|
|
IN PNDIS_PACKET Packet,
|
|
IN PEPVC_I_MINIPORT pMiniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Validates the packet length of an incoming packet
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT PktLength;
|
|
BOOLEAN fValid = FALSE;
|
|
|
|
epvcQueryPacket (Packet, NULL, NULL, NULL, &PktLength);
|
|
|
|
fValid = (PktLength >= pMiniport->MinAcceptablePkt);
|
|
|
|
if (fValid == TRUE)
|
|
{
|
|
fValid = (PktLength <= pMiniport->MaxAcceptablePkt);
|
|
}
|
|
|
|
return fValid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
epvcStripHeaderFromNewPacket (
|
|
IN PEPVC_RCV_STRUCT pRcvStruct,
|
|
IN PEPVC_I_MINIPORT pMiniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
In the pure bridged (ethernet) encapsulation, all ethernet packets
|
|
are preceeded by a 0x00, 0x00 header. Check if it is present
|
|
|
|
in the ethernet/llc case, verify the LLC header is correct.
|
|
|
|
In both cases, allocate a new Ndis Buffer which does not include the
|
|
2684 headers.
|
|
|
|
Store the old head and tail into the NdisPacket and send it up to the
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
|
|
PNDIS_PACKET pPacket = NULL;
|
|
PNDIS_BUFFER pHead, pNewHead =NULL;
|
|
ULONG CurLength = 0;
|
|
PUCHAR pCurVa = NULL;
|
|
ULONG EpvcHeaderLength = 0;
|
|
PUCHAR pEpvcHeader = NULL;
|
|
BOOLEAN fIsCorrectHeader ;
|
|
do
|
|
{
|
|
//
|
|
// we are not interested in the pure ipv4 case
|
|
//
|
|
if (pMiniport->Encap == IPV4_ENCAP_TYPE)
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
|
|
pPacket = pRcvStruct->pNewPacket;
|
|
pHead = pPacket->Private.Head;
|
|
|
|
switch (pMiniport->Encap)
|
|
{
|
|
case IPV4_LLC_SNAP_ENCAP_TYPE:
|
|
case ETHERNET_LLC_SNAP_ENCAP_TYPE:
|
|
{
|
|
EpvcHeaderLength = pMiniport->LlcHeaderLength;
|
|
pEpvcHeader = pMiniport->pLllcHeader;
|
|
break;
|
|
}
|
|
case ETHERNET_ENCAP_TYPE:
|
|
{
|
|
EpvcHeaderLength = ETHERNET_PADDING_LENGTH;
|
|
pEpvcHeader = &gPaddingBytes[0];
|
|
break;
|
|
}
|
|
|
|
case IPV4_ENCAP_TYPE:
|
|
default:
|
|
{
|
|
//
|
|
// pMiniport->Encap is only allowed four values,
|
|
// therefore we should never hit the defualt case.
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
ASSERT (Status != NDIS_STATUS_FAILURE);
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Adjust the length and start VA of the MDL
|
|
//
|
|
CurLength = NdisBufferLength(pHead);
|
|
|
|
pCurVa = NdisBufferVirtualAddress(pHead);
|
|
|
|
|
|
//
|
|
// Check arguments
|
|
//
|
|
if (pCurVa == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (CurLength <= EpvcHeaderLength )
|
|
{
|
|
//
|
|
// we do not handle the case where the header is longer than
|
|
// the first mdl
|
|
//
|
|
ASSERT (CurLength > EpvcHeaderLength );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Compare and make sure that it is the right header
|
|
//
|
|
|
|
fIsCorrectHeader = NdisEqualMemory (pCurVa ,
|
|
pEpvcHeader,
|
|
EpvcHeaderLength) ;
|
|
|
|
|
|
// If the IsCorrectheader is still false, then there is more to do
|
|
if (fIsCorrectHeader == FALSE)
|
|
{
|
|
break;
|
|
}
|
|
|
|
|
|
if (pMiniport->fDoIpEncapsulation == TRUE)
|
|
{
|
|
//
|
|
// In the case of IPEncap + LLC Header, the function
|
|
// which adds the Mac Header will strip the LLC Header
|
|
//
|
|
Status= NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Strip the LLC Header Length
|
|
//
|
|
CurLength -= EpvcHeaderLength;
|
|
pCurVa += EpvcHeaderLength;
|
|
|
|
epvcAllocateBuffer(&Status ,
|
|
&pNewHead,
|
|
NULL,
|
|
pCurVa,
|
|
CurLength
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
pNewHead = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set up the Packet context
|
|
//
|
|
|
|
pPacket->Private.ValidCounts= FALSE;
|
|
|
|
pRcvStruct->pPktContext->Stack.EthLLC.pOldHead = pHead;
|
|
pRcvStruct->pPktContext->Stack.EthLLC.pOldTail = pPacket->Private.Tail;
|
|
|
|
//
|
|
// Set the New Ndis buffer in the Packet
|
|
//
|
|
pNewHead->Next = pHead->Next;
|
|
|
|
pPacket->Private.Head = pNewHead;
|
|
|
|
if (pPacket->Private.Tail == pHead)
|
|
{
|
|
//
|
|
// Update the Tail of the packet as well
|
|
//
|
|
pPacket->Private.Tail = pNewHead;
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|