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.
5577 lines
130 KiB
5577 lines
130 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
callmgr.c - Call Manager Interface routines.
|
|
|
|
Abstract:
|
|
|
|
Call Manager Interface routines for the ATMARP Client, including
|
|
NDIS entry points for that interface.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 02-15-96 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'RGMC'
|
|
|
|
|
|
VOID
|
|
AtmArpCoAfRegisterNotifyHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PCO_ADDRESS_FAMILY pAddressFamily
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS when a Call manager registers its support
|
|
for an Address Family over an adapter. If this is the Address Family we
|
|
are interested in (UNI 3.1), then we start up all LIS' configured on
|
|
this adapter.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - our context passed in NdisOpenAdapter, which is
|
|
a pointer to our Adapter structure.
|
|
pAddressFamily - points to a structure describing the Address Family
|
|
being registered by a Call Manager.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_ADAPTER pAdapter;
|
|
PATMARP_INTERFACE pInterface; // Pointer to new ATMARP Interface
|
|
ULONG NumIFConfigured; // # of LIS' over this adapter
|
|
ULONG NumIFActivated; // # activated successfully here
|
|
|
|
NDIS_STATUS Status;
|
|
NDIS_HANDLE LISConfigHandle; // Handle to per-LIS config
|
|
|
|
struct LLIPBindInfo BindInfo;
|
|
BOOLEAN bProcessingAf;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
pAdapter = NULL_PATMARP_ADAPTER;
|
|
LISConfigHandle = NULL;
|
|
NumIFActivated = 0;
|
|
bProcessingAf = FALSE;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Check if this AF is interesting to us.
|
|
//
|
|
if ((pAddressFamily->AddressFamily != CO_ADDRESS_FAMILY_Q2931) ||
|
|
(pAddressFamily->MajorVersion != 3) ||
|
|
(pAddressFamily->MinorVersion != 1))
|
|
{
|
|
AADEBUGP(AAD_LOUD,
|
|
("CoAfRegisterNotifyHandler: uninteresting AF %d or MajVer %d or MinVer %d\n",
|
|
pAddressFamily->AddressFamily,
|
|
pAddressFamily->MajorVersion,
|
|
pAddressFamily->MinorVersion));
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
break;
|
|
}
|
|
|
|
pAdapter = (PATMARP_ADAPTER)ProtocolBindingContext;
|
|
AA_STRUCT_ASSERT(pAdapter, aaa);
|
|
|
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
|
|
if (pAdapter->Flags & AA_ADAPTER_FLAGS_UNBINDING)
|
|
{
|
|
AADEBUGP(AAD_INFO,
|
|
("CoAfRegisterNotify: Adapter %x is unbinding, bailing out\n", pAdapter));
|
|
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we have already created LIS' on this adapter, we don't want
|
|
// to open this Call Manager (multiple Call Managers supporting the
|
|
// same AF on the same adapter?)
|
|
//
|
|
if (pAdapter->pInterfaceList != NULL_PATMARP_INTERFACE)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotifyHandler: pAdapter 0x%x, IFs (%x) already created!\n",
|
|
pAdapter, pAdapter->pInterfaceList));
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (pAdapter->Flags & AA_ADAPTER_FLAGS_PROCESSING_AF)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotifyHandler: pAdapter 0x%x, Already processing AF!\n",
|
|
pAdapter));
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make sure that we don't let an UnbindAdapter thread preempt us.
|
|
//
|
|
AA_INIT_BLOCK_STRUCT(&pAdapter->UnbindBlock);
|
|
pAdapter->Flags |= AA_ADAPTER_FLAGS_PROCESSING_AF;
|
|
bProcessingAf = TRUE;
|
|
|
|
if (pAdapter->Flags & AA_ADAPTER_FLAGS_AF_NOTIFIED)
|
|
{
|
|
//
|
|
// This can happen when resuming from suspend/hibernate, since
|
|
// we do not get unbound from the adapter. All IFs go away,
|
|
// but the adapter remains.
|
|
//
|
|
// So we skip the one-time init stuff (see below), but go ahead
|
|
// and process the AF and create IFs now.
|
|
//
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotify: Adapter %x seen AF notify already, Flags %x\n",
|
|
pAdapter, pAdapter->Flags));
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do one-time init stuff for this adapter.
|
|
//
|
|
|
|
pAdapter->Flags |= AA_ADAPTER_FLAGS_AF_NOTIFIED;
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
|
|
|
|
//
|
|
// Query the adapter (miniport) for information about the adapter
|
|
// we are bound to.
|
|
//
|
|
Status = AtmArpGetAdapterInfo(pAdapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotifyHandler: Failed to get adapter info.\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the adapter's configuration information from the registry.
|
|
//
|
|
Status = AtmArpCfgReadAdapterConfiguration(pAdapter);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotifyHandler: Failed to open adapter configuration\n"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_WARNING,
|
|
("CoAfRegisterNotify: Adapter %x/%x, starting up\n", pAdapter, pAdapter->Flags));
|
|
|
|
//
|
|
// Initialize some variables so that we know if we failed
|
|
// somewhere in the following loop.
|
|
//
|
|
LISConfigHandle = NULL;
|
|
pInterface = NULL_PATMARP_INTERFACE;
|
|
|
|
//
|
|
// Set up IP and NDIS interfaces for each LIS configured
|
|
// for this adapter. Loop while there are more LIS'.
|
|
//
|
|
for (NumIFConfigured = 0;
|
|
; // Stop only on error or no more LIS
|
|
NumIFConfigured++)
|
|
{
|
|
#ifdef NEWARP
|
|
//
|
|
// TCP/IP's Configuration section for this interface.
|
|
//
|
|
NDIS_STRING IPConfigString;
|
|
#endif // NEWARP
|
|
|
|
//
|
|
// Process LIS # NumIFConfigured.
|
|
//
|
|
|
|
// Open the configuration section for this LIS. We use
|
|
// "NumIFConfigured" as the index of the LIS to be opened.
|
|
//
|
|
LISConfigHandle = AtmArpCfgOpenLISConfiguration(
|
|
pAdapter,
|
|
NumIFConfigured
|
|
#ifdef NEWARP
|
|
,
|
|
&IPConfigString
|
|
#endif // NEWARP
|
|
);
|
|
|
|
if (LISConfigHandle == NULL)
|
|
{
|
|
//
|
|
// This is the normal termination condition, i.e.
|
|
// we reached the end of the LIS list for this
|
|
// adapter.
|
|
//
|
|
AADEBUGP(AAD_INFO, ("NotifyRegAfHandler: cannot open LIS %d\n",
|
|
NumIFConfigured));
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break; // out of for loop
|
|
}
|
|
|
|
|
|
pInterface = AtmArpAddInterfaceToAdapter (
|
|
pAdapter,
|
|
LISConfigHandle,
|
|
&IPConfigString
|
|
);
|
|
|
|
//
|
|
// Close the configuration section for this LIS.
|
|
//
|
|
AtmArpCfgCloseLISConfiguration(LISConfigHandle);
|
|
LISConfigHandle = NULL;
|
|
|
|
if (pInterface == NULL_PATMARP_INTERFACE)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
} // for
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
if (NumIFActivated > 0)
|
|
{
|
|
//
|
|
// We managed to activate atleast one Logical IP Subnet
|
|
// on this adapter.
|
|
//
|
|
pAdapter->InterfaceCount = NumIFActivated;
|
|
}
|
|
|
|
if (bProcessingAf)
|
|
{
|
|
AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
pAdapter->Flags &= ~AA_ADAPTER_FLAGS_PROCESSING_AF;
|
|
AA_SIGNAL_BLOCK_STRUCT(&pAdapter->UnbindBlock, NDIS_STATUS_SUCCESS);
|
|
AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpOpenCallMgr(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start access to the Call Manager on the specified Interface,
|
|
by doing the following:
|
|
- Open Address Family
|
|
|
|
For all of these, we wait for completion in case they pend.
|
|
|
|
It is assumed that the Interface structure is locked.
|
|
|
|
Arguments:
|
|
|
|
pInterface - pointer to the ATMARP interface
|
|
|
|
Return Value:
|
|
|
|
NDIS status.
|
|
|
|
--*/
|
|
{
|
|
PCO_ADDRESS_FAMILY pAddressFamily;
|
|
NDIS_STATUS Status;
|
|
ULONG RequestSize;
|
|
|
|
pAddressFamily = (PCO_ADDRESS_FAMILY)NULL;
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
do {
|
|
|
|
//
|
|
// Allocate everything we need
|
|
//
|
|
RequestSize = sizeof(CO_ADDRESS_FAMILY)+
|
|
sizeof(CO_SAP)+
|
|
sizeof(ATM_SAP)+
|
|
sizeof(ATM_ADDRESS);
|
|
AA_ALLOC_MEM(
|
|
pAddressFamily,
|
|
CO_ADDRESS_FAMILY,
|
|
RequestSize
|
|
);
|
|
|
|
if (pAddressFamily == (PCO_ADDRESS_FAMILY)NULL)
|
|
{
|
|
AADEBUGP(AAD_ERROR, ("OpenCallMgr: alloc failed!\n"));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// DONT remove the following
|
|
//
|
|
AA_SET_MEM((PUCHAR)pAddressFamily, 0, RequestSize);
|
|
|
|
//
|
|
// The Address Family we are interested in is Q.2931 (UNI 3.1)
|
|
//
|
|
pAddressFamily->AddressFamily = CO_ADDRESS_FAMILY_Q2931;
|
|
pAddressFamily->MajorVersion = 3;
|
|
pAddressFamily->MinorVersion = 1;
|
|
|
|
AA_INIT_BLOCK_STRUCT(&(pInterface->Block));
|
|
Status = NdisClOpenAddressFamily(
|
|
pInterface->NdisAdapterHandle,
|
|
pAddressFamily,
|
|
(NDIS_HANDLE)pInterface,
|
|
&AtmArpClientCharacteristics,
|
|
sizeof(AtmArpClientCharacteristics),
|
|
&(pInterface->NdisAfHandle)
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_PENDING)
|
|
{
|
|
//
|
|
// Wait for completion
|
|
//
|
|
Status = AA_WAIT_ON_BLOCK_STRUCT(&(pInterface->Block));
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_ERROR, ("Open Af returned error: 0x%x\n", Status));
|
|
break;
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO, ("Interface: 0x%x, Got NdisAfHandle: 0x%x\n",
|
|
pInterface, pInterface->NdisAfHandle));
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
if (pAddressFamily != (PCO_ADDRESS_FAMILY)NULL)
|
|
{
|
|
AA_FREE_MEM(pAddressFamily);
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD, ("Open Call Mgr returning 0x%x\n", Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCloseCallMgr(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Halt access to the Call Manager on the specified interface. It is
|
|
assumed that all VCs and SAPs pertaining to the "Address Family Open"
|
|
have been released.
|
|
|
|
Arguments:
|
|
|
|
pInterface - pointer to the ATMARP interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_HANDLE NdisAfHandle;
|
|
|
|
NdisAfHandle = pInterface->NdisAfHandle;
|
|
pInterface->NdisAfHandle = NULL;
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Closing Call Mgr on Interface: 0x%x, AfH: 0x%x\n",
|
|
pInterface, NdisAfHandle));
|
|
|
|
if (NdisAfHandle != (NDIS_HANDLE)NULL)
|
|
{
|
|
Status = NdisClCloseAddressFamily(NdisAfHandle);
|
|
|
|
AADEBUGP(AAD_INFO, ("NdisClCloseAF on IF 0x%x returned 0x%x\n",
|
|
pInterface, Status));
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpCloseAfCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pInterface
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpRegisterSaps(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Register all SAPs configured on the given ATMARP interface.
|
|
Atleast one SAP must be present in the list of SAPs on the
|
|
interface.
|
|
|
|
We just issue the NdisClRegisterSap requests for all SAPs.
|
|
We don't wait for completion.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_SAP pAtmArpSap;
|
|
PATMARP_SAP pNextSap;
|
|
PCO_SAP pSapInfo;
|
|
NDIS_STATUS Status;
|
|
NDIS_HANDLE NdisAfHandle;
|
|
ULONG rc; // Ref count on Interface
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
AA_ASSERT(pInterface->NumberOfSaps > 0);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pAtmArpSap = &(pInterface->SapList);
|
|
NdisAfHandle = pInterface->NdisAfHandle;
|
|
|
|
//
|
|
// Make sure that the Interface doesn't go away.
|
|
//
|
|
AtmArpReferenceInterface(pInterface);
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
do
|
|
{
|
|
pSapInfo = pAtmArpSap->pInfo;
|
|
pAtmArpSap->NdisSapHandle = NULL;
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_REG_STATE_MASK,
|
|
AA_SAP_REG_STATE_REGISTERING);
|
|
|
|
pNextSap = pAtmArpSap->pNextSap;
|
|
|
|
//
|
|
// The ATMARP SAP structure itself won't go away as long as
|
|
// the Interface structure lives.
|
|
//
|
|
Status = NdisClRegisterSap(
|
|
NdisAfHandle,
|
|
(NDIS_HANDLE)pAtmArpSap, // ProtocolSapContext
|
|
pSapInfo,
|
|
&(pAtmArpSap->NdisSapHandle)
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpRegisterSapCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pAtmArpSap,
|
|
pSapInfo,
|
|
pAtmArpSap->NdisSapHandle
|
|
);
|
|
}
|
|
|
|
pAtmArpSap = pNextSap;
|
|
}
|
|
while (pAtmArpSap != NULL_PATMARP_SAP);
|
|
|
|
//
|
|
// Remove the reference we added earlier to the Interface.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
rc = AtmArpDereferenceInterface(pInterface);
|
|
if (rc > 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
//
|
|
// else the Interface is gone!
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpDeregisterSaps(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deregister all SAPs on an ATMARP Interface. We issue NdisClDeregisterSap
|
|
calls on all SAPs we have currently registered.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_HANDLE NdisSapHandle;
|
|
ULONG rc; // Reference count on Interface
|
|
PATMARP_SAP pAtmArpSap;
|
|
PATMARP_SAP pNextSap;
|
|
NDIS_STATUS Status;
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
pAtmArpSap = &(pInterface->SapList);
|
|
|
|
//
|
|
// Make sure the Interface structure doesn't go away.
|
|
//
|
|
AtmArpReferenceInterface(pInterface);
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
do
|
|
{
|
|
NdisSapHandle = pAtmArpSap->NdisSapHandle;
|
|
pNextSap = pAtmArpSap->pNextSap;
|
|
|
|
if (NdisSapHandle != NULL)
|
|
{
|
|
Status = NdisClDeregisterSap(NdisSapHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpDeregisterSapCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pAtmArpSap
|
|
);
|
|
}
|
|
}
|
|
|
|
pAtmArpSap = pNextSap;
|
|
}
|
|
while (pAtmArpSap != NULL_PATMARP_SAP);
|
|
|
|
//
|
|
// Remove the reference we added earlier to the Interface.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
rc = AtmArpDereferenceInterface(pInterface);
|
|
if (rc > 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
//
|
|
// else the interface is gone
|
|
//
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpMakeCall(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PATMARP_ATM_ENTRY pAtmEntry LOCKIN NOLOCKOUT,
|
|
IN PATMARP_FLOW_SPEC pFlowSpec,
|
|
IN PNDIS_PACKET pPacketToBeQueued OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Place a call to the given destination. Map the specified flow
|
|
specs to ATM QoS/Traffic parameters.
|
|
|
|
NOTE: The caller is assumed to hold a lock for the ATM Entry,
|
|
which will be released here. The reason we do it this way is so that
|
|
nobody else can come in and try to make another call (of the same kind)
|
|
to this ATM Entry -- once we get a new VC into the ATM Entry's list,
|
|
we can release its lock.
|
|
|
|
SIDE EFFECT: If the NDIS call doesn't pend, then we call our
|
|
MakeCall completion handler from here, and return NDIS_STATUS_PENDING
|
|
to the caller.
|
|
|
|
|
|
Arguments:
|
|
|
|
pInterface - the ARP Interface originating this call
|
|
pAtmEntry - Pointer to ATM Address Entry corresponding to the
|
|
called address.
|
|
pFlowSpec - pointer to a Flow Spec structure containing parameters
|
|
for the call
|
|
pPacketToBeQueued - Optionally, a packet to be queued for transmission when
|
|
the call is established.
|
|
|
|
Return Value:
|
|
|
|
If there is an immediate failure (e.g. allocation failure), we return
|
|
NDIS_STATUS_XXX denoting that failure.
|
|
|
|
If we made it to the call to NdisClMakeCall(), we return NDIS_STATUS_PENDING.
|
|
However, if NDIS returns other than NDIS_STATUS_PENDING, we'd also
|
|
call our MakeCall completion handler.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// New VC structure to be allocated for this call
|
|
//
|
|
PATMARP_VC pVc;
|
|
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_HANDLE ProtocolVcContext;
|
|
NDIS_HANDLE ProtocolPartyContext;
|
|
PNDIS_HANDLE pNdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
BOOLEAN IsPMP;
|
|
PATM_ADDRESS pCalledAddress;
|
|
|
|
//
|
|
// Set of parameters for a MakeCall
|
|
//
|
|
PCO_CALL_PARAMETERS pCallParameters;
|
|
PCO_CALL_MANAGER_PARAMETERS pCallMgrParameters;
|
|
|
|
PQ2931_CALLMGR_PARAMETERS pAtmCallMgrParameters;
|
|
|
|
//
|
|
// All Info Elements that we need to fill:
|
|
//
|
|
Q2931_IE UNALIGNED * pIe;
|
|
AAL_PARAMETERS_IE UNALIGNED * pAalIe;
|
|
ATM_TRAFFIC_DESCRIPTOR_IE UNALIGNED * pTrafficDescriptor;
|
|
ATM_BROADBAND_BEARER_CAPABILITY_IE UNALIGNED * pBbc;
|
|
ATM_BLLI_IE UNALIGNED * pBlli;
|
|
ATM_QOS_CLASS_IE UNALIGNED * pQos;
|
|
|
|
//
|
|
// Total space requirements for the MakeCall
|
|
//
|
|
ULONG RequestSize;
|
|
|
|
//
|
|
// Did we queue the given packet?
|
|
//
|
|
BOOLEAN PacketWasQueued = FALSE;
|
|
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
|
|
AA_ASSERT(pInterface->AdminState == IF_STATUS_UP);
|
|
|
|
|
|
do
|
|
{
|
|
if (pPacketToBeQueued != (PNDIS_PACKET)NULL)
|
|
{
|
|
//
|
|
// Make this a list of exactly one packet.
|
|
//
|
|
AA_SET_NEXT_PACKET(pPacketToBeQueued, NULL);
|
|
}
|
|
|
|
//
|
|
// Fail makecall if atmentry state is really closing.
|
|
//
|
|
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING))
|
|
{
|
|
BOOLEAN ReallyClosing = TRUE;
|
|
|
|
//
|
|
// This may be a harmless close -- if the interface is not shutting
|
|
// down we check if it's a harmless close, else (if the interface
|
|
// is shutting down) we fail the call anyway. Note that we don't
|
|
// claim the interface list lock (which is used to guard access
|
|
// to AtmEntryListUp) -- we don't do this because we currently
|
|
// hold the lock to pAtmEntry (and don't want to release it), so if
|
|
// AtmEntryListUp is in the
|
|
// process of being set to FALSE, when we read it's value here,
|
|
// in the worst case we'll read it's value as TRUE and conclude that
|
|
// the atm entry is not really closing and go ahead and make the call.
|
|
// However in this case, the shutdown routine will invalidate the call.
|
|
//
|
|
if (pInterface->AtmEntryListUp)
|
|
{
|
|
//
|
|
// WARNING: AtmArpAtmEntryIsReallyClosing may clear the
|
|
// CLOSING state (if the entry is basically idle) --
|
|
// see comments in that function.
|
|
//
|
|
ReallyClosing = AtmArpAtmEntryIsReallyClosing(pAtmEntry);
|
|
}
|
|
|
|
if (ReallyClosing)
|
|
{
|
|
AADEBUGP(AAD_FATAL,
|
|
("AtmArpMakeCall -- failing because AE 0x%lx is really closing.\n",
|
|
pAtmEntry));
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Some initialization.
|
|
//
|
|
|
|
|
|
if (AA_IS_FLAG_SET(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_TYPE_MASK,
|
|
AA_ATM_ENTRY_TYPE_UCAST))
|
|
{
|
|
IsPMP = FALSE;
|
|
ProtocolPartyContext = NULL;
|
|
pNdisPartyHandle = NULL;
|
|
pCalledAddress = &(pAtmEntry->ATMAddress);
|
|
}
|
|
#ifdef IPMCAST
|
|
else
|
|
{
|
|
IsPMP = TRUE;
|
|
ProtocolPartyContext = (NDIS_HANDLE)(pAtmEntry->pMcAtmInfo->pMcAtmEntryList);
|
|
pNdisPartyHandle = &(pAtmEntry->pMcAtmInfo->pMcAtmEntryList->NdisPartyHandle);
|
|
pCalledAddress = &(pAtmEntry->pMcAtmInfo->pMcAtmEntryList->ATMAddress);
|
|
}
|
|
#else
|
|
else
|
|
{
|
|
AA_ASSERT(FALSE);
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// Compute all the space needed for the MakeCall, and allocate it
|
|
// in one big block.
|
|
//
|
|
RequestSize = sizeof(CO_CALL_PARAMETERS) +
|
|
sizeof(CO_CALL_MANAGER_PARAMETERS) +
|
|
sizeof(Q2931_CALLMGR_PARAMETERS) +
|
|
ATMARP_MAKE_CALL_IE_SPACE +
|
|
0;
|
|
|
|
AA_ALLOC_MEM(pCallParameters, CO_CALL_PARAMETERS, RequestSize);
|
|
|
|
if (pCallParameters == (PCO_CALL_PARAMETERS)NULL)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("Make Call: alloc (%d) failed\n", RequestSize));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a VC structure for the call
|
|
//
|
|
pVc = AtmArpAllocateVc(pInterface);
|
|
|
|
if (pVc == NULL_PATMARP_VC)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("Make Call: failed to allocate VC\n"));
|
|
AA_FREE_MEM(pCallParameters);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// For a later call to MakeCallComplete
|
|
//
|
|
ProtocolVcContext = (NDIS_HANDLE)pVc;
|
|
|
|
//
|
|
// Get an NDIS handle for this VC
|
|
//
|
|
NdisVcHandle = (NDIS_HANDLE)NULL;
|
|
Status = NdisCoCreateVc(
|
|
pInterface->NdisAdapterHandle,
|
|
pInterface->NdisAfHandle,
|
|
ProtocolVcContext,
|
|
&NdisVcHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
AA_ASSERT(Status != NDIS_STATUS_PENDING);
|
|
|
|
AADEBUGP(AAD_WARNING, ("Make Call: NdisCoCreateVc failed: 0x%x\n", Status));
|
|
AA_FREE_MEM(pCallParameters);
|
|
AtmArpDeallocateVc(pVc);
|
|
break;
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD,
|
|
("Make Call: pAtmEntry 0x%x, pVc 0x%x, got NdisVcHandle 0x%x\n",
|
|
pAtmEntry,
|
|
pVc,
|
|
NdisVcHandle));
|
|
|
|
AtmArpReferenceVc(pVc); // CreateVC reference
|
|
|
|
//
|
|
// At this point, we are sure that we will call NdisClMakeCall.
|
|
//
|
|
|
|
//
|
|
// Now fill in the rest of the VC structure. We don't need a lock
|
|
// for the VC until it gets linked to the ATM Entry structure.
|
|
//
|
|
pVc->NdisVcHandle = NdisVcHandle;
|
|
pVc->Flags = AA_VC_TYPE_SVC |
|
|
AA_VC_OWNER_IS_ATMARP |
|
|
AA_VC_CALL_STATE_OUTGOING_IN_PROGRESS;
|
|
if (IsPMP)
|
|
{
|
|
pVc->Flags |= AA_VC_CONN_TYPE_PMP;
|
|
}
|
|
else
|
|
{
|
|
pVc->Flags |= AA_VC_CONN_TYPE_P2P;
|
|
}
|
|
pVc->FlowSpec = *pFlowSpec;
|
|
|
|
//
|
|
// Make sure that the packet sizes are within the miniport's range.
|
|
//
|
|
if (pVc->FlowSpec.SendMaxSize > pInterface->pAdapter->MaxPacketSize)
|
|
{
|
|
pVc->FlowSpec.SendMaxSize = pInterface->pAdapter->MaxPacketSize;
|
|
}
|
|
if (pVc->FlowSpec.ReceiveMaxSize > pInterface->pAdapter->MaxPacketSize)
|
|
{
|
|
pVc->FlowSpec.ReceiveMaxSize = pInterface->pAdapter->MaxPacketSize;
|
|
}
|
|
|
|
if (pPacketToBeQueued != (PNDIS_PACKET)NULL)
|
|
{
|
|
pVc->PacketList = pPacketToBeQueued;
|
|
PacketWasQueued = TRUE;
|
|
}
|
|
|
|
#ifdef IPMCAST
|
|
AtmArpFillCallParameters(
|
|
pCallParameters,
|
|
RequestSize,
|
|
pCalledAddress,
|
|
&(pInterface->LocalAtmAddress), // Calling address
|
|
&(pVc->FlowSpec),
|
|
IsPMP,
|
|
TRUE // IsMakeCall?
|
|
);
|
|
#else
|
|
//
|
|
// Zero out everything
|
|
//
|
|
AA_SET_MEM((PUCHAR)pCallParameters, 0, RequestSize);
|
|
|
|
//
|
|
// Distribute space amongst the various structures
|
|
//
|
|
pCallMgrParameters = (PCO_CALL_MANAGER_PARAMETERS)
|
|
((PUCHAR)pCallParameters +
|
|
sizeof(CO_CALL_PARAMETERS));
|
|
|
|
|
|
//
|
|
// Set pointers to link the above structures together
|
|
//
|
|
pCallParameters->CallMgrParameters = pCallMgrParameters;
|
|
pCallParameters->MediaParameters = (PCO_MEDIA_PARAMETERS)NULL;
|
|
|
|
pCallMgrParameters->CallMgrSpecific.ParamType = 0;
|
|
pCallMgrParameters->CallMgrSpecific.Length =
|
|
sizeof(Q2931_CALLMGR_PARAMETERS) +
|
|
ATMARP_CALL_IE_SPACE;
|
|
|
|
pAtmCallMgrParameters = (PQ2931_CALLMGR_PARAMETERS)
|
|
pCallMgrParameters->CallMgrSpecific.Parameters;
|
|
|
|
|
|
//
|
|
// Call Manager generic flow parameters:
|
|
//
|
|
pCallMgrParameters->Transmit.TokenRate = (pFlowSpec->SendAvgBandwidth);
|
|
pCallMgrParameters->Transmit.TokenBucketSize = (pFlowSpec->SendMaxSize);
|
|
pCallMgrParameters->Transmit.MaxSduSize = pFlowSpec->SendMaxSize;
|
|
pCallMgrParameters->Transmit.PeakBandwidth = (pFlowSpec->SendPeakBandwidth);
|
|
pCallMgrParameters->Transmit.ServiceType = pFlowSpec->SendServiceType;
|
|
|
|
pCallMgrParameters->Receive.TokenRate = (pFlowSpec->ReceiveAvgBandwidth);
|
|
pCallMgrParameters->Receive.TokenBucketSize = pFlowSpec->ReceiveMaxSize;
|
|
pCallMgrParameters->Receive.MaxSduSize = pFlowSpec->ReceiveMaxSize;
|
|
pCallMgrParameters->Receive.PeakBandwidth = (pFlowSpec->ReceivePeakBandwidth);
|
|
pCallMgrParameters->Receive.ServiceType = pFlowSpec->ReceiveServiceType;
|
|
|
|
//
|
|
// Q2931 Call Manager Parameters:
|
|
//
|
|
|
|
//
|
|
// Called address:
|
|
//
|
|
// TBD: Add Called Subaddress IE in outgoing call.
|
|
//
|
|
AA_COPY_MEM((PUCHAR)&(pAtmCallMgrParameters->CalledParty),
|
|
(PUCHAR)&(pAtmEntry->ATMAddress),
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
//
|
|
// Calling address:
|
|
//
|
|
AA_COPY_MEM((PUCHAR)&(pAtmCallMgrParameters->CallingParty),
|
|
(PUCHAR)&(pInterface->LocalAtmAddress),
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
|
|
//
|
|
// RFC 1755 (Sec 5) says that the following IEs MUST be present in the
|
|
// SETUP message, so fill them all.
|
|
//
|
|
// AAL Parameters
|
|
// Traffic Descriptor
|
|
// Broadband Bearer Capability
|
|
// Broadband Low Layer Info
|
|
// QoS
|
|
//
|
|
|
|
//
|
|
// Initialize the Info Element list
|
|
//
|
|
pAtmCallMgrParameters->InfoElementCount = 0;
|
|
pIe = (PQ2931_IE)(pAtmCallMgrParameters->InfoElements);
|
|
|
|
|
|
//
|
|
// AAL Parameters:
|
|
//
|
|
|
|
{
|
|
UNALIGNED AAL5_PARAMETERS *pAal5;
|
|
|
|
pIe->IEType = IE_AALParameters;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_AAL_PARAMETERS_IE;
|
|
pAalIe = (PAAL_PARAMETERS_IE)pIe->IE;
|
|
pAalIe->AALType = AAL_TYPE_AAL5;
|
|
pAal5 = &(pAalIe->AALSpecificParameters.AAL5Parameters);
|
|
pAal5->ForwardMaxCPCSSDUSize = pFlowSpec->SendMaxSize;
|
|
pAal5->BackwardMaxCPCSSDUSize = pFlowSpec->ReceiveMaxSize;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
//
|
|
// Traffic Descriptor:
|
|
//
|
|
|
|
pIe->IEType = IE_TrafficDescriptor;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_TRAFFIC_DESCR_IE;
|
|
pTrafficDescriptor = (PATM_TRAFFIC_DESCRIPTOR_IE)pIe->IE;
|
|
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pTrafficDescriptor->ForwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->SendPeakBandwidth);
|
|
pTrafficDescriptor->BackwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->ReceivePeakBandwidth);
|
|
pTrafficDescriptor->BestEffort = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Predictive/Guaranteed service (we map this to CBR, see BBC below)
|
|
pTrafficDescriptor->ForwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->SendPeakBandwidth);
|
|
pTrafficDescriptor->BackwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->ReceivePeakBandwidth);
|
|
pTrafficDescriptor->BestEffort = FALSE;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
//
|
|
// Broadband Bearer Capability
|
|
//
|
|
|
|
pIe->IEType = IE_BroadbandBearerCapability;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_BBC_IE;
|
|
pBbc = (PATM_BROADBAND_BEARER_CAPABILITY_IE)pIe->IE;
|
|
|
|
pBbc->BearerClass = BCOB_X;
|
|
pBbc->UserPlaneConnectionConfig = UP_P2P;
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pBbc->TrafficType = TT_NOIND;
|
|
pBbc->TimingRequirements = TR_NOIND;
|
|
pBbc->ClippingSusceptability = CLIP_NOT;
|
|
}
|
|
else
|
|
{
|
|
pBbc->TrafficType = TT_CBR;
|
|
pBbc->TimingRequirements = TR_END_TO_END;
|
|
pBbc->ClippingSusceptability = CLIP_SUS;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
//
|
|
// Broadband Lower Layer Information
|
|
//
|
|
|
|
pIe->IEType = IE_BLLI;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_BLLI_IE;
|
|
pBlli = (PATM_BLLI_IE)pIe->IE;
|
|
AA_COPY_MEM((PUCHAR)pBlli,
|
|
(PUCHAR)&AtmArpDefaultBlli,
|
|
sizeof(ATM_BLLI_IE));
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
//
|
|
// QoS
|
|
//
|
|
|
|
pIe->IEType = IE_QOSClass;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_QOS_IE;
|
|
pQos = (PATM_QOS_CLASS_IE)pIe->IE;
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pQos->QOSClassForward = pQos->QOSClassBackward = 0;
|
|
}
|
|
else
|
|
{
|
|
pQos->QOSClassForward = pQos->QOSClassBackward = 1;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// We add the Call reference and ATM Entry Link reference
|
|
// right here
|
|
//
|
|
AtmArpReferenceVc(pVc); // Call reference (MakeCall coming up)
|
|
AtmArpReferenceVc(pVc); // ATM Entry link reference (coming up below)
|
|
|
|
#ifdef IPMCAST
|
|
if (IsPMP)
|
|
{
|
|
pAtmEntry->pMcAtmInfo->TransientLeaves++;
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// We are ready to make the call. Before we do so, we need to
|
|
// link the VC structure to the ATM Entry, and release the
|
|
// ATM Entry lock
|
|
//
|
|
AtmArpLinkVcToAtmEntry(pVc, pAtmEntry);
|
|
AA_RELEASE_AE_LOCK(pAtmEntry); // acquired by caller
|
|
|
|
//
|
|
// Make the Call now
|
|
//
|
|
Status = NdisClMakeCall(
|
|
NdisVcHandle,
|
|
pCallParameters,
|
|
ProtocolPartyContext,
|
|
pNdisPartyHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
|
|
NdisPartyHandle = ((pNdisPartyHandle != NULL)?
|
|
*pNdisPartyHandle : NULL);
|
|
|
|
AtmArpMakeCallCompleteHandler(
|
|
Status,
|
|
ProtocolVcContext,
|
|
NdisPartyHandle,
|
|
pCallParameters
|
|
);
|
|
Status = NDIS_STATUS_PENDING;
|
|
}
|
|
//
|
|
// else the MakeCall complete handler will be called
|
|
// later
|
|
//
|
|
|
|
} while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ULONG Flags;
|
|
//
|
|
// Something failed within this routine.
|
|
// Recovery:
|
|
// - Release the ATM Entry lock
|
|
// - If we were given a packet for queueing, and we didn't do so,
|
|
// then free it
|
|
//
|
|
Flags = pAtmEntry->Flags;
|
|
AA_RELEASE_AE_LOCK(pAtmEntry); // acquired by caller
|
|
if ((pPacketToBeQueued != (PNDIS_PACKET)NULL) && (!PacketWasQueued))
|
|
{
|
|
AA_HEADER_TYPE HdrType;
|
|
BOOLEAN HdrPresent;
|
|
|
|
if (pFlowSpec->Encapsulation == ENCAPSULATION_TYPE_LLCSNAP)
|
|
{
|
|
HdrPresent = TRUE;
|
|
if (AA_IS_FLAG_SET(Flags,
|
|
AA_ATM_ENTRY_TYPE_MASK,
|
|
AA_ATM_ENTRY_TYPE_UCAST))
|
|
{
|
|
HdrType = AA_HEADER_TYPE_UNICAST;
|
|
}
|
|
else
|
|
{
|
|
HdrType = AA_HEADER_TYPE_NUNICAST;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HdrPresent = FALSE;
|
|
HdrType = AA_HEADER_TYPE_NONE;
|
|
}
|
|
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
pPacketToBeQueued,
|
|
HdrPresent
|
|
);
|
|
}
|
|
}
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Make Call: VC: 0x%x, returning status 0x%x\n",
|
|
pVc, Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpFillCallParameters(
|
|
IN PCO_CALL_PARAMETERS pCallParameters,
|
|
IN ULONG ParametersSize,
|
|
IN PATM_ADDRESS pCalledAddress,
|
|
IN PATM_ADDRESS pCallingAddress,
|
|
IN PATMARP_FLOW_SPEC pFlowSpec,
|
|
IN BOOLEAN IsPMP,
|
|
IN BOOLEAN IsMakeCall
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fill in a Call Parameters structure with the given information,
|
|
thus making it ready for use in an NdisClMakeCall/NdisClAddParty
|
|
call.
|
|
|
|
Arguments:
|
|
|
|
pCallParameters - points to structure to be filled in.
|
|
ParametersSize - size of the above
|
|
pCalledAddress - points to called ATM address
|
|
pCallingAddress - points to calling ATM address
|
|
pFlowSpec - points to Flow spec for this connection
|
|
IsPMP - Is this a point to multipoint connection?
|
|
IsMakeCall - Is this for MakeCall (FALSE => AddParty)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCO_CALL_MANAGER_PARAMETERS pCallMgrParameters;
|
|
|
|
PQ2931_CALLMGR_PARAMETERS pAtmCallMgrParameters;
|
|
|
|
//
|
|
// All Info Elements that we need to fill:
|
|
//
|
|
Q2931_IE UNALIGNED * pIe;
|
|
AAL_PARAMETERS_IE UNALIGNED * pAalIe;
|
|
ATM_TRAFFIC_DESCRIPTOR_IE UNALIGNED * pTrafficDescriptor;
|
|
ATM_BROADBAND_BEARER_CAPABILITY_IE UNALIGNED * pBbc;
|
|
ATM_BLLI_IE UNALIGNED * pBlli;
|
|
ATM_QOS_CLASS_IE UNALIGNED * pQos;
|
|
|
|
//
|
|
// Zero out everything. Don't remove this!
|
|
//
|
|
AA_SET_MEM((PUCHAR)pCallParameters, 0, ParametersSize);
|
|
|
|
//
|
|
// Distribute space amongst the various structures
|
|
//
|
|
pCallMgrParameters = (PCO_CALL_MANAGER_PARAMETERS)
|
|
((PUCHAR)pCallParameters +
|
|
sizeof(CO_CALL_PARAMETERS));
|
|
|
|
|
|
//
|
|
// Set pointers to link the above structures together
|
|
//
|
|
pCallParameters->CallMgrParameters = pCallMgrParameters;
|
|
pCallParameters->MediaParameters = (PCO_MEDIA_PARAMETERS)NULL;
|
|
|
|
|
|
pCallMgrParameters->CallMgrSpecific.ParamType = 0;
|
|
pCallMgrParameters->CallMgrSpecific.Length =
|
|
sizeof(Q2931_CALLMGR_PARAMETERS) +
|
|
(IsMakeCall? ATMARP_MAKE_CALL_IE_SPACE: ATMARP_ADD_PARTY_IE_SPACE);
|
|
|
|
pAtmCallMgrParameters = (PQ2931_CALLMGR_PARAMETERS)
|
|
pCallMgrParameters->CallMgrSpecific.Parameters;
|
|
|
|
if (IsPMP)
|
|
{
|
|
pCallParameters->Flags |= MULTIPOINT_VC;
|
|
}
|
|
|
|
//
|
|
// Call Manager generic flow parameters:
|
|
//
|
|
pCallMgrParameters->Transmit.TokenRate = (pFlowSpec->SendAvgBandwidth);
|
|
pCallMgrParameters->Transmit.TokenBucketSize = (pFlowSpec->SendMaxSize);
|
|
pCallMgrParameters->Transmit.MaxSduSize = pFlowSpec->SendMaxSize;
|
|
pCallMgrParameters->Transmit.PeakBandwidth = (pFlowSpec->SendPeakBandwidth);
|
|
pCallMgrParameters->Transmit.ServiceType = pFlowSpec->SendServiceType;
|
|
|
|
if ((!IsPMP) && (IsMakeCall))
|
|
{
|
|
pCallMgrParameters->Receive.TokenRate = (pFlowSpec->ReceiveAvgBandwidth);
|
|
pCallMgrParameters->Receive.TokenBucketSize = pFlowSpec->ReceiveMaxSize;
|
|
pCallMgrParameters->Receive.MaxSduSize = pFlowSpec->ReceiveMaxSize;
|
|
pCallMgrParameters->Receive.PeakBandwidth = (pFlowSpec->ReceivePeakBandwidth);
|
|
pCallMgrParameters->Receive.ServiceType = pFlowSpec->ReceiveServiceType;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// else receive side values are 0's.
|
|
//
|
|
pCallMgrParameters->Receive.ServiceType = SERVICETYPE_NOTRAFFIC;
|
|
}
|
|
|
|
//
|
|
// Q2931 Call Manager Parameters:
|
|
//
|
|
|
|
//
|
|
// Called address:
|
|
//
|
|
// TBD: Add Called Subaddress IE in outgoing call.
|
|
//
|
|
AA_COPY_MEM((PUCHAR)&(pAtmCallMgrParameters->CalledParty),
|
|
(PUCHAR)pCalledAddress,
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
//
|
|
// Calling address:
|
|
//
|
|
AA_COPY_MEM((PUCHAR)&(pAtmCallMgrParameters->CallingParty),
|
|
(PUCHAR)pCallingAddress,
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
|
|
//
|
|
// RFC 1755 (Sec 5) says that the following IEs MUST be present in the
|
|
// SETUP message, so fill them all.
|
|
//
|
|
// AAL Parameters
|
|
// Traffic Descriptor (only for MakeCall)
|
|
// Broadband Bearer Capability (only for MakeCall)
|
|
// Broadband Low Layer Info
|
|
// QoS (only for MakeCall)
|
|
//
|
|
|
|
//
|
|
// Initialize the Info Element list
|
|
//
|
|
pAtmCallMgrParameters->InfoElementCount = 0;
|
|
pIe = (PQ2931_IE)(pAtmCallMgrParameters->InfoElements);
|
|
|
|
|
|
//
|
|
// AAL Parameters:
|
|
//
|
|
|
|
{
|
|
UNALIGNED AAL5_PARAMETERS *pAal5;
|
|
|
|
pIe->IEType = IE_AALParameters;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_AAL_PARAMETERS_IE;
|
|
pAalIe = (PAAL_PARAMETERS_IE)pIe->IE;
|
|
pAalIe->AALType = AAL_TYPE_AAL5;
|
|
pAal5 = &(pAalIe->AALSpecificParameters.AAL5Parameters);
|
|
pAal5->ForwardMaxCPCSSDUSize = pFlowSpec->SendMaxSize;
|
|
pAal5->BackwardMaxCPCSSDUSize = pFlowSpec->ReceiveMaxSize;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
#ifdef PREPARE_IES_OURSELVES
|
|
//
|
|
// Let the Call Manager convert from generic flow spec to Traffic Descr,
|
|
// Broadband Bearer Cap, and QoS.
|
|
//
|
|
|
|
//
|
|
// Traffic Descriptor:
|
|
//
|
|
|
|
if (IsMakeCall)
|
|
{
|
|
pIe->IEType = IE_TrafficDescriptor;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_TRAFFIC_DESCR_IE;
|
|
pTrafficDescriptor = (PATM_TRAFFIC_DESCRIPTOR_IE)pIe->IE;
|
|
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pTrafficDescriptor->ForwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->SendPeakBandwidth);
|
|
if (!IsPMP)
|
|
{
|
|
pTrafficDescriptor->BackwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->ReceivePeakBandwidth);
|
|
}
|
|
//
|
|
// else we have zero'ed out everything, which is what we want.
|
|
//
|
|
pTrafficDescriptor->BestEffort = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Predictive/Guaranteed service (we map this to CBR, see BBC below)
|
|
pTrafficDescriptor->ForwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->SendPeakBandwidth);
|
|
if (!IsPMP)
|
|
{
|
|
pTrafficDescriptor->BackwardTD.PeakCellRateCLP01 =
|
|
BYTES_TO_CELLS(pFlowSpec->ReceivePeakBandwidth);
|
|
}
|
|
//
|
|
// else we have zero'ed out everything, which is what we want.
|
|
//
|
|
pTrafficDescriptor->BestEffort = FALSE;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
|
|
|
|
//
|
|
// Broadband Bearer Capability
|
|
//
|
|
|
|
if (IsMakeCall)
|
|
{
|
|
pIe->IEType = IE_BroadbandBearerCapability;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_BBC_IE;
|
|
pBbc = (PATM_BROADBAND_BEARER_CAPABILITY_IE)pIe->IE;
|
|
|
|
pBbc->BearerClass = BCOB_X;
|
|
pBbc->UserPlaneConnectionConfig = (IsPMP ? UP_P2MP: UP_P2P);
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pBbc->TrafficType = TT_NOIND;
|
|
pBbc->TimingRequirements = TR_NOIND;
|
|
pBbc->ClippingSusceptability = CLIP_NOT;
|
|
}
|
|
else
|
|
{
|
|
pBbc->TrafficType = TT_CBR;
|
|
pBbc->TimingRequirements = TR_END_TO_END;
|
|
pBbc->ClippingSusceptability = CLIP_SUS;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
|
|
#endif // PREPARE_IES_OURSELVES
|
|
|
|
//
|
|
// Broadband Lower Layer Information
|
|
//
|
|
|
|
pIe->IEType = IE_BLLI;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_BLLI_IE;
|
|
pBlli = (PATM_BLLI_IE)pIe->IE;
|
|
AA_COPY_MEM((PUCHAR)pBlli,
|
|
(PUCHAR)&AtmArpDefaultBlli,
|
|
sizeof(ATM_BLLI_IE));
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
|
|
|
|
#ifdef PREPARE_IES_OURSELVES
|
|
//
|
|
// QoS
|
|
//
|
|
|
|
if (IsMakeCall)
|
|
{
|
|
pIe->IEType = IE_QOSClass;
|
|
pIe->IELength = SIZEOF_Q2931_IE + SIZEOF_ATM_QOS_IE;
|
|
pQos = (PATM_QOS_CLASS_IE)pIe->IE;
|
|
if (pFlowSpec->SendServiceType == SERVICETYPE_BESTEFFORT)
|
|
{
|
|
pQos->QOSClassForward = pQos->QOSClassBackward = 0;
|
|
}
|
|
else
|
|
{
|
|
pQos->QOSClassForward = pQos->QOSClassBackward = 1;
|
|
}
|
|
|
|
pAtmCallMgrParameters->InfoElementCount++;
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
|
|
#endif // PREPARE_IES_OURSELVES
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef IPMCAST
|
|
|
|
BOOLEAN
|
|
AtmArpMcPrepareAtmEntryForClose(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry LOCKIN LOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prepare an ATM Entry that has an outgoing PMP call on it, for Close Call.
|
|
This means that we drop all but the last leaf on this PMP call.
|
|
|
|
NOTE: The caller is assumed to hold the ATM Entry lock
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Points to ATM Entry representing a PMP call
|
|
|
|
Return Value:
|
|
|
|
TRUE iff the connection on this ATM Entry is ready for CloseCall.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_IPMC_ATM_ENTRY pNextMcAtmEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
AA_ASSERT(pAtmEntry->pMcAtmInfo->TransientLeaves == 0);
|
|
AA_ASSERT(pAtmEntry->pVcList != NULL_PATMARP_VC);
|
|
|
|
pInterface = pAtmEntry->pInterface;
|
|
|
|
AAMCDEBUGP(AAD_EXTRA_LOUD,
|
|
("McPrepareAtmEntryForClose: pAtmEntry 0x%x, McList 0x%x, ActiveLeaves %d\n",
|
|
pAtmEntry,
|
|
pAtmEntry->pMcAtmInfo->pMcAtmEntryList,
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves));
|
|
|
|
|
|
//
|
|
// First, prune all members that aren't connected.
|
|
//
|
|
for (pMcAtmEntry = pAtmEntry->pMcAtmInfo->pMcAtmEntryList;
|
|
pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY;
|
|
pMcAtmEntry = pNextMcAtmEntry)
|
|
{
|
|
pNextMcAtmEntry = pMcAtmEntry->pNextMcAtmEntry;
|
|
|
|
//
|
|
// Stop any timer running here.
|
|
//
|
|
(VOID)AtmArpStopTimer(&(pMcAtmEntry->Timer), pInterface);
|
|
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED))
|
|
{
|
|
AtmArpMcUnlinkAtmMember(
|
|
pAtmEntry,
|
|
pMcAtmEntry
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Next, send drop party requests for all but one member.
|
|
//
|
|
while (pAtmEntry->pMcAtmInfo->ActiveLeaves > 1)
|
|
{
|
|
for (pMcAtmEntry = pAtmEntry->pMcAtmInfo->pMcAtmEntryList;
|
|
/* NONE */;
|
|
pMcAtmEntry = pMcAtmEntry->pNextMcAtmEntry)
|
|
{
|
|
AA_ASSERT(pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY);
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_ACTIVE))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
NdisPartyHandle = pMcAtmEntry->NdisPartyHandle;
|
|
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("PrepareAtmEntry: pAtmEntry 0x%x, will DropPty, McAtmEnt 0x%x, PtyHnd 0x%x\n",
|
|
pAtmEntry, pMcAtmEntry, NdisPartyHandle));
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_WACK_DROP_PARTY);
|
|
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves--;
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
Status = NdisClDropParty(
|
|
NdisPartyHandle,
|
|
NULL, // Buffer
|
|
(UINT)0 // Size
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpDropPartyCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pMcAtmEntry
|
|
);
|
|
}
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
//
|
|
// Now, if we have exactly one ATM member in the list of
|
|
// leaves for this PMP, we can CloseCall.
|
|
//
|
|
if (pAtmEntry->pMcAtmInfo->pMcAtmEntryList->pNextMcAtmEntry ==
|
|
NULL_PATMARP_IPMC_ATM_ENTRY)
|
|
{
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCloseCall(
|
|
IN PATMARP_VC pVc LOCKIN NOLOCKOUT
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes an existing call on a VC. It is assumed that a call exists
|
|
on the VC.
|
|
|
|
NOTE: The caller is assumed to hold a lock to the VC structure,
|
|
and it will be released here.
|
|
|
|
SIDE EFFECT: If the NDIS call returns other than NDIS_STATUS_PENDING,
|
|
we call our CloseCall Complete handler from here.
|
|
|
|
Arguments:
|
|
|
|
pVc - Pointer to ATMARP VC structure.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_HANDLE ProtocolVcContext;
|
|
#ifdef IPMCAST
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
#endif
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET PacketList; // Packets queued on this VC
|
|
AA_HEADER_TYPE HdrType; // for queued packets
|
|
BOOLEAN HdrPresent; // for queued packets
|
|
BOOLEAN WasRunning; // Was a timer running on this VC?
|
|
BOOLEAN IsPMP; // Is this a PMP call?
|
|
ULONG rc; // Ref Count on this VC.
|
|
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
ProtocolVcContext = (NDIS_HANDLE)pVc;
|
|
pInterface = pVc->pInterface;
|
|
IsPMP = AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CONN_TYPE_MASK,
|
|
AA_VC_CONN_TYPE_PMP);
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Closing call on VC 0x%x, VC Flags 0x%x, Ref %d, NdisVcHandle 0x%x\n",
|
|
pVc, pVc->Flags, pVc->RefCount, NdisVcHandle));
|
|
|
|
//
|
|
// Remove the list of packets queued on this VC.
|
|
//
|
|
PacketList = pVc->PacketList;
|
|
pVc->PacketList = (PNDIS_PACKET)NULL;
|
|
if (pVc->FlowSpec.Encapsulation == ENCAPSULATION_TYPE_LLCSNAP)
|
|
{
|
|
HdrType = (IsPMP ? AA_HEADER_TYPE_NUNICAST: AA_HEADER_TYPE_UNICAST);
|
|
HdrPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
HdrType = AA_HEADER_TYPE_NONE;
|
|
HdrPresent = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Stop any timer running on this VC.
|
|
//
|
|
WasRunning = AtmArpStopTimer(&(pVc->Timer), pInterface);
|
|
|
|
if (WasRunning)
|
|
{
|
|
//
|
|
// Remove the timer reference on this VC.
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc);
|
|
}
|
|
else
|
|
{
|
|
rc = pVc->RefCount;
|
|
}
|
|
|
|
#ifdef GPC
|
|
//
|
|
// If this VC is associated with a Flow, unlink them.
|
|
//
|
|
if (rc != 0)
|
|
{
|
|
if (pVc->FlowHandle != NULL)
|
|
{
|
|
PATMARP_FLOW_INFO pFlowInfo = (PATMARP_FLOW_INFO)pVc->FlowHandle;
|
|
|
|
if ((PVOID)pVc == InterlockedCompareExchangePointer(
|
|
&(pFlowInfo->VcContext),
|
|
NULL,
|
|
pVc
|
|
))
|
|
{
|
|
pVc->FlowHandle = NULL;
|
|
rc = AtmArpDereferenceVc(pVc); // Unlink from GPC Flow
|
|
}
|
|
}
|
|
}
|
|
#endif // GPC
|
|
|
|
|
|
if (rc != 0)
|
|
{
|
|
//
|
|
// Check the call state on this VC. If the call is active and
|
|
// we have no sends going on, then we close the call.
|
|
// Otherwise, simply mark the VC as closing. We will continue
|
|
// this process when the current operation on the VC completes.
|
|
//
|
|
|
|
if (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE) &&
|
|
(pVc->OutstandingSends == 0))
|
|
{
|
|
//
|
|
// Set VC call state to "Close Call in progress" so that we don't
|
|
// reenter here.
|
|
//
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_CLOSE_IN_PROGRESS);
|
|
|
|
#ifdef IPMCAST
|
|
if (IsPMP)
|
|
{
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry; // last leaf
|
|
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
AA_ASSERT(pAtmEntry->pMcAtmInfo != NULL_PATMARP_IPMC_ATM_INFO);
|
|
|
|
if (pAtmEntry->pMcAtmInfo->TransientLeaves == 0)
|
|
{
|
|
//
|
|
// No AddParty in progress.
|
|
//
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
if (AtmArpMcPrepareAtmEntryForClose(pAtmEntry))
|
|
{
|
|
//
|
|
// The entry is ready for CloseCall.
|
|
//
|
|
AAMCDEBUGP(AAD_LOUD,
|
|
("CloseCall (MC): pAtmEntry 0x%x, ready for close\n", pAtmEntry));
|
|
|
|
//
|
|
// Get the party handle of the last leaf, and unlink
|
|
// it from the PMP structure.
|
|
//
|
|
AA_ASSERT(pAtmEntry->pMcAtmInfo->pMcAtmEntryList !=
|
|
NULL_PATMARP_IPMC_ATM_ENTRY);
|
|
|
|
pMcAtmEntry = pVc->pAtmEntry->pMcAtmInfo->pMcAtmEntryList;
|
|
NdisPartyHandle = pMcAtmEntry->NdisPartyHandle;
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_WACK_DROP_PARTY);
|
|
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves--;
|
|
AA_ASSERT(pAtmEntry->pMcAtmInfo->ActiveLeaves == 0);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
//
|
|
|
|
// There are pending DropParty calls. Mark this VC
|
|
// so that we trigger a CloseCall when all DropParty
|
|
// calls complete.
|
|
//
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CLOSE_STATE_MASK,
|
|
AA_VC_CLOSE_STATE_CLOSING);
|
|
|
|
NdisVcHandle = NULL; // Don't close call now
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are pending AddParty calls. Mark this VC
|
|
// so that we trigger a CloseCall when all AddParty
|
|
// calls complete.
|
|
//
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CLOSE_STATE_MASK,
|
|
AA_VC_CLOSE_STATE_CLOSING);
|
|
|
|
NdisVcHandle = NULL; // Don't close call now
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NdisPartyHandle = NULL;
|
|
}
|
|
|
|
if (NdisVcHandle != NULL)
|
|
{
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
Status = NdisClCloseCall(
|
|
NdisVcHandle,
|
|
NdisPartyHandle,
|
|
(PVOID)NULL, // No Buffer
|
|
(UINT)0 // Size of above
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpCloseCallCompleteHandler(
|
|
Status,
|
|
ProtocolVcContext,
|
|
(NDIS_HANDLE)NULL
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set the call state back to what it was.
|
|
//
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE);
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
#else
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
Status = NdisClCloseCall(
|
|
NdisVcHandle,
|
|
NULL, // NdisPartyHandle
|
|
(PVOID)NULL, // No Buffer
|
|
(UINT)0 // Size of above
|
|
);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpCloseCallCompleteHandler(
|
|
Status,
|
|
ProtocolVcContext,
|
|
(NDIS_HANDLE)NULL
|
|
);
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Some operation is going on here (call setup/close/send). Mark this
|
|
// VC so that we know what to do when this operation completes.
|
|
//
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_CLOSE_STATE_MASK,
|
|
AA_VC_CLOSE_STATE_CLOSING);
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
}
|
|
//
|
|
// else the VC is gone.
|
|
//
|
|
|
|
//
|
|
// Free any packets queued on this VC
|
|
//
|
|
if (PacketList != (PNDIS_PACKET)NULL)
|
|
{
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
PacketList,
|
|
HdrPresent
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpCreateVcHandler(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
OUT PNDIS_HANDLE pProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Entry point called by NDIS when the Call Manager wants to create
|
|
a new endpoint (VC). We allocate a new ATMARP VC structure, and
|
|
return a pointer to it as our VC context.
|
|
|
|
Arguments:
|
|
|
|
ProtocolAfContext - Actually a pointer to the ATMARP Interface structure
|
|
NdisVcHandle - Handle for this VC for all future references
|
|
pProtocolVcContext - Place where we (protocol) return our context for the VC
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if we could create a VC
|
|
NDIS_STATUS_RESOURCES otherwise
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_VC pVc;
|
|
NDIS_STATUS Status;
|
|
|
|
pInterface = (PATMARP_INTERFACE)ProtocolAfContext;
|
|
|
|
pVc = AtmArpAllocateVc(pInterface);
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
*pProtocolVcContext = (NDIS_HANDLE)pVc;
|
|
pVc->NdisVcHandle = NdisVcHandle;
|
|
pVc->Flags = AA_VC_OWNER_IS_CALLMGR;
|
|
AtmArpReferenceVc(pVc); // Create VC ref
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO, ("Create Vc Handler: pVc 0x%x, Status 0x%x\n", pVc, Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpDeleteVcHandler(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Our Delete VC handler. This VC would have been allocated as a result
|
|
of a previous entry into our CreateVcHandler, and possibly used for
|
|
an incoming call.
|
|
|
|
At this time, this VC structure should be free of any calls, and we
|
|
simply free this.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext - pointer to our VC structure
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS always
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
ULONG rc; // Ref count on the VC
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
AA_ASSERT((pVc->Flags & AA_VC_OWNER_MASK) == AA_VC_OWNER_IS_CALLMGR);
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
rc = AtmArpDereferenceVc(pVc);
|
|
if (rc > 0)
|
|
{
|
|
//
|
|
// This can happen if there is a timer still running
|
|
// on this VC. When the timer elapses, the VC will be
|
|
// freed.
|
|
//
|
|
AADEBUGP(AAD_WARNING, ("Delete VC handler: pVc 0x%x, Flags 0x%x, refcount %d, pAtmEntry %x\n",
|
|
pVc, pVc->Flags, rc, pVc->pAtmEntry));
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
//
|
|
// else the VC is gone.
|
|
//
|
|
|
|
AADEBUGP(AAD_LOUD, ("Delete Vc Handler: 0x%x: done\n", pVc));
|
|
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpIncomingCallHandler(
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN OUT PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called when there is an incoming call matching our
|
|
SAP. This could be either an SVC or a PVC. In either case, we store
|
|
FlowSpec information from the incoming call in the VC structure, making
|
|
sure that the MTU for the interface is not violated.
|
|
|
|
For an SVC, we expect a Calling Address to be present in the call,
|
|
otherwise we reject the call. If an ATM Entry with this address exists,
|
|
this VC is linked to that entry, otherwise a new entry with this address
|
|
is created.
|
|
|
|
In the case of a PVC, we ignore any Calling Address information, and
|
|
depend on InATMARP to resolve the ATM Address as well as the IP address
|
|
of the other end.
|
|
|
|
Arguments:
|
|
|
|
ProtocolSapContext - Pointer to ATMARP Interface structure
|
|
ProtocolVcContext - Pointer to ATMARP VC structure
|
|
pCallParameters - Call parameters
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if we accept this call
|
|
NDIS_STATUS_FAILURE if we reject it.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
|
|
CO_CALL_MANAGER_PARAMETERS UNALIGNED * pCallMgrParameters;
|
|
Q2931_CALLMGR_PARAMETERS UNALIGNED * pAtmCallMgrParameters;
|
|
|
|
//
|
|
// To traverse the list of Info Elements
|
|
//
|
|
Q2931_IE UNALIGNED * pIe;
|
|
ULONG InfoElementCount;
|
|
|
|
//
|
|
// Info Elements in the incoming call, that are of interest to us.
|
|
// Initialize these to <not present>.
|
|
//
|
|
ATM_ADDRESS UNALIGNED * pCallingAddress = NULL;
|
|
ATM_CALLING_PARTY_SUBADDRESS_IE UNALIGNED * pCallingSubaddressIe = NULL;
|
|
ATM_ADDRESS UNALIGNED * pCallingSubaddress = NULL;
|
|
AAL_PARAMETERS_IE UNALIGNED * pAal = NULL;
|
|
ATM_TRAFFIC_DESCRIPTOR_IE UNALIGNED * pTrafficDescriptor = NULL;
|
|
ATM_BROADBAND_BEARER_CAPABILITY_IE UNALIGNED * pBbc = NULL;
|
|
ATM_BLLI_IE UNALIGNED * pBlli = NULL;
|
|
ATM_QOS_CLASS_IE UNALIGNED * pQos = NULL;
|
|
|
|
AAL5_PARAMETERS UNALIGNED * pAal5;
|
|
UCHAR AddrTypeLen;
|
|
UCHAR SubaddrTypeLen;
|
|
PUCHAR pAtmSubaddress;
|
|
NDIS_STATUS Status;
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
AA_ASSERT((pVc->Flags & AA_VC_TYPE_MASK) == AA_VC_TYPE_UNUSED);
|
|
AA_ASSERT((pVc->Flags & AA_VC_OWNER_MASK) == AA_VC_OWNER_IS_CALLMGR);
|
|
AA_ASSERT((pVc->Flags & AA_VC_CALL_STATE_MASK) == AA_VC_CALL_STATE_IDLE);
|
|
|
|
pInterface = pVc->pInterface;
|
|
AADEBUGP(AAD_LOUD, ("Incoming Call: IF 0x%x, VC 0x%x, pCallParams 0x%x\n",
|
|
pInterface, pVc, pCallParameters));
|
|
|
|
do
|
|
{
|
|
if (pInterface->AdminState != IF_STATUS_UP)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get the following info from the Incoming call:
|
|
// Calling Address
|
|
// AAL Parameters
|
|
// Traffic Descriptor
|
|
// Broadband Bearer Capability
|
|
// QoS
|
|
//
|
|
pCallMgrParameters = pCallParameters->CallMgrParameters;
|
|
pAtmCallMgrParameters = (PQ2931_CALLMGR_PARAMETERS)
|
|
pCallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
|
|
|
|
pCallingAddress = &(pAtmCallMgrParameters->CallingParty);
|
|
InfoElementCount = pAtmCallMgrParameters->InfoElementCount;
|
|
pIe = (PQ2931_IE)(pAtmCallMgrParameters->InfoElements);
|
|
|
|
while (InfoElementCount--)
|
|
{
|
|
switch (pIe->IEType)
|
|
{
|
|
case IE_AALParameters:
|
|
pAal = (PAAL_PARAMETERS_IE)(pIe->IE);
|
|
break;
|
|
case IE_TrafficDescriptor:
|
|
pTrafficDescriptor = (PATM_TRAFFIC_DESCRIPTOR_IE)(pIe->IE);
|
|
break;
|
|
case IE_BroadbandBearerCapability:
|
|
pBbc = (PATM_BROADBAND_BEARER_CAPABILITY_IE)(pIe->IE);
|
|
break;
|
|
case IE_QOSClass:
|
|
pQos = (PATM_QOS_CLASS_IE)(pIe->IE);
|
|
break;
|
|
case IE_CallingPartySubaddress:
|
|
pCallingSubaddressIe = (ATM_CALLING_PARTY_SUBADDRESS_IE *)(pIe->IE);
|
|
pCallingSubaddress = pCallingSubaddressIe;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
|
|
if ((pCallParameters->Flags & PERMANENT_VC) == 0)
|
|
{
|
|
//
|
|
// This is an SVC.
|
|
//
|
|
|
|
//
|
|
// Make sure all mandatory IEs are present. If not, reject the call
|
|
//
|
|
if ((pAal == (PAAL_PARAMETERS_IE)NULL) ||
|
|
(pTrafficDescriptor == (PATM_TRAFFIC_DESCRIPTOR_IE)NULL) ||
|
|
(pBbc == (PATM_BROADBAND_BEARER_CAPABILITY_IE)NULL) ||
|
|
(pQos == (PATM_QOS_CLASS_IE)NULL))
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("In call: IE missing: AAL 0x%x, TRAF 0x%x, BBC 0x%x, QOS 0x%x",
|
|
pAal,
|
|
pTrafficDescriptor,
|
|
pBbc,
|
|
pQos));
|
|
Status = NDIS_STATUS_AAL_PARAMS_UNSUPPORTED;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We insist on the Calling Address
|
|
// being present, as well
|
|
//
|
|
if (pCallingAddress->NumberOfDigits == 0)
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("In call: calling address missing for SVC\n"));
|
|
Status = NDIS_STATUS_INVALID_ADDRESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pAal != NULL)
|
|
{
|
|
//
|
|
// Make sure that the requested MTU values aren't beyond our
|
|
// capabilities:
|
|
//
|
|
pAal5 = &(pAal->AALSpecificParameters.AAL5Parameters);
|
|
if (pAal5->ForwardMaxCPCSSDUSize > pInterface->pAdapter->MaxPacketSize)
|
|
{
|
|
pAal5->ForwardMaxCPCSSDUSize = pInterface->pAdapter->MaxPacketSize;
|
|
}
|
|
|
|
if (pAal5->BackwardMaxCPCSSDUSize > pInterface->pAdapter->MaxPacketSize)
|
|
{
|
|
pAal5->BackwardMaxCPCSSDUSize = pInterface->pAdapter->MaxPacketSize;
|
|
}
|
|
}
|
|
|
|
#ifdef PREPARE_IES_OURSELVES
|
|
//
|
|
// Get the Flow Specs for this VC from the ATM Info Elements
|
|
//
|
|
pVc->FlowSpec.SendPeakBandwidth =
|
|
CELLS_TO_BYTES(pTrafficDescriptor->ForwardTD.PeakCellRateCLP01);
|
|
pVc->FlowSpec.SendMaxSize = pAal5->ForwardMaxCPCSSDUSize;
|
|
pVc->FlowSpec.ReceivePeakBandwidth =
|
|
CELLS_TO_BYTES(pTrafficDescriptor->BackwardTD.PeakCellRateCLP01);
|
|
pVc->FlowSpec.ReceiveMaxSize = pAal5->BackwardMaxCPCSSDUSize;
|
|
if ((pQos->QOSClassForward == 0) || (pQos->QOSClassBackward == 0))
|
|
{
|
|
pVc->FlowSpec.SendServiceType = SERVICETYPE_BESTEFFORT;
|
|
}
|
|
else
|
|
{
|
|
pVc->FlowSpec.SendServiceType = SERVICETYPE_GUARANTEED;
|
|
}
|
|
#else
|
|
//
|
|
// Get the Flow Specs for this VC
|
|
//
|
|
pVc->FlowSpec.SendPeakBandwidth = pCallMgrParameters->Transmit.PeakBandwidth;
|
|
pVc->FlowSpec.SendAvgBandwidth = pCallMgrParameters->Transmit.TokenRate;
|
|
pVc->FlowSpec.SendMaxSize = pCallMgrParameters->Transmit.MaxSduSize;
|
|
pVc->FlowSpec.SendServiceType = pCallMgrParameters->Transmit.ServiceType;
|
|
|
|
pVc->FlowSpec.ReceivePeakBandwidth = pCallMgrParameters->Receive.PeakBandwidth;
|
|
pVc->FlowSpec.ReceiveAvgBandwidth = pCallMgrParameters->Receive.TokenRate;
|
|
pVc->FlowSpec.ReceiveMaxSize = pCallMgrParameters->Receive.MaxSduSize;
|
|
pVc->FlowSpec.ReceiveServiceType = pCallMgrParameters->Receive.ServiceType;
|
|
|
|
#endif // PREPARE_IES_OURSELVES
|
|
|
|
AADEBUGP(AAD_LOUD, ("InCall: VC 0x%x: Type %s, Calling Addr:\n",
|
|
pVc,
|
|
(((pCallParameters->Flags & PERMANENT_VC) == 0)? "SVC": "PVC")
|
|
));
|
|
AADEBUGPDUMP(AAD_LOUD, pCallingAddress->Address, pCallingAddress->NumberOfDigits);
|
|
AADEBUGP(AAD_LOUD,
|
|
("InCall: VC 0x%x: SendBW: %d, RcvBW: %d, SendSz %d, RcvSz %d\n",
|
|
pVc,
|
|
pVc->FlowSpec.SendPeakBandwidth,
|
|
pVc->FlowSpec.ReceivePeakBandwidth,
|
|
pVc->FlowSpec.SendMaxSize,
|
|
pVc->FlowSpec.ReceiveMaxSize));
|
|
|
|
#if DBG
|
|
if (pCallParameters->Flags & MULTIPOINT_VC)
|
|
{
|
|
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD, "Incoming PMP call from :", pCallingAddress);
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// If this is a PVC, we are done. Accept the call.
|
|
//
|
|
if ((pCallParameters->Flags & PERMANENT_VC) != 0)
|
|
{
|
|
pVc->Flags |= (AA_VC_TYPE_PVC|AA_VC_CALL_STATE_INCOMING_IN_PROGRESS);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Here if SVC. Check if an ATM Entry for this Calling address exists.
|
|
// If an entry exists, link this VC to the entry; otherwise, create a new
|
|
// ATM entry and link this VC to it.
|
|
//
|
|
AddrTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(pCallingAddress);
|
|
if (pCallingSubaddress != (PATM_ADDRESS)NULL)
|
|
{
|
|
SubaddrTypeLen = AA_PKT_ATM_ADDRESS_TO_TYPE_LEN(pCallingSubaddress);
|
|
pAtmSubaddress = pCallingSubaddress->Address;
|
|
}
|
|
else
|
|
{
|
|
SubaddrTypeLen = 0;
|
|
pAtmSubaddress = (PUCHAR)NULL;
|
|
}
|
|
|
|
pAtmEntry = AtmArpSearchForAtmAddress(
|
|
pInterface,
|
|
AddrTypeLen,
|
|
pCallingAddress->Address,
|
|
SubaddrTypeLen,
|
|
pAtmSubaddress,
|
|
AE_REFTYPE_TMP,
|
|
TRUE // Create one if no match found
|
|
);
|
|
|
|
if (pAtmEntry == NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Link this VC to the ATM Entry, and accept this call.
|
|
//
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
{
|
|
ULONG rc;
|
|
AtmArpLinkVcToAtmEntry(pVc, pAtmEntry);
|
|
|
|
//
|
|
// AtmArpSearchForAtmAddress addrefd pAtmEntry for us -- we deref it
|
|
// here (AFTER calling AtmArpLinkVcToAtmEntry).
|
|
//
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP);
|
|
if (rc == 0)
|
|
{
|
|
//
|
|
// We shouldn't get here because AtmArpLinkVcToAtmEntry
|
|
// should have added a reference tp pAtmEntry.
|
|
//
|
|
AA_ASSERT(FALSE);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
//
|
|
|
|
// All checks for an incoming SVC are complete.
|
|
//
|
|
pVc->Flags |= (AA_VC_TYPE_SVC|AA_VC_CALL_STATE_INCOMING_IN_PROGRESS);
|
|
|
|
|
|
AtmArpReferenceVc(pVc); // ATM Entry reference
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("Incoming call: VC 0x%x, Status 0x%x\n", pVc, Status));
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCallConnectedHandler(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called as the final step in an incoming call, to inform
|
|
us that the call is fully setup.
|
|
|
|
For a PVC, we link the ATMARP VC structure in the list of unresolved PVCs,
|
|
and use InATMARP to resolve both the IP and ATM addresses of the other
|
|
end.
|
|
|
|
For an SVC, we send off any packets queued on the VC while we were waiting
|
|
for the Call Connected.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext - Pointer to ATMARP VC structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
PATMARP_INTERFACE pInterface;
|
|
#if DBG
|
|
AA_IRQL EntryIrq, ExitIrq;
|
|
#endif
|
|
|
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
AA_ASSERT((pVc->Flags & AA_VC_CALL_STATE_MASK)
|
|
== AA_VC_CALL_STATE_INCOMING_IN_PROGRESS);
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
//
|
|
// Note down that a call is active on this VC.
|
|
//
|
|
AA_SET_FLAG(
|
|
pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE
|
|
);
|
|
|
|
AtmArpReferenceVc(pVc); // Incoming call reference
|
|
|
|
AADEBUGP(AAD_INFO, ("Call Connected: VC: 0x%x, Flags: 0x%x, ATM Entry: 0x%x\n",
|
|
pVc, pVc->Flags, pVc->pAtmEntry));
|
|
|
|
pInterface = pVc->pInterface;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
if ((pVc->Flags & AA_VC_TYPE_PVC) != 0)
|
|
{
|
|
//
|
|
// This is a PVC, link it to the list of unresolved PVCs, and
|
|
// send an InATMARP request on it.
|
|
//
|
|
pVc->pNextVc = pInterface->pUnresolvedVcs;
|
|
pInterface->pUnresolvedVcs = pVc;
|
|
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_ARP_STATE_MASK,
|
|
AA_VC_INARP_IN_PROGRESS);
|
|
//
|
|
// Start an InARP wait timer while we hold a lock for
|
|
// the Interface
|
|
//
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pVc->Timer),
|
|
AtmArpPVCInARPWaitTimeout,
|
|
pInterface->InARPWaitTimeout,
|
|
(PVOID)pVc
|
|
);
|
|
|
|
|
|
AtmArpReferenceVc(pVc); // Timer ref
|
|
|
|
AtmArpReferenceVc(pVc); // Unresolved VCs Link reference
|
|
|
|
|
|
AADEBUGP(AAD_LOUD, ("PVC Call Connected: VC 0x%x\n", pVc));
|
|
|
|
#ifndef VC_REFS_ON_SENDS
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
#endif // VC_REFS_ON_SENDS
|
|
AtmArpSendInARPRequest(pVc);
|
|
|
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_LOUD, ("SVC Call Connected: VC 0x%x\n", pVc));
|
|
|
|
AtmArpStartSendsOnVc(pVc);
|
|
|
|
//
|
|
// The VC lock is released within StartSendsOnVc()
|
|
//
|
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The interface is marked as down. Close this call.
|
|
//
|
|
|
|
AtmArpCloseCall(pVc);
|
|
|
|
//
|
|
// The VC lock is released within the above
|
|
//
|
|
}
|
|
|
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpIncomingCloseHandler(
|
|
IN NDIS_STATUS CloseStatus,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PVOID pCloseData OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called when a call is closed, either by the network
|
|
or by the remote peer.
|
|
|
|
Arguments:
|
|
|
|
CloseStatus - Reason for the call clearing
|
|
ProtocolVcContext - Actually a pointer to the ATMARP VC structure
|
|
pCloseData - Additional info about the close
|
|
Size - Length of above
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
ULONG rc; // Ref Count
|
|
BOOLEAN VcAbnormalTermination;
|
|
BOOLEAN IsPVC;
|
|
BOOLEAN Found;
|
|
PATM_CAUSE_IE pCauseIe;
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
AADEBUGP(AAD_INFO, ("Incoming Close: pVc 0x%x, Status 0x%x\n", pVc, CloseStatus));
|
|
pCauseIe = (PATM_CAUSE_IE)pCloseData;
|
|
|
|
#if DBG
|
|
if (pCauseIe != (PATM_CAUSE_IE)NULL)
|
|
{
|
|
AADEBUGP(AAD_INFO, ("Incoming Close: pVc 0x%x, Locn 0x%x, Cause 0x%x\n",
|
|
pVc, pCauseIe->Location, pCauseIe->Cause));
|
|
}
|
|
#endif // DBG
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
IsPVC = AA_IS_FLAG_SET(pVc->Flags, AA_VC_TYPE_MASK, AA_VC_TYPE_PVC);
|
|
pInterface = pVc->pInterface;
|
|
|
|
//
|
|
// Stop any timer (e.g. VC aging) running on this VC
|
|
//
|
|
if (AtmArpStopTimer(&(pVc->Timer), pVc->pInterface))
|
|
{
|
|
//
|
|
// A timer WAS running
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc); // Timer reference
|
|
AA_ASSERT(rc > 0);
|
|
}
|
|
|
|
if ((CloseStatus == NDIS_STATUS_DEST_OUT_OF_ORDER) || IsPVC)
|
|
{
|
|
//
|
|
// This is an abnormal close, note down the fact
|
|
//
|
|
VcAbnormalTermination = TRUE;
|
|
}
|
|
else
|
|
{
|
|
VcAbnormalTermination = FALSE;
|
|
}
|
|
|
|
if (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_INCOMING_IN_PROGRESS))
|
|
{
|
|
AADEBUGP(AAD_WARNING,
|
|
("Incoming close: VC 0x%x state is INCOMING_IN_PROGRESS; changing to ACTIVE\n",
|
|
pVc));
|
|
//
|
|
// We're getting a close call for an incoming call that is not yet
|
|
// in the connected state. Since we won't get any further notifications
|
|
// for this call, this call is effectively in the active state.
|
|
// So we set the state to active, and then close the VC.
|
|
// Note: we will not go down the InvalidateAtmEntryPath even
|
|
// if CloseStatus == NDIS_STATUS_DEST_OUT_OF_ORDER;
|
|
// we instead simply close the vc. (If the client is truly out of order,
|
|
// and we want to send to it, well separately try to make an OUTGOING
|
|
// call to the destination, which should fail with "DEST_OUT_OF_ORDER",
|
|
// and we'll end up eventually invalidating the atm entry.
|
|
//
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE);
|
|
AtmArpReferenceVc(pVc); // Incoming call reference
|
|
|
|
VcAbnormalTermination = FALSE;
|
|
}
|
|
|
|
if (VcAbnormalTermination &&
|
|
(pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY))
|
|
{
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("IncomingClose: will invalidate ATM entry %x/%x - IP Entry %x, VC %x/%x\n",
|
|
pAtmEntry, pAtmEntry->Flags,
|
|
pAtmEntry->pIpEntryList,
|
|
pVc, pVc->Flags));
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AtmArpInvalidateAtmEntry(
|
|
pAtmEntry,
|
|
FALSE // Not shutting down
|
|
);
|
|
//
|
|
// AE Lock is released within the above.
|
|
//
|
|
|
|
if (IsPVC)
|
|
{
|
|
//
|
|
// Start a CloseCall right here because InvalidateAtmEntry doesn't.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// VC lock is released above
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AtmArpCloseCall(pVc);
|
|
}
|
|
|
|
AADEBUGP(AAD_LOUD, ("Leaving Incoming Close handler, VC: 0x%x\n", pVc));
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef IPMCAST
|
|
|
|
VOID
|
|
AtmArpAddParty(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN PATMARP_IPMC_ATM_ENTRY pMcAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a party to an existing PMP connection. The ATM Entry contains
|
|
all address information for the connection, and the Multicast ATM
|
|
Entry represents one of the leaves, the one to be added.
|
|
|
|
NOTE: The caller is assumed to hold a lock for the ATM Entry,
|
|
which is released here.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to ATM Entry on which to add the leaf (party).
|
|
pMcAtmEntry - Points to ATM Multicast Entry representing the leaf.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc; // The VC structure for the connection
|
|
NDIS_HANDLE NdisVcHandle;
|
|
PCO_CALL_PARAMETERS pCallParameters;
|
|
ULONG RequestSize;
|
|
NDIS_STATUS Status;
|
|
|
|
AA_ASSERT(pAtmEntry->pVcList != NULL_PATMARP_VC);
|
|
pVc = pAtmEntry->pVcList;
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
//
|
|
// Allocate all the space we need.
|
|
//
|
|
RequestSize = sizeof(CO_CALL_PARAMETERS) +
|
|
sizeof(CO_CALL_MANAGER_PARAMETERS) +
|
|
sizeof(Q2931_CALLMGR_PARAMETERS) +
|
|
ATMARP_ADD_PARTY_IE_SPACE +
|
|
0;
|
|
|
|
AA_ALLOC_MEM(pCallParameters, CO_CALL_PARAMETERS, RequestSize);
|
|
|
|
if (pCallParameters != (PCO_CALL_PARAMETERS)NULL)
|
|
{
|
|
//
|
|
// Fill in Call Parameters.
|
|
//
|
|
AtmArpFillCallParameters(
|
|
pCallParameters,
|
|
RequestSize,
|
|
&(pMcAtmEntry->ATMAddress), // Called address
|
|
&(pAtmEntry->pInterface->LocalAtmAddress), // Calling address
|
|
&(pVc->FlowSpec),
|
|
TRUE, // IsPMP
|
|
FALSE // IsMakeCall?
|
|
);
|
|
}
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_WACK_ADD_PARTY);
|
|
|
|
pAtmEntry->pMcAtmInfo->TransientLeaves++;
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
if (pCallParameters != (PCO_CALL_PARAMETERS)NULL)
|
|
{
|
|
Status = NdisClAddParty(
|
|
NdisVcHandle,
|
|
(NDIS_HANDLE)pMcAtmEntry,
|
|
pCallParameters,
|
|
&(pMcAtmEntry->NdisPartyHandle)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpAddPartyCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pMcAtmEntry,
|
|
pMcAtmEntry->NdisPartyHandle,
|
|
pCallParameters
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpMcTerminateMember(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN PATMARP_IPMC_ATM_ENTRY pMcAtmEntry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Terminate the specified member of a multicast group. If it is
|
|
currently a leaf in the point-to-multipoint connection to the
|
|
group, then we drop it. If it is the LAST leaf, then we close
|
|
the entire connection.
|
|
|
|
NOTE: the caller is assumed to hold the ATM Entry lock, which
|
|
will be released here.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Pointer to ATM Entry
|
|
pMcAtmEntry - Points to ATM Multicast Entry representing the leaf to
|
|
be terminated.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IPMC_ATM_INFO pMcAtmInfo;
|
|
PATMARP_VC pVc;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
pMcAtmInfo = pAtmEntry->pMcAtmInfo;
|
|
pVc = pAtmEntry->pVcList;
|
|
NdisPartyHandle = pMcAtmEntry->NdisPartyHandle;
|
|
|
|
AAMCDEBUGP(AAD_VERY_LOUD,
|
|
("TerminateMember: pAtmEntry 0x%x, pMcAtmEntry 0x%x, pVc 0x%x, NdisPtyHnd 0x%x\n",
|
|
pAtmEntry, pMcAtmEntry, pVc, NdisPartyHandle));
|
|
|
|
#if DBG
|
|
{
|
|
PATMARP_IP_ENTRY pIpEntry = pAtmEntry->pIpEntryList;
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AAMCDEBUGPMAP(AAD_INFO, "Terminating ",
|
|
&pIpEntry->IPAddress,
|
|
&pMcAtmEntry->ATMAddress);
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_TERMINATING))
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
return;
|
|
}
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_TERMINATING);
|
|
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_ACTIVE))
|
|
{
|
|
if (pMcAtmInfo->ActiveLeaves == 1)
|
|
{
|
|
//
|
|
// This is the last active leaf in this connection. Close the call.
|
|
//
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ASSERT(pVc != NULL_PATMARP_VC);
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// VC lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This isn't the only leaf in this connection. Drop this party.
|
|
//
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves--;
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_WACK_DROP_PARTY);
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
Status = NdisClDropParty(
|
|
NdisPartyHandle,
|
|
NULL, // Buffer
|
|
(UINT)0 // Size
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpDropPartyCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pMcAtmEntry
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED))
|
|
{
|
|
//
|
|
// Simply unlink this entry.
|
|
//
|
|
UINT rc;
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP); // temp ref
|
|
AtmArpMcUnlinkAtmMember(pAtmEntry, pMcAtmEntry);
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // temp ref
|
|
if (rc!=0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This party is in a transient state. Let it finish its current
|
|
// operation.
|
|
//
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
|
|
|
|
VOID
|
|
AtmArpIncomingDropPartyHandler(
|
|
IN NDIS_STATUS DropStatus,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN PVOID pCloseData OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called if the network (or remote peer) drops
|
|
a leaf node from a point-to-multipoint call rooted at us.
|
|
|
|
See Section 5.1.5.1 in RFC 2022: we delete the member from
|
|
the multicast group it belongs to. And we start a timer at
|
|
the end of which we mark the multicast group as needing
|
|
revalidation.
|
|
|
|
Arguments:
|
|
|
|
DropStatus - Leaf drop status
|
|
ProtocolPartyContext - Pointer to our Multicast ATM Entry structure
|
|
pCloseData - Optional additional info (ignored)
|
|
Size - of the above (ignored)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
#ifdef IPMCAST
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
ULONG rc;
|
|
|
|
pMcAtmEntry = (PATMARP_IPMC_ATM_ENTRY)ProtocolPartyContext;
|
|
AA_STRUCT_ASSERT(pMcAtmEntry, ame);
|
|
|
|
AA_ASSERT(pMcAtmEntry->pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
AA_ASSERT(pMcAtmEntry->pAtmEntry->pIpEntryList != NULL_PATMARP_IP_ENTRY);
|
|
|
|
pAtmEntry = pMcAtmEntry->pAtmEntry;
|
|
|
|
NdisPartyHandle = pMcAtmEntry->NdisPartyHandle;
|
|
pInterface = pAtmEntry->pInterface;
|
|
|
|
AA_ACQUIRE_IF_TABLE_LOCK(pInterface);
|
|
|
|
pIpEntry = pAtmEntry->pIpEntryList;
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK_DPC(pIpEntry);
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TMP); // TmpRef
|
|
AA_RELEASE_IE_LOCK_DPC(pIpEntry);
|
|
}
|
|
|
|
AA_RELEASE_IF_TABLE_LOCK(pInterface);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Incoming Drop: pMcAtmEntry 0x%x, PtyHnd 0x%x, pAtmEntry 0x%x, IP Addr: %d.%d.%d.%d\n",
|
|
pMcAtmEntry,
|
|
NdisPartyHandle,
|
|
pAtmEntry,
|
|
((PUCHAR)&(pIpEntry->IPAddress))[0],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[1],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[2],
|
|
((PUCHAR)&(pIpEntry->IPAddress))[3]));
|
|
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves--;
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_RCV_DROP_PARTY);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
if (pIpEntry != NULL_PATMARP_IP_ENTRY)
|
|
{
|
|
//
|
|
// We need to revalidate this multicast group after a random
|
|
// delay. Start a random delay timer.
|
|
//
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
|
|
if (!AA_IS_TIMER_ACTIVE(&(pIpEntry->Timer)) &&
|
|
AA_IS_FLAG_SET(pIpEntry->Flags,
|
|
AA_IP_ENTRY_MC_RESOLVE_MASK,
|
|
AA_IP_ENTRY_MC_RESOLVED))
|
|
{
|
|
ULONG RandomDelay;
|
|
|
|
RandomDelay = AA_GET_RANDOM(
|
|
pInterface->MinRevalidationDelay,
|
|
pInterface->MaxRevalidationDelay);
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pIpEntry->Timer),
|
|
AtmArpMcRevalidationDelayTimeout,
|
|
RandomDelay,
|
|
(PVOID)pIpEntry
|
|
);
|
|
|
|
AA_REF_IE(pIpEntry, IE_REFTYPE_TIMER); // Timer ref
|
|
}
|
|
|
|
rc = AA_DEREF_IE(pIpEntry, IE_REFTYPE_TMP);
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Complete the DropParty handshake.
|
|
//
|
|
Status = NdisClDropParty(
|
|
NdisPartyHandle,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpDropPartyCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pMcAtmEntry
|
|
);
|
|
}
|
|
#endif // IPMCAST
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpQosChangeHandler(
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called if the remote peer modifies call parameters
|
|
"on the fly", i.e. after the call is established and running.
|
|
|
|
This isn't supported by existing ATM signalling, and shouldn't happen,
|
|
but we'll allow this.
|
|
|
|
FUTURE: The FlowSpecs associated with the call are affected by this.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext - Pointer to our ATMARP VC structure
|
|
pCallParameters - updated call parameters.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
|
|
AADEBUGP(AAD_WARNING, ("Ignoring Qos Change, VC: 0x%x\n", pVc));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpOpenAfCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE NdisAfHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This handler is called to indicate completion of a previous call
|
|
to NdisClOpenAddressFamily. We would have blocked the thread that
|
|
called this. Wake it up now.
|
|
|
|
By the way, if the call was successful, store the NDIS AF handle
|
|
in our Interface structure.
|
|
|
|
We don't need to acquire locks here because the thread that called
|
|
OpenAddressFamily would have blocked with a lock acquired.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the Open AF
|
|
ProtocolAfContext - Pointer to our ATMARP Interface structure
|
|
NdisAfHandle - NDIS handle to the AF association
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
|
|
pInterface = (PATMARP_INTERFACE)ProtocolAfContext;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AADEBUGP(AAD_INFO, ("Open AF Complete: IF 0x%x, Status 0x%x, AF Handle 0x%x\n",
|
|
pInterface, Status, NdisAfHandle));
|
|
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pInterface->NdisAfHandle = NdisAfHandle;
|
|
}
|
|
|
|
//
|
|
// Wake up the blocked thread
|
|
//
|
|
AA_SIGNAL_BLOCK_STRUCT(&(pInterface->Block), Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpSendIPDelInterface(
|
|
IN PNDIS_WORK_ITEM pWorkItem,
|
|
IN PVOID IfContext
|
|
)
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PVOID IPContext;
|
|
ULONG rc;
|
|
#if DBG
|
|
AA_IRQL EntryIrq, ExitIrq;
|
|
#endif
|
|
|
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
|
#if !BINARY_COMPATIBLE
|
|
AA_ASSERT(EntryIrq == PASSIVE_LEVEL);
|
|
#endif
|
|
|
|
pInterface = (PATMARP_INTERFACE)IfContext;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AA_FREE_MEM(pWorkItem);
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
IPContext = pInterface->IPContext;
|
|
pInterface->IPContext = NULL;
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AADEBUGP(AAD_INFO, ("SendIPDelInterface: IF 0x%x, IPContext 0x%x\n",
|
|
pInterface, IPContext));
|
|
|
|
if (IPContext != NULL)
|
|
{
|
|
(*(pAtmArpGlobalInfo->pIPDelInterfaceRtn))(
|
|
IPContext
|
|
#if IFCHANGE1
|
|
#ifndef ATMARP_WIN98
|
|
,0 // DeleteIndex (unused) -- See 10/14/1998 entry
|
|
// in notes.txt
|
|
#endif
|
|
#endif // IFCHANGE1
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_INFO, ("SendIPDelInterface: NO IPContext"));
|
|
}
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
rc = AtmArpDereferenceInterface(pInterface); // Work Item: Del Interface
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
//
|
|
// else the Interface is gone.
|
|
//
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpCloseAfCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to indicate completion of a call to
|
|
NdisClCloseAddressFamily. Tell IP to Delete this Interface now.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the Close AF (ignored here)
|
|
ProtocolAfContext - Pointer to ATMARP Interface structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
PNDIS_WORK_ITEM pWorkItem;
|
|
NDIS_STATUS NdisStatus;
|
|
BOOLEAN bUnloading;
|
|
#if 0
|
|
PVOID IPContext;
|
|
#endif
|
|
#if DBG
|
|
AA_IRQL EntryIrq, ExitIrq;
|
|
#endif
|
|
|
|
AA_GET_ENTRY_IRQL(EntryIrq);
|
|
#if !BINARY_COMPATIBLE
|
|
AA_ASSERT(EntryIrq == PASSIVE_LEVEL);
|
|
#endif
|
|
|
|
AA_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
pInterface = (PATMARP_INTERFACE)ProtocolAfContext;
|
|
|
|
AADEBUGP(AAD_INFO, ("CloseAfComplete: If 0x%x, Status 0x%x\n",
|
|
pInterface, Status));
|
|
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
pInterface->NdisAfHandle = NULL;
|
|
bUnloading = pAtmArpGlobalInfo->bUnloading;
|
|
|
|
if (pInterface->IPContext != NULL)
|
|
{
|
|
//
|
|
// We haven't seen an IfClose yet.
|
|
//
|
|
AA_ALLOC_MEM(pWorkItem, NDIS_WORK_ITEM, sizeof(NDIS_WORK_ITEM));
|
|
if (pWorkItem == NULL)
|
|
{
|
|
AA_ASSERT(FALSE);
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
IPContext = (PVOID)pInterface->IPContext;
|
|
pInterface->IPContext = NULL;
|
|
#endif
|
|
AtmArpReferenceInterface(pInterface); // Work Item
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
if (bUnloading)
|
|
{
|
|
AtmArpSendIPDelInterface(pWorkItem, (PVOID)pInterface);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Queue a work item so that (a) things unravel easier,
|
|
// (b) we are at passive level when we call IPDelInterface.
|
|
//
|
|
NdisInitializeWorkItem(
|
|
pWorkItem,
|
|
AtmArpSendIPDelInterface,
|
|
(PVOID)pInterface
|
|
);
|
|
|
|
NdisStatus = NdisScheduleWorkItem(pWorkItem);
|
|
|
|
AA_ASSERT(NdisStatus == NDIS_STATUS_SUCCESS);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AADEBUGP(AAD_WARNING, ("CloseAfComplete: NO IPContext"));
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpRegisterSapCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN PCO_SAP pSap,
|
|
IN NDIS_HANDLE NdisSapHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to indicate completion of a call to
|
|
NdisClRegisterSap. If the call was successful, save the
|
|
allocated NdisSapHandle in our SAP structure.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of Register SAP
|
|
ProtocolSapContext - Pointer to our ATMARP Interface structure
|
|
pSap - SAP information we'd passed in the call
|
|
NdisSapHandle - SAP Handle
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_SAP pAtmArpSap;
|
|
|
|
pAtmArpSap = (PATMARP_SAP)ProtocolSapContext;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pAtmArpSap->NdisSapHandle = NdisSapHandle;
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_REG_STATE_MASK,
|
|
AA_SAP_REG_STATE_REGISTERED);
|
|
}
|
|
else
|
|
{
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_REG_STATE_MASK,
|
|
AA_SAP_REG_STATE_IDLE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDeregisterSapCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolSapContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when a previous call to NdisClDeregisterSap
|
|
has completed. If it was successful, we update the state of the ATMARP
|
|
SAP structure representing the Sap.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the Deregister SAP request
|
|
ProtocolSapContext - Pointer to our ATMARP SAP structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PATMARP_INTERFACE pInterface;
|
|
PATMARP_SAP pAtmArpSap;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pAtmArpSap = (PATMARP_SAP)ProtocolSapContext;
|
|
|
|
AA_STRUCT_ASSERT(pAtmArpSap, aas);
|
|
pInterface = pAtmArpSap->pInterface;
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
pAtmArpSap->NdisSapHandle = NULL;
|
|
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_REG_STATE_MASK,
|
|
AA_SAP_REG_STATE_IDLE);
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpMakeCallCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when an outgoing call request (NdisClMakeCall)
|
|
has completed. The "Status" parameter indicates whether the call was
|
|
successful or not.
|
|
|
|
If the call was successful, we send any packets queued for transmission
|
|
on this VC.
|
|
|
|
If the call failed, we free any packets queued on this VC and unlink it
|
|
from the ATM Address Entry it was linked to. If this was an attempt to
|
|
connect to the ATMARP server, delay for a while before attempting to
|
|
connect again.
|
|
|
|
Arguments:
|
|
|
|
Status - Result of the NdisClMakeCall
|
|
ProtocolVcContext - Pointer to ATMARP VC structure
|
|
NdisPartyHandle - Not used (no point-to-multipoint calls)
|
|
pCallParameters - Pointer to call parameters
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
PATMARP_INTERFACE pInterface;
|
|
ULONG rc; // ref count
|
|
BOOLEAN IsServerVc; // Is this the VC to the ATMARP server?
|
|
BOOLEAN IsPMP;
|
|
PNDIS_PACKET PacketList; // List of packets waiting to be sent
|
|
AA_HEADER_TYPE HdrType; // header types for the above
|
|
BOOLEAN HdrPresent;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
|
|
PATMARP_ATM_ENTRY pAtmEntry; // ATM Entry to which this VC is linked
|
|
|
|
Q2931_CALLMGR_PARAMETERS UNALIGNED * pCallMgrSpecific;
|
|
Q2931_IE UNALIGNED * pIe;
|
|
ULONG InfoElementCount;
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
AADEBUGP(AAD_INFO, ("MakeCall Complete: Status 0x%x, VC 0x%x, pAtmEntry 0x%x\n",
|
|
Status, pVc, pVc->pAtmEntry));
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
IsPMP = AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CONN_TYPE_MASK,
|
|
AA_VC_CONN_TYPE_PMP);
|
|
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
|
|
if (pVc->FlowSpec.Encapsulation == ENCAPSULATION_TYPE_LLCSNAP)
|
|
{
|
|
HdrType = (IsPMP? AA_HEADER_TYPE_NUNICAST: AA_HEADER_TYPE_UNICAST);
|
|
HdrPresent = TRUE;
|
|
}
|
|
else
|
|
{
|
|
HdrType = AA_HEADER_TYPE_NONE;
|
|
HdrPresent = FALSE;
|
|
}
|
|
|
|
pInterface = pVc->pInterface;
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
AADEBUGP(AAD_LOUD, ("Make Call Successful on VC 0x%x\n", pVc));
|
|
//
|
|
// Update the call state on this VC, and send queued packets.
|
|
// If this happens to be the VC to the ATMARP Server, we expect
|
|
// to see our initial ARP Request (to register with the server)
|
|
// in this queue.
|
|
//
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE);
|
|
|
|
//
|
|
// Locate the AAL parameters Info Element, and get the updated
|
|
// packet sizes.
|
|
//
|
|
pCallMgrSpecific = (PQ2931_CALLMGR_PARAMETERS)&pCallParameters->CallMgrParameters->CallMgrSpecific.Parameters[0];
|
|
pIe = (PQ2931_IE)&pCallMgrSpecific->InfoElements[0];
|
|
|
|
for (InfoElementCount = 0;
|
|
InfoElementCount < pCallMgrSpecific->InfoElementCount;
|
|
InfoElementCount++)
|
|
{
|
|
if (pIe->IEType == IE_AALParameters)
|
|
{
|
|
AAL_PARAMETERS_IE UNALIGNED * pAalIe;
|
|
UNALIGNED AAL5_PARAMETERS * pAal5;
|
|
|
|
pAalIe = (PAAL_PARAMETERS_IE)&pIe->IE[0];
|
|
AA_ASSERT(pAalIe->AALType == AAL_TYPE_AAL5);
|
|
pAal5 = &pAalIe->AALSpecificParameters.AAL5Parameters;
|
|
|
|
#if DBG
|
|
if (pVc->FlowSpec.SendMaxSize != pAal5->ForwardMaxCPCSSDUSize)
|
|
{
|
|
AADEBUGP(AAD_INFO,
|
|
("CallComplete: Send size changed (%d->%d)\n",
|
|
pVc->FlowSpec.SendMaxSize,
|
|
pAal5->ForwardMaxCPCSSDUSize));
|
|
}
|
|
if (pVc->FlowSpec.ReceiveMaxSize != pAal5->BackwardMaxCPCSSDUSize)
|
|
{
|
|
AADEBUGP(AAD_INFO,
|
|
("CallComplete: Receive size changed (%d->%d)\n",
|
|
pVc->FlowSpec.ReceiveMaxSize,
|
|
pAal5->BackwardMaxCPCSSDUSize));
|
|
}
|
|
#endif // DBG
|
|
pVc->FlowSpec.SendMaxSize = pAal5->ForwardMaxCPCSSDUSize;
|
|
pVc->FlowSpec.ReceiveMaxSize = pAal5->BackwardMaxCPCSSDUSize;
|
|
break;
|
|
}
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
|
|
AA_ASSERT(InfoElementCount != pCallMgrSpecific->InfoElementCount);
|
|
|
|
|
|
//
|
|
// Update the call type on this VC. If this is an SVC, start
|
|
// the VC aging timer.
|
|
//
|
|
if (pCallParameters->Flags & PERMANENT_VC)
|
|
{
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_TYPE_MASK,
|
|
AA_VC_TYPE_PVC);
|
|
}
|
|
else
|
|
{
|
|
ULONG AgingTime;
|
|
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_TYPE_MASK,
|
|
AA_VC_TYPE_SVC);
|
|
|
|
#ifdef IPMCAST
|
|
if (IsPMP)
|
|
{
|
|
AgingTime = pInterface->MulticastEntryAgingTimeout;
|
|
}
|
|
else
|
|
{
|
|
AgingTime = pVc->FlowSpec.AgingTime;
|
|
}
|
|
#else
|
|
AgingTime = pVc->FlowSpec.AgingTime;
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// Start VC aging timer on this SVC.
|
|
//
|
|
if (AgingTime != 0)
|
|
{
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pVc->Timer),
|
|
AtmArpVcAgingTimeout,
|
|
AgingTime,
|
|
(PVOID)pVc
|
|
);
|
|
|
|
AtmArpReferenceVc(pVc); // Timer ref
|
|
}
|
|
}
|
|
|
|
AtmArpStartSendsOnVc(pVc);
|
|
|
|
//
|
|
// The VC lock is released within StartSendsOnVc()
|
|
//
|
|
|
|
#ifdef IPMCAST
|
|
if (IsPMP)
|
|
{
|
|
AtmArpMcMakeCallComplete(
|
|
pAtmEntry,
|
|
NdisPartyHandle,
|
|
Status
|
|
);
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The call failed.
|
|
//
|
|
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_IDLE);
|
|
|
|
//
|
|
// Delete the Call reference
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc);
|
|
AA_ASSERT(rc > 0);
|
|
|
|
//
|
|
// Remove all packets queued on this VC
|
|
//
|
|
PacketList = pVc->PacketList;
|
|
pVc->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
//
|
|
// Was this a call to the ATMARP server?
|
|
//
|
|
if (pInterface->pCurrentServer != NULL)
|
|
{
|
|
IsServerVc = (pVc->pAtmEntry == pInterface->pCurrentServer->pAtmEntry);
|
|
}
|
|
else
|
|
{
|
|
IsServerVc = FALSE;
|
|
}
|
|
|
|
AADEBUGP(AAD_INFO,
|
|
("Make Call FAILED on VC 0x%x IsPMP=%lu IsServer=%lu\n",
|
|
pVc,
|
|
IsPMP,
|
|
IsServerVc
|
|
));
|
|
|
|
#ifdef GPC
|
|
//
|
|
// Unlink this VC from the flow, if linked...
|
|
//
|
|
if (pVc->FlowHandle != NULL)
|
|
{
|
|
PATMARP_FLOW_INFO pFlowInfo = (PATMARP_FLOW_INFO)pVc->FlowHandle;
|
|
if ((PVOID)pVc == InterlockedCompareExchangePointer(
|
|
&(pFlowInfo->VcContext),
|
|
NULL,
|
|
pVc
|
|
))
|
|
{
|
|
pVc->FlowHandle = NULL;
|
|
rc = AtmArpDereferenceVc(pVc); // Unlink from GPC Flow
|
|
AA_ASSERT(rc > 0);
|
|
}
|
|
}
|
|
#endif // GPC
|
|
|
|
|
|
//
|
|
// Unlink this VC from the ATM Entry it belonged to, if any
|
|
//
|
|
AA_ASSERT(pVc->pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
AtmArpUnlinkVcFromAtmEntry(pVc, FALSE);
|
|
|
|
//
|
|
// Delete the ATM Entry reference
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc); // ATM Entry ref
|
|
AA_ASSERT(rc > 0);
|
|
|
|
//
|
|
// Delete the CreateVc reference
|
|
//
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
rc = AtmArpDereferenceVc(pVc); // Create Vc ref
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
|
|
#ifndef VC_REFS_ON_SENDS
|
|
//
|
|
// Delete the NDIS association
|
|
//
|
|
(VOID)NdisCoDeleteVc(NdisVcHandle);
|
|
#endif // VC_REFS_ON_SENDS
|
|
AADEBUGP(AAD_LOUD, ("Deleted NDIS VC on pVc 0x%x: NdisVcHandle 0x%x\n",
|
|
pVc, NdisVcHandle));
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_VC); // Unlink Vc - make call
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
#ifdef IPMCAST
|
|
if (IsPMP)
|
|
{
|
|
AtmArpMcMakeCallComplete(
|
|
pAtmEntry,
|
|
NdisPartyHandle,
|
|
Status
|
|
);
|
|
}
|
|
else
|
|
{
|
|
#endif // IPMCAST
|
|
if (!AA_IS_TRANSIENT_FAILURE(Status))
|
|
{
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AtmArpInvalidateAtmEntry(pAtmEntry, FALSE); // MakeCall failure
|
|
//
|
|
// AE Lock is released within the above.
|
|
//
|
|
}
|
|
#ifdef IPMCAST
|
|
}
|
|
#endif // IPMCAST
|
|
}
|
|
//
|
|
// else the ATM Entry is gone
|
|
//
|
|
|
|
if (IsServerVc)
|
|
{
|
|
BOOLEAN WasRunning;
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
//
|
|
// If we were in the process of registering (or refreshing)
|
|
// ourselves with the server, then retry after a while.
|
|
//
|
|
if (AA_IS_FLAG_SET(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_REGISTERING))
|
|
{
|
|
AA_SET_FLAG(pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_NO_CONTACT);
|
|
|
|
//
|
|
// The server registration timer would have been
|
|
// started -- stop it first.
|
|
//
|
|
WasRunning = AtmArpStopTimer(&(pInterface->Timer), pInterface);
|
|
if (WasRunning)
|
|
{
|
|
rc = AtmArpDereferenceInterface(pInterface);
|
|
}
|
|
else
|
|
{
|
|
rc = pInterface->RefCount;
|
|
}
|
|
|
|
if (rc > 0)
|
|
{
|
|
AtmArpRetryServerRegistration(pInterface);
|
|
//
|
|
// The IF lock is released within the above.
|
|
//
|
|
}
|
|
//
|
|
// else the IF is gone!
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We might have been trying to set up the server VC
|
|
// because of other reasons:
|
|
// - to resolve an unknown IP address
|
|
// - the server ATM address might be shared with other
|
|
// services (e.g. DHCP server)
|
|
//
|
|
// We don't have to retry registration in these cases.
|
|
//
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The Interface is going down: clean up everything first.
|
|
//
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_ACTIVE);
|
|
|
|
//
|
|
// The call had been set up successfully, so close it.
|
|
// AtmArpCloseCall also frees any queued packets on the VC.
|
|
//
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// The VC lock is released by CloseCall
|
|
//
|
|
}
|
|
else
|
|
{
|
|
// MakeCall had failed. (And the IF is going down)
|
|
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_IDLE);
|
|
|
|
//
|
|
// Remove all packets queued on this VC
|
|
//
|
|
PacketList = pVc->PacketList;
|
|
pVc->PacketList = (PNDIS_PACKET)NULL;
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
AtmArpUnlinkVcFromAtmEntry(pVc, TRUE);
|
|
|
|
//
|
|
// Delete the ATM Entry reference
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc); // ATM Entry ref
|
|
|
|
//
|
|
// Delete the Call reference
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc);
|
|
AA_ASSERT(rc > 0);
|
|
|
|
//
|
|
// Delete the CreateVc reference
|
|
//
|
|
rc = AtmArpDereferenceVc(pVc); // Create Vc ref
|
|
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
|
|
#ifndef VC_REFS_ON_SENDS
|
|
//
|
|
// Delete the NDIS association
|
|
//
|
|
(VOID)NdisCoDeleteVc(NdisVcHandle);
|
|
AADEBUGP(AAD_LOUD,
|
|
("MakeCall Fail: Deleted NDIS VC on pVc 0x%x: NdisVcHandle 0x%x\n",
|
|
pVc, NdisVcHandle));
|
|
#endif // !VC_REFS_ON_SENDS
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there was a failure in making the call, or we aborted
|
|
// it for some reason, free all packets that were queued
|
|
// on the VC.
|
|
//
|
|
if (PacketList != (PNDIS_PACKET)NULL)
|
|
{
|
|
AtmArpFreeSendPackets(
|
|
pInterface,
|
|
PacketList,
|
|
HdrPresent
|
|
);
|
|
}
|
|
|
|
//
|
|
// We would have allocated the Call Parameters in MakeCall().
|
|
// We don't need it anymore.
|
|
//
|
|
AA_FREE_MEM(pCallParameters);
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef IPMCAST
|
|
|
|
VOID
|
|
AtmArpMcMakeCallComplete(
|
|
IN PATMARP_ATM_ENTRY pAtmEntry,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Post-processing of a PMP MakeCall completion.
|
|
|
|
Arguments:
|
|
|
|
pAtmEntry - Represents the multicast group to which
|
|
the call was made.
|
|
NdisPartyHandle - Returned from the MakeCall.
|
|
Status - Result of the MakeCall
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_IPMC_ATM_ENTRY * ppMcAtmEntry;
|
|
PATMARP_IPMC_ATM_INFO pMcAtmInfo;
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
//
|
|
// Do we need to update the PMP connection as a result
|
|
// of this event?
|
|
//
|
|
BOOLEAN bWantConnUpdate;
|
|
ULONG DelayBeforeRetry;
|
|
BOOLEAN bAtmEntryLockAcquired;
|
|
|
|
bAtmEntryLockAcquired = TRUE;
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ASSERT(pAtmEntry->pMcAtmInfo != NULL_PATMARP_IPMC_ATM_INFO);
|
|
AA_ASSERT(pAtmEntry->pIpEntryList != NULL_PATMARP_IP_ENTRY);
|
|
|
|
pIpEntry = pAtmEntry->pIpEntryList;
|
|
pMcAtmInfo = pAtmEntry->pMcAtmInfo;
|
|
pInterface = pAtmEntry->pInterface;
|
|
|
|
bWantConnUpdate = FALSE;
|
|
|
|
pMcAtmInfo->TransientLeaves--;
|
|
|
|
//
|
|
// Locate the MC ATM Entry representing the first party.
|
|
//
|
|
for (pMcAtmEntry = pMcAtmInfo->pMcAtmEntryList;
|
|
/* NONE */;
|
|
pMcAtmEntry = pMcAtmEntry->pNextMcAtmEntry)
|
|
{
|
|
AA_ASSERT(pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY);
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_WACK_ADD_PARTY))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("McMakeCallComplete: pAtmEntry 0x%x, pMcAtmEntry 0x%x, Status 0x%x\n",
|
|
pAtmEntry, pMcAtmEntry, Status));
|
|
|
|
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD, "McMakeCall Addr: ", &pMcAtmEntry->ATMAddress);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pMcAtmInfo->ActiveLeaves++;
|
|
|
|
//
|
|
// Update Multicast state
|
|
//
|
|
AA_SET_FLAG(pMcAtmInfo->Flags,
|
|
AA_IPMC_AI_CONN_STATE_MASK,
|
|
AA_IPMC_AI_CONN_ACTIVE);
|
|
|
|
//
|
|
// Update state of "first party"
|
|
//
|
|
pMcAtmEntry->NdisPartyHandle = NdisPartyHandle;
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_ACTIVE);
|
|
|
|
bWantConnUpdate = TRUE;
|
|
|
|
//
|
|
// If we had decided to terminate this member when the
|
|
// MakeCall was going on, then we now mark this as Invalid.
|
|
// When we next update this PMP connection, this member will
|
|
// be removed.
|
|
//
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_TERMINATING))
|
|
{
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_INVALID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// A PMP call failed. If the failure is not "transient",
|
|
// we remove the member we were trying to connect to
|
|
// from the list. If there is atleast one more member
|
|
// that hasn't been attempted yet, try to connect to that.
|
|
//
|
|
|
|
AAMCDEBUGP(AAD_INFO, ("McMakeCall failed: pAtmEntry 0x%x, pMcAtmEntry 0x%x, Status 0x%x ",
|
|
pAtmEntry, pMcAtmEntry, Status));
|
|
AAMCDEBUGPATMADDR(AAD_INFO, " Addr: ", &pMcAtmEntry->ATMAddress);
|
|
|
|
//
|
|
// Update PMP connection state
|
|
//
|
|
AA_SET_FLAG(pAtmEntry->pMcAtmInfo->Flags,
|
|
AA_IPMC_AI_CONN_STATE_MASK,
|
|
AA_IPMC_AI_CONN_NONE);
|
|
|
|
|
|
if (AA_IS_TRANSIENT_FAILURE(Status))
|
|
{
|
|
//
|
|
// Update first party state.
|
|
//
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_TEMP_FAILURE);
|
|
|
|
DelayBeforeRetry = AA_GET_TIMER_DURATION(&(pMcAtmEntry->Timer));
|
|
if (DelayBeforeRetry == 0)
|
|
{
|
|
//
|
|
// First time we're doing this.
|
|
//
|
|
DelayBeforeRetry = AA_GET_RANDOM(
|
|
pInterface->MinPartyRetryDelay,
|
|
pInterface->MaxPartyRetryDelay);
|
|
}
|
|
else
|
|
{
|
|
DelayBeforeRetry = 2*DelayBeforeRetry;
|
|
}
|
|
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pMcAtmEntry->Timer),
|
|
AtmArpMcPartyRetryDelayTimeout,
|
|
DelayBeforeRetry,
|
|
(PVOID)pMcAtmEntry
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED);
|
|
|
|
AtmArpMcUnlinkAtmMember(
|
|
pAtmEntry,
|
|
pMcAtmEntry
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Look for a member that we haven't tried to connect to.
|
|
//
|
|
for (ppMcAtmEntry = &(pMcAtmInfo->pMcAtmEntryList);
|
|
*ppMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY;
|
|
ppMcAtmEntry = &((*ppMcAtmEntry)->pNextMcAtmEntry))
|
|
{
|
|
if (AA_IS_FLAG_SET((*ppMcAtmEntry)->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED))
|
|
{
|
|
//
|
|
// Found one.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*ppMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY)
|
|
{
|
|
pMcAtmEntry = *ppMcAtmEntry;
|
|
|
|
//
|
|
// Move this member to the top of the list.
|
|
// First, unlink from current position.
|
|
//
|
|
*ppMcAtmEntry = pMcAtmEntry->pNextMcAtmEntry;
|
|
|
|
//
|
|
// Now insert this at top of list.
|
|
//
|
|
pMcAtmEntry->pNextMcAtmEntry = pMcAtmInfo->pMcAtmEntryList;
|
|
pMcAtmInfo->pMcAtmEntryList = pMcAtmEntry;
|
|
|
|
bWantConnUpdate = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There is no ATM member that we haven't tried to connect to.
|
|
//
|
|
if (pMcAtmInfo->pMcAtmEntryList == NULL_PATMARP_IPMC_ATM_ENTRY)
|
|
{
|
|
//
|
|
// The list of ATM Members is empty.
|
|
//
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
AtmArpAbortIPEntry(pIpEntry);
|
|
//
|
|
// IE Lock is released within the above.
|
|
//
|
|
|
|
bAtmEntryLockAcquired = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (bWantConnUpdate)
|
|
{
|
|
AA_ASSERT(bAtmEntryLockAcquired == TRUE);
|
|
AtmArpMcUpdateConnection(pAtmEntry);
|
|
//
|
|
// AE Lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
if (bAtmEntryLockAcquired)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
|
|
|
|
VOID
|
|
AtmArpCloseCallCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles completion of a previous NdisClCloseCall.
|
|
It is assumed that Status is always NDIS_STATUS_SUCCESS.
|
|
|
|
We delete the VC on which the call was just closed.
|
|
|
|
Special case: if we just finished closing a PMP call for a multicast
|
|
group that has been told to migrate to a (possibly) new set of
|
|
addresses, start off a new connection now.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the Close Call.
|
|
ProtocolVcContext - Pointer to ATMARP VC structure.
|
|
ProtocolPartyContext - Not used.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_VC pVc;
|
|
PATMARP_VC * ppVc;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_INTERFACE pInterface;
|
|
#ifdef IPMCAST
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry; // represents the last leaf
|
|
PATMARP_IPMC_ATM_INFO pMcAtmInfo;
|
|
#endif // IPMCAST
|
|
ULONG rc; // Ref Count
|
|
NDIS_HANDLE NdisVcHandle;
|
|
BOOLEAN UpdatePMPConnection;
|
|
BOOLEAN AtmEntryIsClosing;
|
|
BOOLEAN IsMarsProblem;
|
|
BOOLEAN IsPVC;
|
|
BOOLEAN Found;
|
|
|
|
pVc = (PATMARP_VC)ProtocolVcContext;
|
|
AA_STRUCT_ASSERT(pVc, avc);
|
|
|
|
AADEBUGP(AAD_VERY_LOUD, ("CloseCallComplete: pVc 0x%x, Flags 0x%x, RefCount %d\n",
|
|
pVc, pVc->Flags, pVc->RefCount));
|
|
|
|
IsPVC = AA_IS_FLAG_SET(pVc->Flags, AA_VC_TYPE_MASK, AA_VC_TYPE_PVC);
|
|
|
|
//
|
|
// This VC may not be linked to an ATM Entry, e.g. for an unresolved
|
|
// Incoming PVC.
|
|
//
|
|
pAtmEntry = pVc->pAtmEntry;
|
|
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AtmEntryIsClosing = AA_IS_FLAG_SET(pAtmEntry->Flags,
|
|
AA_ATM_ENTRY_STATE_MASK,
|
|
AA_ATM_ENTRY_CLOSING);
|
|
}
|
|
else
|
|
{
|
|
AtmEntryIsClosing = FALSE;
|
|
}
|
|
|
|
pInterface = pVc->pInterface;
|
|
|
|
if (IsPVC)
|
|
{
|
|
//
|
|
// Take the PVC out of the unresolved VC list, if it
|
|
// exists there.
|
|
//
|
|
Found = FALSE;
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
ppVc = &(pInterface->pUnresolvedVcs);
|
|
while (*ppVc != NULL_PATMARP_VC)
|
|
{
|
|
if (*ppVc == pVc)
|
|
{
|
|
*ppVc = pVc->pNextVc;
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
ppVc = &((*ppVc)->pNextVc);
|
|
}
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
if (Found)
|
|
{
|
|
AADEBUGP(AAD_FATAL,
|
|
("CloseCallComplete: took VC (PVC) %x out of IF %x\n",
|
|
pVc, pInterface));
|
|
|
|
rc = AtmArpDereferenceVc(pVc); // Unresolved VC list
|
|
}
|
|
else
|
|
{
|
|
rc = pVc->RefCount;
|
|
}
|
|
|
|
if (rc == 0)
|
|
{
|
|
//
|
|
// The VC is gone!
|
|
//
|
|
AADEBUGP(AAD_WARNING,
|
|
("CloseCallComplete: VC (PVC) %x derefed away, IF %x\n",
|
|
pVc, pInterface));
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
}
|
|
|
|
#ifdef IPMCAST
|
|
|
|
//
|
|
// We have lost our connection to the MARS if this was the last
|
|
// VC going to that address. We should atleast be a party on
|
|
// ClusterControlVc.
|
|
//
|
|
IsMarsProblem = FALSE;
|
|
|
|
if (pInterface->AdminState == IF_STATUS_UP)
|
|
{
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
if (pAtmEntry->pVcList->pNextVc == NULL_PATMARP_VC)
|
|
{
|
|
if (pInterface->pCurrentMARS &&
|
|
(pInterface->pCurrentMARS->pAtmEntry == pAtmEntry))
|
|
{
|
|
IsMarsProblem = TRUE;
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
AtmArpReferenceInterface(pInterface);
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdatePMPConnection = FALSE;
|
|
|
|
pMcAtmEntry = (PATMARP_IPMC_ATM_ENTRY)ProtocolPartyContext;
|
|
|
|
//
|
|
// If this is a point-to-multipoint connection that was closed,
|
|
// handle unlinking the last leaf.
|
|
//
|
|
if (pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY)
|
|
{
|
|
//
|
|
// This is a PMP connection.
|
|
//
|
|
AAMCDEBUGP(AAD_LOUD, ("CloseCallComplete (MC): pAtmEntry 0x%x/0x%x\n",
|
|
pAtmEntry, pAtmEntry->Flags));
|
|
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED);
|
|
|
|
AtmArpMcUnlinkAtmMember(pAtmEntry, pMcAtmEntry);
|
|
|
|
pMcAtmInfo = pAtmEntry->pMcAtmInfo;
|
|
AA_ASSERT(pMcAtmInfo != NULL_PATMARP_IPMC_ATM_INFO);
|
|
|
|
//
|
|
// Make the new list of ATM stations (the "Migrate to" list)
|
|
// the current list. This might be NULL.
|
|
//
|
|
pMcAtmInfo->pMcAtmEntryList = pMcAtmInfo->pMcAtmMigrateList;
|
|
pMcAtmInfo->pMcAtmMigrateList = NULL_PATMARP_IPMC_ATM_ENTRY;
|
|
|
|
//
|
|
// If there is a non-empty migrate list, then we have
|
|
// to make a fresh PMP connection.
|
|
//
|
|
UpdatePMPConnection =
|
|
(pMcAtmInfo->pMcAtmEntryList != NULL_PATMARP_IPMC_ATM_ENTRY);
|
|
|
|
AA_SET_FLAG(pMcAtmInfo->Flags,
|
|
AA_IPMC_AI_CONN_STATE_MASK,
|
|
AA_IPMC_AI_CONN_NONE);
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
#endif // IPMCAST
|
|
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
if (pAtmEntry != NULL_PATMARP_ATM_ENTRY)
|
|
{
|
|
AtmArpUnlinkVcFromAtmEntry(pVc, TRUE);
|
|
rc = AtmArpDereferenceVc(pVc); // ATM Entry ref
|
|
AA_ASSERT(rc != 0);
|
|
}
|
|
|
|
rc = AtmArpDereferenceVc(pVc); // Call reference
|
|
AA_ASSERT(rc != 0); // CreateVc reference remains
|
|
AA_SET_FLAG(pVc->Flags,
|
|
AA_VC_CALL_STATE_MASK,
|
|
AA_VC_CALL_STATE_IDLE);
|
|
|
|
AA_ASSERT(pVc->PacketList == NULL);
|
|
|
|
//
|
|
// If this VC belongs to us, delete it.
|
|
//
|
|
if (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_OWNER_MASK,
|
|
AA_VC_OWNER_IS_ATMARP))
|
|
{
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
rc = AtmArpDereferenceVc(pVc); // Create Vc ref
|
|
if (rc != 0)
|
|
{
|
|
// Could still be temp refs...
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
else
|
|
{
|
|
// The VC has been deallocated, and lock released
|
|
}
|
|
|
|
#ifndef VC_REFS_ON_SENDS
|
|
//
|
|
// Delete the NDIS association
|
|
//
|
|
(VOID)NdisCoDeleteVc(NdisVcHandle);
|
|
#endif // VC_REFS_ON_SENDS
|
|
AADEBUGP(AAD_LOUD,
|
|
("CloseCallComplete: deleted NDIS VC on pVc 0x%x: NdisVcHandle 0x%x\n",
|
|
pVc, NdisVcHandle));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// VC belongs to the Call Manager -- take it back to the
|
|
// state it was when it was just created (via our CreateVcHandler).
|
|
// The Call Manager can either re-use it or delete it.
|
|
//
|
|
pVc->Flags = AA_VC_OWNER_IS_CALLMGR;
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
}
|
|
|
|
#ifdef IPMCAST
|
|
if (UpdatePMPConnection)
|
|
{
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("CloseCallComplete: pVc 0x%x, starting update on pAtmEntry 0x%x\n",
|
|
pVc, pAtmEntry));
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AtmArpMcUpdateConnection(pAtmEntry);
|
|
//
|
|
// AE Lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If this was a PMP connection, handle the case
|
|
// of a remote-initiated CloseCall: we need to
|
|
// unlink the ATM Entry from the IP Entry.
|
|
//
|
|
if ((pMcAtmEntry != NULL_PATMARP_IPMC_ATM_ENTRY) &&
|
|
!AtmEntryIsClosing)
|
|
{
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AtmArpInvalidateAtmEntry(pAtmEntry, FALSE); // CloseCallComplete
|
|
}
|
|
}
|
|
|
|
if (IsMarsProblem)
|
|
{
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
rc = AtmArpDereferenceInterface(pInterface);
|
|
if (rc != 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
AtmArpMcHandleMARSFailure(pInterface, FALSE);
|
|
}
|
|
//
|
|
// else the interface is gone.
|
|
//
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef IPMCAST
|
|
|
|
|
|
VOID
|
|
AtmArpAddPartyCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called on completion of a previous call to
|
|
NdisClAddParty. Since we don't use point-to-multipoint connections,
|
|
this should never get called.
|
|
|
|
If the AddParty was successful, we just update state and exit. If it
|
|
failed, we check the failure code. If this indicates a transient
|
|
failure condition, we start a timer so that we reattempt to add this
|
|
party later. Otherwise ("hard" failure), this multicast entry is deleted.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the AddParty
|
|
ProtocolPartyContext - Pointer to an IPMC_ATM_ENTRY structure
|
|
NdisPartyHandle - NDIS' handle for this party
|
|
pCallParameters - what we had passed to NdisClAddParty
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
PATMARP_VC pVc;
|
|
ULONG VcFlags;
|
|
PATMARP_INTERFACE pInterface;
|
|
ULONG DelayBeforeRetry;
|
|
BOOLEAN ClearToSend;
|
|
|
|
pMcAtmEntry = (PATMARP_IPMC_ATM_ENTRY)(ProtocolPartyContext);
|
|
AA_STRUCT_ASSERT(pMcAtmEntry, ame);
|
|
|
|
pAtmEntry = pMcAtmEntry->pAtmEntry;
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
|
|
pAtmEntry->pMcAtmInfo->TransientLeaves--;
|
|
|
|
pVc = pAtmEntry->pVcList;
|
|
VcFlags = pVc->Flags;
|
|
pInterface = pAtmEntry->pInterface;
|
|
|
|
AAMCDEBUGP(AAD_LOUD,
|
|
("AddPartyComplete: Status 0x%x, pAtmEntry 0x%x, pMcAtmEntry 0x%x, pVc 0x%x\n",
|
|
Status, pAtmEntry, pMcAtmEntry, pVc));
|
|
|
|
AAMCDEBUGPATMADDR(AAD_EXTRA_LOUD, "AddParty Addr: ", &pMcAtmEntry->ATMAddress);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_ACTIVE);
|
|
|
|
//
|
|
// If we had decided to terminate this member when the
|
|
// AddParty was going on, then we now mark this as Invalid.
|
|
// When we next update this PMP connection, this member will
|
|
// be removed.
|
|
//
|
|
if (AA_IS_FLAG_SET(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_TERMINATING))
|
|
{
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_GEN_STATE_MASK,
|
|
AA_IPMC_AE_INVALID);
|
|
}
|
|
|
|
pMcAtmEntry->NdisPartyHandle = NdisPartyHandle;
|
|
pAtmEntry->pMcAtmInfo->ActiveLeaves++;
|
|
}
|
|
else
|
|
{
|
|
AAMCDEBUGP(AAD_INFO,
|
|
("AddPartyComplete: Status 0x%x, pAtmEntry 0x%x, to ", Status, pAtmEntry));
|
|
AAMCDEBUGPATMADDR(AAD_INFO, "", &pMcAtmEntry->ATMAddress);
|
|
|
|
//
|
|
// Check if the failure was due to a transient
|
|
// condition.
|
|
//
|
|
if (AA_IS_TRANSIENT_FAILURE(Status))
|
|
{
|
|
//
|
|
// We'll fire a timer, so that we reattempt to
|
|
// connect to this one later. If we had already
|
|
// done this (i.e. time out on failure), then
|
|
// we include a back-off time in the delay.
|
|
//
|
|
DelayBeforeRetry = AA_GET_TIMER_DURATION(&(pMcAtmEntry->Timer));
|
|
if (DelayBeforeRetry == 0)
|
|
{
|
|
//
|
|
// First time we're doing this.
|
|
//
|
|
DelayBeforeRetry = AA_GET_RANDOM(
|
|
pInterface->MinPartyRetryDelay,
|
|
pInterface->MaxPartyRetryDelay);
|
|
}
|
|
else
|
|
{
|
|
DelayBeforeRetry = 2*DelayBeforeRetry;
|
|
}
|
|
|
|
AtmArpStartTimer(
|
|
pInterface,
|
|
&(pMcAtmEntry->Timer),
|
|
AtmArpMcPartyRetryDelayTimeout,
|
|
DelayBeforeRetry,
|
|
(PVOID)pMcAtmEntry
|
|
);
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_TEMP_FAILURE);
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not a transient failure. Delete this member.
|
|
//
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED);
|
|
|
|
AtmArpMcUnlinkAtmMember(
|
|
pAtmEntry,
|
|
pMcAtmEntry
|
|
);
|
|
}
|
|
}
|
|
|
|
ClearToSend = ((pAtmEntry->pMcAtmInfo->TransientLeaves == 0) &&
|
|
(AA_IS_FLAG_SET(pAtmEntry->pMcAtmInfo->Flags,
|
|
AA_IPMC_AI_CONN_STATE_MASK,
|
|
AA_IPMC_AI_CONN_ACTIVE)));
|
|
|
|
pIpEntry = pAtmEntry->pIpEntryList;
|
|
|
|
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
|
|
if (pCallParameters != (PCO_CALL_PARAMETERS)NULL)
|
|
{
|
|
AA_FREE_MEM(pCallParameters);
|
|
}
|
|
|
|
//
|
|
// Check if the VC is closing, and we had held back because
|
|
// this AddParty was in progress. If so, try to continue the
|
|
// CloseCall process.
|
|
//
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
if (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CLOSE_STATE_MASK,
|
|
AA_VC_CLOSE_STATE_CLOSING))
|
|
{
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// VC Lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
PNDIS_PACKET pPacketList;
|
|
|
|
AA_RELEASE_VC_LOCK(pVc);
|
|
|
|
if (ClearToSend && pIpEntry)
|
|
{
|
|
AA_ACQUIRE_IE_LOCK(pIpEntry);
|
|
AA_ASSERT(AA_IE_IS_ALIVE(pIpEntry));
|
|
pPacketList = pIpEntry->PacketList;
|
|
pIpEntry->PacketList = (PNDIS_PACKET)NULL;
|
|
AA_RELEASE_IE_LOCK(pIpEntry);
|
|
|
|
if (pPacketList != (PNDIS_PACKET)NULL)
|
|
{
|
|
AAMCDEBUGP(AAD_INFO, ("AddPtyCompl: pAtmEntry 0x%x, sending pktlist 0x%x\n",
|
|
pAtmEntry, pPacketList));
|
|
|
|
AtmArpSendPacketListOnAtmEntry(
|
|
pInterface,
|
|
pAtmEntry,
|
|
pPacketList,
|
|
TRUE // IsBroadcast
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
VOID
|
|
AtmArpAddPartyCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called on completion of a previous call to
|
|
NdisClAddParty. Since we don't use point-to-multipoint connections,
|
|
this should never get called.
|
|
|
|
Arguments:
|
|
|
|
<Don't care>
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AADEBUGP(AAD_ERROR, ("Add Party Complete unexpectedly called\n"));
|
|
AA_ASSERT(FALSE);
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpDropPartyCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called on completion of a previous call to
|
|
NdisClDropParty. We unlink our party structure and free it.
|
|
|
|
Arguments:
|
|
|
|
Status - Final result of the Drop Party
|
|
ProtocolPartyContext - Pointer to the MC ATM Entry we used
|
|
to represent the party.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
#ifdef IPMCAST
|
|
PATMARP_IPMC_ATM_ENTRY pMcAtmEntry;
|
|
PATMARP_ATM_ENTRY pAtmEntry;
|
|
PATMARP_IP_ENTRY pIpEntry;
|
|
ULONG rc;
|
|
BOOLEAN LockReleased;
|
|
|
|
AAMCDEBUGP(AAD_LOUD, ("DropPartyComplete: Status 0x%x, Context 0x%x\n",
|
|
Status, ProtocolPartyContext));
|
|
|
|
AA_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
|
|
pMcAtmEntry = (PATMARP_IPMC_ATM_ENTRY)ProtocolPartyContext;
|
|
AA_STRUCT_ASSERT(pMcAtmEntry, ame);
|
|
|
|
pAtmEntry = pMcAtmEntry->pAtmEntry;
|
|
AA_ASSERT(pAtmEntry != NULL_PATMARP_ATM_ENTRY);
|
|
AA_STRUCT_ASSERT(pAtmEntry, aae);
|
|
|
|
AA_ACQUIRE_AE_LOCK(pAtmEntry);
|
|
AA_REF_AE(pAtmEntry, AE_REFTYPE_TMP); // temp ref
|
|
|
|
AA_SET_FLAG(pMcAtmEntry->Flags,
|
|
AA_IPMC_AE_CONN_STATE_MASK,
|
|
AA_IPMC_AE_CONN_DISCONNECTED);
|
|
|
|
AtmArpMcUnlinkAtmMember(pAtmEntry, pMcAtmEntry);
|
|
|
|
//
|
|
// If we are in the processing of closing this PMP call,
|
|
// and this event signifies that all preliminary DropParty's
|
|
// are complete, then close the call itself.
|
|
//
|
|
LockReleased = FALSE;
|
|
rc = AA_DEREF_AE(pAtmEntry, AE_REFTYPE_TMP); // temp ref
|
|
|
|
if (rc != 0)
|
|
{
|
|
PATMARP_VC pVc;
|
|
|
|
pVc = pAtmEntry->pVcList;
|
|
if (pVc != NULL_PATMARP_VC)
|
|
{
|
|
if (AA_IS_FLAG_SET(pVc->Flags,
|
|
AA_VC_CLOSE_STATE_MASK,
|
|
AA_VC_CLOSE_STATE_CLOSING) &&
|
|
(pAtmEntry->pMcAtmInfo->NumOfEntries == 1))
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
AA_ACQUIRE_VC_LOCK(pVc);
|
|
|
|
AtmArpCloseCall(pVc);
|
|
//
|
|
// VC lock is released within the above.
|
|
//
|
|
LockReleased = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!LockReleased)
|
|
{
|
|
AA_RELEASE_AE_LOCK(pAtmEntry);
|
|
}
|
|
|
|
#endif // IPMCAST
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpModifyQosCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called on completion of a previous call to
|
|
NdisClModifyCallQoS. Since we don't call this, this should never
|
|
get called.
|
|
|
|
Arguments:
|
|
|
|
<Don't care>
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
AADEBUGP(AAD_ERROR, ("Modify QOS Complete unexpectedly called\n"));
|
|
AA_ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
#ifndef OID_CO_AF_CLOSE
|
|
#define OID_CO_AF_CLOSE 0xFE00000A
|
|
#endif
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpCoRequestHandler(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN OUT PNDIS_REQUEST pNdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS when our Call Manager sends us an
|
|
NDIS Request. NDIS Requests that are of significance to us are:
|
|
- OID_CO_ADDRESS_CHANGE
|
|
The set of addresses registered with the switch has changed,
|
|
i.e. address registration is complete. We issue an NDIS Request
|
|
ourselves to get the list of addresses registered.
|
|
- OID_CO_SIGNALING_ENABLED
|
|
We ignore this as of now.
|
|
- OID_CO_SIGNALING_DISABLED
|
|
We ignore this for now.
|
|
- OID_CO_AF_CLOSE
|
|
The Call Manager wants us to shut down this Interface.
|
|
|
|
We ignore all other OIDs.
|
|
|
|
Arguments:
|
|
|
|
ProtocolAfContext - Our context for the Address Family binding,
|
|
which is a pointer to the ATMARP Interface.
|
|
ProtocolVcContext - Our context for a VC, which is a pointer to
|
|
an ATMARP VC structure.
|
|
ProtocolPartyContext - Our context for a Party. Since we don't do
|
|
PMP, this is ignored (must be NULL).
|
|
pNdisRequest - Pointer to the NDIS Request.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if we recognized the OID
|
|
NDIS_STATUS_NOT_RECOGNIZED if we didn't.
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
NDIS_STATUS Status;
|
|
|
|
pInterface = (PATMARP_INTERFACE)ProtocolAfContext;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
//
|
|
// Initialize
|
|
//
|
|
Status = NDIS_STATUS_NOT_RECOGNIZED;
|
|
|
|
if (pNdisRequest->RequestType == NdisRequestSetInformation)
|
|
{
|
|
switch (pNdisRequest->DATA.SET_INFORMATION.Oid)
|
|
{
|
|
case OID_CO_ADDRESS_CHANGE:
|
|
//
|
|
// The Call Manager says that the list of addresses
|
|
// registered on this interface has changed. Get the
|
|
// (potentially) new ATM address for this interface.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
pInterface->AtmInterfaceUp = FALSE;
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
AtmArpGetAtmAddress(pInterface);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_CO_SIGNALING_ENABLED: // FALLTHRU
|
|
case OID_CO_SIGNALING_DISABLED:
|
|
// Ignored for now
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_CO_AF_CLOSE:
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
pInterface->AdminState = pInterface->State = IF_STATUS_DOWN;
|
|
pInterface->LastChangeTime = GetTimeTicks();
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
AtmArpShutdownInterface(pInterface);
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpCoRequestCompleteHandler(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN PNDIS_REQUEST pNdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by NDIS when a previous call to NdisCoRequest
|
|
that had pended, is complete. We handle this based on the request
|
|
we had sent, which has to be one of:
|
|
- OID_CO_GET_ADDRESSES
|
|
Get all addresses registered on the specified AF binding.
|
|
|
|
Arguments:
|
|
|
|
Status - Status of the Request.
|
|
ProtocolAfContext - Our context for the Address Family binding,
|
|
which is a pointer to the ATMARP Interface.
|
|
ProtocolVcContext - Our context for a VC, which is a pointer to
|
|
an ATMARP VC structure.
|
|
ProtocolPartyContext - Our context for a Party. Since we don't do
|
|
PMP, this is ignored (must be NULL).
|
|
pNdisRequest - Pointer to the NDIS Request.
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_INTERFACE pInterface;
|
|
ULONG Oid;
|
|
|
|
pInterface = (PATMARP_INTERFACE)ProtocolAfContext;
|
|
AA_STRUCT_ASSERT(pInterface, aai);
|
|
|
|
if (pNdisRequest->RequestType == NdisRequestQueryInformation)
|
|
{
|
|
switch (pNdisRequest->DATA.QUERY_INFORMATION.Oid)
|
|
{
|
|
case OID_CO_GET_ADDRESSES:
|
|
AtmArpHandleGetAddressesComplete(
|
|
Status,
|
|
pInterface,
|
|
pNdisRequest
|
|
);
|
|
break;
|
|
|
|
default:
|
|
AADEBUGP(AAD_ERROR,
|
|
("CoRequestComplete: pNdisReq 0x%x, unknown Query Oid 0x%x\n",
|
|
pNdisRequest,
|
|
pNdisRequest->DATA.QUERY_INFORMATION.Oid));
|
|
AA_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Oid = pNdisRequest->DATA.QUERY_INFORMATION.Oid;
|
|
switch (Oid)
|
|
{
|
|
case OID_CO_ADD_ADDRESS: // FALLTHRU
|
|
case OID_CO_DELETE_ADDRESS:
|
|
AtmArpHandleModAddressComplete(
|
|
Status,
|
|
pInterface,
|
|
pNdisRequest,
|
|
Oid
|
|
);
|
|
break;
|
|
|
|
default:
|
|
AADEBUGP(AAD_ERROR,
|
|
("CoRequestComplete: pNdisReq 0x%x, unknown Set Oid 0x%x\n",
|
|
pNdisRequest, Oid));
|
|
AA_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
AA_FREE_MEM(pNdisRequest);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpGetAtmAddress(
|
|
IN PATMARP_INTERFACE pInterface
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a request to the Call Manager to retrieve the ATM address
|
|
registered with the switch on the given interface.
|
|
|
|
This is called when the Call Manager tells us that there has been
|
|
a change in its list of addresses registered with the switch.
|
|
Normally, this happens when we start up our signalling stack (i.e.
|
|
initial address registration), but it might happen during runtime,
|
|
for example, if the link goes down and up, or we get physically
|
|
connected to a different switch...
|
|
|
|
In any case, we issue an NDIS Request to the Call Manager to retrieve
|
|
the first address it has registered. Action then continues in
|
|
AtmArpHandleGetAddressesComplete.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Interface structure for which this event occurred.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_REQUEST pNdisRequest;
|
|
NDIS_HANDLE NdisAfHandle;
|
|
NDIS_HANDLE NdisAdapterHandle;
|
|
NDIS_STATUS Status;
|
|
|
|
PCO_ADDRESS_LIST pAddressList;
|
|
ULONG RequestSize;
|
|
|
|
AADEBUGP(AAD_INFO, ("GetAtmAddress: pIf 0x%x\n", pInterface));
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
NdisAfHandle = pInterface->NdisAfHandle;
|
|
NdisAdapterHandle = pInterface->NdisAdapterHandle;
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
RequestSize = sizeof(CO_ADDRESS_LIST) + sizeof(CO_ADDRESS) + sizeof(ATM_ADDRESS);
|
|
|
|
//
|
|
// Allocate all that we need.
|
|
//
|
|
AA_ALLOC_MEM(pNdisRequest, NDIS_REQUEST, sizeof(NDIS_REQUEST)+RequestSize);
|
|
if (pNdisRequest != (PNDIS_REQUEST)NULL)
|
|
{
|
|
pAddressList = (PCO_ADDRESS_LIST)((PUCHAR)pNdisRequest + sizeof(NDIS_REQUEST));
|
|
|
|
AA_SET_MEM(pAddressList, 0, sizeof(CO_ADDRESS_LIST));
|
|
|
|
Status = AtmArpSendNdisCoRequest(
|
|
NdisAdapterHandle,
|
|
NdisAfHandle,
|
|
pNdisRequest,
|
|
NdisRequestQueryInformation,
|
|
OID_CO_GET_ADDRESSES,
|
|
(PVOID)pAddressList,
|
|
RequestSize
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
AtmArpCoRequestCompleteHandler(
|
|
Status,
|
|
(NDIS_HANDLE)pInterface, // ProtocolAfContext
|
|
NULL, // Vc Context
|
|
NULL, // Party Context
|
|
pNdisRequest
|
|
);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpHandleGetAddressesComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PNDIS_REQUEST pNdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when we have a reply to our previous call to
|
|
NdisCoRequest(OID_CO_GET_ADDRESSES). Check if we got any addresses
|
|
back: if we did, store the address as our Local ATM Address, and
|
|
if conditions are ripe, start registering ourselves with the ARP
|
|
server.
|
|
|
|
Since we allocated the NDIS request, free it here.
|
|
|
|
Arguments:
|
|
|
|
Status - result of the request
|
|
pInterface - ATMARP interface on which the request was issued
|
|
pNdisRequest - the request itself. This will also contain the
|
|
returned address.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCO_ADDRESS_LIST pAddressList;
|
|
ATM_ADDRESS UNALIGNED * pAtmAddress;
|
|
|
|
AADEBUGP(AAD_LOUD, ("GetAddr complete: pIf 0x%x, Status 0x%x\n",
|
|
pInterface, Status));
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pAddressList = (PCO_ADDRESS_LIST)
|
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer;
|
|
|
|
AADEBUGP(AAD_LOUD, ("GetAddr complete: pIf 0x%x, Count %d\n",
|
|
pInterface, pAddressList->NumberOfAddresses));
|
|
|
|
if (pAddressList->NumberOfAddresses > 0)
|
|
{
|
|
//
|
|
// We have atleast one address here. Copy it in.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
pAtmAddress = (ATM_ADDRESS UNALIGNED *)(pAddressList->AddressList.Address);
|
|
AA_COPY_MEM((PUCHAR)&(pInterface->LocalAtmAddress),
|
|
(PUCHAR)pAtmAddress,
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
//
|
|
// Patch the selector byte with whatever is configured for
|
|
// this LIS.
|
|
//
|
|
pInterface->LocalAtmAddress.Address[ATM_ADDRESS_LENGTH-1] =
|
|
(UCHAR)(pInterface->SapSelector);
|
|
|
|
pInterface->AtmInterfaceUp = TRUE;
|
|
|
|
//
|
|
// To force registration:
|
|
//
|
|
AA_SET_FLAG(
|
|
pInterface->Flags,
|
|
AA_IF_SERVER_STATE_MASK,
|
|
AA_IF_SERVER_NO_CONTACT);
|
|
|
|
AtmArpStartRegistration(pInterface);
|
|
//
|
|
// The IF lock is released within the above.
|
|
//
|
|
|
|
#ifdef IPMCAST
|
|
//
|
|
// Attempt to start our Multicast side, too.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
AtmArpMcStartRegistration(pInterface);
|
|
//
|
|
// IF Lock is released within the above.
|
|
//
|
|
#endif // IPMCAST
|
|
|
|
//
|
|
// Add any (additional) addresses we want to register with
|
|
// the switch now.
|
|
//
|
|
AtmArpUpdateAddresses(
|
|
pInterface,
|
|
TRUE // Add them
|
|
);
|
|
}
|
|
//
|
|
// else no address is registered currently.
|
|
//
|
|
}
|
|
//
|
|
// else our request failed! Wait for another ADDRESS_CHANGE.
|
|
//
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtmArpUpdateAddresses(
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN BOOLEAN AddThem
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the list of addresses we want the Call manager to register
|
|
with the switch: either add addresses or delete them. We do this
|
|
only if we are running in an SVC environment.
|
|
|
|
Arguments:
|
|
|
|
pInterface - Pointer to ATMARP Interface
|
|
AddThem - TRUE if caller wants us to add addresses,
|
|
FALSE if caller wats us to delete them.
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_SAP pAtmArpSap;
|
|
PATMARP_SAP pNextSap;
|
|
PATM_SAP pAtmSap;
|
|
PATM_ADDRESS pAtmAddress;
|
|
PCO_ADDRESS pCoAddress;
|
|
PNDIS_REQUEST pNdisRequest;
|
|
NDIS_HANDLE NdisAfHandle;
|
|
NDIS_HANDLE NdisAdapterHandle;
|
|
NDIS_OID Oid;
|
|
ULONG BufferLength;
|
|
NDIS_STATUS Status;
|
|
BOOLEAN StateIsOkay; // Does the current state allow this request
|
|
ULONG rc; // Ref count
|
|
|
|
StateIsOkay = TRUE;
|
|
|
|
BufferLength = sizeof(CO_ADDRESS) + sizeof(ATM_ADDRESS);
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
NdisAfHandle = pInterface->NdisAfHandle;
|
|
NdisAdapterHandle = pInterface->NdisAdapterHandle;
|
|
|
|
if (AddThem)
|
|
{
|
|
Oid = OID_CO_ADD_ADDRESS;
|
|
//
|
|
// This is allowed only if the AdminState for the interface
|
|
// is UP.
|
|
//
|
|
if (pInterface->AdminState != IF_STATUS_UP)
|
|
{
|
|
StateIsOkay = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Oid = OID_CO_DELETE_ADDRESS;
|
|
}
|
|
|
|
//
|
|
// Check all pre-conditions before progressing.
|
|
//
|
|
if (!(pInterface->PVCOnly) &&
|
|
(StateIsOkay) &&
|
|
(pInterface->AtmInterfaceUp) &&
|
|
(pInterface->NumberOfSaps > 1))
|
|
{
|
|
AA_ASSERT(pInterface->SapList.pNextSap != NULL_PATMARP_SAP);
|
|
|
|
//
|
|
// Reference the Interface so that it doesn't go away.
|
|
//
|
|
AtmArpReferenceInterface(pInterface);
|
|
pAtmArpSap = pInterface->SapList.pNextSap;
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
|
|
do
|
|
{
|
|
if (AA_IS_FLAG_SET(
|
|
pAtmArpSap->Flags,
|
|
AA_SAP_ADDRTYPE_MASK,
|
|
AA_SAP_ADDRTYPE_NEED_ADD))
|
|
{
|
|
//
|
|
// This SAP is of the type that needs to be added/deleted
|
|
// via ILMI
|
|
//
|
|
AA_ALLOC_MEM(
|
|
pNdisRequest,
|
|
NDIS_REQUEST,
|
|
sizeof(NDIS_REQUEST)+
|
|
sizeof(CO_ADDRESS)+
|
|
sizeof(ATM_ADDRESS)
|
|
);
|
|
|
|
if (pNdisRequest != (PNDIS_REQUEST)NULL)
|
|
{
|
|
AA_SET_MEM(pNdisRequest, 0, sizeof(NDIS_REQUEST));
|
|
//
|
|
// Stuff in our context for this request, which is a pointer
|
|
// to this ATMARP SAP, into the ProtocolReserved part of
|
|
// this request, so that we can handle completion easily.
|
|
//
|
|
*((PVOID *)(pNdisRequest->ProtocolReserved)) = (PVOID)pAtmArpSap;
|
|
|
|
pCoAddress = (PCO_ADDRESS)((PUCHAR)pNdisRequest + sizeof(NDIS_REQUEST));
|
|
pCoAddress->AddressSize = sizeof(ATM_ADDRESS);
|
|
BufferLength = sizeof(CO_ADDRESS) + sizeof(ATM_ADDRESS);
|
|
|
|
//
|
|
// Save a pointer to the next SAP
|
|
//
|
|
pNextSap = pAtmArpSap->pNextSap;
|
|
|
|
//
|
|
// Get at the ATM address in this SAP.
|
|
//
|
|
pAtmSap = (PATM_SAP)(pAtmArpSap->pInfo->Sap);
|
|
AA_ASSERT(pAtmSap->NumberOfAddresses > 0);
|
|
pAtmAddress = (PATM_ADDRESS)(pAtmSap->Addresses);
|
|
|
|
AA_COPY_MEM(pCoAddress->Address, pAtmAddress, sizeof(ATM_ADDRESS));
|
|
Status = AtmArpSendNdisCoRequest(
|
|
NdisAdapterHandle,
|
|
NdisAfHandle,
|
|
pNdisRequest,
|
|
NdisRequestSetInformation,
|
|
Oid,
|
|
(PVOID)pCoAddress,
|
|
BufferLength
|
|
);
|
|
|
|
//
|
|
// Go to the next SAP in the list.
|
|
//
|
|
pAtmArpSap = pNextSap;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Out of resources.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (pAtmArpSap != NULL_PATMARP_SAP);
|
|
|
|
//
|
|
// Remove the reference we added earlier on.
|
|
//
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
rc = AtmArpDereferenceInterface(pInterface);
|
|
if (rc > 0)
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
//
|
|
// else the Interface is gone!
|
|
}
|
|
else
|
|
{
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
AtmArpHandleModAddressComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN PATMARP_INTERFACE pInterface,
|
|
IN PNDIS_REQUEST pNdisRequest,
|
|
IN ULONG Oid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when we have a reply to our previous call to
|
|
NdisCoRequest(OID_CO_ADD_ADDRESS or OID_CO_DELETE_ADDRESS).
|
|
All we do now is to update the state on the ATMARP SAP.
|
|
|
|
Arguments:
|
|
|
|
Status - the result of our request.
|
|
pInterface - ATMARP interface pointer.
|
|
pNdisRequest - the request we had sent.
|
|
Oid - CO_OID_ADD_ADDRESS or CO_OID_DELETE_ADDRESS
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PATMARP_SAP pAtmArpSap;
|
|
|
|
pAtmArpSap = (PATMARP_SAP)(*((PVOID *)(pNdisRequest->ProtocolReserved)));
|
|
AA_STRUCT_ASSERT(pAtmArpSap, aas);
|
|
|
|
AA_ACQUIRE_IF_LOCK(pInterface);
|
|
|
|
//
|
|
// Update the state on this ATMARP SAP.
|
|
//
|
|
if ((Oid == OID_CO_ADD_ADDRESS) && (Status == NDIS_STATUS_SUCCESS))
|
|
{
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_ILMI_STATE_MASK,
|
|
AA_SAP_ILMI_STATE_ADDED);
|
|
}
|
|
else
|
|
{
|
|
AA_SET_FLAG(pAtmArpSap->Flags,
|
|
AA_SAP_ILMI_STATE_MASK,
|
|
AA_SAP_ILMI_STATE_IDLE);
|
|
}
|
|
|
|
AA_RELEASE_IF_LOCK(pInterface);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
AtmArpSendNdisCoRequest(
|
|
IN NDIS_HANDLE NdisAdapterHandle,
|
|
IN NDIS_HANDLE NdisAfHandle,
|
|
IN PNDIS_REQUEST pNdisRequest,
|
|
IN NDIS_REQUEST_TYPE RequestType,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID pBuffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send an NDIS Connection Oriented request to the Call Manager. We
|
|
allocate an NDIS_REQUEST structure, link the supplied buffer to it,
|
|
and send the request. If the request does not pend, we call our
|
|
completion routine from here.
|
|
|
|
Arguments:
|
|
|
|
NdisAdapterHandle - Binding Handle to be used in the request
|
|
NdisAfHandle - AF Handle value to be used in the request
|
|
pNdisRequest - Pointer to NDIS request structure
|
|
RequestType - Set/Query information
|
|
Oid - OID to be passed in the request
|
|
pBuffer - place for value(s)
|
|
BufferLength - length of above
|
|
|
|
Return Value:
|
|
|
|
Status of the NdisCoRequest.
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Fill in the NDIS Request structure
|
|
//
|
|
pNdisRequest->RequestType = RequestType;
|
|
if (RequestType == NdisRequestQueryInformation)
|
|
{
|
|
pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
|
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer;
|
|
pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
|
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
|
pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength;
|
|
}
|
|
else
|
|
{
|
|
pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
|
|
pNdisRequest->DATA.SET_INFORMATION.InformationBuffer = pBuffer;
|
|
pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
|
|
pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
|
|
pNdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;
|
|
}
|
|
|
|
Status = NdisCoRequest(
|
|
NdisAdapterHandle,
|
|
NdisAfHandle,
|
|
NULL, // No VC handle
|
|
NULL, // No Party Handle
|
|
pNdisRequest);
|
|
|
|
return (Status);
|
|
}
|