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.
2831 lines
60 KiB
2831 lines
60 KiB
/*++
|
|
|
|
Copyright (c) 1992-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ndis.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the code to implement the initialization
|
|
functions for the atmarp server.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder ([email protected]) July 1996
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#define _FILENUM_ FILENUM_NDIS
|
|
|
|
NTSTATUS
|
|
ArpSInitializeNdis(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
NDIS_PROTOCOL_CHARACTERISTICS Chars;
|
|
UINT i, j;
|
|
PUCHAR pTmp;
|
|
|
|
do
|
|
{
|
|
INITIALIZE_SPIN_LOCK(&ArpSPktListLock);
|
|
ExInitializeSListHead(&ArpSPktList);
|
|
|
|
//
|
|
// Start off by allocating packets, mdls and buffer space
|
|
//
|
|
NdisAllocatePacketPoolEx(&Status,
|
|
&ArpSPktPoolHandle,
|
|
ArpSBuffers,
|
|
ArpSBuffers * (MAX_DESC_MULTIPLE-1),
|
|
sizeof(PROTOCOL_RESD));
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
{
|
|
INT SkipAll = 0;
|
|
|
|
DBGPRINT(DBG_LEVEL_ERROR, ("SkipAll = 0x%p.\n", &SkipAll));
|
|
DbgBreakPoint();
|
|
|
|
if (SkipAll)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_ERROR, ("ABORTING ATMARPS\n"));
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
}
|
|
#endif // 0
|
|
|
|
NdisAllocateBufferPool(&Status,
|
|
&ArpSBufPoolHandle,
|
|
ArpSBuffers);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisAllocatePacketPoolEx(&Status,
|
|
&MarsPktPoolHandle,
|
|
MarsPackets,
|
|
MarsPackets * (MAX_DESC_MULTIPLE-1),
|
|
sizeof(PROTOCOL_RESD));
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NdisAllocateBufferPool(&Status,
|
|
&MarsBufPoolHandle,
|
|
ArpSBuffers);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ArpSBufferSpace = ALLOC_NP_MEM(ArpSBuffers*PKT_SPACE, POOL_TAG_BUF);
|
|
if (ArpSBufferSpace == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now that we have the packets and the buffer descriptors, allocate memory for the each of the packets
|
|
// and queue them up in the global list. Fail only if no packets initialized.
|
|
//
|
|
for (i = 0, pTmp = ArpSBufferSpace;
|
|
i < ArpSBuffers;
|
|
i++, pTmp += PKT_SPACE)
|
|
{
|
|
PNDIS_PACKET Pkt;
|
|
PNDIS_BUFFER Buf;
|
|
PPROTOCOL_RESD Resd;
|
|
|
|
//
|
|
// The packet pool is already allocated. NdisAllocatePacket cannot fail.
|
|
//
|
|
NdisAllocatePacket(&Status, &Pkt, ArpSPktPoolHandle);
|
|
ASSERT (Status == NDIS_STATUS_SUCCESS);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DbgPrint("ATMARPS: failed to alloc pkt from %p\n", ArpSPktPoolHandle);
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
Resd = RESD_FROM_PKT(Pkt);
|
|
InitializeListHead(&Resd->ReqList);
|
|
NdisAllocateBuffer(&Status,
|
|
&Buf,
|
|
ArpSBufPoolHandle,
|
|
pTmp,
|
|
PKT_SPACE);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisChainBufferAtFront(Pkt, Buf);
|
|
ExInterlockedPushEntrySList(&ArpSPktList,
|
|
&Resd->FreeList,
|
|
&ArpSPktListLock);
|
|
}
|
|
else
|
|
{
|
|
NdisFreePacket(Pkt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == 0)
|
|
{
|
|
//
|
|
// We could not initialize even one packet, quit.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Now register with NDIS as a protocol. We do this last since we
|
|
// must be ready to accept incoming bind notifications
|
|
//
|
|
RtlZeroMemory(&Chars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
|
|
Chars.MajorNdisVersion = 5;
|
|
Chars.MinorNdisVersion = 0;
|
|
Chars.OpenAdapterCompleteHandler = ArpSOpenAdapterComplete;
|
|
Chars.CloseAdapterCompleteHandler = ArpSCloseAdapterComplete;
|
|
Chars.StatusHandler = ArpSStatus;
|
|
Chars.RequestCompleteHandler = ArpSRequestComplete;
|
|
Chars.ReceiveCompleteHandler = ArpSReceiveComplete;
|
|
Chars.StatusCompleteHandler = ArpSStatusComplete;
|
|
Chars.BindAdapterHandler = ArpSBindAdapter;
|
|
Chars.UnbindAdapterHandler = ArpSUnbindAdapter;
|
|
Chars.PnPEventHandler = ArpSPnPEventHandler;
|
|
|
|
Chars.CoSendCompleteHandler = ArpSCoSendComplete;
|
|
Chars.CoStatusHandler = ArpSCoStatus;
|
|
Chars.CoReceivePacketHandler = ArpSHandleArpRequest;
|
|
Chars.CoAfRegisterNotifyHandler = ArpSCoAfRegisterNotify;
|
|
|
|
RtlInitUnicodeString(&Chars.Name, SERVICE_NAME);
|
|
|
|
NdisRegisterProtocol(&Status, &ArpSProtocolHandle, &Chars, sizeof(Chars));
|
|
} while (FALSE);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
ArpSDeinitializeNdis();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSDeinitializeNdis(
|
|
VOID
|
|
)
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_PACKET Packet;
|
|
PSLIST_ENTRY Entry;
|
|
PPROTOCOL_RESD Resd;
|
|
|
|
if (ArpSProtocolHandle != NULL)
|
|
{
|
|
NdisDeregisterProtocol(&Status, ArpSProtocolHandle);
|
|
ArpSProtocolHandle = NULL;
|
|
}
|
|
|
|
while ((Entry = ExInterlockedPopEntrySList(&ArpSPktList, &ArpSPktListLock)) != NULL)
|
|
{
|
|
Resd = CONTAINING_RECORD(Entry, PROTOCOL_RESD, FreeList);
|
|
Packet = CONTAINING_RECORD(Resd, NDIS_PACKET, ProtocolReserved);
|
|
NdisFreeBuffer(Packet->Private.Head);
|
|
NdisFreePacket(Packet);
|
|
}
|
|
|
|
if (ArpSBufPoolHandle != NULL)
|
|
{
|
|
NdisFreeBufferPool(ArpSBufPoolHandle);
|
|
ArpSBufPoolHandle = NULL;
|
|
}
|
|
|
|
if (ArpSPktPoolHandle != NULL)
|
|
{
|
|
NdisFreePacketPool(ArpSPktPoolHandle);
|
|
ArpSPktPoolHandle = NULL;
|
|
}
|
|
|
|
if (MarsBufPoolHandle != NULL)
|
|
{
|
|
NdisFreeBufferPool(MarsBufPoolHandle);
|
|
MarsBufPoolHandle = NULL;
|
|
}
|
|
|
|
if (MarsPktPoolHandle != NULL)
|
|
{
|
|
NdisFreePacketPool(MarsPktPoolHandle);
|
|
MarsPktPoolHandle = NULL;
|
|
}
|
|
|
|
if (ArpSBufferSpace != NULL)
|
|
{
|
|
FREE_MEM(ArpSBufferSpace);
|
|
ArpSBufferSpace = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSBindAdapter(
|
|
OUT PNDIS_STATUS Status,
|
|
IN NDIS_HANDLE BindContext,
|
|
IN PNDIS_STRING DeviceName,
|
|
IN PVOID SystemSpecific1,
|
|
IN PVOID SystemSpecific2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle incoming bind requests here. Open the adapter, read the per-adapter registry and
|
|
initialize the binding.
|
|
|
|
Arguments:
|
|
|
|
Status Placeholder for returning status
|
|
BindContext Opaque blob to call NdisBindAdapterComplete if we pend this
|
|
DeviceName The adapter name which we should bind to
|
|
SystemSpecific1 To be used with NdisOpenProtocolConfiguration, if the per-adapter
|
|
configuration information is stored with the adapter
|
|
SystemSpecific2 Not currently used.
|
|
|
|
Return Value:
|
|
|
|
Status of the per-adapter initialization
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF;
|
|
NDIS_STATUS OpenErrorStatus;
|
|
UINT SelectedMedium;
|
|
NDIS_MEDIUM SupportedMedium = NdisMediumAtm;
|
|
KIRQL EntryIrql;
|
|
|
|
ARPS_GET_IRQL(&EntryIrql);
|
|
|
|
//
|
|
// Allocate an Interface block and initialize it
|
|
//
|
|
pIntF = ArpSCreateIntF(DeviceName, (PNDIS_STRING)SystemSpecific1, BindContext);
|
|
if (pIntF != NULL)
|
|
{
|
|
//
|
|
// Save the binding context
|
|
//
|
|
pIntF->NdisBindContext = BindContext;
|
|
|
|
*Status = ArpSReadAdapterConfiguration(pIntF);
|
|
|
|
if (*Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Read the Arp cache in now. We prime the arp table to start off.
|
|
//
|
|
if (ArpSFlushTime != 0)
|
|
{
|
|
ArpSReadArpCache(pIntF);
|
|
}
|
|
|
|
//
|
|
// Open the adapter and see if it is interesting to us (mediatype should be atm)
|
|
//
|
|
NdisOpenAdapter(Status,
|
|
&OpenErrorStatus,
|
|
&pIntF->NdisBindingHandle,
|
|
&SelectedMedium,
|
|
&pIntF->SupportedMedium,
|
|
sizeof(NDIS_MEDIUM),
|
|
ArpSProtocolHandle,
|
|
pIntF,
|
|
DeviceName,
|
|
0,
|
|
NULL);
|
|
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
if (*Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSOpenAdapterComplete(pIntF, *Status, OpenErrorStatus);
|
|
}
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
|
|
*Status = NDIS_STATUS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Could not read per-adapter registry. Use defaults.
|
|
//
|
|
LOG_ERROR(*Status);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*Status = NDIS_STATUS_RESOURCES;
|
|
LOG_ERROR(Status);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSOpenAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_STATUS OpenErrorStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Upcall from NDIS to signal completion of a NdisOpenAdapter() call.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to the pIntF
|
|
Status Status of NdisOpenAdapter
|
|
OpenErrorStatus Adapter's code
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolBindingContext;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// First complete the pending bind call.
|
|
//
|
|
NdisCompleteBindAdapter(pIntF->NdisBindContext, Status, OpenErrorStatus);
|
|
pIntF->NdisBindContext = NULL; // We do not need this anymore
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// NdisOpenAdapter() failed - log an error and exit
|
|
//
|
|
LOG_ERROR(Status);
|
|
ArpSCloseAdapterComplete(pIntF, Status);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Insert this into the global adapter list
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&ArpSIfListLock, &OldIrql);
|
|
{
|
|
PINTF pTmpIntF;
|
|
|
|
for (pTmpIntF = ArpSIfList;
|
|
pTmpIntF != NULL;
|
|
pTmpIntF = pTmpIntF->Next)
|
|
{
|
|
if (pTmpIntF == pIntF)
|
|
{
|
|
DbgPrint("ATMARPS: OpenAdComp: IntF %p already in list!\n",
|
|
pTmpIntF);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK_DPC(&pIntF->Lock);
|
|
|
|
pIntF->Flags |= INTF_ADAPTER_OPENED;
|
|
pIntF->Next = ArpSIfList;
|
|
ArpSIfList = pIntF;
|
|
ArpSIfListSize++;
|
|
|
|
RELEASE_SPIN_LOCK_DPC(&pIntF->Lock);
|
|
RELEASE_SPIN_LOCK(&ArpSIfListLock, OldIrql);
|
|
|
|
ArpSQueryAdapter(pIntF);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCoAfRegisterNotify(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PCO_ADDRESS_FAMILY AddressFamily
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolBindingContext;
|
|
NDIS_STATUS Status;
|
|
NDIS_CLIENT_CHARACTERISTICS Chars;
|
|
KIRQL EntryIrql;
|
|
|
|
ARPS_GET_IRQL(&EntryIrql);
|
|
|
|
if ((AddressFamily->AddressFamily == CO_ADDRESS_FAMILY_Q2931) &&
|
|
(AddressFamily->MajorVersion == 3) &&
|
|
(AddressFamily->MinorVersion == 1) &&
|
|
(pIntF->NdisAfHandle == NULL) )
|
|
{
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("AfNotify: IntF %x, Name %Z\n", pIntF, &pIntF->InterfaceName));
|
|
|
|
if (ArpSReferenceIntF(pIntF))
|
|
{
|
|
//
|
|
// We successfully opened the adapter. Now open the address-family
|
|
//
|
|
pIntF->AddrFamily.AddressFamily = CO_ADDRESS_FAMILY_Q2931;
|
|
pIntF->AddrFamily.MajorVersion = 3;
|
|
pIntF->AddrFamily.MinorVersion = 1;
|
|
|
|
ZERO_MEM(&Chars, sizeof(NDIS_CLIENT_CHARACTERISTICS));
|
|
Chars.MajorVersion = 5;
|
|
Chars.MinorVersion = 0;
|
|
Chars.ClCreateVcHandler = ArpSCreateVc;
|
|
Chars.ClDeleteVcHandler = ArpSDeleteVc;
|
|
Chars.ClRequestHandler = ArpSCoRequest;
|
|
Chars.ClRequestCompleteHandler = ArpSCoRequestComplete;
|
|
Chars.ClOpenAfCompleteHandler = ArpSOpenAfComplete;
|
|
Chars.ClCloseAfCompleteHandler = ArpSCloseAfComplete;
|
|
Chars.ClRegisterSapCompleteHandler = ArpSRegisterSapComplete;
|
|
Chars.ClDeregisterSapCompleteHandler = ArpSDeregisterSapComplete;
|
|
Chars.ClMakeCallCompleteHandler = ArpSMakeCallComplete;
|
|
Chars.ClModifyCallQoSCompleteHandler = NULL;
|
|
Chars.ClCloseCallCompleteHandler = ArpSCloseCallComplete;
|
|
Chars.ClAddPartyCompleteHandler = ArpSAddPartyComplete;
|
|
Chars.ClDropPartyCompleteHandler = ArpSDropPartyComplete;
|
|
Chars.ClIncomingCallHandler = ArpSIncomingCall;
|
|
Chars.ClIncomingCallQoSChangeHandler = ArpSIncomingCallQoSChange;
|
|
Chars.ClIncomingCloseCallHandler = ArpSIncomingCloseCall;
|
|
Chars.ClIncomingDropPartyHandler = ArpSIncomingDropParty;
|
|
Chars.ClCallConnectedHandler = ArpSCallConnected;
|
|
|
|
Status = NdisClOpenAddressFamily(pIntF->NdisBindingHandle,
|
|
&pIntF->AddrFamily,
|
|
pIntF, // Use this as the Af context too
|
|
&Chars,
|
|
sizeof(NDIS_CLIENT_CHARACTERISTICS),
|
|
&pIntF->NdisAfHandle);
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
ArpSOpenAfComplete(Status, pIntF, pIntF->NdisAfHandle);
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
ArpSTryCloseAdapter(pIntF);
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
}
|
|
}
|
|
ARPS_CHECK_IRQL(EntryIrql);
|
|
}
|
|
|
|
VOID
|
|
ArpSOpenAfComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE NdisAfHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion processing for the OpenAf call.
|
|
|
|
Arguments:
|
|
|
|
Status Status of OpenAf
|
|
ProtocolAfContext Pointer to the pIntF
|
|
NdisAfHandle Ndis Handle to refer to this Af
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolAfContext;
|
|
PCO_SAP Sap;
|
|
NDIS_HANDLE OldAfHandle;
|
|
KIRQL OldIrql;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
if (pIntF->NdisAfHandle != NULL)
|
|
{
|
|
DbgPrint("ATMARPS: OpenAfComp: IntF %p, NdisAfHandle %p is NOT NULL!\n",
|
|
pIntF, pIntF->NdisAfHandle);
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
OldAfHandle = pIntF->NdisAfHandle;
|
|
pIntF->NdisAfHandle = NdisAfHandle;
|
|
|
|
if (ArpSReferenceIntF(pIntF))
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
pIntF->Flags |= INTF_AF_OPENED;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
//
|
|
// Now register a SAP on this interface
|
|
//
|
|
ArpSRegisterSap(pIntF);
|
|
}
|
|
else
|
|
{
|
|
NDIS_STATUS Sts;
|
|
|
|
Sts = NdisClCloseAddressFamily(pIntF->NdisAfHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseAfComplete(Status, pIntF);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to open the Address family. Cleanup and exit
|
|
//
|
|
LOG_ERROR(Status);
|
|
|
|
ArpSTryCloseAdapter(pIntF);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSRegisterSap(
|
|
IN PINTF pIntF
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Register the Sap for receiving incoming calls. De-register any existing saps (this can
|
|
happen if an address change happens).
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PATM_SAP pAtmSap;
|
|
PATM_ADDRESS pAtmAddress;
|
|
|
|
//
|
|
// Kill previous sap if any and register a new one. Save this while we
|
|
// register the new one. We kill this regardless of whether the new one
|
|
// successfully registers or not - since the address has potentially changed
|
|
//
|
|
if (pIntF->NdisSapHandle != NULL)
|
|
{
|
|
Status = NdisClDeregisterSap(pIntF->NdisSapHandle);
|
|
pIntF->NdisSapHandle = NULL;
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSDeregisterSapComplete(Status, pIntF);
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate memory for registering the SAP, if doing it for the first time.
|
|
//
|
|
if (pIntF->Sap == NULL)
|
|
{
|
|
pIntF->Sap = (PCO_SAP)ALLOC_NP_MEM(sizeof(CO_SAP) + sizeof(ATM_SAP) + sizeof(ATM_ADDRESS), POOL_TAG_SAP);
|
|
}
|
|
|
|
if (pIntF->Sap == NULL)
|
|
{
|
|
LOG_ERROR(Status);
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ZERO_MEM(pIntF->Sap, sizeof(CO_SAP) + sizeof(ATM_SAP) + sizeof(ATM_ADDRESS));
|
|
pAtmSap = (PATM_SAP)pIntF->Sap->Sap;
|
|
pAtmAddress = (PATM_ADDRESS)(pAtmSap->Addresses);
|
|
|
|
pIntF->Sap->SapType = SAP_TYPE_NSAP;
|
|
pIntF->Sap->SapLength = sizeof(ATM_SAP) + sizeof(ATM_ADDRESS);
|
|
|
|
//
|
|
// Fill in the ATM SAP with default values
|
|
//
|
|
COPY_MEM(&pAtmSap->Blli, &ArpSDefaultBlli, sizeof(ATM_BLLI_IE));
|
|
COPY_MEM(&pAtmSap->Bhli, &ArpSDefaultBhli, sizeof(ATM_BHLI_IE));
|
|
|
|
//
|
|
// ATM Address to "listen" on: Wild card everything except the SEL.
|
|
//
|
|
pAtmSap->NumberOfAddresses = 1;
|
|
pAtmAddress->AddressType = SAP_FIELD_ANY_AESA_REST;
|
|
pAtmAddress->NumberOfDigits = 20;
|
|
pAtmAddress->Address[20-1] = pIntF->SelByte;
|
|
|
|
Status = NdisClRegisterSap(pIntF->NdisAfHandle,
|
|
pIntF,
|
|
pIntF->Sap,
|
|
&pIntF->NdisSapHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSRegisterSapComplete(Status,
|
|
pIntF,
|
|
pIntF->Sap,
|
|
pIntF->NdisSapHandle);
|
|
}
|
|
}
|
|
} while (FALSE);
|
|
|
|
if ((Status != NDIS_STATUS_SUCCESS) && (Status != NDIS_STATUS_PENDING))
|
|
{
|
|
Status = NdisClCloseAddressFamily(pIntF->NdisAfHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseAfComplete(Status, pIntF);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSRegisterSapComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN PCO_SAP Sap,
|
|
IN NDIS_HANDLE NdisSapHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolSapContext;
|
|
|
|
ASSERT (Sap == pIntF->Sap);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN,
|
|
("RegisterSapComplete failed (%x): Intf %x, Name %Z\n",
|
|
Status, pIntF, &pIntF->InterfaceName));
|
|
|
|
LOG_ERROR(Status);
|
|
FREE_MEM(pIntF->Sap);
|
|
pIntF->Sap = NULL;
|
|
|
|
ArpSDereferenceIntF(pIntF);
|
|
}
|
|
else
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
pIntF->Flags |= INTF_SAP_REGISTERED;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
pIntF->NdisSapHandle = NdisSapHandle;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSDeregisterSapComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolSapContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolSapContext;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("DeregisterSapComplete: Intf %Z\n", &pIntF->InterfaceName));
|
|
|
|
pIntF->NdisSapHandle = NULL;
|
|
|
|
if (pIntF->Sap)
|
|
{
|
|
FREE_MEM(pIntF->Sap);
|
|
pIntF->Sap = NULL;
|
|
}
|
|
|
|
//
|
|
// Nothing to do here except deref the IntF block here.
|
|
//
|
|
ArpSDereferenceIntF(pIntF);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCloseAfComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolAfContext;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("CloseAfComplete: pIntF %x, Flags %x, Ref %x, Intf %Z\n",
|
|
pIntF, pIntF->Flags, pIntF->RefCount, &pIntF->InterfaceName));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
pIntF->NdisAfHandle = NULL;
|
|
pIntF->Flags &= ~INTF_STOPPING;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
//
|
|
// Nothing much to do except dereference the pIntF
|
|
//
|
|
ArpSDereferenceIntF(pIntF);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCloseAdapterComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolBindingContext;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CloseAdapterComplete: Intf %Z\n", &pIntF->InterfaceName));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
//
|
|
// Set the interface to closing
|
|
//
|
|
ASSERT ((pIntF->Flags & INTF_CLOSING) == 0);
|
|
pIntF->Flags |= INTF_CLOSING;
|
|
pIntF->NdisBindingHandle = NULL;
|
|
|
|
//
|
|
// Stop the timer thread
|
|
//
|
|
KeSetEvent(&pIntF->TimerThreadEvent, IO_NETWORK_INCREMENT, FALSE);
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
//
|
|
// Finally dereference it
|
|
//
|
|
ArpSDereferenceIntF(pIntF);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSCreateVc(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
OUT PNDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolAfContext;
|
|
PARP_VC Vc;
|
|
KIRQL OldIrql;
|
|
NDIS_STATUS Status;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CreateVc: NdisVcHandle %lx, Intf %Z\n", NdisVcHandle, &pIntF->InterfaceName));
|
|
//
|
|
// Allocate a Vc, initialize it and link it into the IntF
|
|
//
|
|
*ProtocolVcContext = NULL; // Assume failure
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
|
|
Vc = (PARP_VC)ALLOC_NP_MEM(sizeof(ARP_VC), POOL_TAG_VC);
|
|
if (Vc != NULL)
|
|
{
|
|
ZERO_MEM(Vc, sizeof(ARP_VC));
|
|
Vc->NdisVcHandle = NdisVcHandle;
|
|
Vc->IntF = pIntF;
|
|
Vc->RefCount = 1; // Dereferenced when DeleteVc is called.
|
|
Vc->VcType = VC_TYPE_INCOMING;
|
|
if (ArpSReferenceIntF(pIntF))
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
if (++(pIntF->ArpStats.CurrentClientVCs) > pIntF->ArpStats.MaxClientVCs)
|
|
{
|
|
pIntF->ArpStats.MaxClientVCs = pIntF->ArpStats.CurrentClientVCs;
|
|
}
|
|
|
|
InsertHeadList(&pIntF->InactiveVcHead, &Vc->List);
|
|
Vc->VcId = pIntF->LastVcId;
|
|
pIntF->LastVcId ++;
|
|
if (pIntF->LastVcId == -1)
|
|
{
|
|
pIntF->LastVcId = 1;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
*ProtocolVcContext = Vc;
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CreateVc: Created Vc %lx, Id %lx\n", Vc, Vc->VcId));
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
FREE_MEM(Vc);
|
|
Status = NDIS_STATUS_CLOSING;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSDeleteVc(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("DeleteVc: For Vc %lx, Id %lx\n", Vc, Vc->VcId));
|
|
|
|
Vc->IntF->ArpStats.CurrentClientVCs--;
|
|
Vc->NdisVcHandle = NULL;
|
|
ArpSDereferenceVc(Vc, FALSE, FALSE);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCoSendComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET Packet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for the previously pended send. Just return the packet to the pool of free packets.
|
|
|
|
|
|
Arguments:
|
|
|
|
Status Status of Completion
|
|
ProtocolVcContext Pointer to the Vc
|
|
Packet The packet in question
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
PPROTOCOL_RESD Resd;
|
|
|
|
Resd = RESD_FROM_PKT(Packet);
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSCoSendComplete: Packet %lx, Vc %lx, ResdVc %lx, Id %lx\n",
|
|
Packet, Vc, Resd->Vc, Vc->VcId));
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_ERROR,
|
|
("ArpSCoSendComplete: Failed for Vc = %lx, status = %lx\n", Vc, Status));
|
|
}
|
|
|
|
if ((Resd->Flags & RESD_FLAG_MARS_PKT) == 0)
|
|
{
|
|
if (Packet->Private.Head == NULL)
|
|
{
|
|
DbgPrint("ATMARPS: sendcomplete: pkt %p head is NULL!\n",
|
|
Packet->Private.Head);
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
}
|
|
ExInterlockedPushEntrySList(&ArpSPktList,
|
|
&Resd->FreeList,
|
|
&ArpSPktListLock);
|
|
|
|
ArpSDereferenceVc(Resd->Vc, FALSE, TRUE);
|
|
}
|
|
else
|
|
{
|
|
MarsFreePacket(Packet);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSIncomingCall(
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN OUT PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for incoming call. We accept the call unless we are shutting down and then
|
|
do the actual processing when the call processing completes.
|
|
|
|
Arguments:
|
|
|
|
ProtocolSapContext Pointer to the IntF
|
|
ProtocolVcContext Pointer to the Vc
|
|
CallParameters Call Parameters
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolSapContext;
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
Q2931_CALLMGR_PARAMETERS UNALIGNED * CallMgrSpecific;
|
|
KIRQL OldIrql;
|
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
|
|
|
ASSERT (Vc->IntF == pIntF);
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSIncomingCall: On Vc %lx, Id %lx\n", Vc, Vc->VcId));
|
|
//
|
|
// Mark the Vc to indicate the call processing is underway
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
pIntF->ArpStats.TotalIncomingCalls++;
|
|
|
|
ASSERT ((Vc->Flags & (ARPVC_CALLPROCESSING | ARPVC_ACTIVE | ARPVC_CALLPROCESSING)) == 0);
|
|
Vc->Flags |= ARPVC_CALLPROCESSING;
|
|
|
|
//
|
|
// Get the remote atm address from the call-parameters
|
|
//
|
|
CallMgrSpecific = (PQ2931_CALLMGR_PARAMETERS)&CallParameters->CallMgrParameters->CallMgrSpecific.Parameters[0];
|
|
Vc->HwAddr.Address = CallMgrSpecific->CallingParty;
|
|
|
|
//
|
|
// Get the max size of packets we can send on this VC, from the
|
|
// AAL5 parameters. Limit it to the size our miniport can support.
|
|
//
|
|
Vc->MaxSendSize = pIntF->MaxPacketSize; // default
|
|
|
|
if (CallMgrSpecific->InfoElementCount > 0)
|
|
{
|
|
Q2931_IE UNALIGNED * pIe;
|
|
AAL5_PARAMETERS UNALIGNED * pAal5;
|
|
ULONG IeCount;
|
|
|
|
pIe = (PQ2931_IE)CallMgrSpecific->InfoElements;
|
|
for (IeCount = CallMgrSpecific->InfoElementCount;
|
|
IeCount != 0;
|
|
IeCount--)
|
|
{
|
|
if (pIe->IEType == IE_AALParameters)
|
|
{
|
|
pAal5 = &(((PAAL_PARAMETERS_IE)pIe->IE)->AALSpecificParameters.AAL5Parameters);
|
|
//
|
|
// Make sure we don't send more than what the caller can handle.
|
|
//
|
|
if (pAal5->ForwardMaxCPCSSDUSize < Vc->MaxSendSize)
|
|
{
|
|
Vc->MaxSendSize = pAal5->ForwardMaxCPCSSDUSize;
|
|
}
|
|
|
|
//
|
|
// Make sure this greater than the min allowed.
|
|
//
|
|
if (pAal5->ForwardMaxCPCSSDUSize < ARPS_MIN_MAX_PKT_SIZE)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN,
|
|
("ArpSIncomingCall: Vc %lx max pkt size too small(%lu)\n",
|
|
Vc, Vc->MaxSendSize));
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Make sure the caller doesn't send more than what our
|
|
// miniport can handle.
|
|
//
|
|
if (pAal5->BackwardMaxCPCSSDUSize > pIntF->MaxPacketSize)
|
|
{
|
|
pAal5->BackwardMaxCPCSSDUSize = pIntF->MaxPacketSize;
|
|
}
|
|
break;
|
|
}
|
|
pIe = (PQ2931_IE)((PUCHAR)pIe + pIe->IELength);
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
ArpSCallConnected(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Last hand-shake in the incoming call path. Move the Vc to the list of active calls.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext Pointer to VC
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
PINTF pIntF;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSCallConnected: On Vc %lx, Id %lx\n", Vc, Vc->VcId));
|
|
|
|
|
|
pIntF = Vc->IntF;
|
|
pIntF->ArpStats.TotalActiveVCs++;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
ASSERT((Vc->Flags & ARPVC_ACTIVE) == 0);
|
|
ASSERT(Vc->Flags & ARPVC_CALLPROCESSING);
|
|
|
|
Vc->Flags |= ARPVC_ACTIVE;
|
|
Vc->Flags &= ~ARPVC_CALLPROCESSING;
|
|
|
|
RemoveEntryList(&Vc->List);
|
|
InsertHeadList(&pIntF->ActiveVcHead, &Vc->List);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSMakeCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle completion of an earlier call to NdisClMakeCall. The only
|
|
outgoing call is for ClusterControlVc. If the status indicates
|
|
success, AddParty's are initiated for all pending Cluster members.
|
|
Otherwise, this cluster member is deleted, and if there are any
|
|
other cluster members in the list, we initiate a MakeCall with
|
|
one of them.
|
|
|
|
Arguments:
|
|
|
|
Status Result of NdisClMakeCall
|
|
ProtocolVcContext Pointer to ClusterControlVc
|
|
NdisPartyHandle If successful, the handle for this party
|
|
CallParameters Pointer to Call parameters
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PINTF pIntF;
|
|
PMARS_VC pVc;
|
|
PCLUSTER_MEMBER pMember;
|
|
PCLUSTER_MEMBER pNextMember;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
|
|
pVc = (PMARS_VC)ProtocolVcContext;
|
|
|
|
if (pVc->VcType == VC_TYPE_CHECK_REGADDR)
|
|
{
|
|
ArpSMakeRegAddrCallComplete(
|
|
Status,
|
|
(PREG_ADDR_CTXT) ProtocolVcContext
|
|
);
|
|
return; // ****** EARLY RETURN ****************
|
|
}
|
|
|
|
pIntF = pVc->pIntF;
|
|
|
|
MARSDBGPRINT(DBG_LEVEL_LOUD,
|
|
("MakeCallComplete: Status %x, pVc %x, VC ConnState %x\n",
|
|
Status, pVc, MARS_GET_VC_CONN_STATE(pVc)));
|
|
|
|
FREE_MEM(CallParameters);
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
//
|
|
// Get the Cluster member we were trying to connect to.
|
|
//
|
|
for (pMember = pIntF->ClusterMembers;
|
|
pMember != NULL_PCLUSTER_MEMBER;
|
|
pMember = (PCLUSTER_MEMBER)pMember->Next)
|
|
{
|
|
if (MARS_GET_CM_CONN_STATE(pMember) == CM_CONN_SETUP_IN_PROGRESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(pMember != NULL_PCLUSTER_MEMBER);
|
|
|
|
pIntF->CCAddingParties--;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
ASSERT(NdisPartyHandle != NULL);
|
|
MARS_SET_CM_CONN_STATE(pMember, CM_CONN_ACTIVE);
|
|
pMember->NdisPartyHandle = NdisPartyHandle;
|
|
|
|
pIntF->CCActiveParties++;
|
|
|
|
if (pMember->Flags & CM_INVALID)
|
|
{
|
|
//
|
|
// Deleting was deferred because the connection was being
|
|
// setup. Now that it's up, strictly speaking we should
|
|
// try to delete it again, BUT we don't because we
|
|
// may also need to add other members now, and we can't really
|
|
// drop the call itself while we're adding other parties!
|
|
//
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("pMember 0x%p is INVALID, but NOT dropping CCVC call.\n",
|
|
pMember));
|
|
|
|
// do nothing...
|
|
}
|
|
|
|
if (MARS_GET_VC_CONN_STATE(pVc) == MVC_CONN_SETUP_IN_PROGRESS)
|
|
{
|
|
MARS_SET_VC_CONN_STATE(pVc, MVC_CONN_ACTIVE);
|
|
|
|
//
|
|
// Add all pending cluster members as parties
|
|
//
|
|
for (pMember = pIntF->ClusterMembers;
|
|
pMember != NULL_PCLUSTER_MEMBER;
|
|
pMember = pNextMember)
|
|
{
|
|
pNextMember = (PCLUSTER_MEMBER)pMember->Next;
|
|
|
|
if (MARS_GET_CM_CONN_STATE(pMember) == CM_CONN_IDLE)
|
|
{
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
MarsAddMemberToClusterControlVc(pIntF, pMember);
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
if (!MarsIsValidClusterMember(pIntF, pNextMember))
|
|
{
|
|
//
|
|
// Oops, the next member has gone away in the
|
|
// mean time. In this unlikely case, we simply
|
|
// quit processing the list early.
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
//
|
|
// Send off any queued packets, if we can.
|
|
//
|
|
MarsSendOnClusterControlVc(pIntF, NULL);
|
|
}
|
|
else
|
|
{
|
|
BOOLEAN fLocked;
|
|
//
|
|
// We are closing down.
|
|
//
|
|
MARS_SET_VC_CONN_STATE(pVc, MVC_CONN_ACTIVE);
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
fLocked = MarsDelMemberFromClusterControlVc(pIntF, pMember, FALSE, 0);
|
|
ASSERT(!fLocked);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("MakeCall error %x, pMember %x to addr:", Status, pMember));
|
|
MARSDUMPATMADDR(DBG_LEVEL_WARN, &pMember->HwAddr.Address, "");
|
|
#if DBG
|
|
if (Status == NDIS_STATUS_CALL_ACTIVE)
|
|
{
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("ATMARPS: MakeCallComp: Intf %p, VC %p, pMember %p, call active!\n",
|
|
pIntF, pVc, pMember));
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Connection failed. Delete this member from our Cluster member list.
|
|
//
|
|
pIntF->MarsStats.FailedCCVCAddParties++;
|
|
MarsDeleteClusterMember(pIntF, pMember);
|
|
|
|
MARS_SET_VC_CONN_STATE(pVc, MVC_CONN_IDLE);
|
|
|
|
//
|
|
// See if we have other Cluster members. If so, pick up one
|
|
// of them and re-initiate the ClusterControlVc.
|
|
//
|
|
for (pMember = pIntF->ClusterMembers;
|
|
pMember != NULL_PCLUSTER_MEMBER;
|
|
pMember = (PCLUSTER_MEMBER)pMember->Next)
|
|
{
|
|
if (MARS_GET_CM_CONN_STATE(pMember) == CM_CONN_IDLE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pMember == NULL_PCLUSTER_MEMBER)
|
|
{
|
|
//
|
|
// No other cluster members, so we'll tear down the CC VC.
|
|
//
|
|
NdisVcHandle = pIntF->ClusterControlVc->NdisVcHandle;
|
|
DBGPRINT(DBG_LEVEL_ERROR,
|
|
("ATMARPS: pIntF %x, deleting CC VC, VcHandle %x\n", pIntF, NdisVcHandle));
|
|
FREE_MEM(pIntF->ClusterControlVc);
|
|
pIntF->ClusterControlVc = NULL;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
if (pMember != NULL_PCLUSTER_MEMBER)
|
|
{
|
|
MarsAddMemberToClusterControlVc(pIntF, pMember);
|
|
}
|
|
else
|
|
{
|
|
Status = NdisCoDeleteVc(NdisVcHandle);
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
MarsFreePacketsQueuedForClusterControlVc(pIntF);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSIncomingCloseCall(
|
|
IN NDIS_STATUS CloseStatus,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PVOID CloseData OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indication of an incoming close call from the network. If this
|
|
is not on ClusterControlVc, then we mark the VC as inactive, and
|
|
move it to the Inactive VC list. If this is on ClusterControlVc,
|
|
there must be only one party on the PMP connection. We update
|
|
that member's state.
|
|
|
|
In any case, we call NdisClCloseCall to complete the handshake.
|
|
|
|
Arguments:
|
|
|
|
CloseStatus Status of Close
|
|
ProtocolVcContext Pointer to VC (ARP_VC or MARS_VC)
|
|
CloseData Optional Close data (IGNORED)
|
|
Size Size of Optional Close Data (OPTIONAL)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
PMARS_VC pMarsVc;
|
|
PINTF pIntF;
|
|
NDIS_STATUS Status;
|
|
|
|
if (Vc->VcType == VC_TYPE_INCOMING)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSIncomingCloseCall: On Vc %lx, Id %lx\n",
|
|
ProtocolVcContext, Vc->VcId));
|
|
|
|
ArpSInitiateCloseCall(Vc);
|
|
}
|
|
else if (Vc->VcType == VC_TYPE_CHECK_REGADDR)
|
|
{
|
|
ArpSIncomingRegAddrCloseCall(
|
|
CloseStatus,
|
|
(PREG_ADDR_CTXT) ProtocolVcContext
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(Vc->VcType == VC_TYPE_MARS_CC);
|
|
pMarsVc = (PMARS_VC)ProtocolVcContext;
|
|
pIntF = pMarsVc->pIntF;
|
|
#if DBG
|
|
if (pIntF->CCAddingParties != 0)
|
|
{
|
|
PCLUSTER_MEMBER pMember;
|
|
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("ATMARPS: pIntF %p, InClose on CCVC %p/%x/%p with %d adding parties\n",
|
|
pIntF, pMarsVc, pMarsVc->Flags, pMarsVc->NdisVcHandle,
|
|
pIntF->CCAddingParties));
|
|
for (pMember = pIntF->ClusterMembers; pMember != NULL; pMember = pMember->Next)
|
|
{
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("ATMARPS: pIntF %p, InClose, pMember %p/%x\n",
|
|
pIntF, pMember, pMember->Flags));
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
MARS_SET_VC_CONN_STATE(pMarsVc, MVC_CONN_CLOSE_RECEIVED);
|
|
{
|
|
PPROTOCOL_RESD Resd;
|
|
|
|
Resd = ALLOC_NP_MEM(sizeof(PROTOCOL_RESD), POOL_TAG_MARS);
|
|
if (Resd != NULL)
|
|
{
|
|
Resd->Flags = RESD_FLAG_KILL_CCVC;
|
|
Resd->Vc = (PARP_VC)pIntF;
|
|
KeInsertQueue(&MarsReqQueue, &Resd->ReqList);
|
|
}
|
|
else
|
|
{
|
|
MarsAbortAllMembers(pIntF);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCloseCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called to complete our call to NdisClCloseCall. If the VC
|
|
is other than ClusterControlVc, we simply update its state.
|
|
|
|
If this is on ClusterControlVc, we delete the last member.
|
|
|
|
Arguments:
|
|
|
|
CloseStatus Status of Close
|
|
Status Status of NdisClCloseCall
|
|
ProtocolVcContext Pointer to our VC structure
|
|
ProtocolPartyContext If the VC is ClusterControlVc, this is a pointer
|
|
to the Cluster Member that was disconnected.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PARP_VC Vc = (PARP_VC)ProtocolVcContext;
|
|
PMARS_VC pMarsVc;
|
|
PCLUSTER_MEMBER pMember;
|
|
PINTF pIntF;
|
|
KIRQL OldIrql;
|
|
BOOLEAN bStopping;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DbgPrint("ATMARPS: CloseCall failed %x on VC %p\n", Status, Vc);
|
|
DbgBreakPoint();
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if (Vc->VcType == VC_TYPE_INCOMING)
|
|
{
|
|
pIntF = Vc->IntF;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("ArpSCloseCallComplete: On Vc %lx\n", Vc));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
ASSERT ((Vc->Flags & ARPVC_CLOSING) != 0);
|
|
Vc->Flags &= ~ARPVC_CLOSING;
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|
|
else if (Vc->VcType == VC_TYPE_CHECK_REGADDR)
|
|
{
|
|
ArpSCloseRegAddrCallComplete(
|
|
Status,
|
|
(PREG_ADDR_CTXT) ProtocolVcContext
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Must be ClusterControlVc
|
|
//
|
|
pMarsVc = (PMARS_VC)ProtocolVcContext;
|
|
pIntF = pMarsVc->pIntF;
|
|
|
|
ASSERT(pMarsVc == pIntF->ClusterControlVc);
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
MARS_SET_VC_CONN_STATE(pMarsVc, MVC_CONN_IDLE);
|
|
|
|
pMember = (PCLUSTER_MEMBER)ProtocolPartyContext;
|
|
MARS_SET_CM_CONN_STATE(pMember, CM_CONN_IDLE);
|
|
|
|
ASSERT(pIntF->CCAddingParties == 0);
|
|
|
|
pIntF->CCActiveParties = pIntF->CCDroppingParties = pIntF->CCAddingParties = 0;
|
|
|
|
bStopping = ((pIntF->Flags & INTF_STOPPING) != 0);
|
|
|
|
MarsDeleteClusterMember(pIntF, pMember);
|
|
|
|
ARPS_ASSERT(pIntF->ClusterControlVc);
|
|
|
|
NdisVcHandle = pIntF->ClusterControlVc->NdisVcHandle;
|
|
FREE_MEM(pIntF->ClusterControlVc);
|
|
pIntF->ClusterControlVc = NULL;
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
if (NdisVcHandle != NULL)
|
|
{
|
|
NDIS_STATUS DeleteStatus;
|
|
|
|
DeleteStatus = NdisCoDeleteVc(NdisVcHandle);
|
|
if (DeleteStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DbgPrint("ATMARPS: CloseCallComp: DeleteVc %p failed %x\n",
|
|
NdisVcHandle, DeleteStatus);
|
|
DbgBreakPoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSAddPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion of NdisClAddParty to add a new party to ClusterControlVc.
|
|
If successful, update the member's state. Otherwise, delete it.
|
|
|
|
Arguments:
|
|
|
|
Status Status of AddParty
|
|
ProtocolPartyContext Pointer to Cluster Member being added
|
|
NdisPartyHandle Valid if AddParty successful
|
|
CallParameters Pointer to AddParty call parameters
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCLUSTER_MEMBER pMember;
|
|
PINTF pIntF;
|
|
KIRQL OldIrql;
|
|
|
|
FREE_MEM(CallParameters);
|
|
|
|
pMember = (PCLUSTER_MEMBER)ProtocolPartyContext;
|
|
pIntF = pMember->pIntF;
|
|
|
|
MARSDBGPRINT(DBG_LEVEL_LOUD,
|
|
("AddPartyComplete: Status %x, pMember %x, NdisPartyHandle %x\n",
|
|
Status, pMember, NdisPartyHandle));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
ASSERT(pMember->pGroupList == NULL_PGROUP_MEMBER);
|
|
|
|
pIntF->CCAddingParties--; // AddPartyComplete
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
MARS_SET_CM_CONN_STATE(pMember, CM_CONN_ACTIVE);
|
|
pMember->NdisPartyHandle = NdisPartyHandle;
|
|
pIntF->CCActiveParties++; // AddPartyComplete
|
|
|
|
if (pMember->Flags & CM_INVALID)
|
|
{
|
|
//
|
|
// Deleting was deferred because the connection was being
|
|
// setup. Now that it's up, we will try to delete it again
|
|
// (should have better luck this time!).
|
|
//
|
|
BOOLEAN fLocked;
|
|
|
|
fLocked = MarsDelMemberFromClusterControlVc(
|
|
pIntF,
|
|
pIntF->ClusterMembers,
|
|
TRUE,
|
|
OldIrql
|
|
);
|
|
if(!fLocked)
|
|
{
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MARSDBGPRINT(DBG_LEVEL_WARN,
|
|
("AddParty Failed: pMember %x, Status %x, Addr: ",
|
|
pMember, Status));
|
|
MARSDUMPATMADDR(DBG_LEVEL_WARN, &pMember->HwAddr.Address, "");
|
|
pIntF->MarsStats.FailedCCVCAddParties++;
|
|
|
|
MARS_SET_CM_CONN_STATE(pMember, CM_CONN_IDLE);
|
|
MarsDeleteClusterMember(pIntF, pMember);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
//
|
|
// Send any queued packets, if appropriate.
|
|
//
|
|
MarsSendOnClusterControlVc(pIntF, NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSDropPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called to signify completion of a previous NdisClDropParty,
|
|
to drop a cluster member off the ClusterControlVc. Delete the member.
|
|
|
|
Arguments:
|
|
|
|
Status Status of DropParty
|
|
ProtocolPartyContext Pointer to Cluster Member being dropped
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PCLUSTER_MEMBER pMember;
|
|
PINTF pIntF;
|
|
PMARS_VC pVc;
|
|
BOOLEAN IsVcClosing;
|
|
|
|
ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
pMember = (PCLUSTER_MEMBER)ProtocolPartyContext;
|
|
pIntF = pMember->pIntF;
|
|
ASSERT(pIntF->ClusterControlVc != NULL_PMARS_VC);
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
MARS_SET_CM_CONN_STATE(pMember, CM_CONN_IDLE);
|
|
pIntF->CCDroppingParties--;
|
|
|
|
//
|
|
// Check if we are closing ClusterControlVc, and just one party is left.
|
|
//
|
|
pVc = pIntF->ClusterControlVc;
|
|
IsVcClosing = ((MARS_GET_VC_CONN_STATE(pVc) == MVC_CONN_NEED_CLOSE) &&
|
|
(pIntF->CCActiveParties == 1) &&
|
|
(pIntF->CCAddingParties + pIntF->CCDroppingParties == 0));
|
|
|
|
MarsDeleteClusterMember(pIntF, pMember);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
if (IsVcClosing)
|
|
{
|
|
BOOLEAN fLocked;
|
|
fLocked = MarsDelMemberFromClusterControlVc(
|
|
pIntF,
|
|
pIntF->ClusterMembers,
|
|
FALSE,
|
|
0
|
|
);
|
|
ASSERT(!fLocked);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSIncomingDropParty(
|
|
IN NDIS_STATUS DropStatus,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN PVOID CloseData OPTIONAL,
|
|
IN UINT Size OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indication that a Cluster Member has dropped off the ClusterControlVc.
|
|
We complete this handshake by calling NdisClDropParty.
|
|
|
|
Arguments:
|
|
|
|
DropStatus Status
|
|
ProtocolPartyContext Pointer to Cluster Member
|
|
CloseData Optional Close data (IGNORED)
|
|
Size Size of Optional Close Data (OPTIONAL)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCLUSTER_MEMBER pMember;
|
|
PINTF pIntF;
|
|
KIRQL OldIrql;
|
|
|
|
pMember = (PCLUSTER_MEMBER)ProtocolPartyContext;
|
|
pIntF = pMember->pIntF;
|
|
ASSERT(MARS_GET_CM_CONN_STATE(pMember) == CM_CONN_ACTIVE);
|
|
|
|
MARSDBGPRINT(DBG_LEVEL_NOTICE,
|
|
("IncomingDropParty: pIntF %x, pMember %x, Addr: ", pIntF, pMember));
|
|
MARSDUMPATMADDR(DBG_LEVEL_NOTICE, &pMember->HwAddr.Address, "");
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
//
|
|
// Remove its membership from all groups.
|
|
// AND disable further groups from being added.
|
|
//
|
|
MarsUnlinkAllGroupsOnClusterMember(pIntF, pMember);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
{
|
|
BOOLEAN fLocked;
|
|
fLocked = MarsDelMemberFromClusterControlVc(pIntF, pMember, FALSE, 0);
|
|
ASSERT(!fLocked);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSCoRequest(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN OUT PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolAfContext;
|
|
KIRQL OldIrql;
|
|
BOOLEAN ValidAf;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CallMgrRequest: Request %lx, Type %d, OID %lx\n",
|
|
NdisRequest, NdisRequest->RequestType, NdisRequest->DATA.SET_INFORMATION.Oid));
|
|
|
|
switch(NdisRequest->DATA.SET_INFORMATION.Oid)
|
|
{
|
|
case OID_CO_ADDRESS_CHANGE:
|
|
ValidAf = FALSE;
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
pIntF->Flags |= INTF_ADDRESS_VALID;
|
|
ValidAf = ((pIntF->Flags & INTF_AF_OPENED) != 0);
|
|
pIntF->NumAddressesRegd = 0;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
if (ValidAf)
|
|
{
|
|
ArpSQueryAndSetAddresses(pIntF);
|
|
}
|
|
break;
|
|
|
|
case OID_CO_AF_CLOSE:
|
|
#if DBG
|
|
DbgPrint("atmarps: OID_CO_AF_CLOSE\n");
|
|
#endif
|
|
if (ArpSReferenceIntF(pIntF))
|
|
{
|
|
//
|
|
// ArpSStopInterface dereferences the pIntF
|
|
//
|
|
(VOID)ArpSStopInterface(pIntF, FALSE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCoRequestComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
|
|
IN PNDIS_REQUEST NdisRequest
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for the NdisCoRequest api.
|
|
|
|
Arguments:
|
|
|
|
Status Status of completion
|
|
ProtocolAfContext Pointer to the IntF structure
|
|
ProtocolVcContext Pointer to the VC structure
|
|
ProtocolPartyContext Not used by us since we do not make calls
|
|
NdisRequest Pointer to the request structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolAfContext;
|
|
BOOLEAN FreeReq = TRUE;
|
|
KIRQL OldIrql;
|
|
PKEVENT pEvent = NULL;
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: Request %lx, Type %d, OID %lx\n",
|
|
NdisRequest, NdisRequest->RequestType, NdisRequest->DATA.QUERY_INFORMATION.Oid));
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
switch(NdisRequest->DATA.SET_INFORMATION.Oid)
|
|
{
|
|
case OID_CO_ADD_ADDRESS:
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: Registered address # %d\n", pIntF->NumAddressesRegd+1));
|
|
|
|
if (pIntF->NumAddressesRegd < pIntF->NumAllocedRegdAddresses)
|
|
{
|
|
PCO_ADDRESS pCoAddr;
|
|
PATM_ADDRESS pAddress;
|
|
|
|
// Copy the registered address from the ndis request into the
|
|
// array of registered addresses.
|
|
//
|
|
pCoAddr = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
|
|
pAddress = (PATM_ADDRESS)(pCoAddr->Address);
|
|
pIntF->RegAddresses[pIntF->NumAddressesRegd] = *pAddress;
|
|
pIntF->NumAddressesRegd ++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// 12/22/1998 JosephJ
|
|
// We could potentially get here if the total number of outstanding add address requests
|
|
// is greater then NumAllocedRegAddresses. One way this could happen is if ArpSQueryAndSetAddresses
|
|
// is called multiple times in quick succession. Note that ArpSQueryAndSetAddresses is called from
|
|
// two places: ArpSCoRequest and ArpSReqdAdaprConfiguration.
|
|
//
|
|
// Previously, we would increment NumAddressRegd in this condition. Now we simply ignore this.
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: CO_ADD_ADDRESS Failed %lx\n", Status));
|
|
}
|
|
|
|
//
|
|
// Try registering the next address. ArpSValidateOneRegAddress will
|
|
// unlink and free pIntF->pRegAddrCtxt if there are no more addresses
|
|
// to be registered.
|
|
//
|
|
if (pIntF->pRegAddrCtxt != NULL)
|
|
{
|
|
ArpSValidateOneRegdAddress(
|
|
pIntF,
|
|
OldIrql
|
|
);
|
|
//
|
|
// Lock released by above call.
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE); // can't get here.
|
|
}
|
|
// We don't want to free this ndis request here, because it's actually
|
|
// part of pIntF->pRegAddrCtxt.
|
|
//
|
|
FreeReq = FALSE;
|
|
break;
|
|
|
|
case OID_CO_GET_ADDRESSES:
|
|
//
|
|
// (On success) We just got our configured address value.
|
|
// We save this value AND THEN move on the next stage of initialization --
|
|
// validating and setting the "registered" addresses -- these are the
|
|
// addresses we read from the registry. See 05/14/1999 notes.txt entry
|
|
// for details.
|
|
//
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
PCO_ADDRESS_LIST pCoAddrList;
|
|
UINT i;
|
|
|
|
pCoAddrList = (PCO_ADDRESS_LIST)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);
|
|
ASSERT(pCoAddrList->NumberOfAddresses == 1);
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: Configured address, %d/%d Size %d\n",
|
|
pCoAddrList->NumberOfAddresses,
|
|
pCoAddrList->NumberOfAddressesAvailable,
|
|
pCoAddrList->AddressList.AddressSize));
|
|
|
|
ASSERT(pCoAddrList->AddressList.AddressSize == (sizeof(CO_ADDRESS) + sizeof(ATM_ADDRESS)));
|
|
COPY_MEM(&pIntF->ConfiguredAddress,
|
|
pCoAddrList->AddressList.Address,
|
|
sizeof(ATM_ADDRESS));
|
|
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: Configured Address (%s): ",
|
|
(pIntF->ConfiguredAddress.AddressType == ATM_E164) ? "E164" : "NSAP"));
|
|
for (i = 0; i < pIntF->ConfiguredAddress.NumberOfDigits; i++)
|
|
{
|
|
DBGPRINT(DBG_LEVEL_INFO + DBG_NO_HDR,
|
|
("%02x ", pIntF->ConfiguredAddress.Address[i]));
|
|
}
|
|
DBGPRINT(DBG_LEVEL_INFO | DBG_NO_HDR, ("\n"));
|
|
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: CO_GET_ADDRESS Failed %lx\n", Status));
|
|
}
|
|
|
|
//
|
|
// Validate and set the registered addresses.
|
|
//
|
|
ArpSValidateAndSetRegdAddresses(pIntF, OldIrql);
|
|
|
|
// IntF lock released by the above.
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
break;
|
|
|
|
case OID_CO_DELETE_ADDRESS:
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("CoRequestComplete: Deleted address. Status=%x\n", Status));
|
|
if (pIntF->DelAddressesEvent != NULL)
|
|
{
|
|
// Someone's waiting for all the addresses to be deleted...
|
|
//
|
|
|
|
ASSERT(pIntF->NumPendingDelAddresses > 0);
|
|
if (--(pIntF->NumPendingDelAddresses) == 0)
|
|
{
|
|
// Deletion of all addresses is over, signal the event.
|
|
//
|
|
pEvent = pIntF->DelAddressesEvent;
|
|
pIntF->DelAddressesEvent = NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
if (pEvent != NULL)
|
|
{
|
|
KeSetEvent(pEvent, IO_NETWORK_INCREMENT, FALSE);
|
|
}
|
|
|
|
if (FreeReq)
|
|
{
|
|
FREE_MEM(NdisRequest);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSIncomingCallQoSChange(
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PCO_CALL_PARAMETERS CallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN, ("QoSChange: Ignored\n"));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ArpSQueryAdapter(
|
|
IN PINTF pIntF
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query the miniport we are bound to for the following info:
|
|
1. Line rate
|
|
2. Max packet size
|
|
|
|
These will overwrite the defaults we set up in ArpSCreateIntF.
|
|
|
|
Arguments:
|
|
|
|
pIntF Pointer to Interface
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
ArpSSendNdisRequest(pIntF,
|
|
OID_GEN_CO_LINK_SPEED,
|
|
(PVOID)&(pIntF->LinkSpeed),
|
|
sizeof(NDIS_CO_LINK_SPEED));
|
|
|
|
ArpSSendNdisRequest(pIntF,
|
|
OID_ATM_MAX_AAL5_PACKET_SIZE,
|
|
(PVOID)&(pIntF->MaxPacketSize),
|
|
sizeof(ULONG));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ArpSSendNdisRequest(
|
|
IN PINTF pIntF,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID pBuffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NDIS Request generator, for sending NDIS requests to the miniport.
|
|
|
|
Arguments:
|
|
|
|
pIntF Ptr to Interface
|
|
Oid The parameter being queried
|
|
pBuffer Points to parameter
|
|
BufferLength Length of above
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PNDIS_REQUEST pRequest;
|
|
|
|
pRequest = (PNDIS_REQUEST)ALLOC_NP_MEM(sizeof(NDIS_REQUEST), POOL_TAG_INTF);
|
|
if (pRequest == (PNDIS_REQUEST)NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ZERO_MEM(pRequest, sizeof(NDIS_REQUEST));
|
|
|
|
//
|
|
// Query for the line rate.
|
|
//
|
|
pRequest->DATA.QUERY_INFORMATION.Oid = Oid;
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer;
|
|
pRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
|
|
pRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
|
|
pRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength;
|
|
|
|
NdisRequest(&Status,
|
|
pIntF->NdisBindingHandle,
|
|
pRequest);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSRequestComplete(
|
|
(NDIS_HANDLE)pIntF,
|
|
pRequest,
|
|
Status);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ArpSRequestComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_REQUEST pRequest,
|
|
IN NDIS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion of our call to NdisRequest(). Do some follow-up.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext Pointer to IntF
|
|
pRequest The request that just completed
|
|
Status Status of NdisRequest()
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF;
|
|
|
|
pIntF = (PINTF)ProtocolBindingContext;
|
|
|
|
switch (pRequest->DATA.QUERY_INFORMATION.Oid)
|
|
{
|
|
case OID_ATM_MAX_AAL5_PACKET_SIZE:
|
|
if (pIntF->MaxPacketSize < pIntF->CCFlowSpec.SendMaxSize)
|
|
{
|
|
pIntF->CCFlowSpec.SendMaxSize =
|
|
pIntF->CCFlowSpec.ReceiveMaxSize = pIntF->MaxPacketSize;
|
|
}
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("Miniport Max AAL5 Packet Size: %d (decimal)\n",
|
|
pIntF->MaxPacketSize));
|
|
break;
|
|
case OID_GEN_CO_LINK_SPEED:
|
|
//
|
|
// Convert to bytes/sec
|
|
//
|
|
pIntF->LinkSpeed.Outbound = (pIntF->LinkSpeed.Outbound * 100 / 8);
|
|
pIntF->LinkSpeed.Inbound = (pIntF->LinkSpeed.Inbound * 100 / 8);
|
|
if (pIntF->LinkSpeed.Outbound < pIntF->CCFlowSpec.SendBandwidth)
|
|
{
|
|
pIntF->CCFlowSpec.SendBandwidth = pIntF->LinkSpeed.Outbound;
|
|
}
|
|
if (pIntF->LinkSpeed.Inbound < pIntF->CCFlowSpec.ReceiveBandwidth)
|
|
{
|
|
pIntF->CCFlowSpec.ReceiveBandwidth = pIntF->LinkSpeed.Inbound;
|
|
}
|
|
DBGPRINT(DBG_LEVEL_INFO,
|
|
("Miniport Link Speed (decimal, bytes/sec): In %d, Out %d\n",
|
|
pIntF->LinkSpeed.Inbound, pIntF->LinkSpeed.Outbound));
|
|
break;
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
FREE_MEM(pRequest);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ArpSUnbindAdapter(
|
|
OUT PNDIS_STATUS UnbindStatus,
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE UnbindContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF = (PINTF)ProtocolBindingContext;
|
|
|
|
DBGPRINT(DBG_LEVEL_WARN,
|
|
("UnbindAdapter: Intf %x, Name %Z\n", pIntF, &pIntF->InterfaceName));
|
|
|
|
if (ArpSReferenceIntF(pIntF))
|
|
{
|
|
//
|
|
// ArpSStopInterface dereferences the pIntF
|
|
//
|
|
*UnbindStatus = ArpSStopInterface(pIntF, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSStopInterface(
|
|
IN PINTF pIntF,
|
|
IN BOOLEAN bCloseAdapter
|
|
)
|
|
//
|
|
// NOTE: ArpSStopInterface MAY be called concurrently multiple times.
|
|
//
|
|
{
|
|
KEVENT CleanupEvent;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
BOOLEAN bWaitForClose;
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("StopInterface: Intf %x, Flags %x, Name %Z, bClose %d\n",
|
|
pIntF, pIntF->Flags, &pIntF->InterfaceName, bCloseAdapter));
|
|
|
|
bWaitForClose = FALSE;
|
|
if (bCloseAdapter)
|
|
{
|
|
|
|
//
|
|
// Event to be set when the IntF cleanup is complete
|
|
//
|
|
if (pIntF->CleanupEvent == NULL)
|
|
{
|
|
KeInitializeEvent(&CleanupEvent, NotificationEvent, FALSE);
|
|
pIntF->CleanupEvent = &CleanupEvent;
|
|
bWaitForClose = TRUE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
//
|
|
// NOTE: we can't simply skip the shutdown steps if
|
|
// INTF_STOPPING is already set, because we need to make sure all the steps
|
|
// are complete before we call NdisCloseAdapter.
|
|
//
|
|
|
|
pIntF->Flags |= INTF_STOPPING;
|
|
|
|
//
|
|
// Start off by de-registering the Sap
|
|
//
|
|
if (pIntF->Flags & INTF_SAP_REGISTERED)
|
|
{
|
|
pIntF->Flags &= ~INTF_SAP_REGISTERED;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
Status = NdisClDeregisterSap(pIntF->NdisSapHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSDeregisterSapComplete(Status, pIntF);
|
|
}
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
}
|
|
|
|
//
|
|
// Walk the list of Active Vcs and close them down
|
|
//
|
|
|
|
while (!IsListEmpty(&pIntF->ActiveVcHead))
|
|
{
|
|
PARP_VC Vc;
|
|
|
|
Vc = CONTAINING_RECORD(pIntF->ActiveVcHead.Flink, ARP_VC, List);
|
|
|
|
if ((Vc->Flags & ARPVC_CLOSING) == 0)
|
|
{
|
|
Vc->Flags |= ARPVC_CLOSING;
|
|
Vc->Flags &= ~ARPVC_ACTIVE;
|
|
|
|
//
|
|
// The ArpEntry part of the Vc gets cleaned up seperately.
|
|
//
|
|
Vc->ArpEntry = NULL;
|
|
|
|
ASSERT(Vc->HwAddr.SubAddress == NULL);
|
|
|
|
RemoveEntryList(&Vc->List);
|
|
InsertHeadList(&pIntF->InactiveVcHead, &Vc->List);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
Status = NdisClCloseCall(Vc->NdisVcHandle, NULL, NULL, 0);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseCallComplete(Status, Vc, NULL);
|
|
}
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
MarsStopInterface(pIntF);
|
|
|
|
//
|
|
// Deregister all registered addresses...
|
|
//
|
|
DeregisterAllAddresses(pIntF);
|
|
|
|
//
|
|
// Now close Address family
|
|
//
|
|
if (pIntF->Flags & INTF_AF_OPENED)
|
|
{
|
|
pIntF->Flags &= ~INTF_AF_OPENED;
|
|
|
|
Status = NdisClCloseAddressFamily(pIntF->NdisAfHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseAfComplete(Status, pIntF);
|
|
}
|
|
}
|
|
|
|
if (bCloseAdapter)
|
|
{
|
|
//
|
|
// Now close the adapter.
|
|
//
|
|
ArpSTryCloseAdapter(pIntF);
|
|
}
|
|
|
|
//
|
|
// Take away reference added by caller.
|
|
//
|
|
ArpSDereferenceIntF(pIntF);
|
|
|
|
if (bWaitForClose)
|
|
{
|
|
//
|
|
// Wait for the cleanup to complete, i.e. last reference on the Interface
|
|
// to go away.
|
|
//
|
|
WAIT_FOR_OBJECT(Status, &CleanupEvent, NULL);
|
|
}
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
ArpSPnPEventHandler(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNET_PNP_EVENT pNetPnPEvent
|
|
)
|
|
{
|
|
PINTF pIntF;
|
|
NDIS_STATUS Status;
|
|
PNET_DEVICE_POWER_STATE pPowerState = (PNET_DEVICE_POWER_STATE)pNetPnPEvent->Buffer;
|
|
|
|
pIntF = (PINTF)ProtocolBindingContext;
|
|
|
|
do
|
|
{
|
|
switch (pNetPnPEvent->NetEvent)
|
|
{
|
|
case NetEventSetPower:
|
|
switch (*pPowerState)
|
|
{
|
|
case NetDeviceStateD0:
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// We can't suspend, so we ask NDIS to Unbind us by
|
|
// returning this status:
|
|
//
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NetEventQueryPower: // FALLTHRU
|
|
case NetEventQueryRemoveDevice: // FALLTHRU
|
|
case NetEventCancelRemoveDevice:
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case NetEventReconfigure:
|
|
if (pIntF)
|
|
{
|
|
Status = ArpSReadAdapterConfiguration(pIntF);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Global changes
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case NetEventBindList:
|
|
default:
|
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
ArpSStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN, ("StatusIndication: Ignored\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSStatusComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN, ("StatusComplete: Ignored\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
ArpSCoStatus(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
|
|
IN NDIS_STATUS GeneralStatus,
|
|
IN PVOID StatusBuffer,
|
|
IN UINT StatusBufferSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DBGPRINT(DBG_LEVEL_WARN, ("CoStatus: Ignored\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
ArpSInitiateCloseCall(
|
|
IN PARP_VC Vc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start off an NDIS Call Closing sequence on the ARP VC, if all
|
|
conditions are right.
|
|
|
|
Arguments:
|
|
|
|
Vc - Pointer to ARP Vc
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PINTF pIntF;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
pIntF = Vc->IntF;
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
|
|
DBGPRINT(DBG_LEVEL_NOTICE,
|
|
("InitiateClose: VC %x, ref %d, flags %x, Pending %d, ArpEntry %x\n",
|
|
Vc, Vc->RefCount, Vc->Flags, Vc->PendingSends, Vc->ArpEntry));
|
|
|
|
if (Vc->PendingSends == 0)
|
|
{
|
|
//
|
|
// No outstanding packets, we can start closing this call.
|
|
//
|
|
|
|
NdisVcHandle = Vc->NdisVcHandle;
|
|
NdisPartyHandle = NULL;
|
|
|
|
Vc->Flags |= ARPVC_CLOSING;
|
|
Vc->Flags &= ~ARPVC_CLOSE_PENDING;
|
|
Vc->Flags &= ~ARPVC_ACTIVE;
|
|
|
|
//
|
|
// The ArpEntry part of the Vc gets cleaned up seperately.
|
|
//
|
|
Vc->ArpEntry = NULL;
|
|
|
|
ASSERT(Vc->HwAddr.SubAddress == NULL);
|
|
|
|
RemoveEntryList(&Vc->List);
|
|
InsertHeadList(&pIntF->InactiveVcHead, &Vc->List);
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
Status = NdisClCloseCall(NdisVcHandle, NdisPartyHandle, NULL, 0);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseCallComplete(Status, Vc, (NDIS_HANDLE)NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Mark this Vc as needing CloseCall.
|
|
//
|
|
Vc->Flags &= ~ARPVC_ACTIVE;
|
|
Vc->Flags |= ARPVC_CLOSE_PENDING;
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
DeregisterAllAddresses(
|
|
IN PINTF pIntF
|
|
)
|
|
{
|
|
//
|
|
// Deregister any registered addresses from the switch.
|
|
//
|
|
ULONG NumAllocedRegdAddresses;
|
|
PATM_ADDRESS RegAddresses;
|
|
KIRQL OldIrql;
|
|
NDIS_STATUS Status;
|
|
ULONG NumAddressesRegd;
|
|
|
|
// Clear the registered address field.
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
NumAllocedRegdAddresses = pIntF->NumAllocedRegdAddresses;
|
|
RegAddresses = pIntF->RegAddresses;
|
|
pIntF->NumAllocedRegdAddresses = 0;
|
|
pIntF->RegAddresses = NULL;
|
|
NumAddressesRegd = pIntF->NumAddressesRegd;
|
|
pIntF->NumAddressesRegd = 0;
|
|
|
|
// Deregister all registered addresses with the switch.
|
|
//
|
|
if (NumAddressesRegd)
|
|
{
|
|
KEVENT DelAddressesEvent;
|
|
BOOLEAN fRet;
|
|
KeInitializeEvent(&DelAddressesEvent, NotificationEvent, FALSE);
|
|
ASSERT(pIntF->DelAddressesEvent == NULL);
|
|
ASSERT(pIntF->NumPendingDelAddresses == 0);
|
|
pIntF->DelAddressesEvent = &DelAddressesEvent;
|
|
pIntF->NumPendingDelAddresses = NumAllocedRegdAddresses;
|
|
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
DBGPRINT(DBG_LEVEL_WARN, ("DeregisterAllAddresses: Going to derigester addresses\n"));
|
|
|
|
fRet = ArpSDeleteIntFAddresses(
|
|
pIntF,
|
|
NumAllocedRegdAddresses,
|
|
RegAddresses
|
|
);
|
|
|
|
if (fRet == FALSE)
|
|
{
|
|
// This means that deregistration was not started for ALL addresses
|
|
// This is a bad situation, and in this case, we don't wait.
|
|
//
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
pIntF->DelAddressesEvent = NULL;
|
|
pIntF->NumPendingDelAddresses = 0;
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
}
|
|
else
|
|
{
|
|
|
|
DBGPRINT(DBG_LEVEL_WARN, ("DeregisterAllAddresses: Waiting for addresses to be deleted\n"));
|
|
WAIT_FOR_OBJECT(Status, &DelAddressesEvent, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
}
|
|
|
|
|
|
// Free RegAddresses.
|
|
//
|
|
if (RegAddresses)
|
|
{
|
|
FREE_MEM(RegAddresses);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ArpSTryCloseAdapter(
|
|
IN PINTF pIntF // NOLOCKIN LOLOCKOUT
|
|
)
|
|
//
|
|
// Close adapter if it's still in the "open" state. Need to
|
|
// guard against closing the adapter more than once.
|
|
//
|
|
{
|
|
KIRQL OldIrql;
|
|
BOOLEAN bCloseAdapter;
|
|
NDIS_STATUS Status;
|
|
|
|
bCloseAdapter = FALSE;
|
|
|
|
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
|
|
if (pIntF->Flags & INTF_ADAPTER_OPENED)
|
|
{
|
|
pIntF->Flags &= ~INTF_ADAPTER_OPENED;
|
|
bCloseAdapter = TRUE;
|
|
}
|
|
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
|
|
|
|
if (bCloseAdapter)
|
|
{
|
|
NdisCloseAdapter(&Status, pIntF->NdisBindingHandle);
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
ArpSCloseAdapterComplete(pIntF, Status);
|
|
}
|
|
}
|
|
}
|
|
|