mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3873 lines
85 KiB
3873 lines
85 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ndis_co.c
|
|
|
|
Abstract:
|
|
|
|
CO-NDIS miniport wrapper functions
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (JameelH) 01-Feb-96
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#include <atm.h>
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_NDIS_CO
|
|
|
|
/*
|
|
Connection-oriented section of NDIS exposes the following objects and apis to
|
|
manipulate these objects.
|
|
|
|
AF Address Family
|
|
SAP Service Access Point
|
|
VC Virtual Circuit
|
|
Party A node in a point-multipoint VC
|
|
|
|
There is a notion of a call-manager and a client on a per-binding basis. The
|
|
call manager acts as a helper dll for NDIS wrapper to manage the aforementioned
|
|
objects.
|
|
|
|
The concept of AF makes possible the existence of multiple call-managers. An
|
|
example of this is the UNI call-manager and a SPANS call-manager for the ATM
|
|
media.
|
|
|
|
SAPs provides a way for incoming calls to be routed to the right entity. A
|
|
protocol can register for more than one SAPs. Its upto the call-manager to
|
|
allow/dis-allow multiple protocol modules to register the same SAP.
|
|
|
|
VCs are created either by a protocol module requesting to make an outbound call
|
|
or by the call-manager dispatching an incoming call. VCs can either be point-point
|
|
or point-multi-point. Leaf nodes can be added to VCs at any time provided the first
|
|
leaf was created appropriately.
|
|
|
|
References:
|
|
|
|
An AF association results in the reference of file-object for the call-manager.
|
|
|
|
A SAP registration results in the reference of the AF.
|
|
|
|
A send or receive does not reference a VC. This is because miniports are required to
|
|
pend DeactivateVc calls till all I/O completes. So when it calls NdisMCoDeactivateVcComplete
|
|
no other packets will be indicated up and there are no sends outstanding.
|
|
*/
|
|
|
|
NDIS_STATUS
|
|
NdisCmRegisterAddressFamily(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily,
|
|
IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
|
|
IN UINT SizeOfCmCharacteristics
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a call from the call-manager to register the address family
|
|
supported by this call-manager.
|
|
|
|
Arguments:
|
|
NdisBindingHandle - Pointer to the call-managers NDIS_OPEN_BLOCK.
|
|
AddressFamily - The address family being registered.
|
|
CmCharacteristics - Call-Manager characteristics
|
|
SizeOfCmCharacteristics - Size of Call-Manager characteristics
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if the address family registration is successfully.
|
|
NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
|
|
family is already registered for this miniport.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
PNDIS_AF_LIST AfList;
|
|
PNDIS_PROTOCOL_BLOCK Protocol;
|
|
PNDIS_M_OPEN_BLOCK CallMgrOpen;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
|
|
CallMgrOpen = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
|
|
Miniport = CallMgrOpen->MiniportHandle;
|
|
Protocol = CallMgrOpen->ProtocolHandle;
|
|
|
|
CoReferencePackage();
|
|
|
|
//
|
|
// Make sure that the miniport is a CoNdis miniport and
|
|
// there is no other module registering the same address family.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Make sure the binding is not closing down
|
|
//
|
|
if (CallMgrOpen->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that the miniport is a CoNdis miniport and
|
|
// protocol is also a NDIS 4.1 or later protocol.
|
|
//
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later miniport
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
|
|
((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
|
|
(Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later protocol
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that the call-manager characteristics are 4.1 or later
|
|
//
|
|
if ((CmCharacteristics->MajorVersion != 4) ||
|
|
(CmCharacteristics->MinorVersion != 1) ||
|
|
(SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later protocol
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Search registered call-managers for this miniport and make sure there is no
|
|
// clash. A call-manager can only register one address family per-open. This
|
|
// is due to the way we cache handlers. Can be over-come if the handlers are
|
|
// identical for each address-family - but decided not to since it is un-interesting.
|
|
//
|
|
for (AfList = Miniport->CallMgrAfList;
|
|
AfList != NULL;
|
|
AfList = AfList->NextOpen)
|
|
{
|
|
if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
|
|
(AfList->Open == CallMgrOpen))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AfList == NULL)
|
|
{
|
|
//
|
|
// No other entity has claimed this address family.
|
|
//
|
|
AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
|
|
if (AfList == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
AfList->AddressFamily = AddressFamily->AddressFamily;
|
|
CopyMemory(&AfList->CmChars,
|
|
CmCharacteristics,
|
|
sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
|
|
|
|
//
|
|
// link it in the miniport list
|
|
//
|
|
AfList->Open = CallMgrOpen;
|
|
AfList->NextOpen = Miniport->CallMgrAfList;
|
|
Miniport->CallMgrAfList = AfList;
|
|
//
|
|
// Now link it in the global list
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
|
|
AfList->NextGlobal = ndisAfList;
|
|
ndisAfList = AfList;
|
|
RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
|
|
|
|
//
|
|
// Finally cache some handlers in the open-block
|
|
//
|
|
CallMgrOpen->CoCreateVcHandler = CmCharacteristics->CmCreateVcHandler;
|
|
CallMgrOpen->CoDeleteVcHandler = CmCharacteristics->CmDeleteVcHandler;
|
|
CallMgrOpen->CmActivateVcCompleteHandler = CmCharacteristics->CmActivateVcCompleteHandler;
|
|
CallMgrOpen->CmDeactivateVcCompleteHandler = CmCharacteristics->CmDeactivateVcCompleteHandler;
|
|
|
|
//
|
|
// Notify existing clients of this registration
|
|
//
|
|
ndisMNotifyAfRegistration(Miniport, AddressFamily);
|
|
}
|
|
} while (FALSE);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisMCmRegisterAddressFamily(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily,
|
|
IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
|
|
IN UINT SizeOfCmCharacteristics
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a call from the miniport supported call-manager to register the address family
|
|
supported by this call-manager.
|
|
|
|
Arguments:
|
|
MiniportAdapterHandle - Pointer to the miniports NDIS_MINIPORT_BLOCK.
|
|
AddressFamily - The address family being registered.
|
|
CmCharacteristics - Call-Manager characteristics
|
|
SizeOfCmCharacteristics - Size of Call-Manager characteristics
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if the address family registration is successfully.
|
|
NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
|
|
family is already registered for this miniport.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
NDIS_STATUS Status;
|
|
PNDIS_AF_LIST AfList;
|
|
KIRQL OldIrql;
|
|
|
|
CoReferencePackage();
|
|
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
|
|
//
|
|
// Make sure that the miniport is a CoNdis miniport and
|
|
// there is no other module registering the same address family.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
do
|
|
{
|
|
//
|
|
// Make sure that the miniport is a CoNdis miniport
|
|
//
|
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later miniport
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that the call-manager characteristics are 4.1 or later
|
|
//
|
|
if ((CmCharacteristics->MajorVersion != 4) ||
|
|
(CmCharacteristics->MinorVersion != 1) ||
|
|
(SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later protocol
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Search registered call-managers for this miniport and make sure there is no
|
|
// clash. A call-manager can only register one address family per-open. This
|
|
// is due to the way we cache handlers. Can be over-come if the handlers are
|
|
// identical for each address-family - but decided not to since it is un-interesting.
|
|
//
|
|
for (AfList = Miniport->CallMgrAfList;
|
|
AfList != NULL;
|
|
AfList = AfList->NextOpen)
|
|
{
|
|
if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
|
|
(AfList->Open == NULL))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (AfList == NULL)
|
|
{
|
|
//
|
|
// No other entity has claimed this address family.
|
|
//
|
|
AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
|
|
if (AfList == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
AfList->AddressFamily = AddressFamily->AddressFamily;
|
|
CopyMemory(&AfList->CmChars,
|
|
CmCharacteristics,
|
|
sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
|
|
|
|
//
|
|
// link it in the miniport list
|
|
//
|
|
AfList->Open = NULL;
|
|
AfList->NextOpen = Miniport->CallMgrAfList;
|
|
Miniport->CallMgrAfList = AfList;
|
|
//
|
|
// Now link it in the global list
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
|
|
AfList->NextGlobal = ndisAfList;
|
|
ndisAfList = AfList;
|
|
RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
|
|
}
|
|
} while (FALSE);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
ndisMNotifyAfRegistration(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If a protocol has a handler for it, notify it that a new address family has
|
|
been registered.
|
|
|
|
Arguments:
|
|
NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
|
|
AddressFamily - Address family in question. If not specified all address
|
|
families for the miniport are reported
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
}
|
|
|
|
NDIS_STATUS
|
|
NdisClOpenAddressFamily(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily,
|
|
IN NDIS_HANDLE ClientAfContext,
|
|
IN PNDIS_CLIENT_CHARACTERISTICS ClCharacteristics,
|
|
IN UINT SizeOfClCharacteristics,
|
|
OUT PNDIS_HANDLE NdisAfHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a call from a NDIS 4.1 or later protocol to open a particular
|
|
address familty - in essence getting a handle to the call-manager.
|
|
|
|
Arguments:
|
|
NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
|
|
PCO_ADDRESS_FAMILY - The address family being registered.
|
|
ClientAfContext - Protocol context associated with this handle.
|
|
NdisAfHandle - Handle returned by NDIS for this address family.
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if the address family open is successfully.
|
|
NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
|
|
called at the completion handler when done.
|
|
NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
|
|
family is not registered for this miniport.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
PNDIS_AF_LIST AfList;
|
|
PNDIS_M_OPEN_BLOCK CallMgrOpen, ClientOpen;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_PROTOCOL_BLOCK Protocol;
|
|
KIRQL OldIrql;
|
|
NTSTATUS Status;
|
|
|
|
*NdisAfHandle = NULL;
|
|
ClientOpen = (PNDIS_M_OPEN_BLOCK)((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle;
|
|
Miniport = ClientOpen->MiniportHandle;
|
|
Protocol = ClientOpen->ProtocolHandle;
|
|
|
|
CoReferencePackage();
|
|
|
|
do
|
|
{
|
|
//
|
|
// Make sure the binding is not closing down
|
|
//
|
|
if (ClientOpen->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that the miniport is a CoNdis miniport and
|
|
// protocol is also a NDIS 4.1 or later protocol.
|
|
//
|
|
if ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion < 4) ||
|
|
((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion == 4) &&
|
|
(Miniport->DriverHandle->MiniportCharacteristics.MinorNdisVersion < 1)) ||
|
|
(Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler == NULL))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later miniport
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
|
|
((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
|
|
(Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later protocol
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that the client characteristics are 4.1 or later
|
|
//
|
|
if ((ClCharacteristics->MajorVersion != 4) ||
|
|
(ClCharacteristics->MinorVersion != 1) ||
|
|
(SizeOfClCharacteristics < sizeof(NDIS_CLIENT_CHARACTERISTICS)))
|
|
{
|
|
//
|
|
// Not a NDIS 4.1 or later protocol
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// Search the miniport block for a registered call-manager for this address family
|
|
//
|
|
for (AfList = Miniport->CallMgrAfList;
|
|
AfList != NULL;
|
|
AfList = AfList->NextOpen)
|
|
{
|
|
if (AfList->AddressFamily == AddressFamily->AddressFamily)
|
|
{
|
|
CallMgrOpen = AfList->Open;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we found a matching call manager, make sure that the callmgr
|
|
// is not currently closing.
|
|
//
|
|
if ((AfList == NULL) ||
|
|
((AfList != NULL) && (AfList->Open->Flags & fMINIPORT_OPEN_CLOSING)) ||
|
|
(Miniport->Flags & (fMINIPORT_CLOSING | fMINIPORT_HALTING)))
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
//
|
|
// NOTE: We can possibly wait a little while here and retry
|
|
// before actually failing this call if (AfList == NULL).
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the AF block.
|
|
//
|
|
pAf = ALLOC_FROM_POOL(sizeof(NDIS_CO_AF_BLOCK), NDIS_TAG_CO);
|
|
if (pAf == NULL)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pAf->References = 1;
|
|
pAf->Flags = 0;
|
|
pAf->Miniport = Miniport;
|
|
|
|
pAf->ClientOpen = ClientOpen;
|
|
pAf->CallMgrOpen = CallMgrOpen = AfList->Open;
|
|
pAf->ClientContext = ClientAfContext;
|
|
|
|
//
|
|
// Reference the call-manager's file object - we do not want to let it
|
|
// duck from under the client.
|
|
//
|
|
//
|
|
// Reference the client and the call-manager opens
|
|
//
|
|
ClientOpen->References++;
|
|
if (CallMgrOpen != NULL)
|
|
{
|
|
ObReferenceObject(CallMgrOpen->FileObject);
|
|
CallMgrOpen->References++;
|
|
}
|
|
else
|
|
{
|
|
ObReferenceObject(Miniport->DeviceObject);
|
|
Miniport->Ref.ReferenceCount ++;
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
INITIALIZE_SPIN_LOCK(&pAf->Lock);
|
|
|
|
//
|
|
// Cache in call-manager entry points
|
|
//
|
|
pAf->CallMgrEntries = &AfList->CmChars;
|
|
|
|
//
|
|
// And also Cache in client entry points
|
|
//
|
|
CopyMemory(&pAf->ClientEntries,
|
|
ClCharacteristics,
|
|
sizeof(NDIS_CLIENT_CHARACTERISTICS));
|
|
|
|
|
|
//
|
|
// Cache some handlers in the open-block
|
|
//
|
|
ClientOpen->CoCreateVcHandler = ClCharacteristics->ClCreateVcHandler;
|
|
ClientOpen->CoDeleteVcHandler = ClCharacteristics->ClDeleteVcHandler;
|
|
|
|
//
|
|
// Now call the CallMgr's OpenAfHandler
|
|
//
|
|
Status = (*AfList->CmChars.CmOpenAfHandler)((CallMgrOpen != NULL) ?
|
|
CallMgrOpen->ProtocolBindingContext :
|
|
Miniport->MiniportAdapterContext,
|
|
AddressFamily,
|
|
pAf,
|
|
&pAf->CallMgrContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmOpenAddressFamilyComplete(Status,
|
|
pAf,
|
|
pAf->CallMgrContext);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmOpenAddressFamilyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisAfHandle,
|
|
IN NDIS_HANDLE CallMgrAfContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for the OpenAddressFamily call. The call manager had pended this
|
|
call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
|
|
supplied here as well
|
|
|
|
Arguments:
|
|
Status - Completion status
|
|
NdisAfHandle - Pointer to the AfBlock
|
|
CallMgrAfContext - Call manager's context used in other calls into the call manager.
|
|
|
|
Return Value:
|
|
NONE. The client's completion handler is called.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
PNDIS_M_OPEN_BLOCK ClientOpen;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
ClientOpen = pAf->ClientOpen;
|
|
Miniport = pAf->Miniport;
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pAf->CallMgrOpen != NULL)
|
|
{
|
|
ObDereferenceObject(pAf->CallMgrOpen->FileObject);
|
|
}
|
|
else
|
|
{
|
|
ObDereferenceObject(Miniport->DeviceObject);
|
|
}
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
pAf->CallMgrContext = CallMgrAfContext;
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// OpenAfHandler failed
|
|
//
|
|
if (pAf->CallMgrOpen != NULL)
|
|
{
|
|
pAf->CallMgrOpen->References--;
|
|
if (pAf->CallMgrOpen->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, pAf->CallMgrOpen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ndisDereferenceMiniport(Miniport);
|
|
}
|
|
|
|
ClientOpen->References--;
|
|
if (ClientOpen->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, ClientOpen);
|
|
}
|
|
FREE_POOL(pAf);
|
|
|
|
CoDereferencePackage();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// queue this CallMgr open onto the miniport open
|
|
//
|
|
pAf->NextAf = ClientOpen->NextAf;
|
|
ClientOpen->NextAf = pAf;
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
//
|
|
// Finally call the client's completion handler
|
|
//
|
|
(*pAf->ClientEntries.ClOpenAfCompleteHandler)(Status,
|
|
pAf->ClientContext,
|
|
(Status == NDIS_STATUS_SUCCESS) ? pAf : NULL);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClCloseAddressFamily(
|
|
IN NDIS_HANDLE NdisAfHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This call closes the Af object which essentially tears down the client-callmanager
|
|
'binding'. Causes all open Vcs to be closed and saps to be de-registered "by the call
|
|
manager".
|
|
|
|
Arguments:
|
|
|
|
NdisAfHandle - Pointer to the Af.
|
|
|
|
Return Value:
|
|
|
|
Status from Call Manager.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Mark the address family as closing and call the call-manager to process.
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
|
|
if (pAf->Flags & AF_CLOSING)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
}
|
|
pAf->Flags |= AF_CLOSING;
|
|
RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Status = (*pAf->CallMgrEntries->CmCloseAfHandler)(pAf->CallMgrContext);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmCloseAddressFamilyComplete(Status, pAf);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmCloseAddressFamilyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisAfHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for the CloseAddressFamily call. The call manager had pended this
|
|
call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
|
|
supplied here as well
|
|
|
|
Arguments:
|
|
Status - Completion status
|
|
NdisAfHandle - Pointer to the AfBlock
|
|
|
|
Return Value:
|
|
NONE. The client's completion handler is called.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
KIRQL OldIrql;
|
|
|
|
Miniport = pAf->Miniport;
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Dereference the file object for the call-manager
|
|
//
|
|
if (pAf->CallMgrOpen != NULL)
|
|
{
|
|
ObDereferenceObject(pAf->CallMgrOpen->FileObject);
|
|
}
|
|
else
|
|
{
|
|
ObDereferenceObject(Miniport->DeviceObject);
|
|
}
|
|
|
|
Miniport = pAf->Miniport;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
if (pAf->CallMgrOpen != NULL)
|
|
{
|
|
pAf->CallMgrOpen->References--;
|
|
if (pAf->CallMgrOpen->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, pAf->CallMgrOpen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ndisDereferenceMiniport(Miniport);
|
|
}
|
|
|
|
pAf->ClientOpen->References--;
|
|
if (pAf->ClientOpen->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, pAf->ClientOpen);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
//
|
|
// Complete the call to the client
|
|
//
|
|
(*pAf->ClientEntries.ClCloseAfCompleteHandler)(Status,
|
|
pAf->ClientContext);
|
|
|
|
//
|
|
// Finally dereference the AF Block, if the call-manager successfully closed it.
|
|
//
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ndisDereferenceAf(pAf);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisReferenceAf(
|
|
IN PNDIS_CO_AF_BLOCK pAf
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN rc = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
|
|
|
|
if ((pAf->Flags & AF_CLOSING) == 0)
|
|
{
|
|
pAf->References ++;
|
|
rc = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferenceAf(
|
|
IN PNDIS_CO_AF_BLOCK pAf
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Done = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
|
|
|
|
ASSERT (pAf->References > 0);
|
|
pAf->References --;
|
|
if (pAf->References == 0)
|
|
{
|
|
ASSERT (pAf->Flags & AF_CLOSING);
|
|
Done = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
|
|
|
|
if (Done)
|
|
FREE_POOL(pAf);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClRegisterSap(
|
|
IN NDIS_HANDLE NdisAfHandle,
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN PCO_SAP Sap,
|
|
OUT PNDIS_HANDLE NdisSapHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a call from a NDIS 4.1 or later protocol to register its SAP
|
|
with the call manager.
|
|
|
|
Arguments:
|
|
NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
|
|
PCO_ADDRESS_FAMILY - The address family being registered.
|
|
ClientAfContext - Protocol context associated with this handle.
|
|
NdisAfHandle - Handle returned by NDIS for this address family.
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if the address family open is successfully.
|
|
NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
|
|
NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
|
|
family is not registered for this miniport.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
PNDIS_CO_SAP_BLOCK pSap;
|
|
|
|
*NdisSapHandle = NULL;
|
|
do
|
|
{
|
|
//
|
|
// Reference the Af for this SAP
|
|
//
|
|
if (!ndisReferenceAf(pAf))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pSap = (PNDIS_CO_SAP_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_SAP_BLOCK), NDIS_TAG_CO);
|
|
if (pSap == NULL)
|
|
{
|
|
*NdisSapHandle = NULL;
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pSap->Flags = 0;
|
|
pSap->References = 1;
|
|
INITIALIZE_SPIN_LOCK(&pSap->Lock);
|
|
pSap->AfBlock = pAf;
|
|
pSap->Sap = Sap;
|
|
pSap->ClientContext = ProtocolSapContext;
|
|
Status = (*pAf->CallMgrEntries->CmRegisterSapHandler)(pAf->CallMgrContext,
|
|
Sap,
|
|
pSap,
|
|
&pSap->CallMgrContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmRegisterSapComplete(Status, pSap, pSap->CallMgrContext);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmRegisterSapComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisSapHandle,
|
|
IN NDIS_HANDLE CallMgrSapContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Completion routine for the registerSap call. The call manager had pended this
|
|
call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
|
|
supplied here as well
|
|
|
|
Arguments:
|
|
Status - Completion status
|
|
NdisAfHandle - Pointer to the AfBlock
|
|
CallMgrAfContext - Call manager's context used in other calls into the call manager.
|
|
|
|
Return Value:
|
|
NONE. The client's completion handler is called.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
pAf = pSap->AfBlock;
|
|
pSap->CallMgrContext = CallMgrSapContext;
|
|
|
|
//
|
|
// Call the clients completion handler
|
|
//
|
|
(*pAf->ClientEntries.ClRegisterSapCompleteHandler)(Status,
|
|
pSap->ClientContext,
|
|
pSap->Sap,
|
|
pSap);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ndisDereferenceAf(pSap->AfBlock);
|
|
FREE_POOL(pSap);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClDeregisterSap(
|
|
IN NDIS_HANDLE NdisSapHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
BOOLEAN fAlreadyClosing;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
|
|
|
|
fAlreadyClosing = FALSE;
|
|
if (pSap->Flags & SAP_CLOSING)
|
|
{
|
|
fAlreadyClosing = TRUE;
|
|
}
|
|
pSap->Flags |= SAP_CLOSING;
|
|
|
|
RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
|
|
|
|
if (fAlreadyClosing)
|
|
{
|
|
return NDIS_STATUS_FAILURE;
|
|
}
|
|
|
|
//
|
|
// Notify the call-manager that this sap is being de-registered
|
|
//
|
|
Status = (*pSap->AfBlock->CallMgrEntries->CmDeregisterSapHandler)(pSap->CallMgrContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmDeregisterSapComplete(Status, pSap);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDeregisterSapComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisSapHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
//
|
|
// Complete the call to the client and deref the sap
|
|
//
|
|
(*pSap->AfBlock->ClientEntries.ClDeregisterSapCompleteHandler)(Status,
|
|
pSap->ClientContext);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ndisDereferenceAf(pSap->AfBlock);
|
|
ndisDereferenceSap(pSap);
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisReferenceSap(
|
|
IN PNDIS_CO_SAP_BLOCK pSap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN rc = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
|
|
|
|
if ((pSap->Flags & SAP_CLOSING) == 0)
|
|
{
|
|
pSap->References ++;
|
|
rc = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferenceSap(
|
|
IN PNDIS_CO_SAP_BLOCK pSap
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Done = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
|
|
|
|
ASSERT (pSap->References > 0);
|
|
pSap->References --;
|
|
if (pSap->References == 0)
|
|
{
|
|
ASSERT (pSap->Flags & SAP_CLOSING);
|
|
Done = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
|
|
|
|
if (Done)
|
|
FREE_POOL(pSap);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCoCreateVc(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE NdisAfHandle OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN OUT PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This is a call from either the call-manager or from the client to create a vc.
|
|
The vc would then be owned by call-manager (signalling vc) or the client.
|
|
This is a synchronous call to all parties and simply creates an end-point over
|
|
which either incoming calls can be dispatched or out-going calls can be made.
|
|
|
|
Arguments:
|
|
NdisBindingHandle - Pointer to the caller's NDIS_OPEN_BLOCK.
|
|
NdisAfHandle - Pointer to the AF Block. Not specified for call-manager's private vcs.
|
|
A miniport resident call-manager must never create call-manager vcs i.e.
|
|
the NdisAfHandle must always be present
|
|
NdisVcHandle - Where the handle to this Vc will be returned.
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if all the components succeed.
|
|
ErrorCode to signify why the call failed.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_CO_VC_BLOCK Vc;
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
NDIS_STATUS Status;
|
|
|
|
Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle);
|
|
Miniport = Open->MiniportHandle;
|
|
*NdisVcHandle = NULL;
|
|
|
|
//
|
|
// Allocate the memory for NDIS_VC_BLOCK
|
|
//
|
|
Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
|
|
if (Vc == NULL)
|
|
return NDIS_STATUS_RESOURCES;
|
|
|
|
//
|
|
// Initialize the VC block
|
|
//
|
|
NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
|
|
INITIALIZE_SPIN_LOCK(&Vc->Lock);
|
|
InitializeListHead(&Vc->CallMgrLinkage);
|
|
InitializeListHead(&Vc->ClientLinkage);
|
|
|
|
//
|
|
// Cache some miniport handlers
|
|
//
|
|
Vc->Miniport = Miniport;
|
|
Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
|
|
Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
|
|
Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
|
|
Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
|
|
|
|
//
|
|
// We have only one reference for vc on creation.
|
|
//
|
|
pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
Vc->AfBlock = pAf;
|
|
Vc->References = 1;
|
|
|
|
//
|
|
// First call the miniport to get its context
|
|
//
|
|
Status = (*Open->MiniportCoCreateVcHandler)(Miniport->MiniportAdapterContext,
|
|
Vc,
|
|
&Vc->MiniportContext);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
FREE_POOL(Vc);
|
|
return Status;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(NdisAfHandle))
|
|
{
|
|
Vc->ClientOpen = pAf->ClientOpen;
|
|
Vc->CallMgrOpen = pAf->CallMgrOpen;
|
|
|
|
Vc->CoSendCompleteHandler =
|
|
pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
|
|
Vc->CoReceivePacketHandler =
|
|
pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
|
|
Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
|
|
Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
|
|
Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
|
|
|
|
Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
|
|
Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
|
|
Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
|
|
|
|
//
|
|
// Determine who the caller is and initialize the other.
|
|
//
|
|
if (Open == pAf->ClientOpen)
|
|
{
|
|
Vc->ClientContext = ProtocolVcContext;
|
|
|
|
if (pAf->CallMgrOpen == NULL)
|
|
{
|
|
Vc->CallMgrContext = Vc->MiniportContext;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Call-up to the call-manager now to get its context
|
|
//
|
|
Status = (*pAf->CallMgrOpen->CoCreateVcHandler)(pAf->CallMgrContext,
|
|
Vc,
|
|
&Vc->CallMgrContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT (pAf->CallMgrOpen == Open);
|
|
|
|
Vc->CallMgrContext = ProtocolVcContext;
|
|
|
|
//
|
|
// Call-up to the client now to get its context
|
|
//
|
|
Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
|
|
Vc,
|
|
&Vc->ClientContext);
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (Open == pAf->ClientOpen)
|
|
{
|
|
//
|
|
// Link this in the open_block
|
|
//
|
|
ExInterlockedInsertHeadList(&Open->InactiveVcHead,
|
|
&Vc->ClientLinkage,
|
|
&Open->SpinLock.SpinLock);
|
|
if (pAf->CallMgrOpen != NULL)
|
|
{
|
|
Vc->DeleteVcContext = Vc->CallMgrContext;
|
|
Vc->CoDeleteVcHandler = pAf->CallMgrOpen->CoDeleteVcHandler;
|
|
ExInterlockedInsertHeadList(&pAf->CallMgrOpen->InactiveVcHead,
|
|
&Vc->CallMgrLinkage,
|
|
&pAf->CallMgrOpen->SpinLock.SpinLock);
|
|
}
|
|
else
|
|
{
|
|
Vc->DeleteVcContext = NULL;
|
|
Vc->CoDeleteVcHandler = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Link this in the open_block
|
|
//
|
|
Vc->DeleteVcContext = Vc->ClientContext;
|
|
Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
|
|
ExInterlockedInsertHeadList(&Open->InactiveVcHead,
|
|
&Vc->CallMgrLinkage,
|
|
&Open->SpinLock.SpinLock);
|
|
ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
|
|
&Vc->ClientLinkage,
|
|
&pAf->ClientOpen->SpinLock.SpinLock);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
|
|
|
|
FREE_POOL(Vc);
|
|
Vc = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is a call-manager only VC and so the call-manager is the client and there
|
|
// is no call-manager associated with it. This VC cannot be used to CoMakeCall or
|
|
// CmDispatchIncomingCall. Set the client values to the call-manager
|
|
//
|
|
// Vc->CoDeleteVcContexr = NULL;
|
|
// Vc->CoDeleteVcHandler = NULL;
|
|
Vc->ClientOpen = Open;
|
|
Vc->ClientContext = ProtocolVcContext;
|
|
Vc->CoSendCompleteHandler =
|
|
Open->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
|
|
Vc->CoReceivePacketHandler =
|
|
Open->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
|
|
|
|
//
|
|
// Do set the following call-manager entries since this VC will need to be
|
|
// activated. Also set the call-managers context for the same reasons.
|
|
//
|
|
Vc->CmActivateVcCompleteHandler = Open->CmActivateVcCompleteHandler;
|
|
Vc->CmDeactivateVcCompleteHandler = Open->CmDeactivateVcCompleteHandler;
|
|
Vc->CallMgrContext = ProtocolVcContext;
|
|
|
|
//
|
|
// Link this in the open_block
|
|
//
|
|
ExInterlockedInsertHeadList(&Open->InactiveVcHead,
|
|
&Vc->ClientLinkage,
|
|
&Open->SpinLock.SpinLock);
|
|
}
|
|
|
|
*NdisVcHandle = Vc;
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCoDeleteVc(
|
|
IN PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronous call from either the call-manager or the client to delete a VC. Only inactive
|
|
VCs can be deleted. Active Vcs or partially active Vcs cannot be.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to delete
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS If all goes well
|
|
NDIS_STATUS_NOT_ACCEPTED If Vc is active
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
if (Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING))
|
|
{
|
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
else if (Vc->Flags & VC_DEACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else
|
|
{
|
|
Vc->Flags |= VC_CLOSING;
|
|
|
|
//
|
|
// Call the miniport to delete it first
|
|
//
|
|
Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Next the non-creator, if any
|
|
//
|
|
if (Vc->CoDeleteVcHandler != NULL)
|
|
{
|
|
Status = (*Vc->CoDeleteVcHandler)(Vc->DeleteVcContext);
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Now de-link the vc from the client and call-manager
|
|
//
|
|
ACQUIRE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
|
|
RemoveEntryList(&Vc->ClientLinkage);
|
|
RELEASE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
|
|
|
|
if (Vc->CallMgrOpen != NULL)
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
|
|
RemoveEntryList(&Vc->CallMgrLinkage);
|
|
RELEASE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ndisDereferenceVc(Vc);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisMCmCreateVc(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE NdisAfHandle,
|
|
IN NDIS_HANDLE MiniportVcContext,
|
|
OUT PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a call by the miniport (with a resident CM) to create a Vc for an incoming call.
|
|
|
|
Arguments:
|
|
MiniportAdapterHandle - Miniport's adapter context
|
|
NdisAfHandle - Pointer to the AF Block.
|
|
MiniportVcContext - Miniport's context to associate with this vc.
|
|
NdisVcHandle - Where the handle to this Vc will be returned.
|
|
|
|
Return Value:
|
|
NDIS_STATUS_SUCCESS if all the components succeed.
|
|
ErrorCode to signify why the call failed.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_CO_VC_BLOCK Vc;
|
|
PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
*NdisVcHandle = NULL;
|
|
|
|
//
|
|
// Allocate the memory for NDIS_VC_BLOCK
|
|
//
|
|
Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
|
|
if (Vc == NULL)
|
|
return NDIS_STATUS_RESOURCES;
|
|
|
|
//
|
|
// Initialize the VC block
|
|
//
|
|
NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
|
|
INITIALIZE_SPIN_LOCK(&Vc->Lock);
|
|
InitializeListHead(&Vc->CallMgrLinkage);
|
|
InitializeListHead(&Vc->ClientLinkage);
|
|
|
|
//
|
|
// Cache some miniport handlers
|
|
//
|
|
Vc->Miniport = Miniport;
|
|
Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
|
|
Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
|
|
Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
|
|
Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
|
|
Vc->MiniportContext = MiniportVcContext;
|
|
|
|
//
|
|
// We have only one reference for vc on creation.
|
|
//
|
|
pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
Vc->AfBlock = pAf;
|
|
Vc->References = 1;
|
|
|
|
ASSERT (ARGUMENT_PRESENT(NdisAfHandle));
|
|
|
|
Vc->ClientOpen = pAf->ClientOpen;
|
|
Vc->CallMgrOpen = NULL;
|
|
|
|
Vc->CoSendCompleteHandler =
|
|
pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
|
|
Vc->CoReceivePacketHandler =
|
|
pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
|
|
Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
|
|
Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
|
|
Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
|
|
|
|
Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
|
|
Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
|
|
Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
|
|
|
|
Vc->CallMgrContext = MiniportVcContext;
|
|
|
|
//
|
|
// Call-up to the client now to get its context
|
|
//
|
|
Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
|
|
Vc,
|
|
&Vc->ClientContext);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Link this in the open_block
|
|
//
|
|
Vc->DeleteVcContext = Vc->ClientContext;
|
|
Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
|
|
ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
|
|
&Vc->ClientLinkage,
|
|
&pAf->ClientOpen->SpinLock.SpinLock);
|
|
}
|
|
else
|
|
{
|
|
Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
|
|
|
|
FREE_POOL(Vc);
|
|
Vc = NULL;
|
|
}
|
|
|
|
*NdisVcHandle = Vc;
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisMCmDeleteVc(
|
|
IN PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a called by the miniport (with a resident CM) to delete a Vc created by it. Identical to
|
|
NdisMCoDeleteVc but a seperate api for completeness.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to delete
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS If all goes well
|
|
NDIS_STATUS_NOT_ACCEPTED If Vc is active
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
return(NdisMCmDeleteVc(NdisVcHandle));
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCmActivateVc(
|
|
IN PNDIS_HANDLE NdisVcHandle,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the call-manager to set the Vc parameters on the Vc. The wrapper
|
|
saved the media id (e.g. Vpi/Vci for atm) in the Vc so that a p-mode protocol can
|
|
get this info as well on receives.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to set parameters on.
|
|
MediaParameters The parameters to set.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING If the miniport pends the call.
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
//
|
|
// Make sure the Vc does not have an activation/de-activation pending
|
|
// Not that it is ok for the Vc to be already active - then it is a re-activation.
|
|
//
|
|
if (Vc->Flags & VC_ACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
else if (Vc->Flags & VC_DEACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else
|
|
{
|
|
Vc->Flags |= VC_ACTIVATE_PENDING;
|
|
|
|
//
|
|
// Save the media id for the Vc
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Now call down to the miniport to activate it
|
|
//
|
|
Status = (*Vc->WCoActivateVcHandler)(Vc->MiniportContext, CallParameters);
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisMCoActivateVcComplete(Status, Vc, CallParameters);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisMCmActivateVc(
|
|
IN PNDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the miniport resident call-manager to set the Vc parameters on the Vc. This is a
|
|
synchronous call.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to set parameters on.
|
|
MediaParameters The parameters to set.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
//
|
|
// Make sure the Vc does not have an activation/de-activation pending
|
|
// Not that it is ok for the Vc to be already active - then it is a re-activation.
|
|
//
|
|
if (Vc->Flags & VC_ACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
else if (Vc->Flags & VC_DEACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else
|
|
{
|
|
Vc->Flags |= VC_ACTIVE;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoActivateVcComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PNDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the mini-port to complete a pending activation call.
|
|
|
|
Arguments:
|
|
|
|
Status Status of activation.
|
|
NdisVcHandle The Vc in question.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
The call-manager's completion routine is called.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
ASSERT (Vc->Flags & VC_ACTIVATE_PENDING);
|
|
|
|
Vc->Flags &= ~VC_ACTIVATE_PENDING;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Vc->Flags |= VC_ACTIVE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
//
|
|
// Complete the call to the call-manager
|
|
//
|
|
(*Vc->CmActivateVcCompleteHandler)(Status, Vc->CallMgrContext, CallParameters);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCmDeactivateVc(
|
|
IN PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the call-manager to de-activate a Vc.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to de-activate the Vc.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING If the miniport pends the call.
|
|
NDIS_STATUS_SUCCESS If all goes well
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
|
|
{
|
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
else if (Vc->Flags & VC_DEACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else
|
|
{
|
|
Vc->Flags |= VC_DEACTIVATE_PENDING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
//
|
|
// Now call down to the miniport to de-activate it
|
|
//
|
|
Status = (*Vc->WCoDeactivateVcHandler)(Vc->MiniportContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisMCoDeactivateVcComplete(Status, Vc);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisMCmDeactivateVc(
|
|
IN PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the miniport resident call-manager to de-activate the Vc. This is a
|
|
synchronous call.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc to set parameters on.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_CLOSING If Vc de-activation is pending
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
|
|
{
|
|
Status = NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
else if (Vc->Flags & VC_DEACTIVATE_PENDING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
Vc->Flags &= ~VC_ACTIVE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoDeactivateVcComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PNDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the mini-port to complete a pending de-activation of a Vc.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle The Vc in question.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
The call-manager's completion routine is called.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
ASSERT (Vc->Flags & VC_DEACTIVATE_PENDING);
|
|
|
|
Vc->Flags &= ~VC_DEACTIVATE_PENDING;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Vc->Flags &= ~VC_ACTIVE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
//
|
|
// Complete the call to the call-manager
|
|
//
|
|
(*Vc->CmDeactivateVcCompleteHandler)(Status, Vc->CallMgrContext);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClMakeCall(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
OUT PNDIS_HANDLE NdisPartyHandle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
PNDIS_CO_PARTY_BLOCK pParty = NULL;
|
|
PVOID CallMgrPartyContext = NULL;
|
|
NDIS_STATUS Status;
|
|
|
|
do
|
|
{
|
|
pAf = Vc->AfBlock;
|
|
ASSERT (pAf != NULL);
|
|
if (!ndisReferenceAf(pAf))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT(NdisPartyHandle))
|
|
{
|
|
*NdisPartyHandle = NULL;
|
|
pParty = (PNDIS_CO_PARTY_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK),
|
|
NDIS_TAG_CO);
|
|
if (pParty == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
pParty->Vc = Vc;
|
|
pParty->ClientContext = ProtocolPartyContext;
|
|
pParty->ClIncomingDropPartyHandler =
|
|
pAf->ClientEntries.ClIncomingDropPartyHandler;
|
|
pParty->ClDropPartyCompleteHandler =
|
|
pAf->ClientEntries.ClDropPartyCompleteHandler;
|
|
}
|
|
|
|
//
|
|
// Pass the request off to the call manager
|
|
//
|
|
Status = (*pAf->CallMgrEntries->CmMakeCallHandler)(Vc->CallMgrContext,
|
|
CallParameters,
|
|
pParty,
|
|
&CallMgrPartyContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmMakeCallComplete(Status,
|
|
Vc,
|
|
pParty,
|
|
CallMgrPartyContext,
|
|
CallParameters);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
} while (FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// These are resource failures and not a failure from call-manager
|
|
//
|
|
if (pParty != NULL)
|
|
{
|
|
FREE_POOL(pParty);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmMakeCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
KIRQL OldIrql;
|
|
|
|
pAf = Vc->AfBlock;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Call completed successfully. Complete it to the client.
|
|
//
|
|
|
|
//
|
|
// Reference the Vc for the client. This is dereferenced when
|
|
// the client calls NdisClCloseCall()
|
|
//
|
|
ndisReferenceVc(Vc);
|
|
|
|
|
|
if (ARGUMENT_PRESENT(NdisPartyHandle))
|
|
{
|
|
pParty->CallMgrContext = CallMgrPartyContext;
|
|
ndisReferenceVc(Vc);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, &OldIrql);
|
|
RemoveEntryList(&Vc->ClientLinkage);
|
|
InsertHeadList(&pAf->ClientOpen->ActiveVcHead,
|
|
&Vc->ClientLinkage);
|
|
RELEASE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, OldIrql);
|
|
}
|
|
else
|
|
{
|
|
ndisDereferenceAf(pAf);
|
|
}
|
|
|
|
(*pAf->ClientEntries.ClMakeCallCompleteHandler)(Status,
|
|
Vc->ClientContext,
|
|
pParty,
|
|
CallParameters);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCmDispatchIncomingCall(
|
|
IN NDIS_HANDLE NdisSapHandle,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Call from the call-manager to dispatch an incoming vc to the client who registered the Sap.
|
|
The client is identified by the NdisSapHandle.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Identifies the miniport on which the Vc is created
|
|
NdisSapHandle - Identifies the client
|
|
CallParameters - Self explanatory
|
|
NdisVcHandle - Pointer to the NDIS_CO_VC_BLOCK created via NdisCmCreateVc
|
|
|
|
Return Value:
|
|
|
|
Return value from the client or an processing error.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_SAP_BLOCK Sap;
|
|
PNDIS_CO_VC_BLOCK Vc;
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
NDIS_STATUS Status;
|
|
|
|
Sap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
|
|
Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
pAf = Sap->AfBlock;
|
|
|
|
ASSERT(pAf == Vc->AfBlock);
|
|
|
|
//
|
|
// Make sure the SAP's not closing
|
|
//
|
|
if (!ndisReferenceSap(Sap))
|
|
{
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Make sure the AF is not closing
|
|
//
|
|
if (!ndisReferenceAf(pAf))
|
|
{
|
|
ndisDereferenceSap(Sap);
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Notify the client of this call
|
|
//
|
|
Status = (*pAf->ClientEntries.ClIncomingCallHandler)(Sap->ClientContext,
|
|
Vc->ClientContext,
|
|
CallParameters);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisClIncomingCallComplete(Status, Vc, CallParameters);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
ndisDereferenceSap(Sap);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisClIncomingCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
KIRQL OldIrql;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, &OldIrql);
|
|
//
|
|
// Reference the Vc. This is dereferenced when NdisClCloseCall is called.
|
|
//
|
|
Vc->References ++;
|
|
RemoveEntryList(&Vc->ClientLinkage);
|
|
InsertHeadList(&Vc->ClientOpen->ActiveVcHead,
|
|
&Vc->ClientLinkage);
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, OldIrql);
|
|
}
|
|
|
|
//
|
|
// Call the call-manager handler to notify that client is done with this.
|
|
//
|
|
(*Vc->AfBlock->CallMgrEntries->CmIncomingCallCompleteHandler)(
|
|
Status,
|
|
Vc->CallMgrContext,
|
|
CallParameters);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDispatchCallConnected(
|
|
IN NDIS_HANDLE NdisVcHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the call-manager to complete the final hand-shake on an incoming call.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - Pointer to the vc block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
|
|
(*Vc->ClCallConnectedHandler)(Vc->ClientContext);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClModifyCallQoS(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initiated by the client to modify the QoS associated with the call.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - Pointer to the vc block
|
|
CallParameters - New call QoS
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Ask the call-manager to take care of this
|
|
//
|
|
Status = (*Vc->CmModifyCallQoSHandler)(Vc->CallMgrContext,
|
|
CallParameters);
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NdisCmModifyCallQoSComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
|
|
//
|
|
// Simply notify the client
|
|
//
|
|
(*Vc->ClModifyCallQoSCompleteHandler)(Status,
|
|
Vc->ClientContext,
|
|
CallParameters);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDispatchIncomingCallQoSChange(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the call-manager to indicate a remote requested change in the call-qos. This is
|
|
simply an indication. A client must respond by either accepting it (do nothing) or reject
|
|
it (by either modifying the call qos or by tearing down the call).
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - Pointer to the vc block
|
|
CallParameters - New call qos
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
|
|
//
|
|
// Simply notify the client
|
|
//
|
|
(*Vc->ClIncomingCallQoSChangeHandler)(Vc->ClientContext,
|
|
CallParameters);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClCloseCall(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PVOID Buffer OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the client to close down a connection established via either NdisClMakeCall
|
|
or accepting an incoming call via NdisClIncomingCallComplete. The optional buffer can
|
|
be specified by the client to send a disconnect message. Upto the call-manager to do
|
|
something reasonable with it.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - Pointer to the vc block
|
|
Buffer - Optional disconnect message
|
|
Size - Size of the disconnect message
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Simply notify the call-manager
|
|
//
|
|
Status = (*Vc->AfBlock->CallMgrEntries->CmCloseCallHandler)(Vc->CallMgrContext,
|
|
(pParty != NULL) ?
|
|
pParty->CallMgrContext :
|
|
NULL,
|
|
Buffer,
|
|
Size);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmCloseCallComplete(Status, Vc, pParty);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmCloseCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - Pointer to the vc block
|
|
|
|
Return Value:
|
|
|
|
Nothing. Client handler called
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
|
|
//
|
|
// Notify the client and dereference the Vc
|
|
//
|
|
(*Vc->AfBlock->ClientEntries.ClCloseCallCompleteHandler)(Status,
|
|
Vc->ClientContext,
|
|
(pParty != NULL) ?
|
|
pParty->CallMgrContext :
|
|
NULL);
|
|
|
|
ndisDereferenceAf(Vc->AfBlock);
|
|
ndisDereferenceVc(Vc);
|
|
if (pParty != NULL)
|
|
{
|
|
ASSERT (Vc == pParty->Vc);
|
|
ndisDereferenceVc(pParty->Vc);
|
|
FREE_POOL(pParty);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDispatchIncomingCloseCall(
|
|
IN NDIS_STATUS CloseStatus,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
|
|
//
|
|
// Notify the client
|
|
//
|
|
(*Vc->AfBlock->ClientEntries.ClIncomingCloseCallHandler)(
|
|
CloseStatus,
|
|
Vc->ClientContext,
|
|
Buffer,
|
|
Size);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClAddParty(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters,
|
|
OUT PNDIS_HANDLE NdisPartyHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Call from the client to the call-manager to add a party to a point-to-multi-point call.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - The handle client obtained via NdisClMakeCall()
|
|
ProtocolPartyContext - Protocol's context for this leaf
|
|
Flags - Call flags
|
|
CallParameters - Call parameters
|
|
NdisPartyHandle - Place holder for the handle to identify the leaf
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING The call has pended and will complete via CoAddPartyCompleteHandler.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_CO_PARTY_BLOCK pParty;
|
|
NDIS_STATUS Status;
|
|
|
|
do
|
|
{
|
|
*NdisPartyHandle = NULL;
|
|
if (!ndisReferenceVc(Vc))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
pParty = ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK), NDIS_TAG_CO);
|
|
if (pParty == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pParty->ClientContext = ProtocolPartyContext;
|
|
pParty->Vc = Vc;
|
|
pParty->ClIncomingDropPartyHandler =
|
|
Vc->AfBlock->ClientEntries.ClIncomingDropPartyHandler;
|
|
pParty->ClDropPartyCompleteHandler =
|
|
Vc->AfBlock->ClientEntries.ClDropPartyCompleteHandler;
|
|
|
|
//
|
|
// Simply call the call-manager to do its stuff.
|
|
//
|
|
Status = (*Vc->AfBlock->CallMgrEntries->CmAddPartyHandler)(
|
|
Vc->CallMgrContext,
|
|
CallParameters,
|
|
pParty,
|
|
&pParty->CallMgrContext);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmAddPartyComplete(Status,
|
|
pParty,
|
|
pParty->CallMgrContext,
|
|
CallParameters);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
} while (FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmAddPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pParty->CallMgrContext = CallMgrPartyContext;
|
|
}
|
|
|
|
//
|
|
// Complete the call to the client
|
|
//
|
|
(*pParty->Vc->AfBlock->ClientEntries.ClAddPartyCompleteHandler)(
|
|
Status,
|
|
pParty->ClientContext,
|
|
pParty,
|
|
CallParameters);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ndisDereferenceVc(pParty->Vc);
|
|
FREE_POOL(pParty);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisClDropParty(
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PVOID Buffer OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Pass it along to the call-manager to handle this
|
|
//
|
|
Status = (*pParty->Vc->AfBlock->CallMgrEntries->CmDropPartyHandler)(
|
|
pParty->CallMgrContext,
|
|
Buffer,
|
|
Size);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCmDropPartyComplete(Status, pParty);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDropPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisPartyHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
|
|
ASSERT (Status != NDIS_STATUS_PENDING);
|
|
|
|
//
|
|
// Complete the call to the client
|
|
//
|
|
(*pParty->ClDropPartyCompleteHandler)(Status,
|
|
pParty->ClientContext);
|
|
ndisDereferenceVc(pParty->Vc);
|
|
FREE_POOL(pParty);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCmDispatchIncomingDropParty(
|
|
IN NDIS_STATUS DropStatus,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PVOID Buffer,
|
|
IN UINT Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by the call-manager to notify the client that this leaf of the multi-party
|
|
call is terminated. The client cannot use the NdisPartyHandle after completing this
|
|
call - synchronously or by calling NdisClIncomingDropPartyComplete.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
|
|
|
|
//
|
|
// Notify the client
|
|
//
|
|
(*pParty->ClIncomingDropPartyHandler)(DropStatus,
|
|
pParty->ClientContext,
|
|
Buffer,
|
|
Size);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisReferenceVc(
|
|
IN PNDIS_CO_VC_BLOCK Vc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN rc = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
if ((Vc->Flags & VC_CLOSING) == 0)
|
|
{
|
|
Vc->References ++;
|
|
rc = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferenceVc(
|
|
IN PNDIS_CO_VC_BLOCK Vc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN Done = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
|
|
|
|
ASSERT (Vc->References > 0);
|
|
Vc->References --;
|
|
if (Vc->References == 0)
|
|
{
|
|
ASSERT (Vc->Flags & VC_CLOSING);
|
|
Done = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
|
|
|
|
if (Done)
|
|
FREE_POOL(Vc);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMCoFreeResources(
|
|
PNDIS_M_OPEN_BLOCK Open
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans-up address family list for call-managers etc.
|
|
|
|
CALLED WITH MINIPORT LOCK HELD.
|
|
|
|
Arguments:
|
|
|
|
Open - Pointer to the Open block for miniports
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_AF_LIST *pAfList, pTmp;
|
|
|
|
Miniport = Open->MiniportHandle;
|
|
|
|
for (pAfList = &Miniport->CallMgrAfList;
|
|
(pTmp = *pAfList) != NULL;
|
|
NOTHING)
|
|
{
|
|
if (pTmp->Open == Open)
|
|
{
|
|
*pAfList = pTmp->NextOpen;
|
|
FREE_POOL(pTmp);
|
|
}
|
|
else
|
|
{
|
|
pAfList = &pTmp->NextOpen;
|
|
}
|
|
}
|
|
|
|
ASSERT (IsListEmpty(&Open->ActiveVcHead));
|
|
ASSERT (IsListEmpty(&Open->InactiveVcHead));
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
NdisCoRequest(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN NDIS_HANDLE NdisAfHandle OPTIONAL,
|
|
IN NDIS_HANDLE NdisVcHandle OPTIONAL,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This api is used for two separate paths.
|
|
1. A symmetric call between the client and the call-manager. This mechanism is a
|
|
two-way mechanism for the call-manager and client to communicate with each other in an
|
|
asynchronous manner.
|
|
2. A request down to the miniport.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Specifies the binding and identifies the caller as call-manager/client
|
|
NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
|
|
request is targeted to the miniport.
|
|
NdisVcHandle - Pointer to optional VC block. If present the request relates to the
|
|
VC
|
|
NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
|
|
to the party.
|
|
NdisRequest - The request itself
|
|
|
|
Return Value:
|
|
NDIS_STATUS_PENDING if the target pends the call.
|
|
NDIS_STATUS_FAILURE if the binding or af is closing.
|
|
Anything else return code from the other end.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_CO_AF_BLOCK pAf;
|
|
NDIS_HANDLE VcContext;
|
|
PNDIS_COREQ_RESERVED ReqRsvd;
|
|
NDIS_STATUS Status;
|
|
|
|
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
|
|
Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
|
|
|
|
do
|
|
{
|
|
if (ARGUMENT_PRESENT(NdisAfHandle))
|
|
{
|
|
CO_REQUEST_HANDLER CoRequestHandler;
|
|
NDIS_HANDLE AfContext, PartyContext;
|
|
|
|
pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
|
|
//
|
|
// Attempt to reference the AF
|
|
//
|
|
if (!ndisReferenceAf(pAf))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
VcContext = NULL;
|
|
PartyContext = NULL;
|
|
NdisZeroMemory(ReqRsvd, sizeof(NDIS_COREQ_RESERVED));
|
|
|
|
//
|
|
// Figure out who we are and call the peer
|
|
//
|
|
if (pAf->ClientOpen == Open)
|
|
{
|
|
//
|
|
// This is the client, so call the call-manager's CoRequestHandler
|
|
//
|
|
CoRequestHandler =
|
|
pAf->CallMgrOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
|
|
AfContext = pAf->CallMgrContext;
|
|
ReqRsvd->AfContext = pAf->ClientContext;
|
|
ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
|
|
if (ARGUMENT_PRESENT(NdisVcHandle))
|
|
{
|
|
VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->CallMgrContext;
|
|
}
|
|
if (ARGUMENT_PRESENT(NdisPartyHandle))
|
|
{
|
|
PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT (pAf->CallMgrOpen == Open);
|
|
//
|
|
// This is the call-manager, so call the client's CoRequestHandler
|
|
//
|
|
CoRequestHandler =
|
|
pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
|
|
AfContext = pAf->ClientContext;
|
|
ReqRsvd->AfContext = pAf->CallMgrContext;
|
|
ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
|
|
if (ARGUMENT_PRESENT(NdisVcHandle))
|
|
{
|
|
ReqRsvd->VcContext = pAf->CallMgrContext;
|
|
VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
|
|
}
|
|
if (ARGUMENT_PRESENT(NdisPartyHandle))
|
|
{
|
|
ReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
|
|
PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now call the handler
|
|
//
|
|
Status = (*CoRequestHandler)(AfContext, VcContext, PartyContext, NdisRequest);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisCoRequestComplete(Status,
|
|
NdisAfHandle,
|
|
NdisVcHandle,
|
|
NdisPartyHandle,
|
|
NdisRequest);
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
|
|
Miniport = Open->MiniportHandle;
|
|
|
|
//
|
|
// Start off by referencing the open.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
if (Open->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
|
|
{
|
|
Status = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
}
|
|
else
|
|
{
|
|
Open->References ++;
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ReqRsvd->Open = Open;
|
|
ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
|
|
ReqRsvd->VcContext = NULL;
|
|
ReqRsvd->Flags = COREQ_DOWNLEVEL;
|
|
ReqRsvd->RealRequest = NdisRequest;
|
|
if (ARGUMENT_PRESENT(NdisVcHandle))
|
|
{
|
|
ReqRsvd->VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
|
|
}
|
|
|
|
//
|
|
// Call the miniport's CoRequest Handler
|
|
//
|
|
Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
|
|
(NdisVcHandle != NULL) ?
|
|
((PNDIS_CO_VC_BLOCK)NdisVcHandle)->MiniportContext :
|
|
NULL,
|
|
NdisRequest);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisMCoRequestComplete(Status,
|
|
Open->MiniportHandle,
|
|
NdisRequest);
|
|
}
|
|
}
|
|
|
|
}
|
|
} while (FALSE);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCoRequestComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisAfHandle,
|
|
IN NDIS_HANDLE NdisVcHandle OPTIONAL,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_COREQ_RESERVED ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
|
|
|
|
//
|
|
// Simply call the request completion handler and deref the Af block
|
|
//
|
|
(*ReqRsvd->CoRequestCompleteHandler)(Status,
|
|
ReqRsvd->AfContext,
|
|
ReqRsvd->VcContext,
|
|
ReqRsvd->PartyContext,
|
|
NdisRequest);
|
|
ndisDereferenceAf((PNDIS_CO_AF_BLOCK)NdisAfHandle);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoRequestComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_COREQ_RESERVED ReqRsvd;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
|
|
Miniport = (PNDIS_MINIPORT_BLOCK)NdisBindingHandle;
|
|
Open = ReqRsvd->Open;
|
|
|
|
if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
|
|
(NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
|
|
(NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength != 0))
|
|
{
|
|
if (Open->Flags & fMINIPORT_OPEN_PMODE)
|
|
{
|
|
*(PULONG)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) |=
|
|
NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL;
|
|
}
|
|
}
|
|
|
|
if (Open != NULL)
|
|
{
|
|
PNDIS_REQUEST RealRequest;
|
|
KIRQL OldIrql;
|
|
|
|
RealRequest = NdisRequest;
|
|
if (ReqRsvd->RealRequest != NULL)
|
|
{
|
|
RealRequest = ReqRsvd->RealRequest;
|
|
RealRequest->DATA.QUERY_INFORMATION.BytesWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
|
|
RealRequest->DATA.QUERY_INFORMATION.BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
|
|
}
|
|
|
|
RealRequest = (ReqRsvd->RealRequest == NULL) ? NdisRequest : ReqRsvd->RealRequest;
|
|
ASSERT ((ReqRsvd->Flags & (COREQ_GLOBAL_REQ | COREQ_QUERY_OIDS)) == 0);
|
|
|
|
if (ReqRsvd->Flags == COREQ_DOWNLEVEL)
|
|
{
|
|
ASSERT(RealRequest != NdisRequest);
|
|
|
|
//
|
|
// Complete the request to the protocol and deref the open
|
|
//
|
|
(*ReqRsvd->RequestCompleteHandler)(ReqRsvd->Open->ProtocolBindingContext,
|
|
RealRequest,
|
|
Status);
|
|
FREE_POOL(NdisRequest);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(RealRequest == NdisRequest);
|
|
|
|
//
|
|
// Complete the request to the protocol and deref the open
|
|
//
|
|
(*ReqRsvd->CoRequestCompleteHandler)(Status,
|
|
ReqRsvd->Open->ProtocolBindingContext,
|
|
ReqRsvd->VcContext,
|
|
NULL,
|
|
NdisRequest);
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
Open->References --;
|
|
if (Open->References == 0)
|
|
{
|
|
ndisMFinishClose(Miniport, Open);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
else if (ReqRsvd->Flags == COREQ_GLOBAL_REQ)
|
|
{
|
|
PIRP Irp;
|
|
PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
|
|
|
|
GlobalRequest = CONTAINING_RECORD(NdisRequest,
|
|
NDIS_QUERY_GLOBAL_REQUEST,
|
|
Request);
|
|
|
|
ASSERT(ReqRsvd->RealRequest == NULL);
|
|
Irp = GlobalRequest->Irp;
|
|
Irp->IoStatus.Information = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
else if (Status == NDIS_STATUS_INVALID_LENGTH)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
else
|
|
{
|
|
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|
FREE_POOL (GlobalRequest);
|
|
}
|
|
else if (ReqRsvd->Flags == COREQ_QUERY_OIDS)
|
|
{
|
|
PNDIS_QUERY_OPEN_REQUEST OpenReq;
|
|
|
|
ASSERT(ReqRsvd->RealRequest == NULL);
|
|
OpenReq = CONTAINING_RECORD(NdisRequest,
|
|
NDIS_QUERY_OPEN_REQUEST,
|
|
Request);
|
|
OpenReq->NdisStatus = Status;
|
|
SET_EVENT(&OpenReq->Event);
|
|
}
|
|
else if (ReqRsvd->Flags == COREQ_QUERY_STATS)
|
|
{
|
|
PNDIS_QUERY_ALL_REQUEST AllReq;
|
|
|
|
ASSERT(ReqRsvd->RealRequest == NULL);
|
|
AllReq = CONTAINING_RECORD(NdisRequest,
|
|
NDIS_QUERY_ALL_REQUEST,
|
|
Request);
|
|
AllReq->NdisStatus = Status;
|
|
SET_EVENT(&AllReq->Event);
|
|
}
|
|
else if (ReqRsvd->Flags == COREQ_QUERY_SET)
|
|
{
|
|
PNDIS_QS_REQUEST QSReq;
|
|
|
|
ASSERT(ReqRsvd->RealRequest == NULL);
|
|
QSReq = CONTAINING_RECORD(NdisRequest,
|
|
NDIS_QS_REQUEST,
|
|
Request);
|
|
QSReq->NdisStatus = Status;
|
|
SET_EVENT(&QSReq->Event);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoIndicateReceivePacket(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Miniport to indicate a set of packets to
|
|
a particular VC.
|
|
|
|
Arguments:
|
|
|
|
NdisVcHandle - The handle suppplied by Ndis when the VC on which
|
|
data is received was first reserved.
|
|
|
|
PacketArray - Array of packets.
|
|
|
|
NumberOfPackets - Number of packets being indicated.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
UINT i, Ref, NumPmodeOpens;
|
|
PPNDIS_PACKET pPktArray;
|
|
NDIS_STATUS Status;
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
|
|
Miniport = Vc->Miniport;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
|
|
|
|
//
|
|
// NOTE that checking Vc Flags for Closing should not be needed since the CallMgr
|
|
// holds onto the protocol's CloseCall request until the ref count goes to zero -
|
|
// which means the miniport has to have completed its RELEASE_VC, which will
|
|
// inturn mandate that we will NOT get any further indications from it.
|
|
// The miniport must not complete a RELEASE_VC until it is no longer indicating data.
|
|
//
|
|
for (i = 0, pPktArray = PacketArray;
|
|
i < NumberOfPackets;
|
|
i++, pPktArray++)
|
|
{
|
|
PNDIS_PACKET Packet;
|
|
NDIS_STATUS SavedStatus;
|
|
|
|
Packet = *pPktArray;
|
|
ASSERT(Packet != NULL);
|
|
|
|
//
|
|
// Set context in the packet so that NdisReturnPacket can do the right thing
|
|
//
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
|
|
|
|
//
|
|
// Ensure that we force re-calculation.
|
|
//
|
|
Packet->Private.ValidCounts = FALSE;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// Indicate the packet to the binding.
|
|
//
|
|
Ref = (*Vc->CoReceivePacketHandler)(Vc->ClientOpen->ProtocolBindingContext,
|
|
Vc->ClientContext,
|
|
Packet);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
if (Ref > 0)
|
|
{
|
|
ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
|
|
PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount += Ref;
|
|
if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
|
|
{
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there are promiscuous opens on this miniport, indicate it to them as well.
|
|
// The client context will identify the VC.
|
|
//
|
|
if (Miniport->PmodeOpens > 0)
|
|
{
|
|
PNDIS_M_OPEN_BLOCK pPmodeOpen;
|
|
|
|
NumPmodeOpens = Miniport->PmodeOpens;
|
|
for (pPmodeOpen = Miniport->OpenQueue;
|
|
(NumPmodeOpens > 0);
|
|
pPmodeOpen = pPmodeOpen->MiniportNextOpen)
|
|
{
|
|
if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
|
|
{
|
|
pPmodeOpen->ReceivedAPacket = TRUE;
|
|
SavedStatus = NDIS_GET_PACKET_STATUS(Packet);
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// For Pmode opens, we pass the VcId to the indication routine
|
|
// since the protocol does not really own the VC.
|
|
//
|
|
Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
|
|
pPmodeOpen->ProtocolBindingContext,
|
|
Vc->pVcId,
|
|
Packet);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
ASSERT(Ref == 0);
|
|
NDIS_SET_PACKET_STATUS(Packet, SavedStatus);
|
|
|
|
NumPmodeOpens --;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// It should be impossible to assert here
|
|
// since the pVc will not lose all of its reference counts
|
|
// until the Miniport completes the RELEASE_VC which is should not
|
|
// do UNTIL there are no outstanding indications.
|
|
//
|
|
ASSERT(Vc->References);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoReceiveComplete(
|
|
IN NDIS_HANDLE MiniportAdapterHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the Miniport to indicate that the receive
|
|
process is complete to all bindings. Only those bindings which
|
|
have received packets will be notified. The Miniport lock is held
|
|
when this is called.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - The handle supplied by Ndis at initialization
|
|
time through miniport initialize.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// check all of the bindings on this adapter
|
|
//
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
NOTHING)
|
|
{
|
|
if (((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0) &&
|
|
Open->ReceivedAPacket)
|
|
{
|
|
//
|
|
// Indicate the binding.
|
|
//
|
|
|
|
Open->ReceivedAPacket = FALSE;
|
|
|
|
Open->References++;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(*Open->ReceiveCompleteHandler)(Open->ProtocolBindingContext);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// possibly the client closed the adapter in the time interval where
|
|
// the spin lock is released.
|
|
//
|
|
if ((--Open->References) == 0)
|
|
{
|
|
//
|
|
// This binding is shutting down. We have to kill it.
|
|
//
|
|
ndisMFinishClose(Miniport, Open);
|
|
|
|
//
|
|
// we have to start over in the loop through all of the
|
|
// Opens since the finishClose could have remove one or more
|
|
// opens from the list
|
|
//
|
|
Open = Miniport->OpenQueue;
|
|
}
|
|
else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
//
|
|
// This Open has been dequeued from the miniport so start over
|
|
// at the beginning of the list
|
|
//
|
|
Open = Miniport->OpenQueue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
}
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisCoSendPackets(
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PPNDIS_PACKET PacketArray,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_PACKET Packet;
|
|
ULONG PacketCount;
|
|
NDIS_STATUS s;
|
|
ULONG NumPmodeOpens;
|
|
|
|
//
|
|
// If there are promiscuous opens on this miniport, this must be indicated to them.
|
|
// Do this before it is send down to the miniport to preserve packet ordering.
|
|
//
|
|
Miniport = Vc->Miniport;
|
|
if (Miniport->PmodeOpens > 0)
|
|
{
|
|
PNDIS_M_OPEN_BLOCK pPmodeOpen;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
NumPmodeOpens = Miniport->PmodeOpens;
|
|
for (pPmodeOpen = Miniport->OpenQueue;
|
|
(NumPmodeOpens > 0);
|
|
pPmodeOpen = pPmodeOpen->MiniportNextOpen)
|
|
{
|
|
if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
|
|
{
|
|
ULONG Ref;
|
|
|
|
pPmodeOpen->ReceivedAPacket = TRUE;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
PacketCount = NumberOfPackets;
|
|
Packet = *PacketArray;
|
|
while (PacketCount--)
|
|
{
|
|
//
|
|
// For Pmode opens, we pass the VcId to the indication routine
|
|
// since the protocol does not really own the VC. On lookback
|
|
// the packet cannot be held.
|
|
//
|
|
s = NDIS_GET_PACKET_STATUS(Packet);
|
|
NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
|
|
Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
|
|
pPmodeOpen->ProtocolBindingContext,
|
|
Vc->pVcId,
|
|
Packet);
|
|
|
|
ASSERT (Ref == 0);
|
|
NDIS_SET_PACKET_STATUS(Packet, s);
|
|
|
|
Packet++;
|
|
}
|
|
NumPmodeOpens--;
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
|
|
//
|
|
// Simply call down to the miniport. The miniport must complete the sends for
|
|
// all cases. The send either succeeds/pends or fails. The miniport cannot
|
|
// ask the wrapper to queue it.
|
|
//
|
|
(*Vc->WCoSendPacketsHandler)(Vc->MiniportContext,
|
|
PacketArray,
|
|
NumberOfPackets);
|
|
|
|
PacketCount = NumberOfPackets;
|
|
Packet = *PacketArray;
|
|
while (PacketCount--)
|
|
{
|
|
NDIS_STATUS s;
|
|
s = NDIS_GET_PACKET_STATUS(Packet);
|
|
if (s != NDIS_STATUS_PENDING)
|
|
{
|
|
(Vc->CoSendCompleteHandler)(s,
|
|
Vc->ClientContext,
|
|
Packet);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoSendComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by the miniport when a send has completed. This
|
|
routine simply calls the protocol to pass along the indication.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - points to the adapter block.
|
|
NdisVcHandle - the handle supplied to the adapter on the OID_RESERVE_VC
|
|
PacketArray - a ptr to an array of NDIS_PACKETS
|
|
NumberOfPackets - the number of packets in PacketArray
|
|
Status - the send status that applies to all packets in the array
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
|
|
//
|
|
// There should not be any reason to grab the spin lock and increment the
|
|
// ref count on Open since the open cannot close until the Vc closes and
|
|
// the Vc cannot close in the middle of an indication because the miniport
|
|
// will not complete a RELEASE_VC until is it no longer indicating
|
|
//
|
|
//
|
|
// Indicate to Protocol;
|
|
//
|
|
|
|
Open = Vc->ClientOpen;
|
|
Miniport = Vc->Miniport;
|
|
|
|
(Vc->CoSendCompleteHandler)(Status,
|
|
Vc->ClientContext,
|
|
Packet);
|
|
|
|
//
|
|
// Technically this Vc should not close since there is a send outstanding
|
|
// on it, and the client should not close a Vc with an outstanding send.
|
|
//
|
|
ASSERT(Vc->References);
|
|
ASSERT(Open->References);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMCoIndicateStatus(
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN ULONG StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles passing CoStatus to the protocol. The miniport calls
|
|
this routine when it has status on a VC or a general status for all Vcs - in
|
|
this case the NdisVcHandle is null.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterHandle - pointer to the mini-port block;
|
|
NdisVcHandle - a pointer to the Vc block
|
|
GeneralStatus - the completion status of the request.
|
|
StatusBuffer - a buffer containing medium and status specific info
|
|
StatusBufferSize - the size of the buffer.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
|
PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
|
|
if (Vc != NULL)
|
|
{
|
|
Open = Vc->ClientOpen;
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
|
|
Open->ProtocolBindingContext,
|
|
Vc->ClientContext,
|
|
GeneralStatus,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// this must be a general status for all clients of this miniport
|
|
// since the Vc handle is null, so indicate this to all protocols.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
NOTHING)
|
|
{
|
|
if ((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0)
|
|
{
|
|
Open->References++;
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
|
|
Open->ProtocolBindingContext,
|
|
NULL,
|
|
GeneralStatus,
|
|
StatusBuffer,
|
|
StatusBufferSize);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
//
|
|
// possibly the client closed the adapter in the time interval where
|
|
// the spin lock is released.
|
|
//
|
|
if ((--Open->References) == 0)
|
|
{
|
|
//
|
|
// This binding is shutting down. We have to kill it.
|
|
//
|
|
ndisMFinishClose(Miniport, Open);
|
|
|
|
//
|
|
// we have to start over in the loop through all of the
|
|
// Opens since the finishClose could have remove one or more
|
|
// opens from the list - this may result in status being indicated
|
|
// twice to a particular protocol....
|
|
//
|
|
Open = Miniport->OpenQueue;
|
|
continue;
|
|
|
|
}
|
|
else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
//
|
|
// This Open has been dequeued from the miniport so start over
|
|
// at the beginning of the list
|
|
//
|
|
Open = Miniport->OpenQueue;
|
|
continue;
|
|
}
|
|
}
|
|
Open = Open->MiniportNextOpen;
|
|
}
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMRejectSend(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles any error cases where a protocol binds to an Atm
|
|
miniport and tries to use the normal NdisSend() call.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Handle returned by NdisOpenAdapter.
|
|
|
|
Packet - the Ndis packet to send
|
|
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS - always fails
|
|
|
|
--*/
|
|
{
|
|
return(NDIS_STATUS_NOT_SUPPORTED);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMRejectSendPackets(
|
|
IN PNDIS_OPEN_BLOCK OpenBlock,
|
|
IN PPNDIS_PACKET Packet,
|
|
IN UINT NumberOfPackets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles any error cases where a protocol binds to an Atm
|
|
miniport and tries to use the normal NdisSend() call.
|
|
|
|
Arguments:
|
|
|
|
OpenBlock - Pointer to the NdisOpenBlock
|
|
|
|
Packet - Pointer to the array of packets to send
|
|
|
|
NumberOfPackets - self-explanatory
|
|
|
|
|
|
Return Value:
|
|
|
|
None - SendCompleteHandler is called for the protocol calling this.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK MiniportOpen = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
|
|
UINT i;
|
|
|
|
for (i = 0; i < NumberOfPackets; i++)
|
|
{
|
|
(*MiniportOpen->SendCompleteHandler)(MiniportOpen->ProtocolBindingContext,
|
|
Packet[i],
|
|
NDIS_STATUS_NOT_SUPPORTED);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisMWrappedRequest(
|
|
IN NDIS_HANDLE NdisBindingHandle,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles wrapping an NdisRequest to NdisCoRequest since a NDIS 4.1
|
|
miniport does not support QueryInformation and SetInformation handlers.
|
|
|
|
Arguments:
|
|
|
|
NdisBindingHandle - Points to the NDIS_OPEN_BLOCK
|
|
|
|
NdisRequest - The request
|
|
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_PENDING If the request pends or an appropriate code if it succeeds/fails
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
KIRQL OldIrql;
|
|
PNDIS_MINIPORT_BLOCK Miniport;
|
|
PNDIS_COREQ_RESERVED ReqRsvd;
|
|
PNDIS_REQUEST NewReq;
|
|
NDIS_STATUS Status;
|
|
PULONG Filter;
|
|
|
|
|
|
Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
|
|
Miniport = Open->MiniportHandle;
|
|
|
|
//
|
|
// Start off by allocating a request. We do this since the original request is not
|
|
// big enough to accomodate the ReqRsvd block
|
|
//
|
|
NewReq = ALLOC_FROM_POOL(sizeof(NDIS_REQUEST), NDIS_TAG_CO);
|
|
if (NewReq == NULL)
|
|
{
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Copy the original request to the new structure
|
|
//
|
|
NewReq->RequestType = NdisRequest->RequestType;
|
|
NewReq->DATA.SET_INFORMATION.Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
|
|
NewReq->DATA.SET_INFORMATION.InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
NewReq->DATA.SET_INFORMATION.InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
|
|
|
|
ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NewReq);
|
|
ReqRsvd->RealRequest = NdisRequest;
|
|
|
|
//
|
|
// Start off by referencing the open.
|
|
//
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
if (Open->Flags & fMINIPORT_OPEN_CLOSING)
|
|
{
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
|
|
{
|
|
Status = NDIS_STATUS_RESET_IN_PROGRESS;
|
|
}
|
|
else
|
|
{
|
|
Open->References ++;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
Filter = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
|
|
|
|
//
|
|
// If this was a request to turn p-mode/l-only on/off then mark things appropriately
|
|
//
|
|
if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
|
|
(NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER))
|
|
{
|
|
if (*Filter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
|
|
{
|
|
if ((Open->Flags & fMINIPORT_OPEN_PMODE) == 0)
|
|
{
|
|
Open->Flags |= fMINIPORT_OPEN_PMODE;
|
|
Miniport->PmodeOpens ++;
|
|
}
|
|
*Filter &= ~(NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL);
|
|
}
|
|
else
|
|
{
|
|
if (Open->Flags & fMINIPORT_OPEN_PMODE)
|
|
{
|
|
Open->Flags &= ~fMINIPORT_OPEN_PMODE;
|
|
Miniport->PmodeOpens --;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ReqRsvd->Open = Open;
|
|
ReqRsvd->RequestCompleteHandler = Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler;
|
|
ReqRsvd->VcContext = NULL;
|
|
ReqRsvd->Flags = COREQ_DOWNLEVEL;
|
|
|
|
if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
|
|
(NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
|
|
(*Filter == 0))
|
|
{
|
|
NewReq->DATA.SET_INFORMATION.BytesRead = 4;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Call the miniport's CoRequest Handler
|
|
//
|
|
Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
|
|
NULL,
|
|
NewReq);
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NdisMCoRequestComplete(Status,
|
|
Open->MiniportHandle,
|
|
NewReq);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|