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.
 
 
 
 
 
 

4956 lines
139 KiB

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
nd.c
Abstract:
ARP1394 ndis handlers (excluding connection-oriented handlers).
Revision History:
Who When What
-------- -------- ----------------------------------------------
josephj 12-01-98 Created, adapting code from atmarpc.sys
Notes:
--*/
#include <precomp.h>
//
// File-specific debugging defaults.
//
#define TM_CURRENT TM_ND
//=========================================================================
// L O C A L P R O T O T Y P E S
//=========================================================================
// ARP1394_BIND_PARAMS is used when creating an adapter object.
//
typedef struct
{
PNDIS_STRING pDeviceName;
PNDIS_STRING pArpConfigName;
PVOID IpConfigHandle;
NDIS_HANDLE BindContext;
} ARP1394_BIND_PARAMS;
NDIS_STATUS
arpPnPReconfigHandler(
IN ARP1394_ADAPTER * pAdapter,
IN PNET_PNP_EVENT pNetPnPEvent
);
ENetAddr
arpGetSecondaryMacAddress (
IN ENetAddr EthernetMacAddress
);
NDIS_STATUS
arpGetEuidTopologyWorkItem(
struct _ARP1394_WORK_ITEM* pWorkItem,
PRM_OBJECT_HEADER pObj ,
PRM_STACK_RECORD pSR
);
VOID
arpAddBackupTasks (
IN ARP1394_GLOBALS* pGlobals,
UINT Num
);
VOID
arpRemoveBackupTasks (
IN ARP1394_GLOBALS* pGlobals,
UINT Num
);
NDIS_STATUS
arpNdSetPower (
ARP1394_ADAPTER *pAdapter,
PNET_DEVICE_POWER_STATE pPowerState,
PRM_STACK_RECORD pSR
);
NDIS_STATUS
arpResume (
IN ARP1394_ADAPTER* pAdapter,
IN ARP_RESUME_CAUSE Cause,
IN PRM_STACK_RECORD pSR
);
const ENetAddr DummyENet = {0xba,0xdb,0xad,0xba,0xdb,0xad};
//=========================================================================
// N D I S H A N D L E R S
//=========================================================================
INT
ArpNdBindAdapter(
OUT PNDIS_STATUS pStatus,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING pDeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
/*++
Routine Description:
This is called by NDIS when it has an adapter for which there is a
binding to the ARP client.
We first allocate an Adapter structure. Then we open our configuration
section for this adapter and save the handle in the Adapter structure.
Finally, we open the adapter.
We don't do anything more for this adapter until NDIS notifies us of
the presence of a Call manager (via our AfRegisterNotify handler).
Arguments:
pStatus - Place to return status of this call
BindContext - NDIS-supplied Bind context. IF this is NULL,
we are calling ourselves to open an adapter in
Ethernet emulation (bridge) mode.
pDeviceName - The name of the adapter we are requested to bind to
SystemSpecific1 - Opaque to us; to be used to access configuration info
SystemSpecific2 - Opaque to us; not used.
Return Value:
Always TRUE. We set *pStatus to an error code if something goes wrong before we
call NdisOpenAdapter, otherwise NDIS_STATUS_PENDING.
--*/
{
NDIS_STATUS Status;
ARP1394_ADAPTER * pAdapter;
#if DBG
KIRQL EntryIrql = KeGetCurrentIrql();
#endif // DBG
ENTER("BindAdapter", 0x5460887b)
RM_DECLARE_STACK_RECORD(sr)
TIMESTAMP("==>BindAdapter");
if (g_SkipAll)
{
TR_WARN(("aborting\n"));
*pStatus = NDIS_STATUS_NOT_RECOGNIZED;
TIMESTAMP("<==BindAdapter");
return TRUE;
}
do
{
PRM_TASK pTask;
ARP1394_BIND_PARAMS BindParams;
// Setup initialization parameters
//
BindParams.pDeviceName = pDeviceName;
BindParams.pArpConfigName = (PNDIS_STRING) SystemSpecific1;
BindParams.IpConfigHandle = SystemSpecific2;
BindParams.BindContext = BindContext;
// Allocate and initialize adapter object.
// This also sets up ref counts for all linkages, plus one
// tempref for us, which we must deref when done.
//
Status = RM_CREATE_AND_LOCK_OBJECT_IN_GROUP(
&ArpGlobals.adapters.Group,
pDeviceName, // Key
&BindParams, // Init params
&((PRM_OBJECT_HEADER)pAdapter),
NULL, // pfCreated
&sr
);
if (FAIL(Status))
{
TR_WARN(("FATAL: Couldn't create adapter object\n"));
pAdapter = NULL;
break;
}
// Allocate task to complete the initialization.
// The task is tmp ref'd for us, and we must deref it when we're done here.
// We implicitly do this by calling RmStartTask below.
//
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskInitializeAdapter, // pfnHandler,
0, // Timeout,
"Task: Initialize Adapter", // szDescription
&pTask,
&sr
);
if (FAIL(Status))
{
pTask = NULL;
break;
}
UNLOCKOBJ(pAdapter, &sr);
// Start the task to complete this initialization.
// NO locks must be held at this time.
// RmStartTask expect's a tempref on the task, which it deref's when done.
// RmStartTask will free the task automatically, whether it completes
// synchronously or asynchronously.
//
Status = RmStartTask(pTask, 0, &sr);
LOCKOBJ(pAdapter, &sr);
} while(FALSE);
if (pAdapter)
{
UNLOCKOBJ(pAdapter, &sr);
if (!PEND(Status) && FAIL(Status))
{
#if 0
RmFreeObjectInGroup(
&ArpGlobals.adapters.Group,
&(pAdapter->Hdr),
NULL, // NULL pTask == synchronous.
&sr
);
#endif // 0
// At this point the adapter should be a "zombie object."
//
ASSERTEX(RM_IS_ZOMBIE(pAdapter), pAdapter);
}
RmTmpDereferenceObject(&pAdapter->Hdr, &sr);
}
*pStatus = Status;
#if DBG
{
KIRQL ExitIrql = KeGetCurrentIrql();
TR_INFO(("Exiting. EntryIrql=%lu, ExitIrql = %lu\n", EntryIrql, ExitIrql));
}
#endif //DBG
RM_ASSERT_CLEAR(&sr);
EXIT()
TIMESTAMP("<==BindAdapter");
return 0;
}
VOID
ArpNdUnbindAdapter(
OUT PNDIS_STATUS pStatus,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
)
/*++
Routine Description:
This routine is called by NDIS when it wants us to unbind
from an adapter. Or, this may be called from within our Unload
handler. We undo the sequence of operations we performed
in our BindAdapter handler.
Arguments:
pStatus - Place to return status of this operation
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to an ATMARP Adapter structure.
UnbindContext - This is NULL if this routine is called from
within our Unload handler. Otherwise (i.e.
NDIS called us), we retain this for later use
when calling NdisCompleteUnbindAdapter.
Return Value:
None. We set *pStatus to NDIS_STATUS_PENDING always.
--*/
{
ENTER("UnbindAdapter", 0x6bff4ab5)
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
RM_DECLARE_STACK_RECORD(sr)
TIMESTAMP("==>UnbindAdapter");
// Get adapter lock and tmpref it.
LOCKOBJ(pAdapter, &sr);
RmTmpReferenceObject(&pAdapter->Hdr, &sr);
do
{
NDIS_STATUS Status;
PRM_TASK pTask;
if (CHECK_POWER_STATE(pAdapter,ARPAD_POWER_LOW_POWER)== TRUE)
{
pAdapter->PoMgmt.bReceivedUnbind = TRUE;;
}
// Allocate task to complete the unbind.
//
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskShutdownAdapter, // pfnHandler,
0, // Timeout,
"Task: Shutdown Adapter", // szDescription
&pTask,
&sr
);
if (FAIL(Status))
{
// Ugly situation. We'll just leave things as they are...
//
pTask = NULL;
TR_WARN(("FATAL: couldn't allocate unbind task!\n"));
break;
}
// Start the task to complete the unbind.
// No locks must be held. RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
UNLOCKOBJ(pAdapter, &sr);
Status = RmStartTask(pTask, (UINT_PTR) UnbindContext, &sr);
LOCKOBJ(pAdapter, &sr);
} while(FALSE);
UNLOCKOBJ(pAdapter, &sr);
RmTmpDereferenceObject(&pAdapter->Hdr, &sr);
*pStatus = NDIS_STATUS_PENDING;
RM_ASSERT_CLEAR(&sr);
TIMESTAMP("<==UnbindAdapter");
EXIT()
}
VOID
ArpNdOpenAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
/*++
Routine Description:
This is called by NDIS when a previous call to NdisOpenAdapter
that had pended has completed. We now complete the BindAdapter
that lead to this.
Arguments:
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to an ARP1394_ADAPTER structure.
Status - Status of OpenAdapter
OpenErrorStatus - Error code in case of failure.
--*/
{
ENTER("OpenAdapterComplete", 0x06d9342c)
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
RM_DECLARE_STACK_RECORD(sr)
TIMESTAMP("==>OpenAdapterComplete");
// We expect a nonzero task here (the bind task), which we unpend.
// No need to grab locks or anything at this stage.
//
{
TR_INFO((
"BindCtxt=0x%p, status=0x%p, OpenErrStatus=0x%p",
ProtocolBindingContext,
Status,
OpenErrorStatus
));
// We don't pass on OpenErrorStatus, so we have just the status
// to pass on, which we do directly as the UINT_PTR "Param".
//
RmResumeTask(pAdapter->bind.pSecondaryTask, (UINT_PTR) Status, &sr);
}
RM_ASSERT_CLEAR(&sr)
EXIT()
TIMESTAMP("<==OpenAdapterComplete");
}
VOID
ArpNdCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
Routine Description:
This is called by NDIS when a previous call to NdisCloseAdapter
that had pended has completed. The task that called NdisCloseAdapter
would have suspended itself, so we simply resume it now.
Arguments:
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to an ARP1394_ADAPTER structure.
Status - Status of CloseAdapter
Return Value:
None
--*/
{
ENTER("CloseAdapterComplete", 0x889d22eb)
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
RM_DECLARE_STACK_RECORD(sr)
TIMESTAMP("==>CloseAdapterComplete");
// We expect a nonzero task here (UNbind task), which we unpend.
// No need to grab locks or anything at this stage.
//
RmResumeTask(pAdapter->bind.pSecondaryTask, (UINT_PTR) Status, &sr);
TIMESTAMP("<==CloseAdapterComplete");
RM_ASSERT_CLEAR(&sr)
EXIT()
}
VOID
ArpNdResetComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
Routine Description:
This routine is called when the miniport indicates that a Reset
operation has just completed. We ignore this event.
Arguments:
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to our Adapter structure.
Status - Status of the reset operation.
Return Value:
None
--*/
{
TIMESTAMP("===ResetComplete");
}
VOID
ArpNdReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++
Routine Description:
This is called by NDIS when the miniport is done with receiving
a bunch of packets, meaning that it is now time to start processing
them. We simply pass this on to IP.
Arguments:
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to an ARP1394_ADAPTER structure.
Return Value:
None
--*/
{
PARP1394_ADAPTER pAdapter;
PARP1394_INTERFACE pIF;
pAdapter = (PARP1394_ADAPTER)ProtocolBindingContext;
pIF = pAdapter->pIF;
//
// WARNING: for perf reasons, we don't do the clean thing of
// locking the adapter, refing pIF, unlocking the adapter,
// calling pIF->ip.RcvCmpltHandler, then derefing pIF.
//
if ((pIF != NULL) && (pIF->ip.Context != NULL))
{
#if MILLEN
ASSERT_PASSIVE();
#endif // MILLEN
pIF->ip.RcvCmpltHandler();
}
}
VOID
ArpNdRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST pNdisRequest,
IN NDIS_STATUS Status
)
/*++
Routine Description:
This is called by NDIS when a previous call we made to NdisRequest() has
completed.
Arguments:
ProtocolBindingContext - Pointer to our Adapter structure
pNdisRequest - The request that completed
Status - Status of the request.
Return Value:
None
--*/
{
PARP_NDIS_REQUEST pArpNdisRequest;
PRM_TASK pTask;
ENTER("ArpNdRequestComplete", 0x8cdf7a6d)
RM_DECLARE_STACK_RECORD(sr)
pArpNdisRequest = CONTAINING_RECORD(pNdisRequest, ARP_NDIS_REQUEST, Request);
pTask = pArpNdisRequest->pTask;
pArpNdisRequest->Status = Status;
if (pTask == NULL)
{
NdisSetEvent(&pArpNdisRequest->Event);
}
else
{
RmResumeTask(pTask, (UINT_PTR) Status, &sr);
}
EXIT()
}
VOID
ArpNdStatus(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS GeneralStatus,
IN PVOID pStatusBuffer,
IN UINT StatusBufferSize
)
/*++
Routine Description:
This routine is called when the miniport indicates an adapter-wide
status change. We ignore this.
Arguments:
<Ignored>
--*/
{
}
VOID
ArpNdStatusComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++
Routine Description:
This routine is called when the miniport wants to tell us about
completion of a status change (?). Ignore this.
Arguments:
<Ignored>
Return Value:
None
--*/
{
}
VOID
ArpNdSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket,
IN NDIS_STATUS Status
)
/*++
Routine Description:
This is the Connection-less Send Complete handler, which signals
completion of such a Send. Since we don't ever use this feature,
we don't expect this routine to be called.
Arguments:
<Ignored>
Return Value:
None
--*/
{
#if TEST_ICS_HACK
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
arpEthSendComplete(
pAdapter,
pNdisPacket,
Status
);
#else // TEST_ICS_HACK
ASSERT(FALSE);
#endif // TEST_ICS_HACK
}
NDIS_STATUS
ArpNdReceive (
NDIS_HANDLE ProtocolBindingContext,
NDIS_HANDLE Context,
VOID *Header,
UINT HeaderSize,
VOID *Data,
UINT Size,
UINT TotalSize
)
/*++
TODO: We need to support this for ICS, because MILL NDIS calls this
handler to indicate packets which have the STATUS_RESOURCES bit set.
--*/
{
return NDIS_STATUS_NOT_RECOGNIZED;
}
INT
ArpNdReceivePacket (
NDIS_HANDLE ProtocolBindingContext,
PNDIS_PACKET Packet
)
{
#if TEST_ICS_HACK
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
arpEthReceivePacket(
pAdapter->pIF,
Packet
);
#endif // TEST_ICS_HACK
return 0; // We return 0 because no one hangs on to this packet.
}
NDIS_STATUS
ArpNdPnPEvent(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNET_PNP_EVENT pNetPnPEvent
)
/*++
Routine Description:
This is the NDIS entry point called when NDIS wants to inform
us about a PNP/PM event happening on an adapter. If the event
is for us, we consume it. Otherwise, we pass this event along
to IP along the first Interface on this adapter.
When IP is done with it, it will call our IfPnPEventComplete
routine.
Arguments:
ProtocolBindingContext - Our context for this adapter binding, which
is a pointer to an ARP1394_ADAPTER structure.
pNetPnPEvent - Pointer to the event.
Return Value:
None
--*/
{
ENTER("PnPEvent", 0x2a517a8c)
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) ProtocolBindingContext;
ARP1394_INTERFACE * pIF = NULL;
NDIS_STATUS Status;
PIP_PNP_RECONFIG_REQUEST pIpReconfigReq;
ULONG Length;
RM_DECLARE_STACK_RECORD(sr)
#ifdef NT
do
{
pIpReconfigReq = (PIP_PNP_RECONFIG_REQUEST)pNetPnPEvent->Buffer;
Length = pNetPnPEvent->BufferLength;
TIMESTAMP1("==>PnPEvent 0x%lx", pNetPnPEvent->NetEvent);
//
// Do we have a binding context?
//
if (pAdapter == NULL)
{
Status = NDIS_STATUS_FAILURE;
break;
}
//
// Is this directed to us?
//
if (pNetPnPEvent->NetEvent == NetEventReconfigure)
{
#if MILLEN
DbgPrint("Arp1394: This should never be called on Millen\n");
//DbgBreakPoint(); // Never called on Millen.
#endif // MILLEN
if (Length < sizeof(IP_PNP_RECONFIG_REQUEST))
{
Status = NDIS_STATUS_RESOURCES;
break;
}
if (pIpReconfigReq->arpConfigOffset != 0)
{
Status = arpPnPReconfigHandler(pAdapter, pNetPnPEvent);
break;
}
}
//
// 01/21/2000 JosephJ: The NIC1394 MCM doesn't close AF's when it's shut
// down by NDIS during a powering down event. So
// we work around this by claiming not to support
// PnP Power so that NDIS closes US as well.
//
if (pNetPnPEvent->NetEvent == NetEventSetPower)
{
PNET_DEVICE_POWER_STATE pPowerState;
pPowerState = (PNET_DEVICE_POWER_STATE) pNetPnPEvent->Buffer;
Status = arpNdSetPower (pAdapter, pPowerState,&sr );
if (Status != NDIS_STATUS_SUCCESS)
{
break;
}
}
else
{
TIMESTAMPX("===PnPEvent (not SetPower)");
}
//
// This belongs to IP....
//
{
LOCKOBJ(pAdapter, &sr);
pIF = pAdapter->pIF;
if ((pIF != NULL) && (pIF->ip.Context != NULL))
{
RmTmpReferenceObject(&pIF->Hdr, &sr);
UNLOCKOBJ(pAdapter, &sr);
#if MILLEN
ASSERT_PASSIVE();
#endif // MILLEN
Status = pIF->ip.PnPEventHandler(
pIF->ip.Context,
pNetPnPEvent
);
RmTmpDereferenceObject(&pIF->Hdr, &sr);
}
else
{
UNLOCKOBJ(pAdapter, &sr);
Status = NDIS_STATUS_SUCCESS;
}
}
}
while (FALSE);
#else
Status = NDIS_STATUS_SUCCESS;
#endif // NT
TR_INFO((" pIF 0x%x, pEvent 0x%x, Evt 0x%x, Status 0x%x\n",
pIF, pNetPnPEvent, pNetPnPEvent->NetEvent, Status));
RM_ASSERT_CLEAR(&sr)
EXIT()
TIMESTAMP("<==PnPEvent");
return Status;
}
VOID
ArpNdUnloadProtocol(
VOID
)
/*++
Routine Description:
Unloads our protocol module. We unbind from all adapters,
and deregister from NDIS as a protocol.
Arguments:
None.
Return Value:
None
--*/
{
ENTER("UnloadProtocol", 0x8143fec5)
RM_DECLARE_STACK_RECORD(sr)
TIMESTAMP("==>UnloadProtocol");
RmUnloadAllGenericResources(&ArpGlobals.Hdr, &sr);
RM_ASSERT_CLEAR(&sr)
TIMESTAMP("<==UnloadProtocol");
EXIT()
return;
}
NDIS_STATUS
arpTaskInitializeAdapter(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler responsible for initializing an adapter.
Arguments:
UserParam for (Code == RM_TASKOP_START) : unused
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pTask);
PTASK_ADAPTERINIT pAdapterInitTask;
enum
{
STAGE_BecomePrimaryTask,
STAGE_ActivateAdapterComplete,
STAGE_DeactivateAdapterComplete,
STAGE_End
} Stage;
ENTER("TaskInitializeAdapter", 0xb6ada31d)
pAdapterInitTask = (PTASK_ADAPTERINIT) pTask;
ASSERT(sizeof(TASK_ADAPTERINIT) <= sizeof(ARP1394_TASK));
//
// Message normalizing code
//
switch(Code)
{
case RM_TASKOP_START:
Stage = STAGE_BecomePrimaryTask;
break;
case RM_TASKOP_PENDCOMPLETE:
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
Stage = RM_PEND_CODE(pTask);
break;
case RM_TASKOP_END:
Status = (NDIS_STATUS) UserParam;
Stage= STAGE_End;
break;
default:
ASSERT(FALSE);
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
}
ASSERTEX(!PEND(Status), pTask);
switch(Stage)
{
case STAGE_BecomePrimaryTask:
{
// If there is a primary task, pend on it, else make ourselves
// the primary task.
//
LOCKOBJ(pAdapter, pSR);
if (pAdapter->bind.pPrimaryTask == NULL)
{
arpSetPrimaryAdapterTask(pAdapter, pTask, ARPAD_PS_INITING, pSR);
UNLOCKOBJ(pAdapter, pSR);
}
else
{
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
UNLOCKOBJ(pAdapter, pSR);
RmPendTaskOnOtherTask(
pTask,
STAGE_BecomePrimaryTask, // we'll try again...
pOtherTask,
pSR
);
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
//
// We're now the primary task. Since we're starting out,
// there should be NO activate/deactivate task.
// (Note: we don't bother getting the adapter lock for these asserts).
//
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
ASSERT(pAdapter->bind.pSecondaryTask == NULL);
//
// Allocate and start the activate adapter task.
//
{
PRM_TASK pActivateTask;
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskActivateAdapter, // pfnHandler,
0, // Timeout,
"Task: Activate Adapter(init)", // szDescription
&pActivateTask,
pSR
);
if (FAIL(Status))
{
pActivateTask = NULL;
TR_WARN(("FATAL: couldn't alloc activate task!\n"));
}
else
{
RmPendTaskOnOtherTask(
pTask,
STAGE_ActivateAdapterComplete,
pActivateTask, // task to pend on
pSR
);
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pActivateTask,
0, // UserParam (unused)
pSR
);
}
}
}
if (PEND(Status)) break;
// FALL THROUGH TO NEXT STAGE
case STAGE_ActivateAdapterComplete:
{
//
// We've run the active-adapter task. On failure, we need to
// cleanup state by calling the deactivate-adapter task.
//
// Save away the failure code for later...
//
pAdapterInitTask->ReturnStatus = Status;
if (FAIL(Status))
{
PRM_TASK pDeactivateTask;
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskDeactivateAdapter, // pfnHandler,
0, // Timeout,
"Task: Deactivate Adapter(init)", // szDescription
&pDeactivateTask,
pSR
);
if (FAIL(Status))
{
pDeactivateTask = NULL;
ASSERT(FALSE); // TODO: use special dealloc task pool for this.
TR_WARN(("FATAL: couldn't alloc deactivate task!\n"));
}
else
{
RmPendTaskOnOtherTask(
pTask,
STAGE_DeactivateAdapterComplete,
pDeactivateTask, // task to pend on
pSR
);
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pDeactivateTask,
0, // UserParam (unused)
pSR
);
}
}
}
break;
case STAGE_DeactivateAdapterComplete:
{
//
// We've completed the deactivate adapter task which we started
// because of some init-adapter failure.
//
// In general, we don't expect the deactivate task to return failure.
//
ASSERT(!FAIL(Status));
// We expect the original status of the init to be a failure (that's
// why we started the deinit in the first place!
//
ASSERT(FAIL(pAdapterInitTask->ReturnStatus));
Status = pAdapterInitTask->ReturnStatus;
}
break;
case STAGE_End:
{
NDIS_HANDLE BindContext;
BOOLEAN BridgeEnabled = ARP_BRIDGE_ENABLED(pAdapter);
//
// We HAVE to be the primary task at this point, becase we simply
// wait and retry until we become one.
//
// Clear the primary task in the adapter object.
//
LOCKOBJ(pAdapter, pSR);
{
ULONG InitState;
InitState = FAIL(Status) ? ARPAD_PS_FAILEDINIT : ARPAD_PS_INITED;
arpClearPrimaryAdapterTask(pAdapter, pTask, InitState, pSR);
}
BindContext = pAdapter->bind.BindContext;
UNLOCKOBJ(pAdapter, pSR);
// On failure, pAdapter should be deallocated.
//
if (FAIL(Status))
{
if(RM_IS_ZOMBIE(pAdapter))
{
TR_WARN(("END: pAdapter is already deallocated.\n"));
}
else
{
//
// On failure, free the adapter here itself, because we're
// not going to call the shutdown task.
//
RmFreeObjectInGroup(
&ArpGlobals.adapters.Group,
&(pAdapter->Hdr),
NULL, // NULL pTask == synchronous.
pSR
);
}
}
if (!BridgeEnabled)
{
// Signal IP that the bind is complete.
//
TIMESTAMP("===Calling IP's BindComplete routine");
RM_ASSERT_NOLOCKS(pSR);
ArpGlobals.ip.pBindCompleteRtn(
Status,
BindContext
);
}
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Code)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskShutdownAdapter(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler responsible for shutting down an IP interface.
Arguments:
UserParam for (Code == RM_TASKOP_START) : UnbindContext
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pTask);
TASK_ADAPTERSHUTDOWN *pMyTask = (TASK_ADAPTERSHUTDOWN*) pTask;
enum
{
STAGE_BecomePrimaryTask,
STAGE_DeactivateAdapterComplete,
STAGE_End
} Stage;
ENTER("TaskShutdownAdapter", 0xe262e828)
//
// Message normalizing code
//
switch(Code)
{
case RM_TASKOP_START:
Stage = STAGE_BecomePrimaryTask;
// Save away the UnbindContext (which we get as UserParam) in
// the task's private context, for use later.
//
pMyTask->pUnbindContext = (NDIS_HANDLE) UserParam;
break;
case RM_TASKOP_PENDCOMPLETE:
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
Stage = RM_PEND_CODE(pTask);
break;
case RM_TASKOP_END:
Status = (NDIS_STATUS) UserParam;
Stage= STAGE_End;
break;
default:
ASSERT(FALSE);
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
}
ASSERTEX(!PEND(Status), pTask);
switch(Stage)
{
case STAGE_BecomePrimaryTask:
{
// If there is a primary task, pend on it, else make ourselves
// the primary task.
// We could get in this situation if someone does a
// "net stop arp1394" while we're in the middle of initializing or
// shutting down the adapter.
//
//
LOCKOBJ(pAdapter, pSR);
if (pAdapter->bind.pPrimaryTask == NULL)
{
arpSetPrimaryAdapterTask(pAdapter, pTask, ARPAD_PS_DEINITING, pSR);
UNLOCKOBJ(pAdapter, pSR);
}
else
{
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
UNLOCKOBJ(pAdapter, pSR);
RmPendTaskOnOtherTask(
pTask,
STAGE_BecomePrimaryTask, // we'll try again...
pOtherTask,
pSR
);
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
//
// We're now the primary task. Since we're starting out,
// there should be NO activate/deactivate task.
// (Note: we don't bother getting the adapter lock for these asserts).
//
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
ASSERT(pAdapter->bind.pSecondaryTask == NULL);
//
// Allocate and start the deactivate adapter task.
//
{
PRM_TASK pDeactivateTask;
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskDeactivateAdapter, // pfnHandler,
0, // Timeout,
"Task: Deactivate Adapter(shutdown)", // szDescription
&pDeactivateTask,
pSR
);
if (FAIL(Status))
{
pDeactivateTask = NULL;
TR_WARN(("FATAL: couldn't alloc deactivate task!\n"));
}
else
{
RmPendTaskOnOtherTask(
pTask,
STAGE_DeactivateAdapterComplete,
pDeactivateTask, // task to pend on
pSR
);
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pDeactivateTask,
0, // UserParam (unused)
pSR
);
}
}
}
break;
case STAGE_DeactivateAdapterComplete:
{
// Nothing to do here -- we clean up in STAGE_End.
//
break;
}
case STAGE_End:
{
//
// We HAVE to be the primary task at this point, becase we simply
// wait and retry until we become one.
//
ASSERT(pAdapter->bind.pPrimaryTask == pTask);
// Clear the primary task in the adapter object.
//
LOCKOBJ(pAdapter, pSR);
arpClearPrimaryAdapterTask(pAdapter, pTask, ARPAD_PS_DEINITED, pSR);
UNLOCKOBJ(pAdapter, pSR);
if(RM_IS_ZOMBIE(pAdapter))
{
TR_WARN(("END: pAdapter is already deallocated.\n"));
}
else
{
// Free the adapter.
// (pAdapter will be allocated, but it will be in a "zombie" state).
//
RmFreeObjectInGroup(
&ArpGlobals.adapters.Group,
&(pAdapter->Hdr),
NULL, // NULL pTask == synchronous.
pSR
);
}
// If there is an unbind-context, signal NDIS that the unbind is
// complete.
//
if (pMyTask->pUnbindContext)
{
TR_WARN(("END: Calling NdisCompleteUnbindAdapter. Status= 0x%lx\n",
Status));
RM_ASSERT_NOLOCKS(pSR);
TIMESTAMP("===Calling NdisCompleteUnbindAdapter");
NdisCompleteUnbindAdapter(
pMyTask->pUnbindContext,
Status
);
}
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Code)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskActivateAdapter(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler responsible for initializing an adapter.
Arguments:
UserParam for (Code == RM_TASKOP_START) : unused
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pTask);
enum
{
PEND_OpenAdapter,
PEND_GetAdapterInfo
};
ENTER("arpTaskActivateAdapter", 0xb6ada31d)
switch(Code)
{
case RM_TASKOP_START:
{
#if MILLEN
NDIS_MEDIUM Medium = NdisMedium802_3;
#else // !MILLEN
NDIS_MEDIUM Medium = NdisMedium802_3;
#endif // !MILLEN
UINT SelMediumIndex = 0;
NDIS_STATUS OpenStatus;
//
// Allocate Backup Tasks
//
arpAddBackupTasks (&ArpGlobals,ARP1394_BACKUP_TASKS);
// Set ourselves as the secondary task.
//
LOCKOBJ(pAdapter, pSR);
arpSetSecondaryAdapterTask(pAdapter, pTask, ARPAD_AS_ACTIVATING, pSR);
UNLOCKOBJ(pAdapter, pSR);
//
// Suspend task and call NdisOpenAdapter...
//
RmSuspendTask(pTask, PEND_OpenAdapter, pSR);
RM_ASSERT_NOLOCKS(pSR);
NdisOpenAdapter(
&Status,
&OpenStatus,
&pAdapter->bind.AdapterHandle,
&SelMediumIndex, // selected medium index
&Medium, // Array of medium types
1, // Size of Media list
ArpGlobals.ndis.ProtocolHandle,
(NDIS_HANDLE)pAdapter, // our adapter bind context
&pAdapter->bind.DeviceName, // pDeviceName
0, // Open options
(PSTRING)NULL // Addressing Info...
);
if (Status != NDIS_STATUS_PENDING)
{
ArpNdOpenAdapterComplete(
(NDIS_HANDLE)pAdapter,
Status,
OpenStatus
);
}
Status = NDIS_STATUS_PENDING;
}
break;
case RM_TASKOP_PENDCOMPLETE:
{
PTASK_ADAPTERACTIVATE pAdapterInitTask;
pAdapterInitTask = (PTASK_ADAPTERACTIVATE) pTask;
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
ASSERT(sizeof(TASK_ADAPTERACTIVATE) <= sizeof(ARP1394_TASK));
switch(RM_PEND_CODE(pTask))
{
case PEND_OpenAdapter:
//
// The open adapter operation is complete. Get adapter
// information and notify IP on success. On failure,
// shutdown the adapter if required, and notify IP of
// the failure.
//
if (FAIL(Status))
{
// Set adapter handle to null -- it may not be hull.
// even though the open adapter has succeeded.
//
pAdapter->bind.AdapterHandle = NULL;
break;
}
// Successfully opened the adapter.
// Now get adapter information from miniport.
// (We use the TASK_ADAPTERINIT.ArpNdisRequest field,
// which is defined specifically for this use).
//
Status = arpPrepareAndSendNdisRequest(
pAdapter,
&pAdapterInitTask->ArpNdisRequest,
NULL, // pTask - Finish the request synchronously
PEND_GetAdapterInfo,
OID_1394_LOCAL_NODE_INFO,
&pAdapterInitTask->LocalNodeInfo,
sizeof(pAdapterInitTask->LocalNodeInfo),
NdisRequestQueryInformation,
pSR
);
ASSERT(!PEND(Status));
if (PEND(Status)) break;
// FALL THROUGH on synchronous completion of arpGetAdapterInfo...
case PEND_GetAdapterInfo:
//
// Done with getting adapter info.
// We need to switch to passive before going further
//
if (!ARP_ATPASSIVE())
{
// We're not at passive level, but we need to be when we
// call IP's add interface. So we switch to passive...
// NOTE: we specify completion code PEND_GetAdapterInfo
// because we want to get back here (except
// we'll be at passive).
//
RmSuspendTask(pTask, PEND_GetAdapterInfo, pSR);
RmResumeTaskAsync(
pTask,
Status,
&pAdapterInitTask->WorkItem,
pSR
);
Status = NDIS_STATUS_PENDING;
break;
}
if (Status == NDIS_STATUS_SUCCESS)
{
//
// Copy over adapter info into pAdapter->info...
// Then read configuration information.
//
LOCKOBJ(pAdapter, pSR);
ARP_ZEROSTRUCT(&pAdapter->info);
// OID_GEN_CO_VENDOR_DESCRIPTION
//
pAdapter->info.szDescription = "NIC1394";
pAdapter->info.DescriptionLength = sizeof("NIC1394");
// TODO -- when you do the real stuff, remember to free it.
// Max Frame size
// TODO: fill in the real adapter's MTU.
//
pAdapter->info.MTU = ARP1394_ADAPTER_MTU;
pAdapter->info.LocalUniqueID =
pAdapterInitTask->LocalNodeInfo.UniqueID;
{
UINT MaxRec;
UINT MaxSpeedCode;
MaxSpeedCode =
pAdapterInitTask->LocalNodeInfo.MaxRecvSpeed;
MaxRec =
pAdapterInitTask->LocalNodeInfo.MaxRecvBlockSize;
#if DBG
while ( !IP1394_IS_VALID_MAXREC(MaxRec)
|| !IP1394_IS_VALID_SSPD(MaxSpeedCode)
|| MaxSpeedCode == 0)
{
TR_WARN(("FATAL: Invalid maxrec(0x%x) or sspd(0x%x)!\n",
MaxRec,
MaxSpeedCode
));
TR_WARN((" &maxrec=0x%p, &sspd=0x%p\n",
&MaxRec,
&MaxSpeedCode
));
DbgBreakPoint();
}
TR_WARN(("Selected maxrec=0x%x and sspd=0x%x.\n",
MaxRec,
MaxSpeedCode
));
#endif // DBG
pAdapter->info.MaxRec = MaxRec;
pAdapter->info.MaxSpeedCode = MaxSpeedCode;
}
// B TODO: we should get this from the NIC -- add
// to the IOCTL OR query the adapter for its
// MAC address.
// For now we put a hardcoded MAC address.
//
#define ARP_FAKE_ETH_ADDRESS(_AdapterNum) \
{ \
0x02 | (((UCHAR)(_AdapterNum) & 0x3f) << 2), \
((UCHAR)(_AdapterNum) & 0x3f), \
0,0,0,0 \
}
#define ARP_DEF_LOCAL_ETH_ADDRESS \
ARP_FAKE_ETH_ADDRESS(0x1)
UNLOCKOBJ(pAdapter, pSR);
//
// Query the adapter for its Mac Addrees
//
{
ENetAddr LocalEthAddr;
ARP_NDIS_REQUEST ArpNdisRequest;
ARP_ZEROSTRUCT (&ArpNdisRequest);
Status = arpPrepareAndSendNdisRequest(
pAdapter,
&ArpNdisRequest,
NULL, // pTask (NULL==BLOCK)
0, // unused
OID_802_3_CURRENT_ADDRESS,
&LocalEthAddr,
sizeof(LocalEthAddr),
NdisRequestQueryInformation,
pSR
);
LOCKOBJ(pAdapter, pSR);
if (Status == NDIS_STATUS_SUCCESS)
{
pAdapter->info.EthernetMacAddress = LocalEthAddr;
}
else
{
//
// we'll make one up if the miniport isn't responding
//
static ENetAddr LocalEthAddr =
ARP_DEF_LOCAL_ETH_ADDRESS;
pAdapter->info.EthernetMacAddress =
LocalEthAddr;
//Do not fail because of a bad request
ASSERT (Status == NDIS_STATUS_SUCCESS);
Status = NDIS_STATUS_SUCCESS;
}
UNLOCKOBJ(pAdapter, pSR);
}
//
// Query the adapter for its Speed
//
{
NDIS_CO_LINK_SPEED CoLinkSpeed;
ARP_NDIS_REQUEST ArpNdisRequest;
ARP_ZEROSTRUCT (&ArpNdisRequest);
Status = arpPrepareAndSendNdisRequest(
pAdapter,
&ArpNdisRequest,
NULL, // pTask (NULL==BLOCK)
0, // unused
OID_GEN_CO_LINK_SPEED,
&CoLinkSpeed,
sizeof(CoLinkSpeed),
NdisRequestQueryInformation,
pSR
);
LOCKOBJ(pAdapter, pSR);
if (Status == NDIS_STATUS_SUCCESS)
{
//
// if nic1394 is in ethernet mode- it will fill in only one ULONG
// therefore rchoose outbound because it is the first ulong
// Multiply by 100 - thats what ethArp does.
//
pAdapter->info.Speed= (CoLinkSpeed.Outbound *100);
}
else
{
//
// we'll make one up if the miniport isn't responding
//
pAdapter->info.Speed = 2000000; // Bytes/sec
//Do not fail because of a bad request
ASSERT (Status == NDIS_STATUS_SUCCESS);
Status = NDIS_STATUS_SUCCESS;
}
UNLOCKOBJ(pAdapter, pSR);
}
// Query the adapter for its Table of RemoteNodes
//
Status = arpGetEuidTopologyWorkItem(NULL, &pAdapter->Hdr, pSR);
// Read Adapter Configuration Information
//
Status = arpCfgReadAdapterConfiguration(pAdapter, pSR);
}
//
// NOTE: if we fail, a higher level task is responsible
// for "running the compensating transaction", i.e., running
// arpTaskDeactivateAdapter.
//
// end case PEND_OpenAdapter, PEND_GetAdapterInfo
break;
default:
{
ASSERTEX(!"Unknown pend op", pTask);
}
break;
} // end switch(RM_PEND_CODE(pTask))
} // case RM_TASKOP_PENDCOMPLETE
break;
case RM_TASKOP_END:
{
Status = (NDIS_STATUS) UserParam;
// We're done -- the status had better not be pending!
//
ASSERTEX(!PEND(Status), pTask);
// Clear ourselves as the secondary task in the adapter object.
//
{
ULONG InitState;
LOCKOBJ(pAdapter, pSR);
InitState = FAIL(Status)
? ARPAD_AS_FAILEDACTIVATE
: ARPAD_AS_ACTIVATED;
arpClearSecondaryAdapterTask(pAdapter, pTask, InitState, pSR);
UNLOCKOBJ(pAdapter, pSR);
}
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Code)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskDeactivateAdapter(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler responsible for shutting down an IP interface.
Arguments:
UserParam for (Code == RM_TASKOP_START) : UnbindContext
--*/
{
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pTask);
BOOLEAN fContinueShutdown = FALSE;
enum
{
PEND_ShutdownIF,
PEND_CloseAdapter
};
ENTER("arpTaskDeactivateAdapter", 0xe262e828)
switch(Code)
{
case RM_TASKOP_START:
{
LOCKOBJ(pAdapter, pSR);
arpSetSecondaryAdapterTask(pAdapter, pTask, ARPAD_AS_DEACTIVATING, pSR);
UNLOCKOBJ(pAdapter, pSR);
fContinueShutdown = TRUE;
}
break;
case RM_TASKOP_PENDCOMPLETE:
{
switch(RM_PEND_CODE(pTask))
{
case PEND_CloseAdapter:
{
//
// The close adapter operation is complete. Free the the
// adapter and if there is an unbind context, notify NDIS
// of unbind completion.
//
ASSERTEX(pAdapter->bind.AdapterHandle == NULL, pAdapter);
Status = (NDIS_STATUS) UserParam;
//
// free the back up tasks allocated in Task Activate Adapter
//
arpRemoveBackupTasks (&ArpGlobals,ARP1394_BACKUP_TASKS);
// Status of the completed operation can't itself be pending!
//
ASSERT(Status != NDIS_STATUS_PENDING);
}
break;
case PEND_ShutdownIF:
{
//
// Closing the IF is complete, continue with the rest
// of the shutdown procedure..
//
ASSERTEX(pAdapter->pIF == NULL, pAdapter);
fContinueShutdown = TRUE;
}
break;
}
}
break;
case RM_TASKOP_END:
{
Status = (NDIS_STATUS) UserParam;
// Clear the secondary task in the adapter object.
//
LOCKOBJ(pAdapter, pSR);
arpClearSecondaryAdapterTask(pAdapter, pTask, ARPAD_AS_DEACTIVATED, pSR);
UNLOCKOBJ(pAdapter, pSR);
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Code)
if (fContinueShutdown)
{
do {
NDIS_HANDLE NdisAdapterHandle;
LOCKOBJ(pAdapter, pSR);
// If required, shutdown interface...
//
if (pAdapter->pIF)
{
PARP1394_INTERFACE pIF = pAdapter->pIF;
RmTmpReferenceObject(&pIF->Hdr, pSR);
UNLOCKOBJ(pAdapter, pSR);
arpDeinitIf(
pIF,
pTask,
PEND_ShutdownIF,
pSR
);
RmTmpDereferenceObject(&pIF->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
ASSERT(pAdapter->pIF == NULL);
NdisAdapterHandle = pAdapter->bind.AdapterHandle;
pAdapter->bind.AdapterHandle = NULL;
UNLOCKOBJ(pAdapter, pSR);
if (NdisAdapterHandle != NULL)
{
//
// Suspend task and call NdisCloseAdapter...
//
RmSuspendTask(pTask, PEND_CloseAdapter, pSR);
RM_ASSERT_NOLOCKS(pSR);
NdisCloseAdapter(
&Status,
NdisAdapterHandle
);
if (Status != NDIS_STATUS_PENDING)
{
ArpNdCloseAdapterComplete(
(NDIS_HANDLE)pAdapter,
Status
);
}
Status = NDIS_STATUS_PENDING;
}
} while (FALSE);
}
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpPnPReconfigHandler(
IN PARP1394_ADAPTER pAdapter,
IN PNET_PNP_EVENT pNetPnPEvent
)
/*++
Routine Description:
Handle a reconfig message on the specified adapter. If no adapter
is specified, it is a global parameter that has changed.
Arguments:
pAdapter - Pointer to our adapter structure
pNetPnPEvent - Pointer to reconfig event
Return Value:
NDIS_STATUS_SUCCESS always, for now.
--*/
{
ENTER("PnPReconfig", 0x39bae883)
NDIS_STATUS Status;
RM_DECLARE_STACK_RECORD(sr)
Status = NDIS_STATUS_FAILURE;
do
{
PIP_PNP_RECONFIG_REQUEST pIpReconfigReq;
PARP1394_INTERFACE pIF;
pIpReconfigReq = (PIP_PNP_RECONFIG_REQUEST)pNetPnPEvent->Buffer;
OBJLOG2(
pAdapter,
"AtmArpPnPReconfig: pIpReconfig 0x%x, arpConfigOffset 0x%x\n",
pIpReconfigReq,
pIpReconfigReq->arpConfigOffset
);
if(pIpReconfigReq->arpConfigOffset == 0)
{
// Invalid structure.
//
ASSERT(!"Invalid pIpReconfigReq");
break;
}
#if 0
//
// Enable this code if we want to validate the passed in config
// Information. This code is currently DISABLED. Instead
// we simply start reconfiguration on the SINGLE interface of
// the specified adapter.
//
//
// TODO: define stucture for IP/1394 -- we're using the ATMARP structure
// here!
//
ATMARPC_PNP_RECONFIG_REQUEST UNALIGNED * pArpReconfigReq;
ULONG uOffset;
PWCH pwc;
NDIS_STRING IPReconfigString;
pArpReconfigReq = (ATMARPC_PNP_RECONFIG_REQUEST UNALIGNED *)
((PUCHAR)pIpReconfigReq + pIpReconfigReq->arpConfigOffset);
//
// Locate the IP interface string passed in...
//
uOffset = pArpReconfigReq->IfKeyOffset;
if (uOffset == 0)
{
Status = NDIS_STATUS_FAILURE;
break;
}
pwc = (PWCH) ((PUCHAR)pArpReconfigReq + uOffset);
//
// ((PUCHAR)pArpReconfigReq + uOffset) points to a
// "counted unicode string", which means that it's an array
// of words, with the 1st word being the length in characters of
// the string (there is no terminating null) and the following
// <length> words being the string itself.
//
// Probe the string -- the passed-in structure could be bogus.
//
try
{
ProbeForRead(
pwc, // start of buffer, including count
pwc[0]+1, // length, including count.
sizeof(*pwc) // sizeof(WCHAR) alignment required.
);
}
except (EXCEPTION_EXECUTE_HANDLER)
{
OBJLOG0(pAdapter, "AtmArpPnPReconfig: Bogus buffer passed in\n");
Status = NDIS_STATUS_FAILURE;
break;
}
// Lookup the IF based on the specified name.
//
IPReconfigString.Length = sizeof(pwc[0])*pwc[0];
IPReconfigString.MaximumLength = IPReconfigString.Length;
IPReconfigString.Buffer = pwc+1;
// TODO: arpGetIfByName is not yet implemented!
//
pIF = arpGetIfByName(
pAdapter,
&sr
);
#else // !0
//
// Since we support only one IF per adapter, and it's extra work
// to verify the string, we completely ignore the contents
// of the pnp event, and instead just start reconfiguration on the
// SINGLE IF associated with pAdapter.
//
LOCKOBJ(pAdapter, &sr);
pIF = pAdapter->pIF;
if (pIF != NULL)
{
RmTmpReferenceObject(&pIF->Hdr, &sr);
}
UNLOCKOBJ(pAdapter, &sr);
#endif // !0
if (pIF == NULL) break;
//
// We've found the IF this reconfig request applies to. Let's
// start reconfiguration on this IF...
//
Status = arpTryReconfigureIf(pIF, pNetPnPEvent, &sr);
RmTmpDereferenceObject(&pIF->Hdr, &sr);
} while (FALSE);
return Status;
}
PRM_OBJECT_HEADER
arpAdapterCreate(
PRM_OBJECT_HEADER pParentObject,
PVOID pCreateParams,
PRM_STACK_RECORD psr
)
/*++
Routine Description:
Allocate and initialize an object of type ARP1394_ADAPTER.
Arguments:
pParentObject - Object that is to be the parent of the adapter.
pCreateParams - Actually a pointer to a ARP1394_BIND_PARAMS structure,
which contains information required to create the adapter.
Return Value:
Pointer to the allocated and initialized object on success.
NULL otherwise.
--*/
{
ARP1394_ADAPTER * pA;
ARP1394_BIND_PARAMS *pBindParams = (ARP1394_BIND_PARAMS*) pCreateParams;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ENTER("arpAdapterCreate", 0xaa25c606)
ARP_ALLOCSTRUCT(pA, MTAG_ADAPTER);
do
{
if (pA == NULL)
{
break;
}
ARP_ZEROSTRUCT(pA);
// Create up-cased version of the DeviceName and save it.
//
// WARNING: On MILLEN, this is actually an ANSI string. However,
// arpCopyUnicodeString works fine even if it's an ANSI string.
//
Status = arpCopyUnicodeString(
&(pA->bind.DeviceName),
pBindParams->pDeviceName,
TRUE // Upcase
);
if (FAIL(Status))
{
pA->bind.DeviceName.Buffer=NULL; // so we don't try to free it later
break;
}
//
// Determine if we're being created in Ethernet Emulation ("Bridge") mode
// We're created in bridge mode if the BindContext is NULL.
//
if (pBindParams->BindContext != NULL)
{
//
// NOTE: We ONLY read configuration if we're operation in
// normal (Not BRIDGE) mode.
//
Status = arpCopyUnicodeString(
&(pA->bind.ConfigName),
pBindParams->pArpConfigName,
FALSE // Don't upcase
);
if (FAIL(Status))
{
pA->bind.ConfigName.Buffer=NULL; // so we don't try to free it later
break;
}
}
pA->bind.BindContext = pBindParams->BindContext;
pA->bind.IpConfigHandle = pBindParams->IpConfigHandle;
RmInitializeLock(
&pA->Lock,
LOCKLEVEL_ADAPTER
);
RmInitializeHeader(
pParentObject,
&pA->Hdr,
MTAG_ADAPTER,
&pA->Lock,
&ArpGlobals_AdapterStaticInfo,
NULL,
psr
);
if (pBindParams->BindContext == NULL)
{
TR_WARN(("pAdapter 0x%p created in BRIDGE mode!\n", pA));
ARP_ENABLE_BRIDGE(pA);
}
}
while(FALSE);
if (FAIL(Status))
{
if (pA != NULL)
{
arpAdapterDelete ((PRM_OBJECT_HEADER) pA, psr);
pA = NULL;
}
}
EXIT()
return (PRM_OBJECT_HEADER) pA;
}
NDIS_STATUS
arpTryReconfigureIf(
PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT
PNET_PNP_EVENT pNetPnPEvent, // OPTIONAL
PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Try to start reconfiguration of the specified IF.
Some special cases:
- If the IF is currently being shutdown, we will synchronously succeed. Why?
Because we don't need to do anything more and it's not an error condition.
- If the IF is currently being started, we (asychronously) wait until
the starting is complete, then shut it down and restart it.
- If the IF is currently UP, we shut it down and restart it.
Arguments:
pIF - The interface to be shutdown/restarted.
pNetPnPEvent - OPTIONAL Ndis pnp event to be completed when the
reconfiguration operation is over. This is optional because
this function can also be called from elsewhere, in particular,
from the ioctl admin utility.
Return Value:
NDIS_STATUS_SUCCESS -- on synchronous success.
NDIS_STATUS_FAILURE -- on synchronous failure.
NDIS_STATUS_PENDING -- if completion is going to happen asynchronously.
--*/
{
NDIS_STATUS Status;
PRM_TASK pTask;
ENTER("arpTryReconfigureIf", 0x65a0bb61)
RM_ASSERT_NOLOCKS(pSR);
do
{
if (CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_DEINITING)
|| CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_DEINITED))
{
Status = NDIS_STATUS_SUCCESS;
break;
}
LOCKOBJ(pIF, pSR);
UNLOCKOBJ(pIF, pSR);
Status = arpAllocateTask(
&pIF->Hdr, // pParentObject,
arpTaskReinitInterface, // pfnHandler,
0, // Timeout,
"Task: DeactivateInterface(reconfig)",// szDescription
&pTask,
pSR
);
if (FAIL(Status))
{
OBJLOG0(pIF, ("Couldn't alloc reinit IF task!\n"));
}
else
{
// Save away pNetPnPEvent in the task structure and start the task.
//
PTASK_REINIT_IF pReinitTask = (PTASK_REINIT_IF) pTask;
ASSERT(sizeof(*pReinitTask)<=sizeof(ARP1394_TASK));
pReinitTask->pNetPnPEvent = pNetPnPEvent;
(void)RmStartTask(pTask, 0, pSR);
Status = NDIS_STATUS_PENDING;
}
} while (FALSE);
EXIT()
return Status;
}
NDIS_STATUS
arpPrepareAndSendNdisRequest(
IN PARP1394_ADAPTER pAdapter,
IN PARP_NDIS_REQUEST pArpNdisRequest,
IN PRM_TASK pTask, // OPTIONAL
IN UINT PendCode,
IN NDIS_OID Oid,
IN PVOID pBuffer,
IN ULONG BufferLength,
IN NDIS_REQUEST_TYPE RequestType,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Send an NDIS Request to query an adapter for information.
If the request pends, block on the ATMARP Adapter structure
till it completes.
Arguments:
pAdapter - Points to ATMARP Adapter structure
pNdisRequest - Pointer to UNITIALIZED NDIS request structure
pTask - OPTIONAL Task. If NULL, we block until the operation
completes.
PendCode - PendCode to suspend pTask
Oid - OID to be passed in the request
pBuffer - place for value(s)
BufferLength - length of above
Return Value:
The NDIS status of the request.
--*/
{
NDIS_STATUS Status;
PNDIS_REQUEST pNdisRequest = &pArpNdisRequest->Request;
ARP_ZEROSTRUCT(pArpNdisRequest);
//
// Fill in the NDIS Request structure
//
if (RequestType == NdisRequestQueryInformation)
{
pNdisRequest->RequestType = NdisRequestQueryInformation;
pNdisRequest->DATA.QUERY_INFORMATION.Oid = Oid;
pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = pBuffer;
pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = BufferLength;
pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten = 0;
pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BufferLength;
}
else
{
ASSERT(RequestType == NdisRequestSetInformation);
pNdisRequest->RequestType = NdisRequestSetInformation;
pNdisRequest->DATA.SET_INFORMATION.Oid = Oid;
pNdisRequest->DATA.SET_INFORMATION.InformationBuffer = pBuffer;
pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength = BufferLength;
pNdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
pNdisRequest->DATA.SET_INFORMATION.BytesNeeded = BufferLength;
}
if (pTask == NULL)
{
// We might potentially wait.
//
ASSERT_PASSIVE();
NdisInitializeEvent(&pArpNdisRequest->Event);
NdisRequest(
&Status,
pAdapter->bind.AdapterHandle,
pNdisRequest
);
if (PEND(Status))
{
NdisWaitEvent(&pArpNdisRequest->Event, 0);
Status = pArpNdisRequest->Status;
}
}
else
{
pArpNdisRequest->pTask = pTask;
RmSuspendTask(pTask, PendCode, pSR);
NdisRequest(
&Status,
pAdapter->bind.AdapterHandle,
pNdisRequest
);
if (!PEND(Status))
{
RmUnsuspendTask(pTask, pSR);
}
}
return Status;
}
ENetAddr
arpGetSecondaryMacAddress (
IN ENetAddr EthernetMacAddress
)
/*++
When we are in the bridge mode, we pretend that there is
only one other Ethernet Card out there on the net. Therefore
only one Ethernet Address needs to be generated.
For now we simply add one to the Local Adapter's Ethernet
address and generate it
--*/
{
ENetAddr NewAddress = EthernetMacAddress; // copy
//
// randomize the returned Mac Address
// by xor ing the address with a random
// 0x0d3070b17715 (a random number)
//
NewAddress.addr[0] ^= 0x00;
NewAddress.addr[1] ^= 0x2f;
NewAddress.addr[2] ^= 0x61;
NewAddress.addr[3] ^= 0x7c;
NewAddress.addr[4] ^= 0x91;
NewAddress.addr[5] ^= 0x30;
// Set the locally administered bit
// and clear the multicast bit.
NewAddress.addr[0] &= 0x20;
return NewAddress;
}
NDIS_STATUS
arpGetEuidTopology (
IN PARP1394_ADAPTER pAdapter,
IN PRM_STACK_RECORD pSR
)
/*++
Queues A workitem to get the EuidTopology
--*/
{
ENTER ("arpGetEuidTopology ",0x97a0abcb)
PARP1394_WORK_ITEM pWorkItem = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
BOOLEAN fQueueWorkItem = FALSE;
do
{
if (pAdapter->fQueryAddress == TRUE)
{
break;
}
LOCKOBJ (pAdapter, pSR);
if (pAdapter->fQueryAddress == FALSE)
{
pAdapter->fQueryAddress = TRUE;
fQueueWorkItem = TRUE;
}
else
{
fQueueWorkItem = FALSE;
}
UNLOCKOBJ(pAdapter, pSR);
if (fQueueWorkItem == FALSE)
{
break;
}
Status = ARP_ALLOCSTRUCT(pWorkItem, MTAG_ARP_GENERIC);
if (Status != NDIS_STATUS_SUCCESS || pWorkItem == NULL)
{
pWorkItem = NULL;
break;
}
arpQueueWorkItem (pWorkItem,
arpGetEuidTopologyWorkItem,
&pAdapter->Hdr,
pSR);
} while (FALSE);
EXIT()
return Status;
}
VOID
arpQueueWorkItem (
PARP1394_WORK_ITEM pWorkItem,
ARP_WORK_ITEM_PROC pFunc,
PRM_OBJECT_HEADER pHdr,
PRM_STACK_RECORD pSR
)
/*++
Sends a request to get the bus topology . Only used in bridge mode
For now only Adapter's are passed in as pHdr
--*/
{
ENTER("arpQueueWorkItem",0xa1de6752)
PNDIS_WORK_ITEM pNdisWorkItem = &pWorkItem->u.NdisWorkItem;
PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER)pHdr;
BOOLEAN fStartWorkItem = FALSE;
LOCKOBJ(pAdapter, pSR);
if (CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITED ) == TRUE)
{
#if RM_EXTRA_CHECKING
RM_DECLARE_STACK_RECORD(sr)
RmLinkToExternalEx(
pHdr, // pHdr
0x5a2fd7ca, // LUID
(UINT_PTR)pWorkItem, // External entity
ARPASSOC_WORK_ITEM, // AssocID
" Outstanding WorkItem",
&sr
);
#else // !RM_EXTRA_CHECKING
RmLinkToExternalFast(pHdr);
#endif // !RM_EXTRA_CHECKING
fStartWorkItem = TRUE;
}
UNLOCKOBJ(pAdapter, pSR);
if (fStartWorkItem == TRUE)
{
NdisInitializeWorkItem ( pNdisWorkItem ,arpGenericWorkItem, pHdr);
pWorkItem->pFunc = pFunc;
NdisScheduleWorkItem(pNdisWorkItem );
}
EXIT()
}
VOID
arpGenericWorkItem(
struct _NDIS_WORK_ITEM * pWorkItem,
PVOID pContext
)
/*++
Generic workitem finction. Takes care of the reference on the pObj
--*/
{
PARP1394_WORK_ITEM pArpWorkItem = (ARP1394_WORK_ITEM*)pWorkItem;
PRM_OBJECT_HEADER pObj = (PRM_OBJECT_HEADER)pContext;
RM_DECLARE_STACK_RECORD(sr)
pArpWorkItem->pFunc (pArpWorkItem, pObj, &sr);
#if RM_EXTRA_CHECKING
{
RmUnlinkFromExternalEx(pObj,
0x548c9d54,
(UINT_PTR)pWorkItem,
ARPASSOC_WORK_ITEM,
&sr
);
}
#else
RmUnlinkFromExternalFast(pObj);
#endif
}
NDIS_STATUS
arpGetEuidTopologyWorkItem(
struct _ARP1394_WORK_ITEM* pWorkItem,
PRM_OBJECT_HEADER pObj,
PRM_STACK_RECORD pSR
)
/*++
workitem to get the topology of the bus .. The WorkItem structure can be null;
--*/
{
PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER)pObj;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP_NDIS_REQUEST ArpRequest;
EUID_TOPOLOGY EuidTopology;
//
// Return if the adapter is not active
//
if (CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_DEINITING ) ==TRUE)
{
ASSERT (CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_DEINITING ) ==FALSE);
return NDIS_STATUS_FAILURE; // early return
}
//
// Initialize the structures
//
ARP_ZEROSTRUCT(&ArpRequest);
ARP_ZEROSTRUCT(&EuidTopology);
//Send the request down
//
Status = \
arpPrepareAndSendNdisRequest(pAdapter,
&ArpRequest,
NULL, //IN PRM_TASK pTask,
0, //IN UINT PendCode,
OID_1394_QUERY_EUID_NODE_MAP,
&EuidTopology,
sizeof (EuidTopology),
NdisRequestQueryInformation ,
pSR
);
if (Status == NDIS_STATUS_SUCCESS)
{
NdisMoveMemory (&pAdapter->EuidMap, &EuidTopology, sizeof (pAdapter->EuidMap));
}
pAdapter->fQueryAddress = FALSE;
return Status;
}
VOID
arpNdProcessBusReset(
IN PARP1394_ADAPTER pAdapter
)
/*++
If the adapter is in the Bridge mode, it will query the
adapter for the bus topology
--*/
{
ENTER("arpNdProcessBusReset ",0x48e7659a)
BOOLEAN BridgeEnabled = ARP_BRIDGE_ENABLED(pAdapter);
RM_DECLARE_STACK_RECORD(SR)
if (BridgeEnabled == TRUE)
{
arpGetEuidTopology (pAdapter, &SR);
}
EXIT()
}
VOID
arpRemoveBackupTasks (
IN ARP1394_GLOBALS* pGlobals,
UINT Num
)
/*++
Removes Num tasks to be used as a backup. However, the number is only a
approximate value as the back up tasks could be in use
--*/
{
PSLIST_HEADER pListHead = &pGlobals->BackupTasks;
PNDIS_SPIN_LOCK pLock = &pGlobals->BackupTaskLock;
UINT i=0;
for (i = 0;i <Num;i++)
{
PSINGLE_LIST_ENTRY pEntry;
pEntry = NdisInterlockedPopEntrySList(pListHead, pLock );
if (pEntry != NULL)
{
TASK_BACKUP* pTask;
ARP1394_TASK *pATask;
pTask = CONTAINING_RECORD (pEntry, TASK_BACKUP, List);
pATask = (ARP1394_TASK*)pTask;
ARP_FREE (pATask);
pGlobals->NumTasks --;
}
}
}
VOID
arpAddBackupTasks (
IN ARP1394_GLOBALS* pGlobals,
UINT Num
)
/*++
Adds Num tasks to be used as a backup.
We are modifying pGlobals without holding the lock
--*/
{
PSLIST_HEADER pListHead = &pGlobals->BackupTasks;
PNDIS_SPIN_LOCK pLock = &pGlobals->BackupTaskLock;
UINT i=0;
for (i = 0;i <Num;i++)
{
ARP1394_TASK *pATask=NULL;
ARP_ALLOCSTRUCT(pATask, MTAG_TASK); // TODO use lookaside lists.
if (pATask != NULL)
{
NdisInterlockedPushEntrySList(pListHead,&pATask->Backup.List, pLock);
pGlobals->NumTasks ++;
}
}
}
VOID
arpAllocateBackupTasks (
ARP1394_GLOBALS* pGlobals
)
/*++
Allocates 4 Tasks to be used as a backup in lowmem conditions
--*/
{
PSLIST_HEADER pListHead = &pGlobals->BackupTasks;
PNDIS_SPIN_LOCK pLock = &pGlobals->BackupTaskLock;
NdisInitializeSListHead (pListHead);
NdisAllocateSpinLock(pLock);
arpAddBackupTasks (pGlobals, 4);
}
VOID
arpFreeBackupTasks (
ARP1394_GLOBALS* pGlobals
)
/*++
Free all the backup tasks hanging off the adapter object
Since this is only called from the Unload handler, the code
presumes that all tasks are complete
We are modifying pGlobals without holding a lock
--*/
{
PSLIST_HEADER pListHead = &pGlobals->BackupTasks;
PNDIS_SPIN_LOCK pLock = &pGlobals->BackupTaskLock;
PSINGLE_LIST_ENTRY pEntry = NULL;
do
{
pEntry = NdisInterlockedPopEntrySList(pListHead, pLock );
if (pEntry != NULL)
{
TASK_BACKUP* pTask;
ARP1394_TASK *pATask;
pTask = CONTAINING_RECORD (pEntry, TASK_BACKUP, List);
pATask = (ARP1394_TASK*)pTask;
ARP_FREE (pATask);
pGlobals->NumTasks --;
}
} while (pEntry != NULL);
ASSERT (pGlobals->NumTasks == 0);
}
ARP1394_TASK *
arpGetBackupTask (
ARP1394_GLOBALS* pGlobals
)
/*++
Removes a task from the Back up task list and returns it
--*/
{
PSLIST_HEADER pListHead = &pGlobals->BackupTasks;
PNDIS_SPIN_LOCK pLock = &pGlobals->BackupTaskLock;
PSINGLE_LIST_ENTRY pEntry = NULL;
TASK_BACKUP* pTask = NULL;
pEntry = NdisInterlockedPopEntrySList(pListHead, pLock);
if (pEntry != NULL)
{
pTask = CONTAINING_RECORD (pEntry, TASK_BACKUP, List);
NdisZeroMemory ( pTask, sizeof (ARP1394_TASK));
MARK_TASK_AS_BACKUP(&pTask->Hdr);
}
return (ARP1394_TASK*)pTask;
}
VOID
arpReturnBackupTask (
IN ARP1394_TASK* pTask
)
//
// We can always return the task to the Slist because we are gauranteed that it
// will be present until all the interfaces are unloaded.
//
{
// re-insert the task
PSLIST_HEADER pListHead = &ArpGlobals.BackupTasks;
PNDIS_SPIN_LOCK pLock = &ArpGlobals.BackupTaskLock;
PTASK_BACKUP pBkTask = (PTASK_BACKUP ) pTask;
NdisInterlockedPushEntrySList(pListHead, &pBkTask->List, pLock);
}
NDIS_STATUS
arpTaskCloseCallLowPower(
IN PRM_TASK pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam, // Unused
IN PRM_STACK_RECORD pSR
)
/*++
This function will close all the open VCs.
This will allow the 1394 miniport to power down without any problem
It will also have to close the Address Families.
This function will also have to return synchronously.
--*/
{
ENTER("arpTaskLowPower", 0x922f875b)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PARPCB_DEST pDest = (ARPCB_DEST*)RM_PARENT_OBJECT(pTask);
TASK_SET_POWER_CALL *pCloseCallTask = (TASK_SET_POWER_CALL *) pTask;
enum
{
PEND_CleanupVcComplete,
};
switch(Code)
{
case RM_TASKOP_START:
{
LOCKOBJ(pDest,pSR);
if (arpNeedToCleanupDestVc(pDest))
{
PRM_TASK pCleanupCallTask = pDest->VcHdr.pCleanupCallTask;
// If there is already an official cleanup-vc task, we pend on it.
// Other wise we allocate our own, pend on it, and start it.
//
if (pCleanupCallTask != NULL)
{
TR_WARN((
"Cleanup-vc task %p exists; pending on it.\n",
pCleanupCallTask));
RmTmpReferenceObject(&pCleanupCallTask->Hdr, pSR);
UNLOCKOBJ(pDest, pSR);
RmPendTaskOnOtherTask(
pTask,
PEND_CleanupVcComplete,
pCleanupCallTask,
pSR
);
RmTmpDereferenceObject(&pCleanupCallTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
else
{
//
// Start the call cleanup task and pend on int.
//
UNLOCKOBJ(pDest, pSR);
RM_ASSERT_NOLOCKS(pSR);
Status = arpAllocateTask(
&pDest->Hdr, // pParentObject,
arpTaskCleanupCallToDest, // pfnHandler,
0, // Timeout,
"Task: CleanupCall on UnloadDest", // szDescription
&pCleanupCallTask,
pSR
);
if (FAIL(Status))
{
TR_WARN(("FATAL: couldn't alloc cleanup call task!\n"));
}
else
{
RmPendTaskOnOtherTask(
pTask,
PEND_CleanupVcComplete,
pCleanupCallTask, // task to pend on
pSR
);
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pCleanupCallTask,
0, // UserParam (unused)
pSR
);
}
break;
}
}
//
// We're here because there is no async unload work to be done.
// We simply return and finish synchronous cleanup in the END
// handler for this task.
//
Status = NDIS_STATUS_SUCCESS;
} // START
break;
case RM_TASKOP_PENDCOMPLETE:
{
switch(RM_PEND_CODE(pTask))
{
case PEND_CleanupVcComplete:
{
//
// There was vc-cleanup to be done, but how it's
// complete. We should be able to synchronously clean up
// this task now
//
#if DBG
LOCKOBJ(pDest, pSR);
ASSERTEX(!arpNeedToCleanupDestVc(pDest), pDest);
UNLOCKOBJ(pDest, pSR);
#endif DBG
Status = NDIS_STATUS_SUCCESS;
}
break;
default:
{
ASSERTEX(!"Unknown pend op", pTask);
}
break;
}
}
break;
case RM_TASKOP_END:
{
ULONG DestRemaining;
PCALL_COUNT pCount = pCloseCallTask->pCount;
ASSERT (pCount != NULL);
if (SetLowPower == pCloseCallTask->Cause )
{
DestRemaining = NdisInterlockedDecrement (&pCount->DestCount);
if ( 0 == DestRemaining )
{
NdisSetEvent (&pCount ->VcEvent);
}
}
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Code)
RmUnlockAll(pSR);
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
INT
arpCloseAllVcOnDest(
PRM_OBJECT_HEADER pHdr,
PVOID pvContext, // Unused
PRM_STACK_RECORD pSR
)
/*++
--*/
{
ENTER ("arpCloseAllVcOnDest", 0xf19a83d5)
PARPCB_DEST pDest = (PARPCB_DEST) pHdr;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PTASK_SET_POWER_CALL pTask = NULL;
PCALL_COUNT pCloseCall = (PCALL_COUNT) pvContext;
do
{
NdisInterlockedIncrement(&pCloseCall->DestCount);
Status = arpAllocateTask(
&pDest->Hdr, // pParentObject,
arpTaskCloseCallLowPower, // pfnHandler,
0, // Timeout,
"Task: Set Power Cleanup VC", // szDescrip.
&(PRM_TASK)pTask,
pSR
);
if (Status != NDIS_STATUS_SUCCESS || pTask == NULL)
{
pTask = NULL;
break;
}
pTask->Cause = SetLowPower;
pTask->pCount = pCloseCall;
RmStartTask((PRM_TASK)pTask, 0,pSR);
} while (FALSE);
if (Status != NDIS_STATUS_SUCCESS)
{
ULONG DestRemaining;
DestRemaining = NdisInterlockedDecrement (&pCloseCall->DestCount);
if ( 0 == DestRemaining )
{
NdisSetEvent (&pCloseCall->VcEvent);
}
}
return TRUE; // continue to enumerate
}
VOID
arpLowPowerCloseAllCalls (
ARP1394_INTERFACE *pIF,
PRM_STACK_RECORD pSR
)
{
CALL_COUNT CloseCallCount;
//
// The Dest Count will be used to make sure that this thread waits for
// all the Close Calls to complete.
//
NdisInitializeEvent (&CloseCallCount.VcEvent);
CloseCallCount.DestCount= 0;
//
// First we go through all the Dests and close calls on them
//
RmWeakEnumerateObjectsInGroup(&pIF->DestinationGroup,
arpCloseAllVcOnDest,
&CloseCallCount,
pSR);
if (CloseCallCount.DestCount != 0)
{
NdisWaitEvent (&CloseCallCount.VcEvent, 0);
}
return;
}
NDIS_STATUS
arpTaskCloseVcAndAF (
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
This task does the work that is common between SetLowPower and and
the Resume failure case
As its name suggests, it simply closes all the VCs and Af.
Its parent task is either a shutdown task or a Set Power task.
As the 2 parents of this task are serialized w.r.t each other,
there is no need for any serialization within this task.
Arguments:
UserParam for (Code == RM_TASKOP_START) : unused
--*/
{
ENTER("arpTaskCloseVcAndAF ", 0xc7c9ad6b)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER* pAdapter = (ARP1394_ADAPTER*)RM_PARENT_OBJECT(pTask);
TASK_POWER * pTaskPower = (TASK_POWER*) pTask;
ARP1394_INTERFACE * pIF = pAdapter->pIF;
ULONG Stage;
enum
{
STAGE_Start,
STAGE_StopMaintenanceTask,
STAGE_CleanupVcComplete,
STAGE_CloseDestinationGroup,
STAGE_SwitchedToPassive,
STAGE_CloseAF,
STAGE_End
};
switch(Code)
{
case RM_TASKOP_START:
Stage = STAGE_Start;
break;
case RM_TASKOP_PENDCOMPLETE:
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
Stage = RM_PEND_CODE(pTask);
break;
case RM_TASKOP_END:
Status = (NDIS_STATUS) UserParam;
Stage= STAGE_End;
break;
default:
ASSERT(FALSE);
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
}
switch(Stage)
{
case STAGE_Start:
{
//
// Stop the IF maintenance task if it's running.
//
Status = arpTryStopIfMaintenanceTask(
pIF,
pTask,
STAGE_StopMaintenanceTask,
pSR
);
if (PEND(Status)) break;
}
// FALL THROUGH
case STAGE_StopMaintenanceTask:
{
LOCKOBJ(pIF, pSR);
TIMESTAMP("===CloseVC and AF:MaintenanceTask stopped");
// Unlink the explicit reference of the broadcast channel destination
// from the interface.
//
if (pIF->pBroadcastDest != NULL)
{
PARPCB_DEST pBroadcastDest = pIF->pBroadcastDest;
pIF->pBroadcastDest = NULL;
// NOTE: We're unlinking the two with the IF lock (which is
// is the same as the pBroadcastDest's lock) held.
// This is OK to do.
//
#if RM_EXTRA_CHECKING
RmUnlinkObjectsEx(
&pIF->Hdr,
&pBroadcastDest->Hdr,
0x66bda49b,
ARPASSOC_LINK_IF_OF_BCDEST,
ARPASSOC_LINK_BCDEST_OF_IF,
pSR
);
#else // !RM_EXTRA_CHECKING
RmUnlinkObjects(&pIF->Hdr, &pBroadcastDest->Hdr, pSR);
#endif // !RM_EXTRA_CHECKING
}
//
// If the VC state needs cleaning up, we need to get a task
// going to clean it up. Other wise we fake the completion of this
// stage so that we move on to the next...
//
if (pIF->recvinfo.VcHdr.NdisVcHandle == NULL)
{
UNLOCKOBJ(pIF, pSR);
Status = NDIS_STATUS_SUCCESS;
}
else
{
PRM_TASK pCleanupCallTask = pIF->recvinfo.VcHdr.pCleanupCallTask;
// If there is already an official cleanup-vc task, we pend on it.
// Other wise we allocate our own, pend on it, and start it.
//
if (pCleanupCallTask != NULL)
{
TR_WARN((
"IF %p Cleanup-vc task %p exists; pending on it.\n",
pIF,
pCleanupCallTask));
RmTmpReferenceObject(&pCleanupCallTask->Hdr, pSR);
UNLOCKOBJ(pIF, pSR);
RmPendTaskOnOtherTask(
pTask,
STAGE_CleanupVcComplete,
pCleanupCallTask,
pSR
);
RmTmpDereferenceObject(&pCleanupCallTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
}
else
{
//
// Start the call cleanup task and pend on int.
//
UNLOCKOBJ(pIF, pSR);
Status = arpAllocateTask(
&pIF->Hdr, // pParentObject,
arpTaskCleanupRecvFifoCall, // pfnHandler,
0, // Timeout,
"Task: CleanupRecvFifo on Set LowPower ", // szDescrip.
&pCleanupCallTask,
pSR
);
if (FAIL(Status))
{
// Couldn't allocate task.
//
TR_WARN(("FATAL: couldn't alloc cleanup call task!\n"));
}
else
{
Status = RmPendTaskOnOtherTask(
pTask,
STAGE_CleanupVcComplete,
pCleanupCallTask,
pSR
);
ASSERT(!FAIL(Status));
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pCleanupCallTask,
0, // UserParam (unused)
pSR
);
// We rely on pending status to decide whether
// or not to fall through to the next stage.
//
Status = NDIS_STATUS_PENDING;
}
}
}
}
if (PEND(Status)) break;
// FALL THROUGH
case STAGE_CleanupVcComplete:
{
TIMESTAMP("===Set LowPower:RecvFifo cleanup complete");
// Initiate unload of all the items in the DestinationGroup.
//
// If we are going to low power state, then close all the VC's
// on these Destinations
//
arpLowPowerCloseAllCalls (pIF, pSR);
//
// Unlink the special "destination VCs". This is executed on both
// Low power and unbind.
//
LOCKOBJ(pIF, pSR);
TIMESTAMP("===Set LowPower:Destination objects cleaned up.");
if (pIF->pMultiChannelDest != NULL)
{
PARPCB_DEST pMultiChannelDest = pIF->pMultiChannelDest;
pIF->pMultiChannelDest = NULL;
// NOTE: We're unlinking the two with the IF lock (which is
// is the same as the pBroadcastDest's lock) held.
// This is OK to do.
//
#if RM_EXTRA_CHECKING
RmUnlinkObjectsEx(
&pIF->Hdr,
&pMultiChannelDest->Hdr,
0xf28090bd,
ARPASSOC_LINK_IF_OF_MCDEST,
ARPASSOC_LINK_MCDEST_OF_IF,
pSR
);
#else // !RM_EXTRA_CHECKING
RmUnlinkObjects(&pIF->Hdr, &pMultiChannelDest->Hdr, pSR);
#endif // !RM_EXTRA_CHECKING
}
if (pIF->pEthernetDest != NULL)
{
PARPCB_DEST pEthernetDest = pIF->pEthernetDest;
pIF->pEthernetDest = NULL;
// NOTE: We're unlinking the two with the IF lock (which is
// is the same as the pBroadcastDest's lock) held.
// This is OK to do.
//
#if RM_EXTRA_CHECKING
RmUnlinkObjectsEx(
&pIF->Hdr,
&pEthernetDest->Hdr,
0xf8eedcd1,
ARPASSOC_LINK_IF_OF_ETHDEST,
ARPASSOC_LINK_ETHDEST_OF_IF,
pSR
);
#else // !RM_EXTRA_CHECKING
RmUnlinkObjects(&pIF->Hdr, &pEthernetDest->Hdr, pSR);
#endif // !RM_EXTRA_CHECKING
}
UNLOCKOBJ(pIF, pSR);
// If required, switch to passive. This check should obviously be done
// without any locks held!
if (!ARP_ATPASSIVE())
{
// We're not at passive level, but we need to be..
// . So we switch to passive...
//
RmSuspendTask(pTask, STAGE_SwitchedToPassive, pSR);
RmResumeTaskAsync(pTask, 0, &pTaskPower->WorkItem, pSR);
Status = NDIS_STATUS_PENDING;
}
else
{
Status = NDIS_STATUS_SUCCESS;
}
}
if (PEND(Status)) break;
// FALL THROUGH
case STAGE_SwitchedToPassive:
{
NDIS_HANDLE NdisAfHandle;
// We're now switched to passive
//
ASSERT(ARP_ATPASSIVE());
//
// We're done with all VCs, etc. Time to close the AF, if it's open.
//
LOCKOBJ(pTask, pSR);
NdisAfHandle = pIF->ndis.AfHandle;
pIF->ndis.AfHandle = NULL;
pAdapter->PoMgmt.bReceivedAf = FALSE;
UNLOCKOBJ(pTask, pSR);
if (NdisAfHandle == NULL)
{
Status = NDIS_STATUS_SUCCESS;
}
else
{
//
// (Debug) Delete the association we added when the
// address family was opened.
//
DBG_DELASSOC(
&pIF->Hdr, // pObject
NdisAfHandle, // Instance1
NULL, // Instance2
ARPASSOC_IF_OPENAF, // AssociationID
pSR
);
//
// Suspend task and call NdisCloseAdapter...
//
pIF->PoMgmt.pAfPendingTask = pTask;
RmSuspendTask(pTask, STAGE_CloseAF, pSR);
RM_ASSERT_NOLOCKS(pSR);
TIMESTAMP("===DeinitIF: Calling NdisClCloseAddressFamily");
Status = NdisClCloseAddressFamily(
NdisAfHandle
);
if (Status != NDIS_STATUS_PENDING)
{
ArpCoCloseAfComplete(
Status,
(NDIS_HANDLE)pIF
);
Status = NDIS_STATUS_PENDING;
}
}
}
if (PEND(Status)) break;
// FALL THROUGH
case STAGE_CloseAF:
{
//
// The close AF operation is complete.
// We've not got anything else to do.
//
TIMESTAMP("===Set Low Power: Done with CloseAF");
// Recover the last status ...
//
pIF->PoMgmt.pAfPendingTask =NULL;
Status = (NDIS_STATUS) UserParam;
// Status of the completed operation can't itself be pending!
//
ASSERT(Status != NDIS_STATUS_PENDING);
//
// By returning Status != pending, we implicitly complete
// this task.
//
}
break;
case STAGE_End:
{
TIMESTAMP("===Set Low Power done: All done!");
// Force status to be success as a transition to LowPower
// cannot fail
//
Status = NDIS_STATUS_SUCCESS;
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Stage)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskLowPower(
IN struct _RM_TASK * pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam,
IN PRM_STACK_RECORD pSR
)
/*++
Routine Description:
Task handler responsible for setting an adapter to low power state
(but leaving it allocated and linked to the adapter).
This task will close all the VCs, AF. However it will leave the Interface
registered with IP and will not delete either the RemoteIP or DEST structures.
This task is a primary Interface task. This task is serialized with the Bind
, Unbind tasks
Arguments:
UserParam for (Code == RM_TASKOP_START) : unused
--*/
{
NDIS_STATUS Status;
PARP1394_INTERFACE pIF;
PTASK_POWER pTaskPower;
UINT Stage;
PARP1394_ADAPTER pAdapter;
enum
{
STAGE_Start,
STAGE_BecomePrimaryTask,
STAGE_ExistingPrimaryTaskComplete,
STAGE_CleanupVcAfComplete,
STAGE_End
};
ENTER("arpTaskLowPower", 0x1a34699e)
Status = NDIS_STATUS_FAILURE;
pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pTask);
pIF = pAdapter->pIF;
pTaskPower = (PTASK_POWER) pTask;
//
// Message normalizing code
//
switch(Code)
{
case RM_TASKOP_START:
Stage = STAGE_Start;
break;
case RM_TASKOP_PENDCOMPLETE:
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
Stage = RM_PEND_CODE(pTask);
break;
case RM_TASKOP_END:
Status = (NDIS_STATUS) UserParam;
Stage= STAGE_End;
break;
default:
ASSERT(FALSE);
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
}
switch(Stage)
{
case STAGE_Start:
{
// There should NOT be another activate/deactivate task running
// on this interface. We fail the SetPower if we receive it in
// while we are activating or deactivating the task
//
TIMESTAMP("===Set Power Low Starting");
if (pIF->pActDeactTask != NULL ||
(CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_INITED) != TRUE))
{
UNLOCKOBJ(pIF, pSR);
*pTaskPower->pStatus = NDIS_STATUS_NOT_SUPPORTED;
Status = NDIS_STATUS_FAILURE;
break;
}
// FALL THROUGH
}
case STAGE_BecomePrimaryTask:
{
//
// Next, we try and set ourselves as the primary Adapter Task.
// This ensures that bind,unbind, and Set Power Tasks are all serialized.
//
LOCKOBJ(pAdapter, pSR);
if (pAdapter->bind.pPrimaryTask == NULL)
{
ULONG CurrentInitState = GET_AD_PRIMARY_STATE(pAdapter);
// Do not change the Init state of the Adapter. However,
// mark the adapter as transitioning to a low power state
//
pTaskPower->PrevState = CurrentInitState;
arpSetPrimaryAdapterTask(pAdapter, pTask, CurrentInitState, pSR);
//
// Set the Power State to Low Power. This will block all
// outstanding sends
//
SET_POWER_STATE (pAdapter, ARPAD_POWER_LOW_POWER);
UNLOCKOBJ(pAdapter, pSR);
}
else
{
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
UNLOCKOBJ(pAdapter, pSR);
RmPendTaskOnOtherTask(
pTask,
STAGE_BecomePrimaryTask, // we'll try again...
pOtherTask,
pSR
);
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
}
if (PEND(Status)) break;
// FALL THROUGH
case STAGE_ExistingPrimaryTaskComplete:
{
PRM_TASK pCloseVCAndAfTask = NULL;
//
// Stop the IF maintenance task if it's running.
//
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskCloseVcAndAF , // pfnHandler,
0, // Timeout,
"Task: Close VC and AF on SetPower", // szDescrip.
&pCloseVCAndAfTask ,
pSR
);
if (FAIL(Status))
{
// Couldn't allocate task.
//
TR_WARN(("FATAL: couldn't alloc cleanup call task!\n"));
break;
}
else
{
Status = RmPendTaskOnOtherTask(
pTask,
STAGE_CleanupVcAfComplete,
pCloseVCAndAfTask,
pSR
);
ASSERT(!FAIL(Status));
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pCloseVCAndAfTask,
0, // UserParam (unused)
pSR
);
}
if (PEND(Status)) break;
}
break;
case STAGE_CleanupVcAfComplete:
{
//
// The close AF operation is complete.
// We've not got anything else to do.
//
TIMESTAMP("===Set LowPower: Done with CloseAF");
// Recover the last status ...
//
Status = (NDIS_STATUS) UserParam;
//
// Status of the completed operation can't itself be pending!
//
ASSERT(Status == NDIS_STATUS_SUCCESS);
//
// By returning Status != pending, we implicitly complete
// this task.
//
}
break;
case STAGE_End:
{
//
// We are done with all async aspects of setting the Low Power state
// Set the event so that the original Low Power thread can return.
//
TIMESTAMP("===Set Low Power done: All done!");
// Recover the last status ...
//
Status = (NDIS_STATUS) UserParam;
*pTaskPower->pStatus = Status;
LOCKOBJ (pAdapter, pSR);
arpClearPrimaryAdapterTask(pAdapter, pTask, pTaskPower->PrevState ,pSR);
UNLOCKOBJ (pAdapter, pSR);
NdisSetEvent (&pAdapter->PoMgmt.Complete);
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Stage)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpMakeCallOnDest(
IN PARPCB_REMOTE_IP pRemoteIp,
IN PARPCB_DEST pDest,
IN PRM_TASK pTaskToPend,
IN ULONG PEND_StageMakeCallComplete,
IN PRM_STACK_RECORD pSR
)
/*++
This function will do a make call on a particular task.
It will also pend pTaskToPend on that make call
--*/
{
ENTER("arpTaskLowPower", 0x922f875b)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
do
{
if (pRemoteIp->pDest != pDest)
{
Status = NDIS_STATUS_FAILURE;
break;
}
if (pDest->VcHdr.pMakeCallTask != NULL )
{
//
// There is an existing task. Pend on it.
//
PRM_TASK pOtherTask = pDest->VcHdr.pMakeCallTask;
RM_DBG_ASSERT_LOCKED(&pRemoteIp->Hdr, pSR);
TR_WARN(("MakeCall task %p exists; pending on it.\n", pOtherTask));
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
DBGMARK(0x0c387a9f);
UNLOCKOBJ(pRemoteIp, pSR);
RmPendTaskOnOtherTask(
pTaskToPend,
PEND_StageMakeCallComplete,
pOtherTask,
pSR
);
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
}
else
{
DBGMARK(0xe9f37ba9);
//
// There is no pMakeCallTask. If it makes sense to start one, we do...
// Note that checking ARP_CAN_SEND_ON_DEST strictly-speaking requires
// at-least a read-lock on the IF send lock. However, we don't need
// precision here -- as long as we don't miss making a call when we
// should (which we won't) we are ok.
//
if (!ARP_CAN_SEND_ON_DEST(pDest) && pDest->VcHdr.pCleanupCallTask==NULL)
{
PRM_TASK pMakeCallTask;
//
// Let's start a MakeCall task and pend on it.
//
Status = arpAllocateTask(
&pDest->Hdr, // pParentObject
arpTaskMakeCallToDest, // pfnHandler
0, // Timeout
"Task: SendFifoMakeCall", // szDescription
&pMakeCallTask,
pSR
);
if (FAIL(Status))
{
// Couldn't allocate task. We fail with STATUS_RESOURCES
//
Status = NDIS_STATUS_RESOURCES;
}
else
{
UNLOCKOBJ(pRemoteIp, pSR);
RmPendTaskOnOtherTask(
pTaskToPend,
PEND_StageMakeCallComplete,
pMakeCallTask,
pSR
);
(VOID)RmStartTask(
pMakeCallTask,
0, // UserParam (unused)
pSR
);
Status = NDIS_STATUS_PENDING;
}
}
else
{
// Calls is ready to do. We finish sending off the packets in
// the END handler.
//
Status = NDIS_STATUS_SUCCESS;
}
}
} while (FALSE);
RmUnlockAll(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskStartGenericVCs (
IN PRM_TASK pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam, // Unused
IN PRM_STACK_RECORD pSR
)
/*++
This function will close all the open VCs.
This will allow the 1394 miniport to power down without any problem
It will also have to close the Address Families.
This function will also have to return synchronously.
--*/
{
ENTER("arpTaskStartGenericVCs", 0x75780ca6)
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
ARP1394_ADAPTER* pAdapter = (ARP1394_ADAPTER*)RM_PARENT_OBJECT(pTask);
TASK_POWER * pTaskPower = (TASK_POWER*) pTask;
ARP1394_INTERFACE * pIF = pAdapter->pIF;
enum
{
PEND_OpenAF,
PEND_SetupBroadcastChannel,
PEND_SetupReceiveVc,
PEND_SetupMultiChannel,
PEND_SetupEthernetVc,
PEND_StartedVC
};
switch(Code)
{
case RM_TASKOP_START:
{
CO_ADDRESS_FAMILY AddressFamily;
//
// This task is inherently serialized as its parent task is serialized.
//
LOCKOBJ (pIF, pSR);
if (pIF->pActDeactTask != NULL)
{
// This should never happen, because the Activate task is
// always started by an active primary task, and at most one primary
// task is active at any point of time.
//
ASSERTEX(!"start: activate/deactivate task exists!", pIF);
Status = NDIS_STATUS_FAILURE;
UNLOCKOBJ(pIF, pSR);
break;
}
UNLOCKOBJ (pIF,pSR);
//
// Now Open the Address Family.
//
NdisZeroMemory(&AddressFamily, sizeof(AddressFamily));
AddressFamily.AddressFamily = CO_ADDRESS_FAMILY_1394;
AddressFamily.MajorVersion = NIC1394_AF_CURRENT_MAJOR_VERSION;
AddressFamily.MinorVersion = NIC1394_AF_CURRENT_MINOR_VERSION;
pIF->PoMgmt.pAfPendingTask = pTask;
RmSuspendTask(pTask, PEND_OpenAF, pSR);
RM_ASSERT_NOLOCKS(pSR);
TIMESTAMP("===ActivateIF: Calling NdisClOpenAddressFamily");
Status = NdisClOpenAddressFamily(
pIF->ndis.AdapterHandle,
&AddressFamily,
(NDIS_HANDLE)pIF,
&ArpGlobals.ndis.CC,
sizeof(ArpGlobals.ndis.CC),
&(pIF->ndis.AfHandle)
);
if (Status != NDIS_STATUS_PENDING)
{
ArpCoOpenAfComplete(
Status,
(NDIS_HANDLE)pIF,
pIF->ndis.AfHandle
);
}
Status = NDIS_STATUS_PENDING;
}
break;
case RM_TASKOP_PENDCOMPLETE:
{
pTaskPower->LastStage = (RM_PEND_CODE(pTask));
Status = (NDIS_STATUS) UserParam;
switch(RM_PEND_CODE(pTask))
{
case PEND_OpenAF:
{
PARPCB_DEST pBroadcastDest;
pIF->PoMgmt.pAfPendingTask = NULL;
if (FAIL(Status))
{
//
// OpenAF failed...
//
break;
}
//
// Successfully opened the address family and waited for
// connect status.
// Now setup the broadcast channel VC.
//
//
TR_INFO(("Interface: 0x%p, Got NdisAfHandle: 0x%p\n",
pIF, pIF->ndis.AfHandle));
//
// Let's create a destination object representing the
// broadcast channel, and make a call to it.
//
Status = arpSetupSpecialDest(
pIF,
NIC1394AddressType_Channel, // This means bcast channel.
pTask, // pParentTask
PEND_SetupBroadcastChannel, // PendCode
&pBroadcastDest,
pSR
);
// Should either fail or pend -- never return success.
//
ASSERT(Status != NDIS_STATUS_SUCCESS);
if (!PEND(Status))
{
OBJLOG0( pIF, "FATAL: Couldn't create BC dest entry.\n");
}
}
break;
case PEND_SetupBroadcastChannel:
{
PRM_TASK pMakeCallTask;
if (FAIL(Status))
{
//
// Couldn't setup the broadcast channel...
//
break;
}
//
// Successfully opened the address family.
// Now setup the receive FIFO VC.
//
//
// TR_INFO(("Interface: 0x%p, Got NdisAfHandle: 0x%p\n",
// pIF, pIF->ndis.AfHandle));
//
// Let's start a MakeCall task and pend on it.
//
Status = arpAllocateTask(
&pIF->Hdr, // pParentObject
arpTaskMakeRecvFifoCall, // pfnHandler
0, // Timeout
"Task: MakeRecvFifoCall", // szDescription
&pMakeCallTask,
pSR
);
if (FAIL(Status))
{
// Couldn't allocate task. Let's do a fake completion of
// this stage...
//
RmSuspendTask(pTask, PEND_SetupReceiveVc, pSR);
RmResumeTask(pTask, (UINT_PTR) Status, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
else
{
RmPendTaskOnOtherTask(
pTask,
PEND_SetupReceiveVc,
pMakeCallTask,
pSR
);
(VOID)RmStartTask(
pMakeCallTask,
0, // UserParam (unused)
pSR
);
Status = NDIS_STATUS_PENDING;
}
}
break;
case PEND_SetupReceiveVc:
{
PARPCB_DEST pMultiChannelDest;
if (FAIL(Status))
{
TR_WARN(("FATAL: COULDN'T SETUP RECEIVE FIFO VC!\n"));
break;
}
//
// Let's create a destination object representing the
// multichannel vc, and make a call to it.
//
Status = arpSetupSpecialDest(
pIF,
NIC1394AddressType_MultiChannel,
pTask, // pParentTask
PEND_SetupMultiChannel, // PendCode
&pMultiChannelDest,
pSR
);
// Should either fail or pend -- never return success.
//
ASSERT(Status != NDIS_STATUS_SUCCESS);
if (!PEND(Status))
{
OBJLOG0( pIF, "FATAL: Couldn't create BC dest entry.\n");
}
else
{
//
// On pending, pMultiChannelDest contains a valid
// pDest which has been tmpref'd.
// Keep a pointer to the broadcast dest in the IF.
// and link the broadcast dest to the IF.
//
{
#if RM_EXTRA_CHECKING
RmLinkObjectsEx(
&pIF->Hdr,
&pMultiChannelDest->Hdr,
0x34639a4c,
ARPASSOC_LINK_IF_OF_MCDEST,
" IF of MultiChannel Dest 0x%p (%s)\n",
ARPASSOC_LINK_MCDEST_OF_IF,
" MultiChannel Dest of IF 0x%p (%s)\n",
pSR
);
#else // !RM_EXTRA_CHECKING
RmLinkObjects(&pIF->Hdr, &pMultiChannelDest->Hdr,pSR);
#endif // !RM_EXTRA_CHECKING
LOCKOBJ(pIF, pSR);
ASSERT(pIF->pMultiChannelDest == NULL);
pIF->pMultiChannelDest = pMultiChannelDest;
UNLOCKOBJ(pIF, pSR);
// arpSetupSpecialDest ref'd pBroadcastDest.
//
RmTmpDereferenceObject(&pMultiChannelDest->Hdr, pSR);
}
}
}
break;
case PEND_SetupMultiChannel:
{
PARPCB_DEST pEthernetDest;
if (FAIL(Status))
{
TR_WARN(("COULDN'T SETUP MULTI-CHANNEL VC (IGNORING FAILURE)!\n"));
break;
}
//
// Let's create a destination object representing the
// ethernet, and make a call to it.
//
Status = arpSetupSpecialDest(
pIF,
NIC1394AddressType_Ethernet,
pTask, // pParentTask
PEND_SetupEthernetVc, // PendCode
&pEthernetDest,
pSR
);
// Should either fail or pend -- never return success.
//
ASSERT(Status != NDIS_STATUS_SUCCESS);
if (!PEND(Status))
{
OBJLOG0( pIF, "FATAL: Couldn't create BC dest entry.\n");
}
else
{
//
// On pending, pEthernetDest contains a valid
// pDest which has been tmpref'd.
// Keep a pointer to the broadcast dest in the IF.
// and link the broadcast dest to the IF.
//
{
#if RM_EXTRA_CHECKING
RmLinkObjectsEx(
&pIF->Hdr,
&pEthernetDest->Hdr,
0xcea46d67,
ARPASSOC_LINK_IF_OF_ETHDEST,
" IF of Ethernet Dest 0x%p (%s)\n",
ARPASSOC_LINK_ETHDEST_OF_IF,
" Ethernet Dest of IF 0x%p (%s)\n",
pSR
);
#else // !RM_EXTRA_CHECKING
RmLinkObjects(&pIF->Hdr, &pEthernetDest->Hdr,pSR);
#endif // !RM_EXTRA_CHECKING
LOCKOBJ(pIF, pSR);
ASSERT(pIF->pEthernetDest == NULL);
pIF->pEthernetDest = pEthernetDest;
UNLOCKOBJ(pIF, pSR);
// arpSetupSpecialDest ref'd pBroadcastDest.
//
RmTmpDereferenceObject(&pEthernetDest->Hdr, pSR);
}
}
}
break;
case PEND_SetupEthernetVc:
{
if (FAIL(Status))
{
TR_WARN(("COULDN'T SETUP ETHERNET VC (IGNORING FAILURE)!\n"));
break;
}
if (!ARP_ATPASSIVE())
{
ASSERT(sizeof(TASK_ACTIVATE_IF)<=sizeof(ARP1394_TASK));
// We're not at passive level, but we need to be when we
// call IP's add interface. So we switch to passive...
// NOTE: we specify completion code PEND_SetupReceiveVc
// because we want to get back here (except
// we'll be at passive).
//
RmSuspendTask(pTask, PEND_SetupEthernetVc, pSR);
RmResumeTaskAsync(
pTask,
Status,
&((TASK_ACTIVATE_IF*)pTask)->WorkItem,
pSR
);
Status = NDIS_STATUS_PENDING;
break;
}
ASSERT(Status == NDIS_STATUS_SUCCESS);
//
// Successfully opened the address family and setup
// the recv VC.
if (!FAIL(Status))
{
//
// Start the maintenance task on this IF.
//
arpStartIfMaintenanceTask(pIF, pSR);
}
} // end case PEND_SetupEthernetVc
break;
default:
{
ASSERTEX(!"Unknown pend op", pTask);
}
break;
} // end switch(RM_PEND_CODE(pTask))
}
break;
case RM_TASKOP_END:
{
//
// Recover the last status ...
//
Status = (NDIS_STATUS) UserParam;
//
// Status of the completed operation can't itself be pending!
//
ASSERT(Status != NDIS_STATUS_PENDING);
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
}
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpTaskOnPower (
IN PRM_TASK pTask,
IN RM_TASK_OPERATION Code,
IN UINT_PTR UserParam, // Unused
IN PRM_STACK_RECORD pSR
)
/*++
Validates the event and passes it off to the correct function.
This presumes that the LowPowerTask has already run
It then waits for that function to finish its work.
--*/
{
ENTER("arpTaskOnPower", 0xccaf09cd)
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
ARP1394_ADAPTER* pAdapter = (ARP1394_ADAPTER*)RM_PARENT_OBJECT(pTask);
TASK_POWER * pTaskPower = (TASK_POWER*) pTask;
ARP1394_INTERFACE * pIF = pAdapter->pIF;
ULONG Stage = 0;
enum
{
STAGE_Start,
STAGE_BecomePrimaryTask,
STAGE_ExistingPrimaryTaskComplete,
STAGE_StartGenericVCs,
PEND_DeinitIF,
STAGE_End
};
pTaskPower = (PTASK_POWER) pTask;
//
// Message normalizing code
//
switch(Code)
{
case RM_TASKOP_START:
Stage = STAGE_Start;
break;
case RM_TASKOP_PENDCOMPLETE:
Status = (NDIS_STATUS) UserParam;
ASSERT(!PEND(Status));
Stage = RM_PEND_CODE(pTask);
break;
case RM_TASKOP_END:
Status = (NDIS_STATUS) UserParam;
Stage= STAGE_End;
break;
default:
ASSERT(FALSE);
return NDIS_STATUS_FAILURE; // ** EARLY RETURN **
}
switch(Stage)
{
case STAGE_Start:
{
// There should NOT be another activate/deactivate task running
// on this interface. We fail the SetPower if we receive it in
// while we are activating or deactivating the task
//
TIMESTAMP("===Set Power ON Starting");
LOCKOBJ(pAdapter, pSR);
if (CHECK_AD_PRIMARY_STATE(pAdapter,ARPAD_PS_INITED) == FALSE)
{
break;
}
//
// Now, make this task the primary task on the adapter
//
if (pAdapter->bind.pPrimaryTask == NULL)
{
// Don't change the Init State of this adapter
//
ULONG CurrentInitState = GET_AD_PRIMARY_STATE(pAdapter);
arpSetPrimaryAdapterTask(pAdapter, pTask, CurrentInitState , pSR);
pAdapter->PoMgmt.bResuming = TRUE;
UNLOCKOBJ(pAdapter, pSR);
}
else
{
PRM_TASK pOtherTask = pAdapter->bind.pPrimaryTask;
RmTmpReferenceObject(&pOtherTask->Hdr, pSR);
UNLOCKOBJ(pAdapter, pSR);
RmPendTaskOnOtherTask(
pTask,
STAGE_BecomePrimaryTask, // we'll try again...
pOtherTask,
pSR
);
RmTmpDereferenceObject(&pOtherTask->Hdr, pSR);
Status = NDIS_STATUS_PENDING;
break;
}
}
if (PEND(Status)) break;
// FALL THROUGH
case STAGE_ExistingPrimaryTaskComplete:
{
PRM_TASK pStartGenericVCs = NULL;
if (pIF->pActDeactTask != NULL)
{
// This should never happen, because the Activate task is
// always started by an active primary task, and at most one primary
// task is active at any point of time.
//
ASSERTEX(!"start: activate/deactivate task exists!", pIF);
Status = NDIS_STATUS_FAILURE;
break;
}
//
// Stop the IF maintenance task if it's running.
//
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject,
arpTaskStartGenericVCs , // pfnHandler,
0, // Timeout,
"Task: arpTaskStartGenericVCs", // szDescrip.
&pStartGenericVCs,
pSR
);
if (FAIL(Status))
{
// Couldn't allocate task.
//
TR_WARN(("FATAL: couldn't alloc start call task!\n"));
break;
}
else
{
Status = RmPendTaskOnOtherTask(
pTask,
STAGE_StartGenericVCs,
pStartGenericVCs,
pSR
);
ASSERT(!FAIL(Status));
// RmStartTask uses up the tmpref on the task
// which was added by arpAllocateTask.
//
Status = RmStartTask(
pStartGenericVCs,
0, // UserParam (unused)
pSR
);
}
if (PEND(Status)) break;
}
break;
case STAGE_StartGenericVCs:
{
//
// The close AF operation is complete.
// We've not got anything else to do.
//
TIMESTAMP("===Set PowerOn: Created VCs");
// Recover the last status ...
//
Status = (NDIS_STATUS) UserParam;
if (Status != NDIS_STATUS_SUCCESS)
{
//
// Undo all the VCs, AFs and Task that
//have been created in arpTaskStartGenericVCs
//
pAdapter->PoMgmt.bFailedResume = TRUE;
arpDeinitIf(pIF, pTask,PEND_DeinitIF, pSR);
Status = NDIS_STATUS_PENDING;
}
}
break;
case PEND_DeinitIF:
{
//
// Set the Failure state on the adapter object here
//
//
// return Failure, so we can inform NDIS of the failure
//
Status = NDIS_STATUS_SUCCESS;
}
break;
case STAGE_End:
{
//
// We are done with all async aspects of setting the Low Power state
// Set the event so that the original Low Power thread can return.
//
TIMESTAMP("===Set Power On done: All done!");
LOCKOBJ (pAdapter, pSR);
if (Status== NDIS_STATUS_SUCCESS)
{
arpClearPrimaryAdapterTask (pAdapter, pTask, ARPAD_PS_INITED,pSR);
}
else
{
arpClearPrimaryAdapterTask (pAdapter, pTask, ARPAD_PS_FAILEDINIT,pSR);
}
SET_POWER_STATE(pAdapter, ARPAD_POWER_NORMAL);;
UNLOCKOBJ (pAdapter, pSR);
*pTaskPower->pStatus = Status;
NdisSetEvent (&pAdapter->PoMgmt.Complete);
}
break;
default:
{
ASSERTEX(!"Unknown task op", pTask);
}
break;
} // switch (Stage)
RM_ASSERT_NOLOCKS(pSR);
EXIT()
return Status;
}
NDIS_STATUS
arpStandby (
IN ARP1394_ADAPTER *pAdapter,
IN NET_DEVICE_POWER_STATE DeviceState,
IN PRM_STACK_RECORD pSR
)
/*++
arpStandby does the work for putting the adapter into standby.
It synchronously return Success, Failure or Not Supported.
If the Adapter structure has not inited, then this function returns
Not supported
--*/
{
PARP1394_INTERFACE pIF = pAdapter->pIF;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
PTASK_POWER pSetPowerTask = NULL;
NDIS_STATUS TaskStatus = NDIS_STATUS_FAILURE;
ENTER ("arpStandby ", 0x2087f71a)
do
{
//
// If we have been asked to standby before the Interface has initialized
// then we return NOT_SUPPORTED. This will cause NDIS to unbind the the ARP
// from the miniport .
//
if (pIF == NULL)
{
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
if(!CHECK_IF_PRIMARY_STATE(pIF, ARPIF_PS_INITED))
{
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject
arpTaskLowPower, // pfnHandler
0, // Timeout
"Task: Set Power Low", // szDescription
&(PRM_TASK)pSetPowerTask,
pSR
);
if (NDIS_STATUS_SUCCESS != Status || NULL == pSetPowerTask)
{
pSetPowerTask = NULL;
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
pSetPowerTask->pStatus = &TaskStatus;
pSetPowerTask ->PowerState = DeviceState;
NdisInitializeEvent(&pAdapter->PoMgmt.Complete);
RmStartTask((PRM_TASK)pSetPowerTask,0,pSR);
NdisWaitEvent (&pAdapter->PoMgmt.Complete, 0);
//
// Set the variable for the wakeup
//
pAdapter->PoMgmt.bReceivedSetPowerD0= FALSE;
Status = NDIS_STATUS_SUCCESS;
break;
} while (FALSE);
EXIT();
return Status;
}
NDIS_STATUS
arpResume (
IN ARP1394_ADAPTER* pAdapter,
IN ARP_RESUME_CAUSE Cause,
IN PRM_STACK_RECORD pSR
)
/*++
This function manages the starting of the Resume Task.
The resume task can only be started once after receiving an AfNotify
and a Set Power.
However, an Unbind can come in and unbind the adapter in the middle of this.
This function does not start the resume if the adapter is already unbinding
--*/
{
BOOLEAN bSetPowerOnTask = FALSE;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PTASK_POWER pSetPowerTask = NULL;
NDIS_STATUS TaskStatus;
ENTER ("arpResume", 0x3dddc538)
do
{
if (CHECK_POWER_STATE(pAdapter, ARPAD_POWER_NORMAL)== TRUE)
{
break;
}
LOCKOBJ (pAdapter, pSR);
if (Cause == Cause_SetPowerD0)
{
pAdapter->PoMgmt.bReceivedSetPowerD0 = TRUE;
}
//
// If we have already received an Unbind, then don't do anything.
//
if ( pAdapter->PoMgmt.bReceivedUnbind == FALSE)
{
//
// If we have not received an unbind,
// then this thread needs to all the work to
// reactivate the arp module.
//
bSetPowerOnTask = TRUE;
}
UNLOCKOBJ(pAdapter,pSR);
if (bSetPowerOnTask == FALSE)
{
break;
}
//
// Start the Set Power Task
//
Status = arpAllocateTask(
&pAdapter->Hdr, // pParentObject
arpTaskOnPower, // pfnHandler
0, // Timeout
"Task: SetPower On", // szDescription
&(PRM_TASK)pSetPowerTask,
pSR
);
if (Status != NDIS_STATUS_SUCCESS || NULL == pSetPowerTask)
{
break;
}
pSetPowerTask->pStatus = &TaskStatus;
NdisResetEvent (&pAdapter->PoMgmt.Complete);
RmStartTask ((PRM_TASK)pSetPowerTask,0,pSR);
NdisWaitEvent (&pAdapter->PoMgmt.Complete, 0);
Status = TaskStatus;
} while (FALSE);
EXIT()
return Status;
}
NDIS_STATUS
arpNdSetPower (
ARP1394_ADAPTER *pAdapter,
PNET_DEVICE_POWER_STATE pPowerState,
PRM_STACK_RECORD pSR
)
/*++
Validates the event and passes it off to the correct function
--*/
{
ENTER("arpNdSetPower ", 0x21c4013a)
TASK_POWER *pSetPowerTask = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
NDIS_STATUS TaskStatus = NDIS_STATUS_NOT_SUPPORTED;
//
// The bridge is present.Close all the VCs if we are going to
// a low power or re-create all the VC if we are going to D0
//
if (NetDeviceStateD0 == (*pPowerState))
{
Status = arpResume(pAdapter, Cause_SetPowerD0, pSR);
}
else
{
Status = arpStandby(pAdapter, *pPowerState, pSR);
}
return Status;
}