Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

2741 lines
56 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);
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;
PSINGLE_LIST_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;
//
// 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
{
pIntF->Flags |= INTF_ADAPTER_OPENED;
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;
KIRQL OldIrql;
if (Status == NDIS_STATUS_SUCCESS)
{
pIntF->NdisAfHandle = NdisAfHandle;
if (ArpSReferenceIntF(pIntF))
{
//
// Insert this into the global adapter list
//
ACQUIRE_SPIN_LOCK(&ArpSIfListLock, &OldIrql);
ACQUIRE_SPIN_LOCK_DPC(&pIntF->Lock);
pIntF->Flags |= INTF_AF_OPENED;
pIntF->Next = ArpSIfList;
ArpSIfList = pIntF;
ArpSIfListSize++;
RELEASE_SPIN_LOCK_DPC(&pIntF->Lock);
RELEASE_SPIN_LOCK(&ArpSIfListLock, 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;
DBGPRINT(DBG_LEVEL_NOTICE,
("CloseAfComplete: pIntF %x, Flags %x, Ref %x, Intf %Z\n",
pIntF, pIntF->Flags, pIntF->RefCount, &pIntF->InterfaceName));
pIntF->NdisAfHandle = NULL;
//
// 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)
{
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, "");
//
// 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;
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 (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)
{
(VOID)NdisCoDeleteVc(NdisVcHandle);
}
}
}
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);
}
}
}