/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: co.c Abstract: ARP1394 connection-oriented handlers. Revision History: Who When What -------- -------- ---------------------------------------------- josephj 12-01-98 Created Notes: --*/ #include // // File-specific debugging defaults. // #define TM_CURRENT TM_CO //========================================================================= // L O C A L P R O T O T Y P E S // // The following functions and typedefs are accessed only in this file. // //========================================================================= UINT arpRecvFifoReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ); VOID arpRecvFifoIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ); VOID arpDestIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ); VOID arpDestSendComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ); UINT arpDestReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ); NDIS_STATUS arpTaskUnloadEthDhcpEntry( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ); NDIS_STATUS arpInitializeIfPools( IN PARP1394_INTERFACE pIF, IN PRM_STACK_RECORD pSR ); VOID arpDeInitializeIfPools( IN PARP1394_INTERFACE pIF, IN PRM_STACK_RECORD pSR ); #if ARP_DEFERIFINIT MYBOOL arpIsAdapterConnected( IN PARP1394_ADAPTER pAdapter, IN PRM_STACK_RECORD pSR ); #endif // ARP_DEFERIFINIT #if DBG VOID arpDbgDisplayMapping( IP_ADDRESS IpAddress, PNIC1394_DESTINATION pHwAddr, char * szPrefix ); #define ARP_DUMP_MAPPING(_Ip, _Hw, _sz) \ arpDbgDisplayMapping(_Ip, _Hw, _sz) #else // !DBG #define ARP_DUMP_MAPPING(_Ip, _Hw, _sz) \ (0) #endif NDIS_STATUS arpSetupSpecialDest( IN PARP1394_INTERFACE pIF, IN NIC1394_ADDRESS_TYPE AddressType, IN PRM_TASK pParentTask, IN UINT PendCode, OUT PARPCB_DEST * ppSpecialDest, PRM_STACK_RECORD pSR ); VOID arpTryAbortPrimaryIfTask( PARP1394_INTERFACE pIF, PRM_STACK_RECORD pSR ); VOID arpDoLocalIpMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ); VOID arpDoRemoteIpMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ); VOID arpDoRemoteEthMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ); VOID arpDoMcapDbMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTIme, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ); VOID arpDoDhcpTableMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ); INT arpMaintainOneLocalIp( PRM_OBJECT_HEADER pHdr, PVOID pvContext, PRM_STACK_RECORD pSR ); INT arpMaintainOneRemoteIp( PRM_OBJECT_HEADER pHdr, PVOID pvContext, PRM_STACK_RECORD pSR ); INT arpMaintainOneRemoteEth( PRM_OBJECT_HEADER pHdr, PVOID pvContext, PRM_STACK_RECORD pSR ); INT arpMaintainOneDhcpEntry( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ); VOID arpUpdateLocalIpDest( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN PARPCB_LOCAL_IP pLocalIp, IN PARP_DEST_PARAMS pDestParams, PRM_STACK_RECORD pSR ); UINT arpFindAssignedChannel( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN IP_ADDRESS IpAddress, IN UINT CurrentTime, PRM_STACK_RECORD pSR ); UINT arpFindFreeChannel( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT PRM_STACK_RECORD pSR ); VOID arpUpdateRemoteIpDest( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN PARPCB_REMOTE_IP pRemoteIp, IN PARP_DEST_PARAMS pDestParams, PRM_STACK_RECORD pSR ); VOID arpRemoteDestDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); VOID arpRefreshArpEntry( PARPCB_REMOTE_IP pRemoteIp, PRM_STACK_RECORD pSR ); INT arpMaintainArpCache( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpRemoteDestCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpDhcpTableEntryCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); VOID arpDhcpTableEntryDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); // ARP1394_INTERFACE_StaticInfo contains static information about // objects of type ARP1394_INTERFACE; // RM_STATIC_OBJECT_INFO ARP1394_INTERFACE_StaticInfo = { 0, // TypeUID 0, // TypeFlags "INTERFACE", // TypeName 0, // Timeout NULL, // pfnCreate arpObjectDelete, // pfnDelete NULL, // LockVerifier 0, // length of resource table NULL // Resource Table }; // Specialized VC handlers for the RECEIVE_FIFO VC // ARP_STATIC_VC_INFO g_ArpRecvFifoVcStaticInfo = { // Description // "Recv FIFO VC", // Description // // Specialized VC handlers. // NULL, // NULL SendComplete handler. arpRecvFifoReceivePacket, arpRecvFifoIncomingClose, // VC_TYPE // ARPVCTYPE_RECV_FIFO, FALSE // FALSE == Is NOT Dest VC }; // Specialized VC handlers for the BROADCAST VC // ARP_STATIC_VC_INFO g_ArpBroadcastChannelVcStaticInfo = { // Description // "Broadcast VC", // Description // // Specialized VC handlers. // // arpBroadcastChannelSendComplete, // arpBroadcastChannelReceivePacket, // arpBroadcastChannelIncomingClose, arpDestSendComplete, arpDestReceivePacket, arpDestIncomingClose, // VC_TYPE // ARPVCTYPE_BROADCAST_CHANNEL, TRUE // Is dest VC }; // Specialized VC handlers for a send FIFO VC. // ARP_STATIC_VC_INFO g_ArpSendFifoVcStaticInfo = { // Description // "Send FIFO VC", // Description // // Specialized VC handlers. // // arpSendFifoSendComplete, // arpSendFifoIncomingClose, arpDestSendComplete, NULL, // NULL Recv Pkt handler. arpDestIncomingClose, // VC_TYPE // ARPVCTYPE_SEND_FIFO, TRUE // Is dest VC }; // Specialized VC handlers for the MULTICHANNEL VC // ARP_STATIC_VC_INFO g_ArpMultiChannelVcStaticInfo = { // Description // "MultiChannel VC", // Description // // Specialized VC handlers. // NULL, // NULL Send complete handler. arpDestReceivePacket, arpDestIncomingClose, // arpMultiChannelReceivePacket, // arpMultiChannelIncomingClose, // VC_TYPE // ARPVCTYPE_MULTI_CHANNEL, TRUE // Is dest VC }; // Specialized VC handlers for the ETHERNET VC // ARP_STATIC_VC_INFO g_ArpEthernetVcStaticInfo = { // Description // "Ethernet VC", // Description // // Specialized VC handlers. // // arpEthernetSendComplete, // arpEthernetIncomingClose, arpDestSendComplete, arpEthernetReceivePacket, arpDestIncomingClose, // VC_TYPE // ARPVCTYPE_ETHERNET, TRUE // Is dest VC }; // Specialized VC handlers for RECV CHANNEL VCs // ARP_STATIC_VC_INFO g_ArpRecvChannelVcStaticInfo = { // Description // "Recv Channel VC", // Description // // Specialized VC handlers. // NULL, // NULL Send complete handler. // arpRecvChannelReceivePacket, // arpRecvChannelIncomingClose, arpDestReceivePacket, arpDestIncomingClose, // VC_TYPE // ARPVCTYPE_RECV_CHANNEL, TRUE // Is dest VC }; // Specialized VC handlers for SEND CHANNEL VCs // ARP_STATIC_VC_INFO g_ArpSendChannelVcStaticInfo = { // Description // "Send Channel VC", // Description // // Specialized VC handlers. // // arpSendChannelSendComplete, // arpSendChannelIncomingClose, arpDestSendComplete, NULL, // NULL receive packet handler. arpDestIncomingClose, // VC_TYPE // ARPVCTYPE_SEND_CHANNEL, TRUE // Is dest VC }; NDIS_STATUS arpCreateInterface( IN PARP1394_ADAPTER pAdapter, OUT PARP1394_INTERFACE *ppIF, IN PRM_STACK_RECORD pSR ); VOID arpDeleteInterface( IN PARP1394_INTERFACE pIF, IN PRM_STACK_RECORD pSR ); VOID arpActivateIf( PARP1394_INTERFACE pIF, PRM_TASK pCallingTask, // OPTIONAL UINT SuspendCode, // OPTIONAL PRM_STACK_RECORD pSR ); VOID arpDeactivateIf( PARP1394_INTERFACE pIF, PRM_TASK pCallingTask, // OPTIONAL UINT SuspendCode, // OPTIONAL PRM_STACK_RECORD pSR ); NDIS_STATUS arpCallIpAddInterface( IN ARP1394_INTERFACE* pIF, IN PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpLocalIpCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); VOID arpLocalIpDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpRemoteIpCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpRemoteEthCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); VOID arpRemoteIpDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); VOID arpRemoteEthDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); PRM_OBJECT_HEADER arpDestinationCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ); VOID arpDestinationDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ); VOID arpAddStaticArpEntries( IN ARP1394_INTERFACE *pIF, IN PRM_STACK_RECORD pSR ); MYBOOL arpNeedToCleanupDestVc( ARPCB_DEST *pDest // LOCKING LOCKOUT ); VOID arpDeinitDestination( PARPCB_DEST pDest, MYBOOL fOnlyIfUnused, PRM_STACK_RECORD pSR ); VOID arpDeinitRemoteIp( PARPCB_REMOTE_IP pRemoteIp, PRM_STACK_RECORD pSR ); VOID arpDeinitRemoteEth( PARPCB_REMOTE_ETH pRemoteEth, PRM_STACK_RECORD pSR ); //========================================================================= // C O N N E C T I O N - O R I E N T E D H A N D L E R S //========================================================================= VOID ArpCoAfRegisterNotify( IN NDIS_HANDLE ProtocolBindingContext, IN PCO_ADDRESS_FAMILY pAddressFamily ) /*++ Routine Description: This routine is called by NDIS when a Call manager registers its support for an Address Family over an adapter. If this is the Address Family we are interested in (1394), then we create and initialize an IP interface for this adapter. Arguments: ProtocolBindingContext - our context passed in NdisOpenAdapter, which is a pointer to our Adapter structure. pAddressFamily - points to a structure describing the Address Family being registered by a Call Manager. --*/ { ENTER("CoAfRegisterNotify", 0x51041947) PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER) ProtocolBindingContext; NDIS_STATUS Status; RM_DECLARE_STACK_RECORD(sr) do { PRM_TASK pTask; PARP1394_INTERFACE pIF; // Check if this AF is interesting to us. // if ((pAddressFamily->AddressFamily != CO_ADDRESS_FAMILY_1394) || (pAddressFamily->MajorVersion != NIC1394_AF_CURRENT_MAJOR_VERSION) || (pAddressFamily->MinorVersion != NIC1394_AF_CURRENT_MINOR_VERSION)) { TR_INFO( ("Uninteresting AF %d or MajVer %d or MinVer %d\n", pAddressFamily->AddressFamily, pAddressFamily->MajorVersion, pAddressFamily->MinorVersion)); break; } LOCKOBJ(pAdapter, &sr); // If we already have an interface active, we ignore this notification. // if (pAdapter->pIF != NULL) { UNLOCKOBJ (pAdapter, &sr); ASSERT (CHECK_POWER_STATE (pAdapter,ARPAD_POWER_LOW_POWER) == FALSE); TR_WARN( ("pAdapter 0x%p, IF already created!\n", pAdapter)); ASSERTEX(FALSE, pAdapter); break; } // Create Interface // Status = arpCreateInterface( pAdapter, &pIF, &sr ); if (FAIL(Status)) { break; } // // Allocate and start task to complete the interface initialization... // Status = arpAllocateTask( &pIF->Hdr, // pParentObject arpTaskInitInterface, // pfnHandler 0, // Timeout "Task: InitInterface", // szDescription &pTask, &sr ); if (FAIL(Status)) { TR_WARN(("FATAL: couldn't alloc init intf task!\n")); arpDeleteInterface(pIF, &sr ); break; } pAdapter->pIF = pIF; arpSetPrimaryIfTask(pIF, pTask, ARPIF_PS_INITING, &sr); UNLOCKOBJ(pAdapter, &sr); RM_ASSERT_NOLOCKS(&sr); (VOID)RmStartTask( pTask, 0, // UserParam (unused) &sr ); // // The InitializeTask will do all required cleanup on failure, including // deallocating the interface. // } while (FALSE); RmUnlockAll(&sr); RM_ASSERT_CLEAR(&sr); EXIT() } VOID ArpCoOpenAfComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE NdisAfHandle ) /*++ Routine Description: NDIS calls this function to indicate completion of a previous call to NdisClOpenAddressFamily. Arguments: Status - return status of the open address family call. ProtocolAfContext - actually a pointer to our interface control block. NdisAfHandle - the new Ndis AF handle for this adapter. --*/ { ENTER("OpenAfComplete", 0x86a3c14d) PARP1394_INTERFACE pIF = (PARP1394_INTERFACE) ProtocolAfContext; PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF); RM_DECLARE_STACK_RECORD(sr) TIMESTAMP("==>OpenAfComplete"); // We expect a nonzero task here (the pActDeactTask), which we unpend // after filling in the Ndis Af Handle. // { TR_INFO(( "AfCtxt=0x%lx, status=0x%lx, NdisAfHandle=0x%lx", ProtocolAfContext, Status, NdisAfHandle )); // We don't pass on NdisAfHandle -- instead we place it in pIF. // if (Status == NDIS_STATUS_SUCCESS) { LOCKOBJ(pIF, &sr); ASSERTEX(pIF->ndis.AfHandle == NULL, pIF); DBG_ADDASSOC( &pIF->Hdr, // pObject NdisAfHandle, // Instance1 NULL, // Instance2 ARPASSOC_IF_OPENAF, // AssociationID " Open AF NdisHandle=%p\n",// szFormat &sr ); pIF->ndis.AfHandle = NdisAfHandle; UNLOCKOBJ(pIF, &sr); } // This could have been caused by a resume or a bind. // In each case, resume the appropriate task // if (CHECK_POWER_STATE (pAdapter, ARPAD_POWER_LOW_POWER) == TRUE) { RmResumeTask (pIF->PoMgmt.pAfPendingTask, (UINT_PTR)Status , &sr); } else { // We expect a nonzero task here (UNbind task), which we unpend. // No need to grab locks or anything at this stage. // RmResumeTask(pIF->pActDeactTask, (UINT_PTR) Status, &sr); } } RM_ASSERT_CLEAR(&sr) TIMESTAMPX("<==OpenAfComplete"); EXIT() } VOID ArpCoCloseAfComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolAfContext ) /*++ Routine Description: NDIS calls this function to indicate completion of a previous call to NdisClCloseAddressFamily. Arguments: Status - return status of the close address family call. ProtocolAfContext - actually a pointer to our interface control block. --*/ { ENTER("CloseAfComplete", 0x0cc281db) PARP1394_INTERFACE pIF = (PARP1394_INTERFACE) ProtocolAfContext; PARP1394_ADAPTER pAdapter=(ARP1394_ADAPTER*)RM_PARENT_OBJECT(pIF); RM_DECLARE_STACK_RECORD(sr) TIMESTAMP("==>ArpCoCloseAfComlete"); // This could happen because of a Set Power to a low power state. // of an actual unbind. In each case, resume the task that would // have been waiting for the CloseAf to complete. // if (CHECK_POWER_STATE (pAdapter, ARPAD_POWER_NORMAL) == TRUE || pAdapter->PoMgmt.bFailedResume ) { // We expect a nonzero task here (UNbind task), which we unpend. // No need to grab locks or anything at this stage. // RmResumeTask(pIF->pActDeactTask, (UINT_PTR) Status, &sr); } else { RmResumeTask (pIF->PoMgmt.pAfPendingTask, (UINT_PTR)Status , &sr); } RM_ASSERT_CLEAR(&sr) TIMESTAMP("<==ArpCoCloseAfComlete"); EXIT() } VOID ArpCoSendComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ Routine Description: NDIS calls this function to indicate completion of a previous call to NdisCoSendPackets. Arguments: Status - return status of the send packet call. ProtocolVcContext - actually a pointer to our context for this VC. This is either a pointer to an ARPCB_DEST (if the VC is for a call to a remote FIFO address or channel), or to ARP1394_INTERFACE (if the VC is for a call to the single RECEIVE FIFO for this interface.) pNdisPacket - The packet that was sent. --*/ { PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; // // We use the special status NDIS_STATUS_NOT_RESETTABLE to indicate // that the an encapsulation buffer hasn't been inserted into the IP packet. // (See 2/5/2000 notes.txt entry). So we want to make sure that the miniport // doesn't return this status. // ASSERT(Status != NDIS_STATUS_NOT_RESETTABLE); pVcHdr->pStaticInfo->CoSendCompleteHandler( Status, ProtocolVcContext, pNdisPacket ); } VOID ArpCoStatus( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_STATUS GeneralStatus, IN PVOID pStatusBuffer, IN UINT StatusBufferSize ) /*++ Routine Description: This routine is called when the miniport indicates a status change, possibly on a VC. We ignore this. Arguments: --*/ { PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER)ProtocolBindingContext; PNIC1394_STATUS_BUFFER p1394StatusBuffer = (PNIC1394_STATUS_BUFFER )pStatusBuffer; do { if (CHECK_AD_ACTIVE_STATE(pAdapter, ARPAD_AS_ACTIVATED)==FALSE) { break; } if (GeneralStatus != NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { break; } if ((p1394StatusBuffer->Signature == NIC1394_MEDIA_SPECIFIC) && (p1394StatusBuffer->Event == NIC1394_EVENT_BUS_RESET )) { arpNdProcessBusReset(pAdapter); break; } }while (FALSE); } UINT ArpCoReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ HOT PATH Routine Description: This is routine is called when a packet is received on a VC owned by the arp module. If it is an ARP/MCAP-related packet, we consume it ourselves. Otherwise, we pass it up to IP. Arguments: ProtocolBindingContext - Actually a pointer to our Adapter structure ProtocolVcContext - Actually a pointer to our VC context, which is either ARP1394_INTERFACE (for the recv FIFO vc) or ARPCB_DEST (for vcs to remote destinations or to channels). pNdisPacket - NDIS packet being received. Return Value: 0 -- If we consume the packet ourselves (because we don't hold on to ARP/MCAP OR if we're calling the IP's IPRcvHandler (in which case we're ASSUMING IP doesn't hold on to the packet either). Set by IP -- if we're calling IP's IPRcvPktHandler --*/ { PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; UINT Ret; ARP_INIT_REENTRANCY_COUNT() ARP_INC_REENTRANCY(); Ret = pVcHdr->pStaticInfo->CoReceivePacketHandler( ProtocolBindingContext, ProtocolVcContext, pNdisPacket ); ARP_DEC_REENTRANCY(); return Ret; } NDIS_STATUS ArpCoCreateVc( IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE NdisVcHandle, OUT PNDIS_HANDLE pProtocolVcContext ) /*++ Routine Description: Entry point called by NDIS when the Call Manager wants to create a new endpoint (VC). We don't expect this to be called, because all our calls are outgoing. Arguments: Return Value: NDIS_STATUS_FAILURE --*/ { // We don't expect this, because all our calls are outgoing. // ASSERT(!"Unexpected"); return NDIS_STATUS_FAILURE; } NDIS_STATUS ArpCoDeleteVc( IN NDIS_HANDLE ProtocolVcContext ) /*++ Routine Description: Entry point called by NDIS when the Call Manager wants to delete a VC for an INCOMING call. We don't expect this to be called, because all our calls are outgoing. Arguments: Return Value: NDIS_STATUS_FAILURE --*/ { ASSERT(!"Unexpected"); return 0; } NDIS_STATUS ArpCoIncomingCall( IN NDIS_HANDLE ProtocolSapContext, IN NDIS_HANDLE ProtocolVcContext, IN OUT PCO_CALL_PARAMETERS pCallParameters ) /*++ Routine Description: Entry point called by NDIS when the Call Manager wants to indicate an INCOMING call. We don't expect this to be called, because all our calls are outgoing. Arguments: Return Value: NDIS_STATUS_FAILURE --*/ { ASSERT(!"Unexpected"); return NDIS_STATUS_FAILURE; } VOID ArpCoCallConnected( IN NDIS_HANDLE ProtocolVcContext ) /*++ Routine Description: Entry point called by NDIS when the Call Manager wants to indicate that an INCOMING call has reach the connected state. We don't expect this to be called, because all our calls are outgoing. Arguments: --*/ { ASSERT(!"Unexpected"); } VOID ArpCoIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ) /*++ Routine Description: This handler is called by NDIS when a call is closed unsolicited, either by the network or by the remote peer. We need to unload all resources associated with this VC. Arguments: CloseStatus - Reason for the call clearing ProtocolVcContext - A pointer to the our context for this VC. pCloseData - (Ignored) Size - (Ignored) --*/ { PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pVcHdr->pStaticInfo->ClIncomingCloseCallHandler( CloseStatus, ProtocolVcContext, pCloseData, Size ); } VOID ArpCoQosChange( IN NDIS_HANDLE ProtocolVcContext, IN PCO_CALL_PARAMETERS pCallParameters ) /*++ Routine Description: This handler is called by NDIS if the remote peer modifies call parameters "on the fly", i.e. after the call is established and running. We do not expect or support this. Arguments: ProtocolVcContext - Pointer to our context for this VC pCallParameters - updated call parameters. --*/ { ASSERT(!"Unimplemented"); } VOID ArpCoMakeCallComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN NDIS_HANDLE NdisPartyHandle OPTIONAL, IN PCO_CALL_PARAMETERS pCallParameters ) /*++ Routine Description: This routine is called by NDIS when an outgoing call request (NdisClMakeCall) has completed. The "Status" parameter indicates whether the call was successful or not. Arguments: Status - Result of the NdisClMakeCall ProtocolVcContext - Pointer to our context for this VC. NdisPartyHandle - Not used (no point-to-multipoint calls) pCallParameters - Pointer to call parameters --*/ { PRM_TASK pTask; PARP1394_INTERFACE pIF; PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; RM_DECLARE_STACK_RECORD(sr) if (pVcHdr->pStaticInfo->IsDestVc) { // // This is destination VC (either send FIFO or channel) // PARPCB_DEST pDest; pDest = CONTAINING_RECORD(pVcHdr, ARPCB_DEST, VcHdr); ASSERT_VALID_DEST(pDest); pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pDest); if (pVcHdr->pStaticInfo->VcType == ARPVCTYPE_SEND_FIFO) { DBGMARK(0x8a1c2e4d); if (Status == NDIS_STATUS_SUCCESS) { LOGSTATS_SuccessfulSendFifoMakeCalls(pIF); } else { LOGSTATS_FailedSendFifoMakeCalls(pIF); } } else { // // NOTE -- Ethernet is treated as "channel" // DBGMARK(0xb803909b); if (Status == NDIS_STATUS_SUCCESS) { LOGSTATS_SuccessfulChannelMakeCalls(pIF); } else { LOGSTATS_FailedChannelMakeCalls(pIF); } } } else { DBGMARK(0xd32d028c); ASSERT(pVcHdr->pStaticInfo->VcType == ARPVCTYPE_RECV_FIFO); pIF = CONTAINING_RECORD( pVcHdr, ARP1394_INTERFACE, recvinfo.VcHdr); ASSERT_VALID_INTERFACE(pIF); } pTask = pVcHdr->pMakeCallTask; ASSERT(pTask != NULL); RmResumeTask(pTask, (UINT_PTR) Status, &sr); RM_ASSERT_CLEAR(&sr) } VOID ArpCoCloseCallComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN NDIS_HANDLE ProtocolPartyContext OPTIONAL ) /*++ Routine Description: This routine handles completion of a previous NdisClCloseCall. We delete the VC on which the call was just closed, regardless of the value of Status. Arguments: Status - Status of the Close Call. ProtocolVcContext - Pointer to our contex for this VC. ProtocolPartyContext - Not used. --*/ { PRM_TASK pTask; PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; RM_DECLARE_STACK_RECORD(sr) DBGMARK(0x0ecb7bd5); pTask = pVcHdr->pCleanupCallTask; ASSERT(pTask != NULL); RmResumeTask(pTask, (UINT_PTR) Status, &sr); RM_ASSERT_CLEAR(&sr) } VOID ArpCoModifyQosComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PCO_CALL_PARAMETERS pCallParameters ) /*++ Routine Description: This routine is called by NDIS on completion of a previous call to NdisClModifyCallQoS. Since we don't call this, this should never get called. Arguments: --*/ { ASSERT(!"Unexpected"); } NDIS_STATUS ArpCoRequest( IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, IN OUT PNDIS_REQUEST pNdisRequest ) /*++ Routine Description: This routine is called by NDIS when our Call Manager sends us an NDIS Request. NDIS Requests that are of significance to us are: - OID_CO_AF_CLOSE The Call Manager wants us to shut down this Interface. We ignore all other OIDs. Arguments: ProtocolAfContext - Our context for the Address Family binding. ProtocolVcContext - Our context for a VC. ProtocolPartyContext - Our context for a Party. Since we don't do PMP, this is ignored (must be NULL). pNdisRequest - Pointer to the NDIS Request. Return Value: NDIS_STATUS_SUCCESS if we recognized the OID NDIS_STATUS_NOT_RECOGNIZED if we didn't. TODO: handle AF_CLOSE --*/ { NDIS_STATUS Status = NDIS_STATUS_NOT_RECOGNIZED; ENTER("ArpCoRequest", 0x0d705cb5) PARP1394_INTERFACE pIF = (PARP1394_INTERFACE) ProtocolAfContext; RM_DECLARE_STACK_RECORD(sr) if (pNdisRequest->RequestType == NdisRequestSetInformation) { switch (pNdisRequest->DATA.SET_INFORMATION.Oid) { case OID_CO_AF_CLOSE: // TODO -- initiate shutdown of interface. // But I don't think we will actually ever get this from // NIC1394! // ASSERT(!"Unimplemented!"); Status = NDIS_STATUS_SUCCESS; break; default: ASSERT(!"Unexpected OID from NIC1394!"); Status = NDIS_STATUS_FAILURE; break; } } TR_INFO(( "Called. pIF=0x%p. pReq=0x%p. Oid=0x%lu. Return status=0x%lx\n", pIF, pNdisRequest->RequestType, pNdisRequest->DATA.SET_INFORMATION.Oid, Status )); RM_ASSERT_CLEAR(&sr); EXIT() return (Status); } VOID ArpCoRequestComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, IN PNDIS_REQUEST pNdisRequest ) /*++ Routine Description: This routine is called by NDIS when a previous call to NdisCoRequest that had pended, is complete. We handle this based on the request we had sent, which has to be one of: - OID_NIC1394_LOCAL_NODE_INFO Get NIC1394 adapter information. - OID_NIC1394_VC_INFO Get updated NIC1394 information about this VC. Arguments: Status - Status of the Request. ProtocolAfContext - Our context for the Address Family binding. ProtocolVcContext - Our context for a VC. ProtocolPartyContext - Our context for a Party. Since we don't do PMP, this is ignored (must be NULL). pNdisRequest - Pointer to the NDIS Request. --*/ { // // TODO: unimplemented. // } //========================================================================= // P R I V A T E F U N C T I O N S // //========================================================================= NDIS_STATUS arpTaskInitInterface( 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 loading a newly-created IP interface. This is a primary task for the interface object. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status; PARP1394_INTERFACE pIF; ENTER("TaskInitInterface", 0x4d42506c) // Following are the list of pending states for this task. // enum { PEND_InitAdapterComplete, PEND_ActivateIfComplete, PEND_DeinitIfOnFailureComplete }; Status = NDIS_STATUS_FAILURE; pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pTask); switch(Code) { case RM_TASKOP_START: { CO_ADDRESS_FAMILY AddressFamily; // // We expect to ALREADY be the active primary task. // No need to get the IF lock to do this check... // if (pIF->pPrimaryTask != pTask) { ASSERT(!"start: we are not the active primary task!"); Status = NDIS_STATUS_FAILURE; break; } // // Determine if adapter initialization is ongoing. If it is, we need // to wait for it to complete. // { PARP1394_ADAPTER pAdapter; PRM_TASK pAdapterInitTask; // No need to lock pIF to get pAdapter... // pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF); LOCKOBJ(pAdapter, pSR); if (CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITING)) { pAdapterInitTask = pAdapter->bind.pPrimaryTask; ASSERT(pAdapterInitTask->pfnHandler == arpTaskInitializeAdapter); RmTmpReferenceObject(&pAdapterInitTask->Hdr, pSR); OBJLOG0( pIF, "Waiting for adapter init to complere.\n" ); Status = NDIS_STATUS_PENDING; } else { pAdapterInitTask = NULL; if (CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITED)) { Status = NDIS_STATUS_SUCCESS; } else { OBJLOG1( pIF, "Failing init because adapter state(0x%x) is not INITED.\n", GET_AD_PRIMARY_STATE(pAdapter) ); Status = NDIS_STATUS_FAILURE; } } UNLOCKOBJ(pAdapter, pSR); RM_ASSERT_NOLOCKS(pSR); if (pAdapterInitTask != NULL) { RmPendTaskOnOtherTask( pTask, PEND_InitAdapterComplete, pAdapterInitTask, pSR ); RmTmpDereferenceObject(&pAdapterInitTask->Hdr, pSR); } } if (!PEND(Status) && !FAIL(Status)) { // // Activate the interface... // arpActivateIf(pIF, pTask, PEND_ActivateIfComplete, pSR); Status = NDIS_STATUS_PENDING; } } break; case RM_TASKOP_PENDCOMPLETE: { Status = (NDIS_STATUS) UserParam; switch(RM_PEND_CODE(pTask)) { case PEND_InitAdapterComplete: { // // Activate the interface... // // if (!FAIL(Status)) { arpActivateIf(pIF, pTask, PEND_ActivateIfComplete, pSR); Status = NDIS_STATUS_PENDING; } } break; case PEND_ActivateIfComplete: { LOCKOBJ(pIF, pSR); if (FAIL(Status)) { arpClearPrimaryIfTask(pIF, pTask, ARPIF_PS_FAILEDINIT, pSR); UNLOCKOBJ(pIF, pSR); arpDeinitIf( pIF, pTask, // pCallingTask PEND_DeinitIfOnFailureComplete, pSR ); Status = NDIS_STATUS_PENDING; } else { // // Successful activation. Clear the primary task // and set the primary state appropriately. // arpClearPrimaryIfTask(pIF, pTask, ARPIF_PS_INITED, pSR); UNLOCKOBJ(pIF, pSR); } } // end case PEND_ActivateIfComplete break; case PEND_DeinitIfOnFailureComplete: { // We expect pIF to be deallocated... // ASSERT(RM_IS_ZOMBIE(pIF)); // // We ignore the return status of shutdown inteface. // and set Status to failure, because it is // the init interface task that is failing. // Status = NDIS_STATUS_FAILURE; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { // // Nothing to do here. (Debug) Do some checking. // #if (DBG) Status = (NDIS_STATUS) UserParam; if (FAIL(Status)) { ASSERT(RM_IS_ZOMBIE(pIF)); } ASSERT(pIF->pPrimaryTask != pTask); #endif // DBG } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS arpTaskActivateInterface( 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 activating an already initialized IP interface. Activating consists of: - Reading configuration information - Opening the address family - Initiating the recv FIFO call Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; PARP1394_INTERFACE pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pTask); PARP1394_ADAPTER pAdapter; ENTER("TaskActivateInterface", 0x950cb22e) // Following are the list of pending states for this task. // enum { PEND_OpenAF, PEND_SetupBroadcastChannel, PEND_SetupReceiveVc, PEND_SetupMultiChannel, PEND_SetupEthernetVc }; // No need to lock pIF to get pAdapter... // pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF); switch(Code) { case RM_TASKOP_START: { CO_ADDRESS_FAMILY AddressFamily; TIMESTAMP("===ActivateIF: Starting"); // Fail initialization if the adapter is not INITED. // { LOCKOBJ(pAdapter, pSR); if (!CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITED)) { OBJLOG1( pIF, "Failing init because adapter state(0x%x) is not INITED.\n", GET_AD_PRIMARY_STATE(pAdapter) ); Status = NDIS_STATUS_FAILURE; UNLOCKOBJ(pAdapter, pSR); break; } UNLOCKOBJ(pAdapter, pSR); } 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; } arpSetSecondaryIfTask(pIF, pTask, ARPIF_AS_ACTIVATING, pSR); // FIRST, we have to re-enable all the groups in the // IF structure, which may be disabled if this activation // is happening after a deactivation... // RmEnableGroup(&pIF->LocalIpGroup, pSR); RmEnableGroup(&pIF->RemoteIpGroup, pSR); if (ARP_BRIDGE_ENABLED(pAdapter)) { RmEnableGroup(&pIF->RemoteEthGroup, pSR); RmEnableGroup (&pIF->EthDhcpGroup, pSR); } RmEnableGroup(&pIF->DestinationGroup, pSR); UNLOCKOBJ(pIF, pSR); // Pick up configuration info for this interface. // Status = arpCfgGetInterfaceConfiguration( pIF, pSR ); if (FAIL(Status)) { OBJLOG1(pIF, "Cannot open IF configuration. Status=0x%lx\n", Status); break; } // // Suspend task and call NdisClOpenAddressFamily... // NdisZeroMemory(&AddressFamily, sizeof(AddressFamily)); AddressFamily.AddressFamily = CO_ADDRESS_FAMILY_1394; AddressFamily.MajorVersion = NIC1394_AF_CURRENT_MAJOR_VERSION; AddressFamily.MinorVersion = NIC1394_AF_CURRENT_MINOR_VERSION; 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: { Status = (NDIS_STATUS) UserParam; switch(RM_PEND_CODE(pTask)) { case PEND_OpenAF: { PARPCB_DEST pBroadcastDest; if (FAIL(Status)) { // // OpenAF failed... // break; } // Check if the adapter state is inited and fail if not. // We keep coming down this path if we're waiting for // the adapter to switch to the "connected" status -- so // in the mean time, if we're shutting down the adapter, // we want to bail out. // if (!CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITED)) { TR_WARN(( "Failing init because adapter state(0x%x) is not INITED.\n", GET_AD_PRIMARY_STATE(pAdapter) )); TIMESTAMP("===ActivateIF: Failing Init because adapter state is not inited"); Status = NDIS_STATUS_FAILURE; break; } else { ASSERT(sizeof(TASK_ACTIVATE_IF)<=sizeof(ARP1394_TASK)); // // If we're not at passive, we need to switch to // passive before we can call arpIsAdapterConnected(). // if (!ARP_ATPASSIVE()) { // NOTE: we specify completion code PEND_OpenAF // because we want to get back here (except // we'll be at passive). // RmSuspendTask(pTask, PEND_OpenAF, pSR); RmResumeTaskAsync( pTask, NDIS_STATUS_SUCCESS, &((TASK_ACTIVATE_IF*)pTask)->WorkItem, pSR ); Status = NDIS_STATUS_PENDING; break; } if (!arpIsAdapterConnected(pAdapter, pSR)) { // // Let's wait awhile and try again. // TR_INFO(( "Delaying IF init until adapter goes" " to connect state.\n" )); RmSuspendTask(pTask, PEND_OpenAF, pSR); RmResumeTaskDelayed( pTask, NDIS_STATUS_SUCCESS, ARP1394_WAIT_FOR_CONNECT_STATUS_TIMEOUT, &((TASK_ACTIVATE_IF*)pTask)->Timer, pSR ); Status = NDIS_STATUS_PENDING; 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"); } else { // } } 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)) { // Ignore the failure. TR_WARN(("COULDN'T SETUP MULTI-CHANNEL VC (IGNORING FAILURE)!\n")); } // // 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")); Status = NDIS_STATUS_SUCCESS; } 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. // Announce this new interface to IP // TR_INFO(("Interface: 0x%p, Setup recv VC 0x%p\n", pIF, pIF->recvinfo.VcHdr.NdisVcHandle)); if (!ARP_BRIDGE_ENABLED(pAdapter)) { Status = arpCallIpAddInterface( pIF, pSR ); // We don't expect a pending return here. // ASSERT(Status != NDIS_STATUS_PENDING); if (!FAIL(Status)) { LOCKOBJ(pIF, pSR); // Add any static arp intries // arpAddStaticArpEntries(pIF, pSR); UNLOCKOBJ(pIF, pSR); } } 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)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { Status = (NDIS_STATUS) UserParam; LOCKOBJ(pIF, pSR); // // Was this task able to update the Interface' state // if (GET_IF_ACTIVE_STATE(pIF) == ARPIF_AS_ACTIVATING) { // // If so, then set the new state // ASSERT (pIF->pActDeactTask == pTask) if (FAIL(Status)) { // // Failure. Whoever was responsible for starting this task // is also responsible for cleaning up after a failed // activation. // arpClearSecondaryIfTask(pIF, pTask, ARPIF_AS_FAILEDACTIVATE, pSR); } else { // // Success // arpClearSecondaryIfTask(pIF, pTask, ARPIF_AS_ACTIVATED, pSR); } } else { // // Only an early failure should get us here. // Set the flag for informational purposes // ASSERT (FAIL(Status) == TRUE); ASSERT (pIF->pActDeactTask == NULL); ASSERT (!CHECK_AD_PRIMARY_STATE(pAdapter, ARPAD_PS_INITED)); SET_IF_ACTIVE_STATE(pIF, ARPIF_AS_FAILEDACTIVATE); } UNLOCKOBJ(pIF, pSR); } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS arpCallIpAddInterface( IN ARP1394_INTERFACE * pIF, // NOLOCKIN NOLOCKOUT IN PRM_STACK_RECORD pSR ) /*++ Routine Description: Call's IP's AddInterfaceRtn (ArpGlobals.ip.pAddInterfaceRtn), passing it a structure continging pointers to our IP handlers and related information. --*/ { ENTER("CallIpAddInterface", 0xe47fc4d4) struct LLIPBindInfo BindInfo; ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF); NDIS_STATUS Status; NdisZeroMemory(&BindInfo, sizeof(BindInfo)); RM_ASSERT_NOLOCKS(pSR); #if ENABLE_OFFLOAD #error "Unimplemented" // // Query and set NIC offload capabilities. // BindInfo.lip_OffloadFlags = pAdapter->Offload.Flags; BindInfo.lip_MaxOffLoadSize = pAdapter->Offload.MaxOffLoadSize; BindInfo.lip_MaxSegments = pAdapter->Offload.MinSegmentCount; #endif // ENABLE_OFFLOAD BindInfo.lip_context = (PVOID)pIF; BindInfo.lip_transmit = ArpIpMultiTransmit; BindInfo.lip_transfer = ArpIpTransfer; BindInfo.lip_close = ArpIpClose; BindInfo.lip_addaddr = ArpIpAddAddress; BindInfo.lip_deladdr = ArpIpDelAddress; BindInfo.lip_invalidate = ArpIpInvalidate; BindInfo.lip_open = ArpIpOpen; BindInfo.lip_qinfo = ArpIpQueryInfo; BindInfo.lip_setinfo = ArpIpSetInfo; BindInfo.lip_getelist = ArpIpGetEList; BindInfo.lip_arpresolveip = ArpSendARPApi; BindInfo.lip_mss = pIF->ip.MTU; BindInfo.lip_speed = pAdapter->info.Speed; // // Set LIP_COPY_FLAG to avoid having TransferData // called all the time. // BindInfo.lip_flags = LIP_COPY_FLAG; #if MILLEN #if (ARP1394_IP_PHYSADDR_LEN > 7) #error "Win98 doesn't like addrlen to be > 7" #endif #endif // MILLEN BindInfo.lip_addrlen = ARP1394_IP_PHYSADDR_LEN; BindInfo.lip_addr = (PUCHAR) &pAdapter->info.EthernetMacAddress; { ENetAddr *pMacAddr = (ENetAddr *)BindInfo.lip_addr; TR_INFO (("ARP1394 INTERFACE ADDRESS %x %x %x %x %x %x\n", pMacAddr->addr[0],pMacAddr->addr[1],pMacAddr->addr[2],pMacAddr->addr[3],pMacAddr->addr[4],pMacAddr->addr[5])); TR_INFO (("UNIQUE ID Address %I64x \n",pAdapter->info.LocalUniqueID)); } BindInfo.lip_pnpcomplete = ArpIpPnPComplete; Status = ArpGlobals.ip.pAddInterfaceRtn( &pAdapter->bind.DeviceName, NULL, // IfName (unused) -- See 10/14/1998 entry // in atmarpc.sys, notes.txt &pIF->ip.ConfigString, pAdapter->bind.IpConfigHandle, (PVOID)pIF, ArpIpDynRegister, &BindInfo ,0, // RequestedIndex (unused) -- See 10/14/1998 entry // in notes.txt // IF_TYPE_IPOVER_ATM, // TODO: change to 1394 IF_TYPE_IEEE1394, IF_ACCESS_BROADCAST, IF_CONNECTION_DEDICATED ); if (Status == IP_SUCCESS) { Status = NDIS_STATUS_SUCCESS; } else { // // Sometimes IP can fail AddInterface synchronously. At that time, there // may be an Resolve Local IP address Task going on. Keep the AddAddrCmplRtn // function pointer. // IPAddAddrCmpltRtn AddAddrCmplRtn = pIF->ip.AddAddrCmplRtn; ARP_ZEROSTRUCT(&(pIF->ip)); pIF->ip.AddAddrCmplRtn = AddAddrCmplRtn; TR_WARN(("IPAddInterface ret 0x%p\n", Status)); Status = NDIS_STATUS_FAILURE; } RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } ULONG arpIpAddressHash( PVOID pKey ) /*++ Routine Description: Hash function responsible for returning a hash of pKey, which we expect to be an Ip address (literally, not ptr to one). Return Value: ULONG-sized hash of the IP address. --*/ { ULONG u = (ULONG) (ULONG_PTR) pKey; // win64 safe (ip addr is 4 bytes) char *pc = (char *) &u; // // The ip address is in network order, but we would like the 1st byte // to contain the most variable information (to maximize the hashing benefit), // while still keeping most of the information in the hash (so that the quick // compare based on the hash key will be more effective). We could reversse // the byte order of the entire address, but instead we simply xor in the 4th // byte into the 1st byte position (fewer instructions, for whatever that's // worth.) // return u ^ pc[3]; } ULONG arpRemoteDestHash( PVOID pKey ) /*++ Routine Description: Hash function responsible for returning a hash of pKey, which we expect to be an Ip address (literally, not ptr to one). Return Value: ULONG-sized hash of the IP address. --*/ { ULONG u = 0; char *pc = NULL; u = *((PULONG)pKey); // win64 safe (ip addr is 4 bytes) pc = (char *) &u; // // The ip address is in network order, but we would like the 1st byte // to contain the most variable information (to maximize the hashing benefit), // while still keeping most of the information in the hash (so that the quick // compare based on the hash key will be more effective). We could reversse // the byte order of the entire address, but instead we simply xor in the 4th // byte into the 1st byte position (fewer instructions, for whatever that's // worth.) // return u ^ pc[3]; } BOOLEAN arpLocalIpCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_LOCAL_IP. Arguments: pKey - Actually the IP address (not ptr to IP address) in network-byte order. pItem - Points to ARPCB_LOCAL_IP.Hdr.HashLink. Return Value: TRUE IFF the key (IP address) exactly matches the key of the specified LocalIp object. --*/ { ARPCB_LOCAL_IP *pLIP = CONTAINING_RECORD(pItem, ARPCB_LOCAL_IP, Hdr.HashLink); if (pLIP->IpAddress == (ULONG) (ULONG_PTR) pKey) { return TRUE; } else { return FALSE; } } BOOLEAN arpRemoteDestCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_REMOTE_IP. Arguments: pKey - Actually the IP address (not ptr to IP address) in network-byte order. pItem - Points to ARPCB_REMOTE_IP.Hdr.HashLink. Return Value: TRUE IFF the key (IP address) exactly matches the key of the specified RemoteIp object. --*/ { ENTER ("arpRemoteDestCompareKey", 0x62b9d9ae) PREMOTE_DEST_KEY pRemoteDestKey = (PREMOTE_DEST_KEY)pKey; ARPCB_REMOTE_IP *pRIP = CONTAINING_RECORD(pItem, ARPCB_REMOTE_IP, Hdr.HashLink); BOOLEAN fCompare = FALSE; if ((pRIP->Key.u.u32 == pRemoteDestKey->u.u32) && (pRIP->Key.u.u16 == pRemoteDestKey->u.u16)) { fCompare = TRUE; } TR_INFO( ("Comparision %d Key %x %x %x %x %x %x pRemoteIP %x %x %x %x %x %x\n", fCompare, pRemoteDestKey->ENetAddress.addr[0], pRemoteDestKey->ENetAddress.addr[1], pRemoteDestKey->ENetAddress.addr[2], pRemoteDestKey->ENetAddress.addr[3], pRemoteDestKey->ENetAddress.addr[4], pRemoteDestKey->ENetAddress.addr[5], pRIP->Key.ENetAddress.addr[0], pRIP->Key.ENetAddress.addr[1], pRIP->Key.ENetAddress.addr[2], pRIP->Key.ENetAddress.addr[3], pRIP->Key.ENetAddress.addr[4], pRIP->Key.ENetAddress.addr[5])); EXIT(); return fCompare; // success } BOOLEAN arpRemoteIpCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_REMOTE_IP. Arguments: pKey - Actually the IP address pItem - Points to ARPCB_REMOTE_IP.Hdr.HashLink. Return Value: TRUE IFF the key (IP address) exactly matches the key of the specified RemoteIp object. --*/ { ARPCB_REMOTE_IP *pRIP = CONTAINING_RECORD(pItem, ARPCB_REMOTE_IP, Hdr.HashLink); if (pRIP->IpAddress == (ULONG) (ULONG_PTR) pKey) { return TRUE; } else { return FALSE; } } BOOLEAN arpRemoteEthCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_REMOTE_ETH. Arguments: pKey - Actually the IP address (not ptr to IP address) in network-byte order. pItem - Points to ARPCB_REMOTE_ETH.Hdr.HashLink. Return Value: TRUE IFF the key (IP address) exactly matches the key of the specified RemoteEth object. --*/ { ARPCB_REMOTE_ETH *pRE = CONTAINING_RECORD(pItem, ARPCB_REMOTE_ETH, Hdr.HashLink); if (pRE->IpAddress == (ULONG) (ULONG_PTR) pKey) { return TRUE; } else { return FALSE; } } BOOLEAN arpDestinationCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_DEST. Arguments: pKey - Actually a pointer to a ARP_DEST_PARAMS structure. pItem - Points to ARPCB_DEST.Hdr.HashLink. Return Value: TRUE IFF the key (HW address) exactly matches the key of the specified Dest object. --*/ { ARPCB_DEST *pD = CONTAINING_RECORD(pItem, ARPCB_DEST, Hdr.HashLink); PARP_DEST_PARAMS pDestParams = (PARP_DEST_PARAMS) pKey; NIC1394_DESTINATION *pKeyHwAddr = &pDestParams->HwAddr; NIC1394_ADDRESS_TYPE AddressType = pKeyHwAddr->AddressType; if (pD->Params.HwAddr.AddressType == AddressType) { if (AddressType == NIC1394AddressType_FIFO) { if (pKeyHwAddr->FifoAddress.UniqueID == pD->Params.HwAddr.FifoAddress.UniqueID && pKeyHwAddr->FifoAddress.Off_Low == pD->Params.HwAddr.FifoAddress.Off_Low && pKeyHwAddr->FifoAddress.Off_High == pD->Params.HwAddr.FifoAddress.Off_High) { return TRUE; } } else if (AddressType == NIC1394AddressType_Channel) { if (pKeyHwAddr->Channel == pD->Params.HwAddr.Channel) { if (pDestParams->ReceiveOnly == pD->Params.ReceiveOnly) { return TRUE; } } } else if (AddressType == NIC1394AddressType_MultiChannel) { return TRUE; } else if (AddressType == NIC1394AddressType_Ethernet) { return TRUE; } } return FALSE; } ULONG arpDestinationHash( PVOID pKey ) /*++ Routine Description: Hash function responsible for returning a hash of pKey, which we expect to be pointer to a NIC1394_DESTINATION HW address. IMPORTANT: Since that address is a union of channel or Fifo (different sizes), we expect that the structure was first zero'd out (no uninitialized bits). We expect this pointer to be quadword aligned. Arguments: pKey - Actually a pointer to a ARP_DEST_KEY structure. Return Value: ULONG-sized hash of pKey. --*/ { ULONG *pu = (ULONG*) pKey; // We expect both channel and fifo are at the beginning of the structure, // and the structure is atleast 2 dwords. // NOTE: we only look at the HwAddr field of ARP_DEST_PARAMS, so both // send and receive destinations will hash to the same value. Big deal. // ASSERT( FIELD_OFFSET(ARP_DEST_PARAMS, HwAddr) == 0 && FIELD_OFFSET(NIC1394_DESTINATION, FifoAddress) == 0 && FIELD_OFFSET(NIC1394_DESTINATION, Channel) == 0 && sizeof(NIC1394_DESTINATION) >= 2*sizeof(*pu)); // Return 1st DWORD xor 2nd DWORD // return pu[0] ^ pu[1]; } BOOLEAN arpDhcpTableCompareKey( PVOID pKey, PRM_HASH_LINK pItem ) /*++ Routine Description: Hash comparison function for ARPCB_DEST. Arguments: pKey - Actually a pointer to the xid . pItem - Points to ARPCB_DEST.Hdr.HashLink. Return Value: TRUE IFF the key (HW address) exactly matches the key of the specified Dest object. --*/ { ARP1394_ETH_DHCP_ENTRY *pEntry = CONTAINING_RECORD(pItem, ARP1394_ETH_DHCP_ENTRY , Hdr.HashLink); if (pEntry->xid== (*(PULONG)pKey)) { return TRUE; } else { return FALSE; } } ULONG arpDhcpTableHash ( PVOID pKey ) /*++ Routine Description: Arguments: pKey - Actually a pointer to a Xid of a dhcp transaction . Return Value: ULONG-sized hash of pKey. --*/ { ULONG *pu = (ULONG*) pKey; return (*pu); } // arpLocalIp_HashInfo contains information required maintain a hashtable // of ARPCB_LOCAL_IP objects. // RM_HASH_INFO arpLocalIp_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpLocalIpCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpIpAddressHash // pfnHash }; // arpRemoteIp_HashInfo contains information required maintain a hashtable // of ARPCB_REMOTE_IP objects. // RM_HASH_INFO arpRemoteIp_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpRemoteIpCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpIpAddressHash // pfnHash }; // arpRemoteIp_HashInfo contains information required maintain a hashtable // of ARPCB_REMOTE_IP objects. // RM_HASH_INFO arpRemoteEth_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpRemoteEthCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpIpAddressHash // pfnHash }; // arpDestination_HashInfo contains information required maintain a hashtable // of ARPCB_DEST objects. // RM_HASH_INFO arpDestination_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpDestinationCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpDestinationHash // pfnHash }; // arpRemoteDest_HashInfo contains information required maintain a hashtable // of ARPCB_REMOTE_IP objects. // RM_HASH_INFO arpRemoteDest_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpRemoteDestCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpRemoteDestHash // pfnHash }; // arpRemoteDest_HashInfo contains information required maintain a hashtable // of ARPCB_REMOTE_IP objects. // RM_HASH_INFO arpDhcpTable_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator arpDhcpTableCompareKey, // fnCompare // Function to generate a ULONG-sized hash. // arpDhcpTableHash // pfnHash }; // ArpGlobal_LocalIpStaticInfo contains static information about // objects of type ARPCB_LOCAL_IP. // RM_STATIC_OBJECT_INFO ArpGlobal_LocalIpStaticInfo = { 0, // TypeUID 0, // TypeFlags "LocalIp", // TypeName 0, // Timeout arpLocalIpCreate, // pfnCreate arpLocalIpDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpLocalIp_HashInfo }; // ArpGlobal_RemoteIpStaticInfo contains static information about // objects of type ARPCB_REMOTE_IP. // RM_STATIC_OBJECT_INFO ArpGlobal_RemoteIpStaticInfo = { 0, // TypeUID 0, // TypeFlags "RemoteIp", // TypeName 0, // Timeout arpRemoteDestCreate, // pfnCreate arpRemoteIpDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpRemoteDest_HashInfo }; // ArpGlobal_RemoteEthStaticInfo contains static information about // objects of type ARPCB_REMOTE_ETH. // RM_STATIC_OBJECT_INFO ArpGlobal_RemoteEthStaticInfo = { 0, // TypeUID 0, // TypeFlags "RemoteEth", // TypeName 0, // Timeout arpRemoteEthCreate, // pfnCreate arpRemoteEthDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpRemoteEth_HashInfo }; // ArpGlobal_DestinationStaticInfo contains static information about // objects of type ARPCB_DEST. // RM_STATIC_OBJECT_INFO ArpGlobal_DestinationStaticInfo = { 0, // TypeUID 0, // TypeFlags "Destination", // TypeName 0, // Timeout arpDestinationCreate, // pfnCreate arpDestinationDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpDestination_HashInfo }; RM_STATIC_OBJECT_INFO ArpGlobal_RemoteDestStaticInfo = { 0, // TypeUID 0, // TypeFlags "RemoteIp", // TypeName 0, // Timeout arpRemoteDestCreate, // pfnCreate arpRemoteDestDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpRemoteDest_HashInfo }; RM_STATIC_OBJECT_INFO ArpGlobal_DhcpTableStaticInfo = { 0, // TypeUID 0, // TypeFlags "DhcpTableEntry", // TypeName 0, // Timeout arpDhcpTableEntryCreate, // pfnCreate arpDhcpTableEntryDelete, // pfnDelete NULL, // pfnVerifyLock 0, // Size of resource table NULL, // ResourceTable &arpDhcpTable_HashInfo }; NDIS_STATUS arpTaskDeactivateInterface( 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 deactivating an IP interface (but leaving it allocated and linked to the adapter). Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status; PARP1394_INTERFACE pIF; PTASK_DEACTIVATE_IF pShutdownTask; UINT Stage; PARP1394_ADAPTER pAdapter; enum { STAGE_Start, STAGE_StopMaintenanceTask, STAGE_CleanupVcComplete, STAGE_CloseLocalIpGroup, STAGE_CloseRemoteIpGroup, STAGE_CloseRemoteEthGroup, STAGE_CloseRemoteDhcpGroup, STAGE_CloseDestinationGroup, STAGE_SwitchedToPassive, STAGE_CloseAF, STAGE_CloseIp, STAGE_End }; ENTER("TaskDeactivateInterface", 0x1a34699e) Status = NDIS_STATUS_FAILURE; pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pTask); pShutdownTask = (PTASK_DEACTIVATE_IF) pTask; pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF); // // 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. Why? Because an activate/deactivate task is ONLY // started in the context of the active primary task, and there can be // ONLY one active primary task on this IF at any one time. // TIMESTAMP("===DeinitIF:Starting"); LOCKOBJ(pIF, pSR); if (pIF->pActDeactTask != NULL) { ASSERT(!"pIF->pActDeactTask != NULL"); UNLOCKOBJ(pIF, pSR); Status = NDIS_STATUS_FAILURE; break; } arpSetSecondaryIfTask(pIF, pTask, ARPIF_AS_DEACTIVATING, pSR); UNLOCKOBJ(pIF, pSR); // // 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("===DeinitIF: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 shutdown IF", // 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("===DeinitIF:RecvFifo cleanup complete"); // Initiate unload of all the items in the LocalIpGroup. // OBJLOG1(pTask, " Unloading LocalIpGroup 0x%p\n", &pIF->LocalIpGroup); RmUnloadAllObjectsInGroup( &pIF->LocalIpGroup, arpAllocateTask, arpTaskUnloadLocalIp, NULL, // userParam pTask, // pTask to unpend when the unload completes. STAGE_CloseLocalIpGroup, // uTaskPendCode pSR ); Status = NDIS_STATUS_PENDING; } break; case STAGE_CloseLocalIpGroup: { // Initiate unload of all the items in the RemoteIpGroup. // TIMESTAMP("===DeinitIF:LocalIp objects cleaned up."); OBJLOG1( pTask, " Unloading RemoteIpGroup 0x%p\n", &pIF->RemoteIpGroup ); RmUnloadAllObjectsInGroup( &pIF->RemoteIpGroup, arpAllocateTask, arpTaskUnloadRemoteIp, NULL, // userParam pTask, // pTask to unpend when the unload is complete. STAGE_CloseRemoteIpGroup, // uTaskPendCode pSR ); Status = NDIS_STATUS_PENDING; } break; case STAGE_CloseRemoteIpGroup: { if (ARP_BRIDGE_ENABLED(pAdapter)) { // Initiate unload of all the items in the RemoteEthGroup. // TIMESTAMP("===DeinitIF:RemoteIp objects cleaned up."); OBJLOG1( pTask, " Unloading RemoteEthGroup 0x%p\n", &pIF->RemoteEthGroup ); RmUnloadAllObjectsInGroup( &pIF->RemoteEthGroup, arpAllocateTask, arpTaskUnloadRemoteEth, NULL, // userParam pTask, // pTask to unpend when the unload is complete. STAGE_CloseRemoteEthGroup, // uTaskPendCode pSR ); Status = NDIS_STATUS_PENDING; break; } else { // Bridging not enabled ... // FALL THROUGH.... } } case STAGE_CloseRemoteEthGroup: { // Initiate unload of all the items in the DestinationGroup. // if (ARP_BRIDGE_ENABLED(pAdapter)) { TIMESTAMP("===DeinitIF:RemoteEth Dhcp objects cleaned up."); OBJLOG1(pTask, " Unloading EthDhcpGroup 0x%p\n", &pIF->EthDhcpGroup); RmUnloadAllObjectsInGroup( &pIF->EthDhcpGroup, arpAllocateTask, arpTaskUnloadEthDhcpEntry, NULL, // userParam pTask, // pTask to unpend when the unload is complete. STAGE_CloseRemoteDhcpGroup, // uTaskPendCode pSR ); Status = NDIS_STATUS_PENDING; break; } else { // Bridging not enabled ... // FALL THROUGH.... } } case STAGE_CloseRemoteDhcpGroup: { // Initiate unload of all the items in the DestinationGroup. // TIMESTAMP("===DeinitIF:RemoteIp objects cleaned up."); OBJLOG1(pTask, " Unloading DestinationGroup 0x%p\n", &pIF->DestinationGroup); RmUnloadAllObjectsInGroup( &pIF->DestinationGroup, arpAllocateTask, arpTaskUnloadDestination, NULL, // userParam pTask, // pTask to unpend when the unload is complete. STAGE_CloseDestinationGroup, // uTaskPendCode pSR ); Status = NDIS_STATUS_PENDING; } break; case STAGE_CloseDestinationGroup: { // // Unlink the special "destination VCs" // LOCKOBJ(pIF, pSR); TIMESTAMP("===DeinitIF: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 when we // call IP's del interface. So we switch to passive... // RmSuspendTask(pTask, STAGE_SwitchedToPassive, pSR); RmResumeTaskAsync(pTask, 0, &pShutdownTask->WorkItem, pSR); Status = NDIS_STATUS_PENDING; } else { Status = NDIS_STATUS_SUCCESS; } } if (PEND(Status)) break; // FALL THROUGH case STAGE_SwitchedToPassive: { PVOID IpContext; TIMESTAMP("===DeinitIF:Switched to Passive(if we aren't already)."); // We're now switched to passive // ASSERT(ARP_ATPASSIVE()); // If required, del the IP interface. // LOCKOBJ(pIF, pSR); IpContext = pIF->ip.Context; if (IpContext == NULL) { // Pretend that we're waiting on IpClose because // we fall through below. // pShutdownTask->fPendingOnIpClose = TRUE; UNLOCKOBJ(pIF, pSR); Status = NDIS_STATUS_SUCCESS; } else { ASSERT(!ARP_BRIDGE_ENABLED(pAdapter)); pIF->ip.Context = NULL; ASSERT(!pShutdownTask->fPendingOnIpClose); // Note: a task's lock is it's parent's lock, and this task's // parent is pIF... // pShutdownTask->fPendingOnIpClose = TRUE; UNLOCKOBJ(pIF, pSR); // We'll suspend this task, waiting for our ArpIpClose routine to // be called... // RmSuspendTask(pTask, STAGE_CloseIp, pSR); TIMESTAMP("===DeinitIF:Calling IP's DellInterface Rtn"); ArpGlobals.ip.pDelInterfaceRtn( IpContext ,TRUE // DeleteIndex (unused) ); Status = NDIS_STATUS_PENDING; } } if (PEND(Status)) break; // FALL THROUGH case STAGE_CloseIp: { NDIS_HANDLE NdisAfHandle; TIMESTAMP("===DeinitIF:Done with deleting IP interface (if there was one)"); // // IP has called our arpIpClose function (if we'd bound to IP) // NOTE: Task's locks actually are their parent's locks, // which in this case is pIF; // // We're done with all VCs, etc. Time to close the AF, if it's open. // LOCKOBJ(pTask, pSR); ASSERT(pShutdownTask->fPendingOnIpClose); pShutdownTask->fPendingOnIpClose = FALSE; NdisAfHandle = pIF->ndis.AfHandle; pIF->ndis.AfHandle = NULL; 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... // 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("===DeinitIF: 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_PENDING); // // By returning Status != pending, we implicitly complete // this task. // } break; case STAGE_End: { // // We are done with all async aspects of shutting down the interface. // Nothing to do besides clearing the actdeact task. // LOCKOBJ(pIF, pSR); arpClearSecondaryIfTask(pIF, pTask, ARPIF_AS_FAILEDACTIVATE, pSR); UNLOCKOBJ(pIF, pSR); TIMESTAMP("===DeinitIF: All done!"); // Force status to be success // Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown task op", pTask); } break; } // switch (Stage) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS arpTaskDeinitInterface( 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 deinitializing and deleting an interface. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status; PARP1394_INTERFACE pIF; MYBOOL fTryInitiateUnload; enum { PEND_ExistingPrimaryTaskComplete, PEND_DeactivateIfComplete }; ENTER("TaskDeinitInterface", 0xf059b63b) Status = NDIS_STATUS_FAILURE; pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pTask); fTryInitiateUnload = FALSE; switch(Code) { case RM_TASKOP_START: { fTryInitiateUnload = TRUE; } break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_ExistingPrimaryTaskComplete: { fTryInitiateUnload = TRUE; } break; case PEND_DeactivateIfComplete: { ASSERT(pIF->pPrimaryTask == pTask); // We're done deactivating the IF. We actually delete the IF // in the context of the END handler... // Status = NDIS_STATUS_SUCCESS; } break; } } break; case RM_TASKOP_END: { // // We are done with all async aspects of unloading the interface. // Now on to synchronous cleanup and deallocation... // ARP1394_ADAPTER * pAdapter; // Nothing to do if we're not the active primary task. // if (pIF->pPrimaryTask != pTask) { // We should only get here if pIF was unloaded by someone else.... // ASSERT(RM_IS_ZOMBIE(pIF)); Status = NDIS_STATUS_SUCCESS; break; } pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF); LOCKOBJ(pAdapter, pSR); // Remove linkage to adapter. Note: pIF lock is the adapter lock. // pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF); ASSERT(pIF->Hdr.pLock == pAdapter->Hdr.pLock); ASSERT(pAdapter->pIF == pIF); pAdapter->pIF = NULL; // Clear ourselves as the primary task of the interface object. // arpClearPrimaryIfTask(pIF, pTask, ARPIF_PS_DEINITED, pSR); // Deallocate the IF (adapter lock must be held when calling this) // arpDeleteInterface(pIF, pSR); UNLOCKOBJ(pAdapter, pSR); // Force status to be success // Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown task op", pTask); } break; } // switch (Code) if (fTryInitiateUnload) { LOCKOBJ(pIF, pSR); if (pIF->pPrimaryTask!=NULL) { // // There is an existing primary task -- we wait for it to complete. // PRM_TASK pPrimaryTask = pIF->pPrimaryTask; RmTmpReferenceObject(&pPrimaryTask->Hdr, pSR); UNLOCKOBJ(pIF,pSR); RmPendTaskOnOtherTask( pTask, PEND_ExistingPrimaryTaskComplete, pPrimaryTask, pSR ); arpTryAbortPrimaryIfTask(pIF, pSR); RmTmpDereferenceObject(&pPrimaryTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; } else if (!RM_IS_ZOMBIE(pIF)) { // // There is no primary task currently, and the IF is not already // been unloaded -- make pTask the primary task, // and initiate deactivation of the IF. When it's done, we'll actually // delete the IF. // arpSetPrimaryIfTask(pIF, pTask, ARPIF_PS_DEINITING, pSR); UNLOCKOBJ(pIF,pSR); arpDeactivateIf(pIF, pTask, PEND_DeactivateIfComplete, pSR); Status = NDIS_STATUS_PENDING; } else { // pIF is already unloaded.... // UNLOCKOBJ(pIF, pSR); Status = NDIS_STATUS_SUCCESS; } } RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS arpTaskReinitInterface( 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 reiniting (deactivating, then activating) an interface. This is a primary interface task. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status; PARP1394_INTERFACE pIF; MYBOOL fTryInitiateReinit; enum { PEND_ExistingPrimaryTaskComplete, PEND_DeactivateIfComplete, PEND_ActivateIfComplete, PEND_DeinitInterfaceOnFailureComplete }; ENTER("TaskReinitInterface", 0x8b670f05) Status = NDIS_STATUS_FAILURE; pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pTask); fTryInitiateReinit = FALSE; switch(Code) { case RM_TASKOP_START: { fTryInitiateReinit = TRUE; } break; case RM_TASKOP_PENDCOMPLETE: { Status = (NDIS_STATUS) UserParam; switch(RM_PEND_CODE(pTask)) { case PEND_ExistingPrimaryTaskComplete: { fTryInitiateReinit = TRUE; } break; case PEND_DeactivateIfComplete: { // // We're done deactivating the IF. We now // activate the IF. // arpActivateIf(pIF, pTask, PEND_ActivateIfComplete, pSR); Status = NDIS_STATUS_PENDING; } break; case PEND_ActivateIfComplete: { // We're done activating the IF. // LOCKOBJ(pIF, pSR); if (FAIL(Status)) { arpClearPrimaryIfTask(pIF, pTask, ARPIF_PS_FAILEDINIT, pSR); UNLOCKOBJ(pIF, pSR); arpDeinitIf( pIF, pTask, // pCallingTask PEND_DeinitInterfaceOnFailureComplete, pSR ); Status = NDIS_STATUS_PENDING; } else { // // Successful activation. Clear the primary task // and set the primary state appropriately. // arpClearPrimaryIfTask(pIF, pTask, ARPIF_PS_INITED, pSR); UNLOCKOBJ(pIF, pSR); } } // end case PEND_ActivateIfComplete break; case PEND_DeinitInterfaceOnFailureComplete: { // We expect pIF to be deallocated... // ASSERT(RM_IS_ZOMBIE(pIF)); // // We ignore the return status of deinit inteface. // and set Status to failure, because it is // the reinit interface task that is failing. // Status = NDIS_STATUS_FAILURE; } break; } } break; case RM_TASKOP_END: { PARP1394_ADAPTER pAdapter; PTASK_REINIT_IF pReinitTask; pAdapter = (PARP1394_ADAPTER) RM_PARENT_OBJECT(pIF); pReinitTask = (PTASK_REINIT_IF) pTask; Status = (NDIS_STATUS) UserParam; if (FAIL(Status)) { ASSERT(RM_IS_ZOMBIE(pIF)); } ASSERT(pIF->pPrimaryTask != pTask); // // IF the reconfig event is non NULL, signal completion of the net pnp // event that started this // reconfig task. No need to claim any locks here -- the fields // referenced below are not going to change... // if (pReinitTask->pNetPnPEvent != NULL) { NdisCompletePnPEvent( Status, pAdapter->bind.AdapterHandle, pReinitTask->pNetPnPEvent ); } } break; default: { ASSERTEX(!"Unknown task op", pTask); } break; } // switch (Code) if (fTryInitiateReinit) { LOCKOBJ(pIF, pSR); if (pIF->pPrimaryTask!=NULL) { // // There is an existing primary task -- we wait for it to complete. // PRM_TASK pPrimaryTask = pIF->pPrimaryTask; RmTmpReferenceObject(&pIF->pPrimaryTask->Hdr, pSR); UNLOCKOBJ(pIF,pSR); RmPendTaskOnOtherTask( pTask, PEND_ExistingPrimaryTaskComplete, pPrimaryTask, pSR ); RmTmpDereferenceObject(&pIF->pPrimaryTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; } else { // // There is no primary task currently -- make pTask the primary task, // and initiate deactivation of the IF. When it's done, we'll // reactivate the IF. // arpSetPrimaryIfTask(pIF, pTask, ARPIF_PS_REINITING, pSR); UNLOCKOBJ(pIF,pSR); arpDeactivateIf(pIF, pTask, PEND_DeactivateIfComplete, pSR); Status = NDIS_STATUS_PENDING; } } RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS arpTaskUnloadLocalIp( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) /*++ Routine Description: Task handler responsible for shutting down an IP interface. 3/26/1999 JosephJ TODO -- this being one of the earlier-written tasks, is ripe for a re-write! Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskUnloadLocalIp", 0xf42aaa68) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_LOCAL_IP* pLocalIp = (ARPCB_LOCAL_IP*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pLocalIp); // Following are the list of pending states for this task. // enum { PEND_OtherUnloadComplete, PEND_AddressRegistrationComplete }; switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pLocalIp, pSR); // First check if pLocalIp is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pLocalIp)) { Status = NDIS_STATUS_SUCCESS; break; } // // pLocalIp is allocated. Now check if there is already a // shutdown task attached to pLocalIp. // if (pLocalIp->pUnloadTask != NULL) { // // There is a shutdown task. We pend on it. // PRM_TASK pOtherTask = pLocalIp->pUnloadTask; TR_WARN(("Unload task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pLocalIp, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherUnloadComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no unload task going on. Let's // make this task THE unload task. // pLocalIp->pUnloadTask = pTask; // // Since we're THE unload task, add an association to pLocalIp, // which will only get cleared when the pLocalIp->pUnloadTask field // above is cleared. // DBG_ADDASSOC( &pLocalIp->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_LOCALIP_UNLOAD_TASK, // AssociationID " Official unload task 0x%p (%s)\n", // szFormat pSR ); // // If there is a registration task going, we cancel it and // wait for it to complete. // if (pLocalIp->pRegistrationTask != NULL) { PRM_TASK pOtherTask = pLocalIp->pRegistrationTask; TR_WARN(("Registration task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pLocalIp, pSR); RmPendTaskOnOtherTask( pTask, PEND_AddressRegistrationComplete, pOtherTask, pSR ); // // TODO Cancel Registration task (we haven't implemented cancel // yet!) // RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; 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_OtherUnloadComplete: { // // There was another unload task going when we started, and // it's now complete. Nothing for us to do... // // TODO need standard way to propagate the error code. // Status = (NDIS_STATUS) UserParam; } break; case PEND_AddressRegistrationComplete: { // // There was address-registration going on, but how it's // complete. We should be able to synchronously clean up // this task now // // // If we're here, that means we're THE official unload // task. Let's assert that fact. // (no need to get the lock on the object). // ASSERTEX(pLocalIp->pUnloadTask == pTask, pLocalIp); Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pLocalIp, pSR); // // We're done. There should be no async activities left to do. // ASSERTEX(pLocalIp->pRegistrationTask == NULL, pLocalIp); // // If we're THE unload task, we go on and deallocate the object. // if (pLocalIp->pUnloadTask == pTask) { PARPCB_DEST pDest = pLocalIp->pDest; // // pLocalIp had better not be in a zombie state -- THIS task // is the one responsible for deallocating the object! // ASSERTEX(!RM_IS_ZOMBIE(pLocalIp), pLocalIp); if (pDest != NULL) { RmTmpReferenceObject(&pDest->Hdr, pSR); arpUnlinkLocalIpFromDest(pLocalIp, pSR); } pLocalIp->pUnloadTask = NULL; // Delete the association we added when we set // pLocalIp->pUnloadTask to pTask. // DBG_DELASSOC( &pLocalIp->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_LOCALIP_UNLOAD_TASK, // AssociationID pSR ); RmFreeObjectInGroup( &pIF->LocalIpGroup, &(pLocalIp->Hdr), NULL, // NULL pTask == synchronous. pSR ); ASSERTEX(RM_IS_ZOMBIE(pLocalIp), pLocalIp); UNLOCKOBJ(pLocalIp, pSR); // // If we were linked to a pDest, we unload it if it's // no longer used by anyone else. // if (pDest != NULL) { arpDeinitDestination(pDest, TRUE, pSR); // TRUE==only if // unused. RmTmpDereferenceObject(&pDest->Hdr, pSR); } } else { // // We weren't THE unload task, nothing left to do. // The object had better be in the zombie state.. // ASSERTEX( pLocalIp->pUnloadTask == NULL && RM_IS_ZOMBIE(pLocalIp), pLocalIp ); Status = NDIS_STATUS_SUCCESS; } Status = (NDIS_STATUS) UserParam; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } NDIS_STATUS arpTaskUnloadRemoteIp( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) /*++ This task is responsible for shuttingdown and eventually deleting a remote IP object. It goes through the following stages: - Cancel any ongoing address resolution and wait for that to complete. - Unlink itself from a Destination object, if it's linked to one. - Remove itself from the interface's LocalIpGroup (and thereby deallocate itself). UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskUnloadRemoteIp", 0xf42aaa68) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_REMOTE_IP* pRemoteIp = (ARPCB_REMOTE_IP*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pRemoteIp); // Following are the list of pending states for this task. // enum { PEND_AtPassiveLevel, PEND_OtherUnloadComplete, PEND_SendPktsComplete, PEND_ResolutionComplete }; switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pRemoteIp, pSR); // First check if pRemoteIp is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pRemoteIp)) { Status = NDIS_STATUS_SUCCESS; break; } // // pRemoteIp is allocated. Now check if there is already a // shutdown task attached to pRemoteIp. // if (pRemoteIp->pUnloadTask != NULL) { // // There is a shutdown task. We pend on it. // PRM_TASK pOtherTask = pRemoteIp->pUnloadTask; TR_WARN(("Unload task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pRemoteIp, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherUnloadComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no unload task going on. Let's // make this task THE unload task. // pRemoteIp->pUnloadTask = pTask; // // Since we're THE unload task, add an association to pRemoteIp, // which will only get cleared when the pRemoteIp->pUnloadTask field // above is cleared. // DBG_ADDASSOC( &pRemoteIp->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_REMOTEIP_UNLOAD_TASK, // AssociationID " Official unload task 0x%p (%s)\n", // szFormat pSR ); // // if we are at dpc level then resume at passive // RmSuspendTask(pTask, PEND_AtPassiveLevel, pSR); UNLOCKOBJ(pRemoteIp,pSR); Status = NDIS_STATUS_PENDING; if (!ARP_ATPASSIVE()) { // We're not at passive level, . So we switch to passive... // RmResumeTaskAsync( pTask, Status, &((TASK_UNLOAD_REMOTE*)pTask)->WorkItem, pSR ); } else { // We resume right away if we are already at passive RmResumeTask(pTask,PEND_AtPassiveLevel,pSR); } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_AtPassiveLevel: { LOCKOBJ (pRemoteIp, pSR); // // If there is a SendPkts task going, we cancel it and // wait for it to complete. // WARNING: We only do this check and wait ONCE. So we RELY // on the fact that once there is a NONNULL pRemoteIp->pUnloadTask, // NO NEW pSendPktsTasks will bind itself to pRemoteIP. If you // look at the code for arpTaskSendPktsOnRemoteIp, you will // see that it does not bind itself if pRemoteIp->pUnloadTask is nonnull // if (pRemoteIp->pSendPktsTask != NULL) { PRM_TASK pOtherTask = pRemoteIp->pSendPktsTask; TR_WARN(("SendPkts task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pRemoteIp, pSR); RmPendTaskOnOtherTask( pTask, PEND_SendPktsComplete, pOtherTask, pSR ); // // TODO Cancel SendPks task (we haven't implemented cancel // yet!) // RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; 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. // if (pRemoteIp->pResolutionTask != NULL) { PRM_TASK pOtherTask = pRemoteIp->pResolutionTask ; TR_WARN(("Resolution task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pRemoteIp, pSR); RmPendTaskOnOtherTask( pTask, PEND_ResolutionComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // If there were no tasks pending then we have completed our task. // Status = NDIS_STATUS_SUCCESS; } break; case PEND_OtherUnloadComplete: { // // There was another unload task going when we started, and // it's now complete. Nothing for us to do... // // TODO need standard way to propagate the error code. // Status = (NDIS_STATUS) UserParam; } break; case PEND_SendPktsComplete: { // // There was a SendPktsTask going on, but how it's // complete. We should be able to synchronously clean up // this task now // // // If we're here, that means we're THE official unload // task. Let's assert that fact. // (no need to get the lock on the object). // ASSERT(pRemoteIp->pUnloadTask == pTask); Status = NDIS_STATUS_SUCCESS; } break; case PEND_ResolutionComplete: { // // There was a resolution Task going on, but how it's // complete. We should be able to synchronously clean up // this task now // // // If we're here, that means we're THE official unload // task. Let's assert that fact. // (no need to get the lock on the object). // ASSERT(pRemoteIp->pUnloadTask == pTask); Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pRemoteIp, pSR); // // We're done. There should be no async activities left to do. // ASSERTEX(pRemoteIp->pResolutionTask == NULL, pRemoteIp); ASSERTEX(pRemoteIp->pSendPktsTask == NULL, pRemoteIp); // // If we're THE unload task, we go on and deallocate the object. // if (pRemoteIp->pUnloadTask == pTask) { PARPCB_DEST pDest = pRemoteIp->pDest; // // pRemoteIp had better not be in a zombie state -- THIS task // is the one responsible for deallocating the object! // ASSERTEX(!RM_IS_ZOMBIE(pRemoteIp), pRemoteIp); if (pDest != NULL) { RmTmpReferenceObject(&pDest->Hdr, pSR); arpUnlinkRemoteIpFromDest(pRemoteIp, pSR); } pRemoteIp->pUnloadTask = NULL; // Del the association between pRCE and pRemoteIp... // ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); arpDelRceList(pRemoteIp, pSR); ARP_UNLOCK_IF_SEND_LOCK(pIF, pSR); RmFreeObjectInGroup( &pIF->RemoteIpGroup, &(pRemoteIp->Hdr), NULL, // NULL pTask == synchronous. pSR ); ASSERTEX(RM_IS_ZOMBIE(pRemoteIp), pRemoteIp); // Delete the association we added when we set // pRemoteIp->pUnloadTask to pTask. // DBG_DELASSOC( &pRemoteIp->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_REMOTEIP_UNLOAD_TASK, // AssociationID pSR ); UNLOCKOBJ(pRemoteIp, pSR); // // If we were linked to a pDest, we unload it if it's // no longer used by anyone else. // if (pDest != NULL) { arpDeinitDestination(pDest, TRUE, pSR); // TRUE==only if // unused. RmTmpDereferenceObject(&pDest->Hdr, pSR); } } else { // // We weren't THE unload task, nothing left to do. // The object had better be in the zombie state.. // ASSERTEX( pRemoteIp->pUnloadTask == NULL && RM_IS_ZOMBIE(pRemoteIp), pRemoteIp ); Status = NDIS_STATUS_SUCCESS; } Status = (NDIS_STATUS) UserParam; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } NDIS_STATUS arpTaskUnloadRemoteEth( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) /*++ This task is responsible for shuttingdown and eventually deleting a remote IP object. It goes through the following stages: - Cancel any ongoing address resolution and wait for that to complete. - Unlink itself from a Destination object, if it's linked to one. - Remove itself from the interface's LocalIpGroup (and thereby deallocate itself). UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskUnloadRemoteEth", 0xf42aaa68) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_REMOTE_ETH* pRemoteEth = (ARPCB_REMOTE_ETH*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pRemoteEth); // Following are the list of pending states for this task. // enum { PEND_AtPassiveLevel, PEND_OtherUnloadComplete }; switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pRemoteEth, pSR); // First check if pRemoteEth is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pRemoteEth)) { Status = NDIS_STATUS_SUCCESS; break; } // // pRemoteEth is allocated. Now check if there is already a // shutdown task attached to pRemoteEth. // if (pRemoteEth->pUnloadTask != NULL) { // // There is a shutdown task. We pend on it. // PRM_TASK pOtherTask = pRemoteEth->pUnloadTask; TR_WARN(("Unload task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pRemoteEth, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherUnloadComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no unload task going on. Let's // make this task THE unload task. // pRemoteEth->pUnloadTask = pTask; // // Since we're THE unload task, add an association to pRemoteEth, // which will only get cleared when the pRemoteEth->pUnloadTask field // above is cleared. // DBG_ADDASSOC( &pRemoteEth->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_REMOTEETH_UNLOAD_TASK, // AssociationID " Official unload task 0x%p (%s)\n", // szFormat pSR ); // // We're here because there is no async unload work to be done. // // if we are at dpc level then resume at passive // RmSuspendTask(pTask, PEND_AtPassiveLevel, pSR); UNLOCKOBJ(pRemoteEth,pSR); Status = NDIS_STATUS_PENDING; if (!ARP_ATPASSIVE()) { // We're not at passive level, . So we switch to passive... // RmResumeTaskAsync( pTask, Status, &((TASK_UNLOAD_REMOTE*)pTask)->WorkItem, pSR ); } else { // We resume right away if we are already at passive RmResumeTask(pTask,PEND_AtPassiveLevel,pSR); } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_AtPassiveLevel: { // Status = NDIS_STATUS_SUCCESS; } break; case PEND_OtherUnloadComplete: { // // There was another unload task going when we started, and // it's now complete. Nothing for us to do... // // TODO need standard way to propagate the error code. // Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pRemoteEth, pSR); // // We're done. There should be no async activities left to do. // // // If we're THE unload task, we go on and deallocate the object. // if (pRemoteEth->pUnloadTask == pTask) { // // pRemoteEth had better not be in a zombie state -- THIS task // is the one responsible for deallocating the object! // ASSERTEX(!RM_IS_ZOMBIE(pRemoteEth), pRemoteEth); pRemoteEth->pUnloadTask = NULL; RmFreeObjectInGroup( &pIF->RemoteEthGroup, &(pRemoteEth->Hdr), NULL, // NULL pTask == synchronous. pSR ); ASSERTEX(RM_IS_ZOMBIE(pRemoteEth), pRemoteEth); // Delete the association we added when we set // pRemoteEth->pUnloadTask to pTask. // DBG_DELASSOC( &pRemoteEth->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_REMOTEETH_UNLOAD_TASK, // AssociationID pSR ); UNLOCKOBJ(pRemoteEth, pSR); } else { // // We weren't THE unload task, nothing left to do. // The object had better be in the zombie state.. // ASSERTEX( pRemoteEth->pUnloadTask == NULL && RM_IS_ZOMBIE(pRemoteEth), pRemoteEth ); Status = NDIS_STATUS_SUCCESS; } Status = (NDIS_STATUS) UserParam; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } NDIS_STATUS arpTaskUnloadDestination( 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 unloading a destination. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskUnloadDestination", 0x93f66831) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_DEST* pDest = (ARPCB_DEST*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); // Following are the list of pending states for this task. // enum { PEND_OtherUnloadComplete, PEND_CleanupVcComplete }; switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pDest, pSR); // First check if pDest is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pDest)) { Status = NDIS_STATUS_SUCCESS; break; } // // pDest is allocated. Now check if there is already a // shutdown task attached to pDest. // if (pDest->pUnloadTask != NULL) { // // There is a shutdown task. We pend on it. // PRM_TASK pOtherTask = pDest->pUnloadTask; TR_WARN(("Unload task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pDest, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherUnloadComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no unload task going on. Let's // make this task THE unload task. // pDest->pUnloadTask = pTask; // // Since we're THE unload task, add an association to pDest, // which will only get cleared when the pDest->pUnloadTask field // above is cleared. // DBG_ADDASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_UNLOAD_TASK, // AssociationID " Official unload task 0x%p (%s)\n", // szFormat pSR ); // // If the VC state needs cleaning up, we need to get a task // going to clean it up. // 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_OtherUnloadComplete: { // // There was another unload task going when we started, and // it's now complete. Nothing for us to do... // // TODO need standard way to propagate the error code. // Status = (NDIS_STATUS) UserParam; } break; 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); // // If we're here, that means we're THE official unload // task. Let's assert that fact. // ASSERT(pDest->pUnloadTask == pTask); UNLOCKOBJ(pDest, pSR); #endif DBG Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pDest, pSR); // // We're done. There should be no async activities left to do. // ASSERTEX(!arpNeedToCleanupDestVc(pDest), pDest); // // If we're THE unload task, we go on and deallocate the object. // if (pDest->pUnloadTask == pTask) { // // pDest had better not be in a zombie state -- THIS task // is the one responsible for deallocating the object! // ASSERTEX(!RM_IS_ZOMBIE(pDest), pDest); arpUnlinkAllRemoteIpsFromDest(pDest, pSR); RmFreeObjectInGroup( &pIF->DestinationGroup, &(pDest->Hdr), NULL, // NULL pTask == synchronous. pSR ); ASSERTEX(RM_IS_ZOMBIE(pDest), pDest); pDest->pUnloadTask = NULL; // Delete the association we added when we set // pDest->pUnloadTask to pTask. // DBG_DELASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_UNLOAD_TASK, // AssociationID pSR ); } else { // // We weren't THE unload task, nothing left to do. // The object had better be in the zombie state.. // ASSERTEX( pDest->pUnloadTask == NULL && RM_IS_ZOMBIE(pDest), pDest ); Status = NDIS_STATUS_SUCCESS; } Status = (NDIS_STATUS) UserParam; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } // The following structure is to define a set of hard-coded arp entries... // typedef struct { IP_ADDRESS IpAddress; NIC1394_FIFO_ADDRESS DestFifoAddr; } UNICAST_REMOTE_IP_INFO; // FakeDestinationsInfo contains information to setup a set of hard-coded // arp entries.. // UNICAST_REMOTE_IP_INFO FakeDestinationsInfo[] = { // //{IpAddr, {UniqueID, OffLow, OffHi}} // #if 0 {0x0100000a, {0, 0, 0x100}}, // 10.0.0.1 -> (0, 0, 0x100) {0x0200000a, {0, 0, 0x100}}, // 10.0.0.2 {0x0300000a, {0, 0, 0x100}}, // 10.0.0.3 {0x0400000a, {0, 0, 0x100}}, // 10.0.0.4 {0x020000e0, {0, 0, 0x100}}, // 224.0.0.2 (mcast port) {0xff00000a, {0, 0, 0x100}}, // 10.0.0.-1 (local bcast) {0xffffffff, {0, 0, 0x100}}, // -1.-1.-1.-1 (bcast) #endif //0 {0, {0, 0, 0}}, // Must be last -- Indicates end. }; VOID arpAddStaticArpEntries( IN ARP1394_INTERFACE *pIF, // LOCKING LOCKOUT IN PRM_STACK_RECORD pSR ) /*++ Routine Description: Add static items into the RemoteIp group (the arp cache). TODO: we currently put in some fake entries. --*/ { UNICAST_REMOTE_IP_INFO *pRemoteIpInfo; RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR); for( pRemoteIpInfo = FakeDestinationsInfo; pRemoteIpInfo->IpAddress != 0; pRemoteIpInfo++) { NDIS_STATUS Status; Status = arpAddOneStaticArpEntry( pIF, pRemoteIpInfo->IpAddress, &pRemoteIpInfo->DestFifoAddr, pSR ); if (FAIL(Status)) { break; } } } VOID arpLinkRemoteIpToDest( ARPCB_REMOTE_IP *pRemoteIp, // LOCKIN LOCKOUT ARPCB_DEST *pDest, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Link a remote IP entry (pRemoteIp) to the specified destination HW entry (pDest). Update the pRemoteIp's state to indicate that this is resolved. --*/ { ENTER("arpLinkRemoteIpToDest", 0x3be06bc6) ARP_DUMP_MAPPING( pRemoteIp->IpAddress, (pDest==NULL)? NULL : &pDest->Params.HwAddr, "Linking Remote IP"); TR_INFO(("Linking IP 0x%08lx to Dest addr 0x%08lx\n", pRemoteIp->IpAddress, (UINT) pDest->Params.HwAddr.FifoAddress.UniqueID // Truncation )); RM_DBG_ASSERT_LOCKED(&pRemoteIp->Hdr, pSR); RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR); if (pRemoteIp->pDest != NULL) { ASSERT(!"pRemoteIp->pDest != NULL"); } else { pRemoteIp->pDest = pDest; InsertHeadList(&pDest->listIpToThisDest, &pRemoteIp->linkSameDest); #if RM_EXTRA_CHECKING RmLinkObjectsEx( &pRemoteIp->Hdr, &pDest->Hdr, 0x597d0495, ARPASSOC_LINK_IPADDR_OF_DEST, " REMOTE_IP of 0x%p (%s)\n", ARPASSOC_LINK_DEST_OF_IPADDR, " DEST of 0x%p (%s)\n", pSR ); #else // !RM_EXTRA_CHECKING RmLinkObjects(&pRemoteIp->Hdr, &pDest->Hdr, pSR); #endif // !RM_EXTRA_CHECKING // Now set the pRemoteIp state to reflect that it RESOLVED. // SET_REMOTEIP_RESOLVE_STATE(pRemoteIp, ARPREMOTEIP_RESOLVED); } EXIT() } VOID arpUnlinkRemoteIpFromDest( ARPCB_REMOTE_IP *pRemoteIp, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Unlink the remote IP entry (pRemoteIp) from the destination HW entry its linked to. Clear pRemoteIp's resolved flag. --*/ { ENTER("arpUnlinkRemoteIpFromDest", 0xc5809147) ARPCB_DEST *pDest = pRemoteIp->pDest; ARP_DUMP_MAPPING( pRemoteIp->Key.IpAddress, (pDest==NULL)? NULL : &pDest->Params.HwAddr, "Unlink Remote IP"); TR_INFO(("Unlinking IP 0x%p (Addr 0x%08lx) from Dest 0x%p (addr 0x%08lx)\n", pRemoteIp, pRemoteIp->Key.IpAddress, pDest, (pDest==NULL) ? 0 :((UINT) pDest->Params.HwAddr.FifoAddress.UniqueID) // Truncation )); if (pDest == NULL) { ASSERT(!"pRemoteIp->pDest == NULL"); } else { // // We assume that both objects share the same lock. // ASSERT(pRemoteIp->Hdr.pLock == pDest->Hdr.pLock); RM_DBG_ASSERT_LOCKED(&pRemoteIp->Hdr, pSR); RemoveEntryList(&pRemoteIp->linkSameDest); pRemoteIp->pDest = NULL; // Now set the pRemoteIp state to reflect that it UNRESOLVED. // SET_REMOTEIP_RESOLVE_STATE(pRemoteIp, ARPREMOTEIP_UNRESOLVED); #if RM_EXTRA_CHECKING RmUnlinkObjectsEx( &pRemoteIp->Hdr, &pDest->Hdr, 0x5ad067aa, ARPASSOC_LINK_IPADDR_OF_DEST, ARPASSOC_LINK_DEST_OF_IPADDR, pSR ); #else // !RM_EXTRA_CHECKING RmUnlinkObjects(&pRemoteIp->Hdr, &pDest->Hdr, pSR); #endif // !RM_EXTRA_CHECKING } EXIT() } VOID arpUnlinkAllRemoteIpsFromDest( ARPCB_DEST *pDest, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Unlink all RemoteIps (if any) from destination pDest. --*/ { ENTER("arpUnlinkAllRemoteIpsFromDest", 0x35120630) TR_INFO(("Unlinking All RemoteIps from Dest 0x%p (addr 0x%08lx)\n", pDest, ((UINT) pDest->Params.HwAddr.FifoAddress.UniqueID) // Truncation )); RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR); while (!IsListEmpty(&pDest->listIpToThisDest)) { LIST_ENTRY *pLink; ARPCB_REMOTE_IP *pRemoteIp; pLink = RemoveHeadList(&pDest->listIpToThisDest); pRemoteIp = CONTAINING_RECORD( pLink, ARPCB_REMOTE_IP, linkSameDest ); arpUnlinkRemoteIpFromDest(pRemoteIp, pSR); } EXIT() } VOID arpLinkLocalIpToDest( ARPCB_LOCAL_IP *pLocalIp, // LOCKIN LOCKOUT ARPCB_DEST *pDest, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Link a remote IP entry (pLocalIp) to the specified destination HW entry (pDest). Update the pLocalIp's state to indicate that this is resolved. --*/ { ENTER("arpLinkLocalIpToDest", 0x3be06bc6) ARP_DUMP_MAPPING(pLocalIp->IpAddress, &pDest->Params.HwAddr, "Linking Local IP"); #if 0 TR_INFO(("Linking Local IP 0x%08lx to Dest addr 0x%08lx\n", pLocalIp->IpAddress, (UINT) pDest->Params.HwAddr.FifoAddress.UniqueID // Truncation )); #endif // 0 RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR); RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR); if (pLocalIp->pDest != NULL) { ASSERT(!"pLocalIp->pDest != NULL"); } else { // // LocalIps may only be linked to pDests of type // ReceiveOnly. // ASSERT(pDest->Params.ReceiveOnly); pLocalIp->pDest = pDest; InsertHeadList(&pDest->listLocalIp, &pLocalIp->linkSameDest); #if RM_EXTRA_CHECKING RmLinkObjectsEx( &pLocalIp->Hdr, &pDest->Hdr, 0x597d0495, ARPASSOC_LINK_IPADDR_OF_DEST, " LOCAL_IP of 0x%p (%s)\n", ARPASSOC_LINK_DEST_OF_IPADDR, " DEST of Local 0x%p (%s)\n", pSR ); #else // !RM_EXTRA_CHECKING RmLinkObjects(&pLocalIp->Hdr, &pDest->Hdr, pSR); #endif // !RM_EXTRA_CHECKING } EXIT() } VOID arpUnlinkLocalIpFromDest( ARPCB_LOCAL_IP *pLocalIp, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Unlink the local IP entry (pLocalIp) from the destination HW entry its linked to. --*/ { ENTER("arpUnlinkLocalIpFromDest", 0xc5809147) ARPCB_DEST *pDest = pLocalIp->pDest; ARP_DUMP_MAPPING( pLocalIp->IpAddress, (pDest==NULL)? NULL : &pDest->Params.HwAddr, "Unlink Local IP"); TR_INFO(("Unlinking Local IP 0x%p (Addr 0x%08lx) from Dest 0x%p (addr 0x%08lx)\n", pLocalIp, pLocalIp->IpAddress, pDest, (pDest==NULL) ? 0 :((UINT) pDest->Params.HwAddr.FifoAddress.UniqueID) // Truncation )); if (pDest == NULL) { ASSERT(!"pLocalIp->pDest == NULL"); } else { // // We assume that both objects share the same lock. // ASSERT(pLocalIp->Hdr.pLock == pDest->Hdr.pLock); RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR); // // LocalIps may only be unlinked from pDests of type // ReceiveOnly. // ASSERT(pDest->Params.ReceiveOnly); RemoveEntryList(&pLocalIp->linkSameDest); #if RM_EXTRA_CHECKING RmUnlinkObjectsEx( &pLocalIp->Hdr, &pDest->Hdr, 0x5ad067aa, ARPASSOC_LINK_IPADDR_OF_DEST, ARPASSOC_LINK_DEST_OF_IPADDR, pSR ); #else // !RM_EXTRA_CHECKING RmUnlinkObjects(&pLocalIp->Hdr, &pDest->Hdr, pSR); #endif // !RM_EXTRA_CHECKING pLocalIp->pDest = NULL; } EXIT() } VOID arpUnlinkAllLocalIpsFromDest( ARPCB_DEST *pDest, // LOCKIN LOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: Unlink all Localif any) from destination pDest. --*/ { ENTER("arpUnlinkAllLocalIpsFromDest", 0x35120630) TR_INFO(("Unlinking All LocalIps from Dest 0x%p (addr 0x%08lx)\n", pDest, ((UINT) pDest->Params.HwAddr.FifoAddress.UniqueID) // Truncation )); RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR); // // LocalIps may only be unlinked from pDests of type // ReceiveOnly. // ASSERT(pDest->Params.ReceiveOnly); while (!IsListEmpty(&pDest->listLocalIp)) { LIST_ENTRY *pLink; ARPCB_LOCAL_IP *pLocalIp; pLink = RemoveHeadList(&pDest->listLocalIp); pLocalIp = CONTAINING_RECORD( pLink, ARPCB_LOCAL_IP, linkSameDest ); arpUnlinkLocalIpFromDest(pLocalIp, pSR); } EXIT() } MYBOOL arpNeedToCleanupDestVc( ARPCB_DEST *pDest // LOCKING LOCKOUT ) /*++ Routine Description: Deterinine if we need to do any cleanup work on destination pDest. "Cleanup work" includes if there is any ongoing asynchronous activity involving pDest, such as a make call or close call in progress. Return Value: TRUE iff there is cleanup work to be done. FALSE otherwise. --*/ { // Note -- return true if pDest->VcHdr.pCleanupCallTask is non-NULL, even if there // is nothing else to be done -- we do have to wait for this pCleanupCallTask // to complete. if ( pDest->VcHdr.pMakeCallTask != NULL || pDest->VcHdr.pCleanupCallTask!=NULL || pDest->VcHdr.NdisVcHandle!=NULL) { return TRUE; } else { return FALSE; } } PRM_OBJECT_HEADER arpLocalIpCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_LOCAL_IP. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Actually the IP address (not a pointer to the IP address) to associate with this local IP. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ARPCB_LOCAL_IP *pLocalIp; PRM_OBJECT_HEADER pHdr; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pLocalIp, MTAG_LOCAL_IP); if (Status != NDIS_STATUS_SUCCESS || pLocalIp== NULL) { return NULL; } ARP_ZEROSTRUCT(pLocalIp); pHdr = (PRM_OBJECT_HEADER) pLocalIp; ASSERT(pHdr == &pLocalIp->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_LOCAL_IP, pParentObject->pLock, &ArpGlobal_LocalIpStaticInfo, NULL, // szDescription pSR ); pLocalIp->IpAddress = (IP_ADDRESS) (UINT_PTR) pCreateParams; } return pHdr; } VOID arpLocalIpDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_LOCAL_IP. Arguments: pHdr - Actually a pointer to the local ip object to be freed. --*/ { ARPCB_LOCAL_IP *pLocalIp = (ARPCB_LOCAL_IP *) pHdr; ASSERT(pLocalIp->Hdr.Sig == MTAG_LOCAL_IP); pLocalIp->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); } PRM_OBJECT_HEADER arpRemoteIpCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_REMOTE_IP. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Actually the IP address (not a pointer to the IP address) to associate with this remote IP object. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ARPCB_REMOTE_IP *pRemoteIp; PRM_OBJECT_HEADER pHdr; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pRemoteIp, MTAG_REMOTE_IP); if (Status != NDIS_STATUS_SUCCESS || pRemoteIp == NULL) { return NULL; } ARP_ZEROSTRUCT(pRemoteIp); pHdr = (PRM_OBJECT_HEADER) pRemoteIp; ASSERT(pHdr == &pRemoteIp->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_REMOTE_IP, pParentObject->pLock, &ArpGlobal_RemoteIpStaticInfo, NULL, // szDescription pSR ); pRemoteIp->IpAddress = (IP_ADDRESS) (UINT_PTR) pCreateParams; // Initialize various other stuff... InitializeListHead(&pRemoteIp->sendinfo.listSendPkts); if (arpCanTryMcap(pRemoteIp->IpAddress)) { SET_REMOTEIP_MCAP(pRemoteIp, ARPREMOTEIP_MCAP_CAPABLE); } } return pHdr; } PRM_OBJECT_HEADER arpRemoteEthCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_REMOTE_ETH. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Points to a ARP_REMOTE_ETH_PARAMS structure to associate with this remote IP object. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ARPCB_REMOTE_ETH *pRemoteEth; PARP_REMOTE_ETH_PARAMS pMyParams = (PARP_REMOTE_ETH_PARAMS) pCreateParams; PRM_OBJECT_HEADER pHdr; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pRemoteEth, MTAG_REMOTE_ETH); if (Status != NDIS_STATUS_SUCCESS || pRemoteEth == NULL) { return NULL; } ARP_ZEROSTRUCT(pRemoteEth); pHdr = (PRM_OBJECT_HEADER) pRemoteEth; ASSERT(pHdr == &pRemoteEth->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_REMOTE_ETH, pParentObject->pLock, &ArpGlobal_RemoteEthStaticInfo, NULL, // szDescription pSR ); pRemoteEth->IpAddress = pMyParams->IpAddress; pRemoteEth->EthAddress = pMyParams->EthAddress; } return pHdr; } VOID arpRemoteIpDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_REMOTE_IP. Arguments: pHdr - Actually a pointer to the remote ip object to be freed. --*/ { ARPCB_REMOTE_IP *pRemoteIp = (ARPCB_REMOTE_IP *) pHdr; ASSERT(pRemoteIp->Hdr.Sig == MTAG_REMOTE_IP); pRemoteIp->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); } VOID arpRemoteEthDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_REMOTE_IP. Arguments: pHdr - Actually a pointer to the remote ip object to be freed. --*/ { ARPCB_REMOTE_ETH *pRemoteEth = (ARPCB_REMOTE_ETH *) pHdr; ASSERT(pRemoteEth->Hdr.Sig == MTAG_REMOTE_ETH); pRemoteEth->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); } PRM_OBJECT_HEADER arpDestinationCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_DEST. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Actually a pointer to a ARP_DEST_KEY containing the hw addresses to associate with this object. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ARPCB_DEST *pDest; PRM_OBJECT_HEADER pHdr; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pDest, MTAG_DEST); if (Status != NDIS_STATUS_SUCCESS || pDest == NULL) { return NULL; } ARP_ZEROSTRUCT(pDest); pHdr = (PRM_OBJECT_HEADER) pDest; ASSERT(pHdr == &pDest->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_DEST, pParentObject->pLock, &ArpGlobal_DestinationStaticInfo, NULL, // szDescription pSR ); pDest->Params = *((PARP_DEST_PARAMS) pCreateParams); InitializeListHead(&pDest->listIpToThisDest); InitializeListHead(&pDest->listLocalIp); } return pHdr; } VOID arpDestinationDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_DEST. Arguments: pHdr - Actually a pointer to the destination object to be freed. --*/ { ARPCB_DEST *pDest = (ARPCB_DEST *) pHdr; ASSERT(pDest->Hdr.Sig == MTAG_DEST); pDest->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); } PRM_OBJECT_HEADER arpDhcpTableEntryCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_REMOTE_IP. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Actually the IP address (not a pointer to the IP address) to associate with this remote IP object. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ENTER ("arpRemoteDestCreate", 0xa896311a) ARP1394_ETH_DHCP_ENTRY *pEntry = NULL; ULONG xid = *(PULONG)pCreateParams; PRM_OBJECT_HEADER pHdr; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pEntry, MTAG_ARP_GENERIC); if (Status != NDIS_STATUS_SUCCESS || pEntry == NULL) { return NULL; } ARP_ZEROSTRUCT(pEntry); pHdr = (PRM_OBJECT_HEADER) pEntry; ASSERT(pHdr == &pEntry->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_ARP_GENERIC, pParentObject->pLock, &ArpGlobal_DhcpTableStaticInfo , NULL, // szDescription pSR ); TR_INFO( ("New XID %x \n", xid)); // set up the key pEntry->xid = xid; } EXIT() return pHdr; } VOID arpDhcpTableEntryDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_REMOTE_IP. Arguments: pHdr - Actually a pointer to the remote ip object to be freed. --*/ { ARP1394_ETH_DHCP_ENTRY *pEntry = (ARP1394_ETH_DHCP_ENTRY*) pHdr; ASSERT(pEntry->Hdr.Sig == MTAG_ARP_GENERIC); pEntry->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); } NDIS_STATUS arpTaskMakeCallToDest( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) /*++ This task is responsible for making a call to a destination (either send-FIFO or send/recv-CHANNEL). Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskMakeCallToDest", 0x25108eaa) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_DEST * pDest = (ARPCB_DEST*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); TASK_MAKECALL * pMakeCallTask = (TASK_MAKECALL*) pTask; // Following are the list of pending states for this task. // enum { PEND_OtherMakeCallTaskComplete, PEND_MakeCallComplete }; ASSERT(sizeof(ARP1394_TASK) >= sizeof(*pMakeCallTask)); switch(Code) { case RM_TASKOP_START: { BOOLEAN IsFifo; PARP_STATIC_VC_INFO pVcStaticInfo; LOCKOBJ(pDest, pSR); DBGMARK(0x7a74bf2a); // First check if pDest is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pDest)) { Status = NDIS_STATUS_FAILURE; break; } // If there is a call cleanup task in progress, we fail right away... // if (pDest->VcHdr.pCleanupCallTask != NULL) { OBJLOG2( pDest, "Failing MakeCall task %p because Cleanup task %p exists.\n", pTask, pDest->VcHdr.pCleanupCallTask ); Status = NDIS_STATUS_FAILURE; break; } // // pDest is allocated. Now check if there is already a // MakeCall task attached to pDest. // if (pDest->VcHdr.pMakeCallTask != NULL) { // // There is a make-call task. We pend on it. // PRM_TASK pOtherTask = pDest->VcHdr.pMakeCallTask; OBJLOG1( pTask, "MakeCall task %p exists; pending on it.\n", pOtherTask); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pDest, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherMakeCallTaskComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // Grab the IF send lock and make sure we're in the position to make a // call -- there should be no VC handle. // We must do this BEFORE we become the official task, so that we don't // wipe out the connection as part of our cleanup. // ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); if (pDest->VcHdr.NdisVcHandle != NULL) { OBJLOG1( pTask, "VcHandle 0x%p already exists!, failing make call attempt.\n", pDest->VcHdr.NdisVcHandle); Status = NDIS_STATUS_FAILURE; break; } ASSERT(pDest->sendinfo.OkToSend == FALSE); ASSERT(pDest->sendinfo.NumOutstandingSends == 0); // // There is no MakeCall task going on, and there's no VC handle. Let's // make this task THE MakeCall task. // pDest->VcHdr.pMakeCallTask = pTask; // // Since we're THE MakeCall task, add an association to pDest, // which will only get cleared when the pDest->VcHdr.pMakeCallTask field // above is cleared. // DBG_ADDASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_MAKECALL_TASK, // AssociationID " Official makecall task 0x%p (%s)\n", // szFormat pSR ); // Setup call params. // { PNIC1394_MEDIA_PARAMETERS p1394Params = (PNIC1394_MEDIA_PARAMETERS) &pMakeCallTask->MediaParams.Parameters; PNIC1394_DESTINATION pDestAddr = &pDest->Params.HwAddr; //No need: ARP_ZEROSTRUCT(&pMakeCallTask->CallParams); //No need: ARP_ZEROSTRUCT(&pMakeCallTask->MediaParams); pMakeCallTask->CallParams.MediaParameters = (PCO_MEDIA_PARAMETERS) &pMakeCallTask->MediaParams; pMakeCallTask->MediaParams.ParamType = NIC1394_MEDIA_SPECIFIC; IsFifo = FALSE; switch(pDestAddr->AddressType) { case NIC1394AddressType_Channel: pMakeCallTask->MediaParams.Flags = TRANSMIT_VC | RECEIVE_VC; pVcStaticInfo = &g_ArpBroadcastChannelVcStaticInfo; break; case NIC1394AddressType_FIFO: pMakeCallTask->MediaParams.Flags = TRANSMIT_VC; pVcStaticInfo = &g_ArpSendFifoVcStaticInfo; IsFifo = TRUE; break; case NIC1394AddressType_MultiChannel: pMakeCallTask->MediaParams.Flags = RECEIVE_VC; pVcStaticInfo = &g_ArpMultiChannelVcStaticInfo; break; case NIC1394AddressType_Ethernet: pMakeCallTask->MediaParams.Flags = TRANSMIT_VC | RECEIVE_VC; pVcStaticInfo = &g_ArpEthernetVcStaticInfo; break; default: ASSERT(FALSE); break; } TR_INFO(("Our Parameters offset = 0x%lx; Official offset = 0x%lx\n", FIELD_OFFSET(ARP1394_CO_MEDIA_PARAMETERS, Parameters), FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific.Parameters))); ASSERT(FIELD_OFFSET(ARP1394_CO_MEDIA_PARAMETERS, Parameters) == FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific.Parameters)); p1394Params->Destination = *pDestAddr; // struct copy. p1394Params->Flags = NIC1394_VCFLAG_FRAMED; p1394Params->MaxSendBlockSize = -1; // (nic should pick) p1394Params->MaxSendSpeed = -1; // (nic should pick) p1394Params->MTU = ARP1394_ADAPTER_MTU; // TODO -- make above based on // config. } // Now create a vc and make the call... // { RmUnlockAll(pSR); Status = arpInitializeVc( pIF, pVcStaticInfo, &pDest->Hdr, &pDest->VcHdr, pSR ); if (FAIL(Status)) { break; } // Save away the fields within sendinfo... // ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); pDest->sendinfo.OkToSend = FALSE; pDest->sendinfo.IsFifo = IsFifo; ARP_UNLOCK_IF_SEND_LOCK(pIF, pSR); RmSuspendTask(pTask, PEND_MakeCallComplete, pSR); DBGMARK(0xef9d8be3); // // Make the Call now // if (IsFifo) { LOGSTATS_TotalSendFifoMakeCalls(pIF); } else { LOGSTATS_TotalChannelMakeCalls(pIF); } RM_ASSERT_NOLOCKS(pSR); #if ARPDBG_FAKE_CALLS Status = arpDbgFakeNdisClMakeCall( pDest->VcHdr.NdisVcHandle, &pMakeCallTask->CallParams, NULL, // ProtocolPartyContext NULL, // NdisPartyHandle &pDest->Hdr, &pDest->VcHdr, pSR ); #else // !ARPDBG_FAKE_CALLS Status = NdisClMakeCall( pDest->VcHdr.NdisVcHandle, &pMakeCallTask->CallParams, NULL, // ProtocolPartyContext NULL // NdisPartyHandle ); #endif // !ARPDBG_FAKE_CALLS if (!PEND(Status)) { ArpCoMakeCallComplete( Status, (NDIS_HANDLE) (&pDest->VcHdr), NULL, &pMakeCallTask->CallParams ); Status = NDIS_STATUS_PENDING; } } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OtherMakeCallTaskComplete: { // // There was another makecall task going when we started, and // it's now complete. Nothing for us to do... // Status = (NDIS_STATUS) UserParam; } break; case PEND_MakeCallComplete: { // // The make call is complete. We're done... // Status = (NDIS_STATUS) UserParam; #if ARPDBG_FAKE_CALLS // // In the fake case, we give the "user" the opportunity to change // the status to Success for the special VC (BROADCAST // MCAP, ETHERNET) make call fails, // because otherwise the adapter bind itself is going to fail. // // We do this even in the retail build (if ARPDBG_FAKE_CALLS is // enabled). // if ((1 || FAIL(Status)) && !pDest->sendinfo.IsFifo) { // To try the failure path of the BC make call, enable // the if 0 code. Currently we change status to success // so that stress tests which include loading/unloading // of the driver will run without breaking here everytime. // #if 1 DbgPrint( "A13: Fake %s failed. &Status=%p.\n", pDest->VcHdr.pStaticInfo->Description, &Status ); DbgBreakPoint(); #else Status = NDIS_STATUS_SUCCESS; #endif } #endif // ARPDBG_FAKE_CALLS LOCKOBJ(pDest, pSR); ASSERT (pDest->VcHdr.pMakeCallTask == pTask); ASSERT(pDest->VcHdr.NdisVcHandle != NULL); ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); DBGMARK(0xd50a6864); if (FAIL(Status)) { pDest->sendinfo.OkToSend = FALSE; } else { // // Success! Packets can now be sent over this VC without // further ado. // pDest->sendinfo.OkToSend = TRUE; } RmUnlockAll(pSR); } 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; LOCKOBJ(pDest, pSR); if (pDest->VcHdr.pMakeCallTask == pTask) { // // We're the official pMakeCallTask // // Delete the association we added when we set // pDest->VcHdr.pMakeCallTask to pTask. // DBG_DELASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_MAKECALL_TASK, // AssociationID pSR ); // Remove reference to us in pDest. // pDest->VcHdr.pMakeCallTask = NULL; if (FAIL(Status) && pDest->VcHdr.NdisVcHandle != NULL) { UNLOCKOBJ(pDest, pSR); // WARNING: the above completely nukes out pDest.VcHdr. // arpDeinitializeVc(pIF, &pDest->VcHdr, &pDest->Hdr, pSR); } } } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } NDIS_STATUS arpTaskCleanupCallToDest( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) /*++ This task is responsible for cleaning up a previously-made call to a destination. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskCleanupCallToDest", 0xc89dfb47) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARPCB_DEST * pDest = (ARPCB_DEST*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); MYBOOL fCloseCall = FALSE; NDIS_HANDLE NdisVcHandle = NULL; // Following are the list of pending states for this task. // enum { PEND_OtherCleanupTaskComplete, PEND_OutstandingSendsComplete, PEND_CloseCallComplete }; DBGMARK(0x6198198e); switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pDest, pSR); // First check if pDest is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pDest)) { Status = NDIS_STATUS_SUCCESS; break; } // // pDest is allocated. Now check if there is already a // CleanupCall task attached to pDest. // if (pDest->VcHdr.pCleanupCallTask != NULL) { // // There is an existing CleanupCall task. We pend on it. // PRM_TASK pOtherTask = pDest->VcHdr.pCleanupCallTask; OBJLOG1( pTask, "CleanupVc task %p exists; pending on it.\n", pOtherTask ); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pDest, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherCleanupTaskComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no CleanupCall task going on. Let's // make this task THE CleanupCall task. // pDest->VcHdr.pCleanupCallTask = pTask; // // Since we're THE CleanupCall task, add an association to pDest, // which will only get cleared when the pDest->VcHdr.pCleanupCallTask field // above is cleared. // DBG_ADDASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_CLEANUPCALL_TASK, // AssociationID " Official CleanupCall task 0x%p (%s)\n", // szFormat pSR ); // // Grab the IF send lock and disable further sends on this vc; // Also if there are pending sends, we'll need to suspend ourselves // until all the sends are done. // ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); pDest->sendinfo.OkToSend = FALSE; // There should be no other task waiting for outstanding sends to // complete -- only the OFFICIAL CleanupTask (that's us) explicitly // waits for sends to complete. // ASSERTEX(pDest->sendinfo.pSuspendedCleanupCallTask == NULL, pDest->sendinfo.pSuspendedCleanupCallTask); if (pDest->sendinfo.NumOutstandingSends != 0) { DBGMARK(0xea3987f0); // // Outstanding sends, we need to suspend ourselves until // the count goes to zero... // pDest->sendinfo.pSuspendedCleanupCallTask = pTask; // Following association will be cleared when we are resumed // after the outstanding sends goes to zero. // DBG_ADDASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_CLEANUPCALLTASK_WAITING_ON_SENDS,// AssociationID " Vc tasks 0x%p (%s) waiting on outstanding sends\n", pSR ); RmSuspendTask(pTask, PEND_OutstandingSendsComplete, pSR); Status = NDIS_STATUS_PENDING; } else { DBGMARK(0x306bc5c3); // // If we're here, we're free to go on and close the call. // fCloseCall = TRUE; NdisVcHandle = pDest->VcHdr.NdisVcHandle; } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OtherCleanupTaskComplete: { // // There was another cleanup-vc task going when we started, and // it's now complete. Nothing for us to do... // Status = NDIS_STATUS_SUCCESS; } break; case PEND_OutstandingSendsComplete: { // We were waiting for outstanding sends to complete, and // the last one to complete has resumed us (after setting // pDest->sendinfo.pSuspendedCleanupCallTask to NULL). // ARP_WRITELOCK_IF_SEND_LOCK(pIF, pSR); ASSERT(pDest->sendinfo.pSuspendedCleanupCallTask == NULL); ASSERT(!ARP_CAN_SEND_ON_DEST(pDest)); ASSERT(pDest->sendinfo.NumOutstandingSends==0); NdisVcHandle = pDest->VcHdr.NdisVcHandle; ARP_UNLOCK_IF_SEND_LOCK(pIF, pSR); // There were outstanding sends, but how there are none. // We should be able to close the call now. // fCloseCall = TRUE; DBGMARK(0xf3b10866); Status = NDIS_STATUS_SUCCESS; break; } break; case PEND_CloseCallComplete: { // // The close call is complete... // LOCKOBJ(pDest, pSR); ASSERT(pDest->VcHdr.pCleanupCallTask == pTask); // Delete the association we added when we set // pDest->VcHdr.pCleanupCallTask to pTask. // DBG_DELASSOC( &pDest->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_DEST_CLEANUPCALL_TASK, // AssociationID pSR ); pDest->VcHdr.pCleanupCallTask = NULL; RmUnlockAll(pSR); DBGMARK(0xa590bb4f); arpDeinitializeVc(pIF, &pDest->VcHdr, &pDest->Hdr, pSR); Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pDest, pSR); DBGMARK(0xcfc9dbaf); // // We're done. There should be no async activities left to do. // #if DBG ARP_READLOCK_IF_SEND_LOCK(pIF, pSR); ASSERTEX(pDest->VcHdr.NdisVcHandle == NULL, pDest); ASSERTEX(!ARP_CAN_SEND_ON_DEST(pDest), pDest); ASSERTEX(pDest->sendinfo.NumOutstandingSends==0, pDest); ARP_UNLOCK_IF_SEND_LOCK(pIF, pSR); #endif DBG Status = NDIS_STATUS_SUCCESS; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); if (fCloseCall) { DBGMARK(0x653b1cc3); RmSuspendTask(pTask, PEND_CloseCallComplete, pSR); #if ARPDBG_FAKE_CALLS Status = arpDbgFakeNdisClCloseCall( NdisVcHandle, NULL, // No party handle NULL, // No Buffer 0, // Size of above &pDest->Hdr, &pDest->VcHdr, pSR ); #else // !ARPDBG_FAKE_CALLS Status = NdisClCloseCall( NdisVcHandle, NULL, // No party handle NULL, // No Buffer 0 // Size of above ); #endif // !ARPDBG_FAKE_CALLS if (Status != NDIS_STATUS_PENDING) { ArpCoCloseCallComplete( Status, (NDIS_HANDLE) &pDest->VcHdr, (NDIS_HANDLE)NULL ); Status = NDIS_STATUS_PENDING; } } EXIT() return Status; } NDIS_STATUS arpTaskMakeRecvFifoCall( IN PRM_TASK pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) /*++ Routine Description: This task is responsible for making a call to the interface's single receive FIFO. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskMakeRecvFifoCall", 0x25108eaa) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pTask); TASK_MAKECALL * pMakeCallTask = (TASK_MAKECALL*) pTask; // Following are the list of pending states for this task. // enum { PEND_OtherMakeCallTaskComplete, PEND_MakeCallComplete }; ASSERT(sizeof(ARP1394_TASK) >= sizeof(*pMakeCallTask)); switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pIF, pSR); DBGMARK(0x6d7d9959); // If there is a call cleanup task in progress, we fail right away... // if (pIF->recvinfo.VcHdr.pCleanupCallTask != NULL) { OBJLOG2( pIF, "Failing MakeCall task %p because Cleanup task %p exists.\n", pIF, pIF->recvinfo.VcHdr.pCleanupCallTask ); Status = NDIS_STATUS_FAILURE; break; } // // Now check if there is already a // MakeCall task attached to pIF. // if (pIF->recvinfo.VcHdr.pMakeCallTask != NULL) { // // There is a make-call task. We pend on it. // PRM_TASK pOtherTask = pIF->recvinfo.VcHdr.pMakeCallTask; OBJLOG1( pTask, "MakeCall task %p exists; pending on it.\n", pOtherTask); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pIF, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherMakeCallTaskComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no MakeCall task going on. Let's // make this task THE MakeCall task. // pIF->recvinfo.VcHdr.pMakeCallTask = pTask; // // Since we're THE MakeCall task, add an association to pIF, // which will only get cleared when the pIF->pMakeCallTask field // above is cleared. // DBG_ADDASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_MAKECALL_TASK, // AssociationID " Official makecall task 0x%p (%s)\n", // szFormat pSR ); // // Make sure we're in the position to make a // call -- there should be no VC handle. // if (pIF->recvinfo.VcHdr.NdisVcHandle != NULL) { OBJLOG1( pTask, "VcHandle 0x%p already exists!, failing make call attempt.\n", pIF->recvinfo.VcHdr.NdisVcHandle); Status = NDIS_STATUS_FAILURE; break; } // Setup call params. // { PNIC1394_MEDIA_PARAMETERS p1394Params = (PNIC1394_MEDIA_PARAMETERS) &pMakeCallTask->MediaParams.Parameters; NIC1394_DESTINATION DestAddr; PNIC1394_DESTINATION pDestAddr; ARP_ZEROSTRUCT(&DestAddr); // TODO: put real values.... // DestAddr.FifoAddress.UniqueID = 0; DestAddr.FifoAddress.Off_Low = 0; DestAddr.FifoAddress.Off_High = 0x100; DestAddr.AddressType = NIC1394AddressType_FIFO; pDestAddr = &DestAddr; //No need: ARP_ZEROSTRUCT(&pMakeCallTask->CallParams); //No need: ARP_ZEROSTRUCT(&pMakeCallTask->MediaParams); pMakeCallTask->CallParams.MediaParameters = (PCO_MEDIA_PARAMETERS) &pMakeCallTask->MediaParams; pMakeCallTask->MediaParams.Flags = RECEIVE_VC; pMakeCallTask->MediaParams.ParamType = NIC1394_MEDIA_SPECIFIC; ASSERT(FIELD_OFFSET(ARP1394_CO_MEDIA_PARAMETERS, Parameters) == FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific.Parameters)); p1394Params->Destination = *pDestAddr; // struct copy. p1394Params->Flags = NIC1394_VCFLAG_FRAMED; p1394Params->MaxSendBlockSize = -1; // (nic should pick) p1394Params->MaxSendSpeed = -1; // (nic should pick) p1394Params->MTU = ARP1394_ADAPTER_MTU; // TODO -- make above based on // config. } // Now create a vc and make the call... // { NDIS_HANDLE NdisVcHandle; RmUnlockAll(pSR); Status = arpInitializeVc( pIF, &g_ArpRecvFifoVcStaticInfo, &pIF->Hdr, &pIF->recvinfo.VcHdr, pSR ); if (FAIL(Status)) { break; } NdisVcHandle = pIF->recvinfo.VcHdr.NdisVcHandle; RmSuspendTask(pTask, PEND_MakeCallComplete, pSR); DBGMARK(0xf313a276); // // Make the Call now // RM_ASSERT_NOLOCKS(pSR); #if ARPDBG_FAKE_CALLS Status = arpDbgFakeNdisClMakeCall( NdisVcHandle, &pMakeCallTask->CallParams, NULL, // ProtocolPartyContext NULL, // NdisPartyHandle &pIF->Hdr, &pIF->recvinfo.VcHdr, pSR ); #else // !ARPDBG_FAKE_CALLS Status = NdisClMakeCall( NdisVcHandle, &pMakeCallTask->CallParams, NULL, // ProtocolPartyContext NULL // NdisPartyHandle ); #endif // !ARPDBG_FAKE_CALLS if (!PEND(Status)) { ArpCoMakeCallComplete( Status, (NDIS_HANDLE) &pIF->recvinfo.VcHdr, NULL, &pMakeCallTask->CallParams ); Status = NDIS_STATUS_PENDING; } } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OtherMakeCallTaskComplete: { // // There was another makecall task going when we started, and // it's now complete. Nothing for us to do... // Status = (NDIS_STATUS) UserParam; } break; case PEND_MakeCallComplete: { // // The make call is complete. We're done... // Status = (NDIS_STATUS) UserParam; #if ARPDBG_FAKE_CALLS // // In the fake case, we give the "user" the opportunity to change // the status to Success if the recv FIFO make call fails, // because otherwise the adapter bind itself is going to fail. // // We do this even in the retail build (if ARPDBG_FAKE_CALLS is // enabled). // if (FAIL(Status)) { // To try the failure path of the recv fifo make call, enable // the if 0 code. Currently we change status to success // so that stress tests which include loading/unloading // of the driver will run without breaking here everytime. // #if 0 DbgPrint( "A13: FakeRecvMakeCall failed. &Status=%p.\n", &Status ); DbgBreakPoint(); #else Status = NDIS_STATUS_SUCCESS; #endif } #endif // ARPDBG_FAKE_CALLS LOCKOBJ(pIF, pSR); ASSERT (pIF->recvinfo.VcHdr.pMakeCallTask == pTask); ASSERT(pIF->recvinfo.VcHdr.NdisVcHandle != NULL); // On success, update pIF->recvinfo.offset. // if (!FAIL(Status)) { PNIC1394_MEDIA_PARAMETERS p1394Params = (PNIC1394_MEDIA_PARAMETERS) &pMakeCallTask->MediaParams.Parameters; pIF->recvinfo.offset.Off_Low = p1394Params->Destination.FifoAddress.Off_Low; pIF->recvinfo.offset.Off_High = p1394Params->Destination.FifoAddress.Off_High; } DBGMARK(0xa3b591b7); RmUnlockAll(pSR); } 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; LOCKOBJ(pIF, pSR); if (pIF->recvinfo.VcHdr.pMakeCallTask == pTask) { // // We're the official pMakeCallTask // // Delete the association we added when we set // pIF->recvinfo.VcHdr.pMakeCallTask to pTask. // DBG_DELASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_MAKECALL_TASK, // AssociationID pSR ); // Remove reference to us in pIF. // pIF->recvinfo.VcHdr.pMakeCallTask = NULL; if (FAIL(Status) && pIF->recvinfo.VcHdr.NdisVcHandle != NULL) { UNLOCKOBJ(pIF, pSR); // WARNING: the above completely nukes out VcHdr. // arpDeinitializeVc(pIF, &pIF->recvinfo.VcHdr, &pIF->Hdr, pSR); } } } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; } NDIS_STATUS arpTaskCleanupRecvFifoCall( IN PRM_TASK pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) /*++ Routine Description: This task is responsible for cleaning up a previously-made call to the IF's single recvFIFO VC. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskCleanupRecvFifoCall", 0x6e9581f7) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pTask); MYBOOL fCloseCall = FALSE; NDIS_HANDLE NdisVcHandle = NULL; // Following are the list of pending states for this task. // enum { PEND_MakeCallTaskComplete, PEND_OtherCleanupTaskComplete, PEND_CloseCallComplete }; DBGMARK(0xa651415b); switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pIF, pSR); // First check if pIF is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pIF)) { Status = NDIS_STATUS_SUCCESS; break; } // // pIF is allocated. Now check if there is already a // CleanupCall task attached to pIF. // if (pIF->recvinfo.VcHdr.pCleanupCallTask != NULL) { // // There is an existing CleanupCall task. We pend on it. // PRM_TASK pOtherTask = pIF->recvinfo.VcHdr.pCleanupCallTask; OBJLOG1( pTask, "CleanupVc task %p exists; pending on it.\n", pOtherTask ); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pIF, pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherCleanupTaskComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no CleanupCall task going on. Let's // make this task THE CleanupCall task. // pIF->recvinfo.VcHdr.pCleanupCallTask = pTask; // // Since we're THE CleanupCall task, add an association to pIF, // which will only get cleared when the pIF->recvinfo.VcHdr.pCleanupCallTask // field above is cleared. // DBG_ADDASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_CLEANUPCALL_TASK, // AssociationID " Official CleanupCall task 0x%p (%s)\n", // szFormat pSR ); if (pIF->recvinfo.VcHdr.pMakeCallTask != NULL) { // Oops, there is a make call task ongoing. // TODO: abort the makecall task. // For now, we just wait until it's complete. // PRM_TASK pOtherTask = pIF->recvinfo.VcHdr.pMakeCallTask; OBJLOG1( pTask, "MakeCall task %p exists; pending on it.\n", pOtherTask ); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pIF, pSR); RmPendTaskOnOtherTask( pTask, PEND_MakeCallTaskComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } else { NdisVcHandle = pIF->recvinfo.VcHdr.NdisVcHandle; if (NdisVcHandle != NULL) { fCloseCall = TRUE; } else { // Nothing to do. Status = NDIS_STATUS_SUCCESS; } } } // START break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OtherCleanupTaskComplete: { // // There was another cleanup-vc task going when we started, and // it's now complete. Nothing for us to do... // Status = NDIS_STATUS_SUCCESS; } break; case PEND_MakeCallTaskComplete: { // // There was a makecall task going when we started, and // it's now complete. We go on to cleanup the call. // There cannot be another makecall task now, because a // makecall task doesn't start if there is an active // cleanupcall task. // ASSERT(pIF->recvinfo.VcHdr.pMakeCallTask == NULL); NdisVcHandle = pIF->recvinfo.VcHdr.NdisVcHandle; if (NdisVcHandle != NULL) { fCloseCall = TRUE; } else { // Nothing to do. Status = NDIS_STATUS_SUCCESS; } } break; case PEND_CloseCallComplete: { // // The close call is complete... // LOCKOBJ(pIF, pSR); ASSERT(pIF->recvinfo.VcHdr.pCleanupCallTask == pTask); // Delete the association we added when we set // pIF->recvinfo.VcHdr.pCleanupCallTask to pTask. // DBG_DELASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_CLEANUPCALL_TASK, // AssociationID pSR ); pIF->recvinfo.VcHdr.pCleanupCallTask = NULL; // Delete the VC... // ASSERT(pIF->recvinfo.VcHdr.NdisVcHandle != NULL); UNLOCKOBJ(pIF, pSR); DBGMARK(0xc6b52f21); arpDeinitializeVc(pIF, &pIF->recvinfo.VcHdr, &pIF->Hdr, pSR); Status = NDIS_STATUS_SUCCESS; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pIF, pSR); DBGMARK(0xc65b2f08); // // We're done. There should be no async activities left to do. // ASSERTEX(pIF->recvinfo.VcHdr.NdisVcHandle == NULL, pIF); Status = NDIS_STATUS_SUCCESS; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); if (fCloseCall) { DBGMARK(0x04d5b2d9); RmSuspendTask(pTask, PEND_CloseCallComplete, pSR); #if ARPDBG_FAKE_CALLS Status = arpDbgFakeNdisClCloseCall( NdisVcHandle, NULL, // No party handle NULL, // No Buffer 0, // Size of above &pIF->Hdr, &pIF->recvinfo.VcHdr, pSR ); #else // !ARPDBG_FAKE_CALLS Status = NdisClCloseCall( NdisVcHandle, NULL, // No party handle NULL, // No Buffer 0 // Size of above ); #endif // !ARPDBG_FAKE_CALLS if (Status != NDIS_STATUS_PENDING) { ArpCoCloseCallComplete( Status, (NDIS_HANDLE) &pIF->recvinfo.VcHdr, (NDIS_HANDLE)NULL ); Status = NDIS_STATUS_PENDING; } } EXIT() return Status; } NDIS_STATUS arpAddOneStaticArpEntry( IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT IN IP_ADDRESS IpAddress, IN PNIC1394_FIFO_ADDRESS pFifoAddr, IN PRM_STACK_RECORD pSR ) /*++ Routine Description: Create a pRemoteIp and IP address IpAddress and (if not already existing) create a pDest object with hw address pFifoAddr and link the two. Return Value: NDIS_STATUS_SUCCESS on success. Ndis failure code on failure (could be because of a resource allocation failure or because there already exists a pRemoteIp with the specified IP address). --*/ { INT fCreated = FALSE; ARPCB_REMOTE_IP *pRemoteIp = NULL; ARPCB_DEST *pDest = NULL; NDIS_STATUS Status; ARP_DEST_PARAMS DestParams; REMOTE_DEST_KEY RemoteDestKey; RM_DBG_ASSERT_LOCKED(&pIF->Hdr, pSR); ARP_ZEROSTRUCT(&DestParams); DestParams.HwAddr.AddressType = NIC1394AddressType_FIFO; DestParams.HwAddr.FifoAddress = *pFifoAddr; // struct copy REMOTE_DEST_KEY_INIT(&RemoteDestKey); RemoteDestKey.IpAddress = IpAddress; do { Status = RmLookupObjectInGroup( &pIF->RemoteIpGroup, RM_CREATE|RM_NEW, (PVOID) (&RemoteDestKey), (PVOID) (&RemoteDestKey), // pCreateParams (RM_OBJECT_HEADER**) &pRemoteIp, &fCreated, // pfCreated pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "Couldn't add fake static localIp entry with addr 0x%lx\n", IpAddress ); break; } // Now create a destination item for this structure. // Status = RmLookupObjectInGroup( &pIF->DestinationGroup, RM_CREATE, //NOT RM_NEW (could be existing) &DestParams, &DestParams, // pParams (RM_OBJECT_HEADER**) &pDest, &fCreated, pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "Couldn't add fake dest entry with hw addr 0x%lx\n", (UINT) DestParams.HwAddr.FifoAddress.UniqueID // Truncation ); #if 0 TR_WARN(( "Couldn't add fake dest entry with hw addr 0x%lx\n", (UINT) DestParams.HwAddr.FifoAddress.UniqueID // Truncation )); #endif // 0 // // We'll leave the RemoteIp entry around -- it will be cleaned up later. // We do have to deref the tmpref added when looking it up. // RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR); break; } // // We've created both RemoteIp and Destination entries. Now link them. // (We still have the IF lock, which is the same as the RemoteIP and // desination locks for now). // // TODO: will need to change this when pRemoteIp gets its own lock. // RM_ASSERT_SAME_LOCK_AS_PARENT(pRemoteIp); RM_ASSERT_SAME_LOCK_AS_PARENT(pDest); arpLinkRemoteIpToDest( pRemoteIp, pDest, pSR ); // Now set the pRemoteIp state to reflect that it is STATIC and FIFO // SET_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_STATIC); SET_REMOTEIP_FCTYPE(pRemoteIp, ARPREMOTEIP_FIFO); // Finally, remove the tmprefs added in the lookups. // RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR); RmTmpDereferenceObject(&pDest->Hdr, pSR); } while (FALSE); return Status; } VOID arpActivateIf( PARP1394_INTERFACE pIF, PRM_TASK pCallingTask, // OPTIONAL UINT SuspendCode, // OPTIONAL PRM_STACK_RECORD pSR ) /*++ Routine Description: Initiate the asynchronous activation of pIF. NO locks must be held on entrance and none are held on exit. Arguments: pIF - Interface to activate. pCallingTask - Optional task to suspend and resume when activation completes (possibly async). SuspendCode - SuspendCode for the above task. --*/ { PRM_TASK pTask; NDIS_STATUS Status; RM_ASSERT_NOLOCKS(pSR); Status = arpAllocateTask( &pIF->Hdr, // pParentObject, arpTaskActivateInterface, // pfnHandler, 0, // Timeout, "Task: Activate Interface", // szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pIF, ("FATAL: couldn't alloc Activate IF task!\n")); ASSERT(FALSE); if (pCallingTask != NULL) { RmSuspendTask(pCallingTask, SuspendCode, pSR); RmResumeTask(pCallingTask, Status, pSR); } } else { if (pCallingTask != NULL) { RmPendTaskOnOtherTask( pCallingTask, SuspendCode, pTask, pSR ); } (void)RmStartTask(pTask, 0, pSR); } } VOID arpDeinitIf( PARP1394_INTERFACE pIF, PRM_TASK pCallingTask, // OPTIONAL UINT SuspendCode, // OPTIONAL PRM_STACK_RECORD pSR ) /*++ Routine Description: Initiate the asynchronous unload of pIF. If pIF is currently being loaded (initialized), abort the initializeation or wait for it to complete before unloading it. If pIF is currently being unloaded and pCallingTask is NULL, return right away, else (pCallingTask is not NULL), suspend pCallingTask and make it pend until the unload completes. NO locks must be held on entrance and none are held on exit. Arguments: pIF - Interface to unload. pCallingTask - Optional task to suspend if unload is completing async. SuspendCode - SuspendCode for the above task. Return Value: NDIS_STATUS_SUCCESS -- on synchronous success OR pCallingTask==NULL NDIS_STATUS_PENDING -- if pCallingTask is made to pend until the operation completes. --*/ { PRM_TASK pTask; NDIS_STATUS Status; // // NOTE: We could check to see if pIF can be synchronously unloaded, // and if so unload it right here. We don't bother because that's just // more code, and with dubious perf benefit. // RM_ASSERT_NOLOCKS(pSR); Status = arpAllocateTask( &pIF->Hdr, // pParentObject, arpTaskDeinitInterface, // pfnHandler, 0, // Timeout, "Task: Deinit Interface", // szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pIF, ("FATAL: couldn't alloc close IF task!\n")); ASSERT(FALSE); if (pCallingTask != NULL) { RmSuspendTask(pCallingTask, SuspendCode, pSR); RmResumeTask(pCallingTask, Status, pSR); } } else { if (pCallingTask != NULL) { RmPendTaskOnOtherTask( pCallingTask, SuspendCode, pTask, pSR ); } (void)RmStartTask(pTask, 0, pSR); } } VOID arpDeinitDestination( PARPCB_DEST pDest, // NOLOCKIN NOLOCKOUT MYBOOL fOnlyIfUnused, PRM_STACK_RECORD pSR ) /*++ Routine Description: Initate the unload of destination pDest. If fOnlyIfUnused is TRUE, then only do this if there are no local or remote IPs pointing to it. NOTE: it's possible that some pLocal/pRemoteIps may be linked to pDest AFTER we've decided to deinit pDest. Tough luck -- in this unlikely event, we'll unload this pDest, and the unlinked pLocals/pRemotes will have to re-figure who to link to. --*/ { ENTER("DeinitDestination", 0xc61b8f82) PRM_TASK pTask; NDIS_STATUS Status; RM_ASSERT_NOLOCKS(pSR); if (fOnlyIfUnused) { // // We don't deinit the destination if there are local or remote ip's // linked to it, OR if it is the broadcast channel. // LOCKOBJ(pDest, pSR); if ( !IsListEmpty(&pDest->listLocalIp) || !IsListEmpty(&pDest->listIpToThisDest) || pDest == ((PARP1394_INTERFACE) RM_PARENT_OBJECT(pDest)) ->pBroadcastDest) { UNLOCKOBJ(pDest, pSR); return; // ********* EARLY RETURN ********** } UNLOCKOBJ(pDest, pSR); } #if DBG if (pDest->Params.HwAddr.AddressType == NIC1394AddressType_FIFO) { PUCHAR puc = (PUCHAR) &pDest->Params.HwAddr.FifoAddress; TR_WARN(("Deiniting Destination: FIFO %02lx-%02lx-%02lx-%02lx-%02lx-%02lx-%02lx-%02lx.\n", puc[0], puc[1], puc[2], puc[3], puc[4], puc[5], puc[6], puc[7])); } else if (pDest->Params.HwAddr.AddressType == NIC1394AddressType_Channel) { TR_WARN(("Deiniting Destination: Channel %lu.\n", pDest->Params.HwAddr.Channel)); } #endif // DBG Status = arpAllocateTask( &pDest->Hdr, // pParentObject, arpTaskUnloadDestination, // pfnHandler, 0, // Timeout, "Task: Unload Dest", // szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pDest, ("FATAL: couldn't alloc unload dest task!\n")); } else { (VOID) RmStartTask( pTask, 0, // UserParam (unused) pSR ); } } VOID arpDeactivateIf( PARP1394_INTERFACE pIF, PRM_TASK pCallingTask, // OPTIONAL UINT SuspendCode, // OPTIONAL PRM_STACK_RECORD pSR ) /*++ Routine Description: Initiate the asynchronous deactivation of pIF. "Deactivation" consists of tearing down any activity and handles associated with this IF. The IF will remain allocated linked to the adapter. NO locks must be held on entrance and none are held on exit. Arguments: pIF - Interface to unload. pCallingTask - Optional task to suspend if deactivation is completing async. SuspendCode - SuspendCode for the above task. --*/ { PRM_TASK pTask; NDIS_STATUS Status; // // NOTE: We could check to see if pIF can be synchronously deactivated, // and if so deactivate it right here. We don't bother because that's just // more code, and with dubious perf benefit. // RM_ASSERT_NOLOCKS(pSR); Status = arpAllocateTask( &pIF->Hdr, // pParentObject, arpTaskDeactivateInterface, // pfnHandler, 0, // Timeout, "Task: DeactivateInterface",// szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pIF, ("FATAL: couldn't alloc deactivate IF task!\n")); ASSERT(FALSE); if (pCallingTask != NULL) { RmSuspendTask(pCallingTask, SuspendCode, pSR); RmResumeTask(pCallingTask, Status, pSR); } } else { if (pCallingTask != NULL) { RmPendTaskOnOtherTask( pCallingTask, SuspendCode, pTask, pSR ); } (void)RmStartTask(pTask, 0, pSR); } } NDIS_STATUS arpCreateInterface( IN PARP1394_ADAPTER pAdapter, // LOCKIN LOCKOUT OUT PARP1394_INTERFACE *ppIF, IN PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocates and performs basic initialization of an interface object. The interface object subsequently needs to be initialized by the starting the initialization task before it is completely initialized. *ppIF shares the same lock as it's parent, pAdapter. Arguments: pAdapter - Adapter that will own the interface. ppIF - Place to store the allocated interface. Return Value: NDIS_STATUS_SUCCESS on successful allocation and initialization of the interface. NDIS failure code on failure. --*/ { NDIS_STATUS Status; ARP1394_INTERFACE *pIF; ENTER("arpCreateInterface", 0x938c36ff) RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR); do { Status = ARP_ALLOCSTRUCT(pIF, MTAG_INTERFACE); if (Status != NDIS_STATUS_SUCCESS || pIF == NULL) { Status = NDIS_STATUS_RESOURCES; break; } ARP_ZEROSTRUCT(pIF); RmInitializeHeader( &(pAdapter->Hdr), // pParentObject &pIF->Hdr, MTAG_INTERFACE, &pAdapter->Lock, &ARP1394_INTERFACE_StaticInfo, NULL, // szDescription pSR ); // Note arpInitializeIfPools expects pIF to be locked. We know it's locked // because it shares the same lock as it's parent, and the parent is lozked. // Status = arpInitializeIfPools(pIF, pSR); if (FAIL(Status)) { RmDeallocateObject( &(pIF->Hdr), pSR ); pIF = NULL; break; } // // Intialize the various groups in the interface... // RmInitializeGroup( &pIF->Hdr, // pOwningObject &ArpGlobal_LocalIpStaticInfo, &(pIF->LocalIpGroup), "LocalIp group", // szDescription pSR ); RmInitializeGroup( &pIF->Hdr, // pOwningObject &ArpGlobal_RemoteIpStaticInfo, &(pIF->RemoteIpGroup), "RemoteIp group", // szDescription pSR ); RmInitializeGroup( &pIF->Hdr, // pOwningObject &ArpGlobal_RemoteEthStaticInfo, &(pIF->RemoteEthGroup), "RemoteEth group", // szDescription pSR ); RmInitializeGroup( &pIF->Hdr, // pOwningObject &ArpGlobal_DhcpTableStaticInfo, &(pIF->EthDhcpGroup), "Eth Dhcp group", // szDescription pSR ); RmInitializeGroup( &pIF->Hdr, // pOwningObject &ArpGlobal_DestinationStaticInfo, &(pIF->DestinationGroup), "Destination group", // szDescription pSR ); // // Cache the adapter handle. // pIF->ndis.AdapterHandle = pAdapter->bind.AdapterHandle; // TODO -- put the real IP MTU (based on adapter info and config info) // pIF->ip.MTU = ARP1394_ADAPTER_MTU-16; // Bytes ('-16' accounts for // the encapsulation header. // 16 is overkill: 4 should // be enough.) // Init stuff in pIF->sendinfo (the const header pools were initialized // earlier, because their initialization could fail). // RmInitializeLock(&pIF->sendinfo.Lock, LOCKLEVEL_IF_SEND); InitializeListHead(&pIF->sendinfo.listPktsWaitingForHeaders); arpResetIfStats(pIF, pSR); pIF->ip.ATInstance = INVALID_ENTITY_INSTANCE; pIF->ip.IFInstance = INVALID_ENTITY_INSTANCE; pIF->ip.BroadcastAddress = 0xFFFFFFFF; // Defaults to all-1's. // // Do any other non-failure-prone initialization here. // } while (FALSE); *ppIF = pIF; EXIT() return Status; } VOID arpDeleteInterface( IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT (adapter lock) IN PRM_STACK_RECORD pSR ) { ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF); RM_ASSERT_OBJLOCKED(&pAdapter->Hdr, pSR); // We expect that the adapter has already removed it's reference to pIF. // ASSERT(pAdapter->pIF != pIF); // Deinitialize all the groups in the IF ... // RmDeinitializeGroup(&(pIF->LocalIpGroup), pSR); RmDeinitializeGroup(&(pIF->RemoteIpGroup), pSR); RmDeinitializeGroup(&(pIF->RemoteEthGroup), pSR); RmDeinitializeGroup(&(pIF->DestinationGroup), pSR); RmDeinitializeGroup(&(pIF->EthDhcpGroup),pSR); // Deinit the various pools associated with pIF. // arpDeInitializeIfPools(pIF, pSR); // Verify that everything is truly done... // ASSERTEX(pIF->pPrimaryTask == NULL, pIF); ASSERTEX(pIF->pActDeactTask == NULL, pIF); ASSERTEX(pIF->ip.Context == NULL, pIF); ASSERTEX(pIF->ndis.AfHandle == NULL, pIF); // Add any other checks you want here... // Deallocate the IF // RmDeallocateObject( &(pIF->Hdr), pSR ); } VOID arpResetIfStats( IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT IN PRM_STACK_RECORD pSR ) { ENTER("arpResetIfStats", 0x3eb52cda) RM_ASSERT_OBJLOCKED(&pIF->Hdr, pSR); // Zero stats // // ARP_ZEROSTRUCT(&(pIF->stats)); // Set the timestamp indicating start of stats collection. // NdisGetCurrentSystemTime(&(pIF->stats.StatsResetTime)); // Get the perf counter frequency (we don't need to do this each time, but // why bother special casing.) // (VOID) KeQueryPerformanceCounter(&(pIF->stats.PerformanceFrequency)); EXIT() } NDIS_STATUS arpInitializeVc( PARP1394_INTERFACE pIF, PARP_STATIC_VC_INFO pVcInfo, PRM_OBJECT_HEADER pOwner, PARP_VC_HEADER pVcHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Initialize the Vc Header; Allocate the NdisVcHandle; Arguments: pIF - Interface this applies to pVcInfo - Static info about this VC pOwner - Owning object (for referencing) pVcHdr - Protocol Vc context to initialize --*/ { NDIS_STATUS Status; NDIS_HANDLE NdisVcHandle; ENTER("arpInitializeVc", 0x36fe9837) // (DEBUG ONLY) Verify that all fields are already zero. // TODO: We don't assert that pVcHdr->pMakeCallTask == NULL, because // it's already set on entry -- we should clean up the semantics of // arpInitializeVc. // ASSERT ( pVcHdr->pStaticInfo == NULL && pVcHdr->NdisVcHandle == NULL && pVcHdr->pCleanupCallTask == NULL ); NdisVcHandle = NULL; // Try to create Ndis VC // Status = NdisCoCreateVc( pIF->ndis.AdapterHandle, pIF->ndis.AfHandle, (NDIS_HANDLE) pVcHdr, // ProtocolVcContext, &NdisVcHandle ); if (FAIL(Status)) { TR_WARN(("Couldn't create VC handle\n")); pVcHdr->NdisVcHandle = NULL; } else { pVcHdr->pStaticInfo = pVcInfo; pVcHdr->NdisVcHandle = NdisVcHandle; // Link-to-external pOwningObject to the ndis-vc handle. // #if RM_EXTRA_CHECKING #define szARPASSOC_EXTLINK_TO_NDISVCHANDLE " Linked to NdisVcHandle 0x%p\n" RmLinkToExternalEx( pOwner, // pHdr 0xb57e657b, // LUID (UINT_PTR) NdisVcHandle, // External entity ARPASSOC_EXTLINK_TO_NDISVCHANDLE, // AssocID szARPASSOC_EXTLINK_TO_NDISVCHANDLE, pSR ); #else // !RM_EXTRA_CHECKING RmLinkToExternalFast(pOwner); #endif // !RM_EXTRA_CHECKING } EXIT() return Status; } VOID arpDeinitializeVc( PARP1394_INTERFACE pIF, PARP_VC_HEADER pVcHdr, PRM_OBJECT_HEADER pOwner, // NOLOCKIN NOLOCKOUT PRM_STACK_RECORD pSR ) /*++ Routine Description: DeInitialize the Vc Header; Deallocate the NdisVcHandle; Arguments: pIF - Interface this applies to pOwner - Owning object (for de-referencing) pVcHdr - Protocol Vc context to de-initialize --*/ { ENTER("arpDeinitializeVc", 0x270b29ac) NDIS_HANDLE NdisVcHandle; RM_ASSERT_NOLOCKS(pSR); LOCKHDR(pOwner, pSR); // (DEBUG ONLY) Verify that there is no make-call or close-call task. // ASSERT( pVcHdr->pMakeCallTask == NULL && pVcHdr->pCleanupCallTask == NULL ); NdisVcHandle = pVcHdr->NdisVcHandle; // Zero out the structure. // ARP_ZEROSTRUCT(pVcHdr); UNLOCKHDR(pOwner, pSR); RM_ASSERT_NOLOCKS(pSR); // Delete the Link-to-external pOwningObject to the ndis-vc handle. // #if RM_EXTRA_CHECKING RmUnlinkFromExternalEx( pOwner, // pHdr 0xee1b4fe3, // LUID (UINT_PTR) NdisVcHandle, // External entity ARPASSOC_EXTLINK_TO_NDISVCHANDLE, // AssocID pSR ); #else // !RM_EXTRA_CHECKING RmUnlinkFromExternalFast(pOwner); #endif // !RM_EXTRA_CHECKING // Delete the ndis vc handle. // NdisCoDeleteVc(NdisVcHandle); EXIT() } UINT arpRecvFifoReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) /*++ HOT PATH --*/ { PARP_VC_HEADER pVcHdr; PARP1394_INTERFACE pIF; pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pIF = CONTAINING_RECORD( pVcHdr, ARP1394_INTERFACE, recvinfo.VcHdr); ASSERT_VALID_INTERFACE(pIF); return arpProcessReceivedPacket( pIF, pNdisPacket, FALSE // IsChannel ); } VOID arpRecvFifoIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ) { PARP_VC_HEADER pVcHdr; PARP1394_INTERFACE pIF; RM_DECLARE_STACK_RECORD(sr) pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pIF = CONTAINING_RECORD( pVcHdr, ARP1394_INTERFACE, recvinfo.VcHdr); ASSERT_VALID_INTERFACE(pIF); // // This is the IF receive FIFO VC. For now, geting an incoming close on // the receive FIFO vc results in our initiating the deinit of pIF. // OBJLOG1(pIF,"Got incoming close on recv FIFO!. Status=0x%lx\n", CloseStatus); (VOID) arpDeinitIf( pIF, NULL, // pCallingTask 0, // SuspendCode &sr ); RM_ASSERT_CLEAR(&sr); } VOID arpBroadcastChannelIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ) { PARP_VC_HEADER pVcHdr; PARP1394_INTERFACE pIF; ARPCB_DEST * pDest; RM_DECLARE_STACK_RECORD(sr) pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pDest = CONTAINING_RECORD( pVcHdr, ARPCB_DEST, VcHdr); ASSERT_VALID_DEST(pDest); pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); // // Since all our calls are outgoing, getting an IncomingClose means that // the call was in the active state. Anyway, what we need to do is update the // call state and start the VcCleanupTask for this Vc. // // // This is the broadcast channel VC. // FOR NOW: we leave the IF alone, but deinit the dest-VC. // OBJLOG1(pDest,"Got incoming close! Status=0x%lx\n", CloseStatus); LOGSTATS_IncomingClosesOnChannels(pIF); (VOID) arpDeinitDestination(pDest, FALSE, &sr); // FALSE == force deinit RM_ASSERT_CLEAR(&sr); } UINT arpProcessReceivedPacket( IN PARP1394_INTERFACE pIF, IN PNDIS_PACKET pNdisPacket, IN MYBOOL IsChannel ) { ENTER("arpProcessReceivedPacket", 0xe317990b) UINT TotalLength; // Total bytes in packet PNDIS_BUFFER pNdisBuffer; // Pointer to first buffer UINT BufferLength; UINT ReturnCount; PVOID pvPktHeader; PNIC1394_ENCAPSULATION_HEADER pEncapHeader; const UINT MacHeaderLength = sizeof(NIC1394_ENCAPSULATION_HEADER); ARP1394_ADAPTER * pAdapter = (ARP1394_ADAPTER*) RM_PARENT_OBJECT(pIF); BOOLEAN fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter); DBGMARK(0x2361f585); ReturnCount = 0; NdisQueryPacket( pNdisPacket, NULL, NULL, &pNdisBuffer, &TotalLength ); if (TotalLength > 0) { NdisQueryBuffer( pNdisBuffer, (PVOID *)&pvPktHeader, &BufferLength ); } else { pvPktHeader = NULL; BufferLength = 0; } pEncapHeader = (PNIC1394_ENCAPSULATION_HEADER) pvPktHeader; TR_INFO( ("Rcv: NDISpkt 0x%x, NDISbuf 0x%x, Buflen %d, Totlen %d, Pkthdr 0x%x\n", pNdisPacket, pNdisBuffer, BufferLength, TotalLength, pvPktHeader)); // TODO -- we include mcap/arp in InOctets below, is this the right thing? // ARP_IF_STAT_ADD(pIF, InOctets, TotalLength); LOGSTATS_TotRecvs(pIF, pNdisPacket); if (IsChannel) { LOGSTATS_RecvChannelCounts(pIF, pNdisPacket); } else { LOGSTATS_RecvFifoCounts(pIF, pNdisPacket); } if (BufferLength < MacHeaderLength || pvPktHeader == NULL) { // Packet is too small, discard. // ARP_IF_STAT_INCR(pIF, InDiscards); return 0; // EARLY RETURN } if (fBridgeMode) { arpEthReceive1394Packet( pIF, pNdisPacket, pvPktHeader, BufferLength, IsChannel ); return 0; // ********* EARLY RETURN ******* } // // Discard the packet if the IP interface is not open // if (!CHECK_IF_IP_STATE(pIF, ARPIF_IPS_OPEN)) { TR_INFO(("Discardning received pkt because pIF 0x%p IP IF is not open.\n", pIF)); return 0; // ********* EARLY RETURN ******* } // // At this point, pEncapHeader contains the IP/1394 unfragmented encapsulation // header. We look at the ethertype to decide what to do with it. // if (pEncapHeader->EtherType == H2N_USHORT(NIC1394_ETHERTYPE_IP)) { // // The EtherType is IP, so we pass up this packet to the IP layer. // (Also we indicate all packets we receive on the broadcast channel // to the ethernet VC). // TR_INFO( ("Rcv: pPkt 0x%x: EtherType is IP, passing up.\n", pNdisPacket)); if (IsChannel) { ARP_IF_STAT_INCR(pIF, InNonUnicastPkts); } else { ARP_IF_STAT_INCR(pIF, InUnicastPkts); } if (NDIS_GET_PACKET_STATUS(pNdisPacket) != NDIS_STATUS_RESOURCES) { UINT DataSize; #define ARP_MIN_1ST_RECV_BUFSIZE 512 // // Following are notes taken from atmarpc.sys sources... // // 2/8/1998 JosephJ // We set DataSize to the total payload size, // unless the first buffer is too small to // hold the IP header. In the latter case, // we set DataSize to be the size of the 1st buffer // (minus the LLS/SNAP header size). // // This is to work around a bug in tcpip. // // 2/25/1998 JosephJ // Unfortunately we have to back out YET AGAIN // because large pings (eg ping -l 4000) doesn't // work -- bug#297784 // Hence the "0" in "0 && DataSize" below. // Take out the "0" to put back the per fix. // // // Note: MacHeaderLength is the TOTAL size of the stuff before the // start of the IP pkt. This includes the size of the encapsulation // header plus (for channels only) the size of the GASP header. // DataSize = BufferLength - MacHeaderLength; { LOGSTATS_CopyRecvs(pIF, pNdisPacket); } pIF->ip.RcvPktHandler( pIF->ip.Context, (PVOID)((PUCHAR)pEncapHeader+sizeof(*pEncapHeader)), // start of data DataSize, TotalLength, (NDIS_HANDLE)pNdisPacket, MacHeaderLength, IsChannel, 0, pNdisBuffer, &ReturnCount, NULL ); } else { LOGSTATS_ResourceRecvs(pIF, pNdisPacket); pIF->ip.RcvHandler( pIF->ip.Context, (PVOID)((PUCHAR)pEncapHeader+sizeof(*pEncapHeader)), BufferLength - MacHeaderLength, TotalLength - MacHeaderLength, (NDIS_HANDLE)pNdisPacket, MacHeaderLength, IsChannel, NULL ); } } else if (pEncapHeader->EtherType == H2N_USHORT(NIC1394_ETHERTYPE_ARP)) { PIP1394_ARP_PKT pArpPkt = (PIP1394_ARP_PKT) pEncapHeader; if (TotalLength != BufferLength) { ASSERT(!"Can't deal with TotalLength != BufferLength"); } else { arpProcessArpPkt( pIF, pArpPkt, BufferLength ); } } else if (pEncapHeader->EtherType == H2N_USHORT(NIC1394_ETHERTYPE_MCAP)) { PIP1394_MCAP_PKT pMcapPkt = (PIP1394_MCAP_PKT) pEncapHeader; if (TotalLength != BufferLength) { ASSERT(!"Can't deal wiht TotalLength != BufferLength"); } else { arpProcessMcapPkt( pIF, pMcapPkt, BufferLength ); } } else { // // Discard packet -- unknown/bad EtherType // TR_INFO(("Encap hdr 0x%x, bad EtherType 0x%x\n", pEncapHeader, pEncapHeader->EtherType)); ARP_IF_STAT_INCR(pIF, UnknownProtos); } EXIT() return ReturnCount; } NDIS_STATUS arpInitializeIfPools( IN PARP1394_INTERFACE pIF, IN PRM_STACK_RECORD pSR ) /*++ Routine Description: This routine is called in the context of creating an interface. It allocate the various buffer and packet pools associated with the interface. It cleans up all pools on failure. Arguments: pIF - Interface to initialize Return Value: NDIS_STATUS_SUCCESS on success Ndis failure code otherwise. --*/ { ENTER("arpInitializeIfPools", 0x0a3b1b32) MYBOOL fHeaderPoolInitialized = FALSE; MYBOOL fPacketPoolInitialized = FALSE; MYBOOL fEthernetPoolsInitialized = FALSE; NDIS_STATUS Status; do { // TODO: replace 10, 100, by constants, or perhaps global vars. Status = arpInitializeConstBufferPool( 10, //NumBuffersToCache, 100, //MaxBuffers, &Arp1394_IpEncapHeader, //pvMem, sizeof(Arp1394_IpEncapHeader), //cbMem, &pIF->Hdr, &pIF->sendinfo.HeaderPool, pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "Couldn't initialize const header pool (Status=0x%lx)!\n", Status ); break; } fHeaderPoolInitialized = TRUE; Status = arpAllocateControlPacketPool( pIF, ARP1394_MAX_PROTOCOL_PACKET_SIZE, pSR ); if (FAIL(Status)) { TR_WARN(( "Couldn't allocate control packet pool (Status=0x%lx)!\n", Status )); break; } fPacketPoolInitialized = TRUE; Status = arpAllocateEthernetPools( pIF, pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "Couldn't allocate ethernet packet pool (Status=0x%lx)!\n", Status ); break; } fEthernetPoolsInitialized = TRUE; } while (FALSE); if (FAIL(Status)) { if (fHeaderPoolInitialized) { // Deinit the header const buffer pool. // arpDeinitializeConstBufferPool(&pIF->sendinfo.HeaderPool, pSR); } if (fPacketPoolInitialized) { // Deinit the control packet pool // arpFreeControlPacketPool( pIF,pSR); } if (fEthernetPoolsInitialized) { // Deinit the ethernet packet pool // arpFreeEthernetPools(pIF, pSR); } } else { ASSERT(fHeaderPoolInitialized && fPacketPoolInitialized); ASSERT(fEthernetPoolsInitialized); } return Status; } VOID arpDeInitializeIfPools( IN PARP1394_INTERFACE pIF, // LOCKIN LOCKOUT IN PRM_STACK_RECORD pSR ) /*++ Routine Description: This routine is called in the context of deleting an interface. It cleans up the various buffer and packet pools associated with the interface. Should NOT be called with a partially-initialized pIF. Arguments: pIF - Interface to deinit pools --*/ { ENTER("arpDeInitializeIfPools", 0x1a54488d) RM_ASSERT_OBJLOCKED(&pIF->Hdr, pSR); // Deinit the header const buffer pool. // arpDeinitializeConstBufferPool(&pIF->sendinfo.HeaderPool, pSR); // Deinit the control packet pool // arpFreeControlPacketPool(pIF,pSR); // Deinit the ethernet packet and buffer pool // arpFreeEthernetPools(pIF,pSR); } MYBOOL arpIsAdapterConnected( IN PARP1394_ADAPTER pAdapter, // NOLOCKIN NOLOCKOUT IN PRM_STACK_RECORD pSR ) { ENTER("arpIsAdapterConnected", 0x126b577a) // static UINT u = 0; MYBOOL fRet; ARP_NDIS_REQUEST ArpNdisRequest; NDIS_MEDIA_STATE ConnectStatus; NDIS_STATUS Status; RM_ASSERT_NOLOCKS(pSR); #if 0 if (u==0) { fRet = FALSE; u=1; } else { fRet = TRUE; } #else // !0 Status = arpPrepareAndSendNdisRequest( pAdapter, &ArpNdisRequest, NULL, // pTask (NULL==BLOCK) 0, // unused OID_1394_IP1394_CONNECT_STATUS, &ConnectStatus, sizeof(ConnectStatus), NdisRequestQueryInformation, pSR ); ASSERT(!PEND(Status)); fRet = FALSE; if (!FAIL(Status)) { if (ConnectStatus == NdisMediaStateConnected) { fRet = TRUE; } } #endif // !0 RM_ASSERT_NOLOCKS(pSR); EXIT() return fRet; } NDIS_STATUS arpSetupSpecialDest( IN PARP1394_INTERFACE pIF, IN NIC1394_ADDRESS_TYPE AddressType, IN PRM_TASK pParentTask, IN UINT PendCode, OUT PARPCB_DEST * ppSpecialDest, IN PRM_STACK_RECORD pSR ) { ENTER("SetupSpecialDest", 0x745a806d) ARP_DEST_PARAMS DestParams; PCHAR szDescription; PARPCB_DEST pDest; INT fCreated = FALSE; PRM_TASK pMakeCallTask; NDIS_STATUS Status; MYBOOL fBroadcastDest = FALSE; ULONG LookupFlags = 0; PARP1394_ADAPTER pAdapter = (PARP1394_ADAPTER)RM_PARENT_OBJECT(pIF); *ppSpecialDest = NULL; // // Let's create a destination object representing the // multichannel, and make a call to it. // ARP_ZEROSTRUCT(&DestParams); DestParams.HwAddr.AddressType = AddressType; switch(AddressType) { case NIC1394AddressType_Channel: DestParams.HwAddr.Channel = NIC1394_BROADCAST_CHANNEL; fBroadcastDest = TRUE; szDescription = "Task: Broadcast MakeCall"; break; case NIC1394AddressType_MultiChannel: szDescription = "Task: MultiChannel MakeCall"; break; case NIC1394AddressType_Ethernet: szDescription = "Task: Ethernet MakeCall"; break; default: ASSERT(FALSE); return NDIS_STATUS_FAILURE; // ****** EARLY RETURN ***** } #if RM_EXTRA_CHECKING switch(AddressType) { case NIC1394AddressType_Channel: szDescription = "Task: Broadcast MakeCall"; break; case NIC1394AddressType_MultiChannel: szDescription = "Task: MultiChannel MakeCall"; break; case NIC1394AddressType_Ethernet: szDescription = "Task: Ethernet MakeCall"; break; default: ASSERT(FALSE); return NDIS_STATUS_FAILURE; // ****** EARLY RETURN ***** } #endif // RM_EXTRA_CHECKING // Now create a destination item for this structure. // if (CHECK_POWER_STATE(pAdapter,ARPAD_POWER_LOW_POWER) == TRUE) { // In the resume, the Destination structures are aleady there // so don't create a new one. LookupFlags = 0; } else { // // We don't expect it to already exist in the non PM case // LookupFlags = RM_CREATE | RM_NEW; } Status = RmLookupObjectInGroup( &pIF->DestinationGroup, LookupFlags , &DestParams, // Key &DestParams, // pParams (RM_OBJECT_HEADER**) &pDest, &fCreated, pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "FATAL: Couldn't create special dest type %d.\n", AddressType); } else { Status = arpAllocateTask( &pDest->Hdr, // pParentObject arpTaskMakeCallToDest, // pfnHandler 0, // Timeout szDescription, &pMakeCallTask, pSR ); if (FAIL(Status)) { RmTmpDereferenceObject(&pDest->Hdr, pSR); // NOTE: Even on failure, we leave the newly-created // special dest object. It will get cleaned up when // the interface is unloaded. // } else { *ppSpecialDest = pDest; if (fBroadcastDest) { // pDest 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, &pDest->Hdr, 0xacc1dbe9, ARPASSOC_LINK_IF_OF_BCDEST, " IF of Broadcast Dest 0x%p (%s)\n", ARPASSOC_LINK_BCDEST_OF_IF, " Broadcast Dest of IF 0x%p (%s)\n", pSR ); #else // !RM_EXTRA_CHECKING RmLinkObjects(&pIF->Hdr, &pDest->Hdr,pSR); #endif // !RM_EXTRA_CHECKING LOCKOBJ(pIF, pSR); ASSERT(pIF->pBroadcastDest == NULL); pIF->pBroadcastDest = pDest; UNLOCKOBJ(pIF, pSR); // arpSetupSpecialDest ref'd pDest. // RmTmpDereferenceObject(&pDest->Hdr, pSR); } RmPendTaskOnOtherTask( pParentTask, PendCode, pMakeCallTask, pSR ); (VOID)RmStartTask( pMakeCallTask, 0, // UserParam (unused) pSR ); Status = NDIS_STATUS_PENDING; } } return Status; } VOID arpDestSendComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) { PARP_VC_HEADER pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; PARPCB_DEST pDest = CONTAINING_RECORD(pVcHdr, ARPCB_DEST, VcHdr); PARP1394_INTERFACE pIF = (PARP1394_INTERFACE) RM_PARENT_OBJECT(pDest); ASSERT_VALID_DEST(pDest); ASSERT_VALID_INTERFACE(pIF); // The call to NdisCoSendPacket returns. arpCompleteSentPkt( Status, pIF, pDest, pNdisPacket ); } UINT arpDestReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET pNdisPacket ) // // Standard Recv Handler for most Vcs // { PARP_VC_HEADER pVcHdr; PARPCB_DEST pDest; PARP1394_INTERFACE pIF; PARP1394_ADAPTER pAdapter ; BOOLEAN fBridgeMode ; pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pDest = CONTAINING_RECORD( pVcHdr, ARPCB_DEST, VcHdr); ASSERT_VALID_DEST(pDest); pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); ASSERT_VALID_INTERFACE(pIF); pAdapter = (PARP1394_ADAPTER)pIF->Hdr.pParentObject; fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter); // // if we are in bridge mode, then check to see if // this is a loopback packet // if (fBridgeMode == TRUE) { PLOOPBACK_RSVD pLoopbackRsvd = (PLOOPBACK_RSVD) pNdisPacket->ProtocolReserved; BOOLEAN fIsLoopbackPacket = (pLoopbackRsvd->LoopbackTag == NIC_LOOPBACK_TAG); if (fIsLoopbackPacket == TRUE) { // drop the packet as it is a loopback packet return 0; } // else it is a normal receive. continue to arpProcessReceivedPacket } // // Process the receive packet // return arpProcessReceivedPacket( pIF, pNdisPacket, TRUE // IsChannel ); } VOID arpDestIncomingClose( IN NDIS_STATUS CloseStatus, IN NDIS_HANDLE ProtocolVcContext, IN PVOID pCloseData OPTIONAL, IN UINT Size OPTIONAL ) { PARP_VC_HEADER pVcHdr; PARP1394_INTERFACE pIF; ARPCB_DEST * pDest; ENTER("arpDestIncomingClose",0x8727a7f1) RM_DECLARE_STACK_RECORD(sr) pVcHdr = (PARP_VC_HEADER) ProtocolVcContext; pDest = CONTAINING_RECORD( pVcHdr, ARPCB_DEST, VcHdr); ASSERT_VALID_DEST(pDest); pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDest); // // Since all our calls are outgoing, getting an IncomingClose means that // the call was in the active state. Anyway, what we need to do is update the // call state and start the VcCleanupTask for this Vc. // // // We leave the IF alone, but deinit the dest-VC. // OBJLOG1(pDest,"Got incoming close! Status=0x%lx\n", CloseStatus); LOGSTATS_IncomingClosesOnChannels(pIF); { ARP1394_ADAPTER *pAdapter = (ARP1394_ADAPTER*)RM_PARENT_OBJECT(pIF); BOOLEAN fBridgeMode = ARP_BRIDGE_ENABLED(pAdapter); NDIS_STATUS Status = NDIS_STATUS_FAILURE; // // If the Bridge is enabled, then just close the call on the destination. // In the normal case, we delete the destintation structure. if (fBridgeMode == TRUE) { PRM_TASK pCleanupCallTask = NULL; // // In the Bridgecase we want to keep alive our knowledge // about the 1394 network as we // can only learn this knowledge from Ethernet arps // which are outside our control. // // // AN incoming close signifies that the Remote Node that this Dest // represents has gone away. We want to keep the Dest structure alive // in case the other node resumes from standby/ hibernate and // does not send out any ARPs so we cannot learn its address. // // Status = arpAllocateTask( &pDest->Hdr, // pParentObject, arpTaskCleanupCallToDest, // pfnHandler, 0, // Timeout, "Task: CleanupCall on UnloadDest", // szDescription &pCleanupCallTask, &sr ); if (FAIL(Status)) { TR_WARN(("FATAL: couldn't alloc cleanup call task!\n")); } else { // RmStartTask uses up the tmpref on the task // which was added by arpAllocateTask. // Status = RmStartTask( pCleanupCallTask, 0, // UserParam (unused) &sr ); } } else { (VOID) arpDeinitDestination(pDest, FALSE, &sr); // FALSE == forced deinit } } RM_ASSERT_CLEAR(&sr); } VOID arpTryAbortPrimaryIfTask( PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT PRM_STACK_RECORD pSR ) { ENTER("arpTryAbortPrimaryIfTask", 0x39c51d16) RM_ASSERT_NOLOCKS(pSR); LOCKOBJ(pIF,pSR); if (pIF->pActDeactTask!=NULL) { // // Actually // delayed. // PRM_TASK pTask = pIF->pActDeactTask; RmTmpReferenceObject(&pTask->Hdr, pSR); UNLOCKOBJ(pIF,pSR); if (pTask->pfnHandler == arpTaskActivateInterface) { TASK_ACTIVATE_IF *pActivateIfTask = (TASK_ACTIVATE_IF *) pTask; UINT TaskResumed; TR_WARN(("Aborting ActivateIfTask %p\n", pTask)); RmResumeDelayedTaskNow( &pActivateIfTask->TskHdr, &pActivateIfTask->Timer, &TaskResumed, pSR ); } RmTmpDereferenceObject(&pTask->Hdr, pSR); } else { UNLOCKOBJ(pIF,pSR); } RM_ASSERT_NOLOCKS(pSR); EXIT() } NDIS_STATUS arpTaskIfMaintenance( 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 periodic IF maintenance. Arguments: UserParam for (Code == RM_TASKOP_START) : unused --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARP1394_INTERFACE * pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pTask); PTASK_IF_MAINTENANCE pIfTask; enum { STAGE_Start, STAGE_ResumeDelayed, STAGE_End } Stage; ENTER("TaskIfMaintenance", 0x57e523ed) pIfTask = (PTASK_IF_MAINTENANCE) pTask; ASSERT(sizeof(TASK_IF_MAINTENANCE) <= sizeof(ARP1394_TASK)); // // 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 ** } ASSERTEX(!PEND(Status), pTask); switch(Stage) { case STAGE_Start: { // If there is already a maintenance task, we exit immediately. // LOCKOBJ(pIF, pSR); if (pIF->pMaintenanceTask == NULL) { pIF->pMaintenanceTask = pTask; DBG_ADDASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_MAINTENANCE_TASK, // AssociationID " Official maintenance task 0x%p (%s)\n", // szFormat pSR ); } else { // There already is a maintenance task. We're done. // UNLOCKOBJ(pIF, pSR); Status = NDIS_STATUS_SUCCESS; break; } UNLOCKOBJ(pIF, pSR); // // We're now the official maintenance task for this interface. // // We move on to the next stage, after a delay, and to get // out of the current context. // pIfTask->Delay = 5; // Arbitrary initial delay (seconds) RmSuspendTask(pTask, STAGE_ResumeDelayed, pSR); RmResumeTaskDelayed( pTask, 0, 1000 * pIfTask->Delay, &pIfTask->Timer, pSR ); Status = NDIS_STATUS_PENDING; } break; case STAGE_ResumeDelayed: { UINT Time; UINT Delta; MYBOOL fProcessed; // // If qe're quitting, we get out of here. // Otherwise we'll send a packet either on the ethernet VC // or via the miniport's connectionless ethernet interface. // if (pIfTask->Quit) { Status = NDIS_STATUS_SUCCESS; break; } Time = arpGetSystemTime(); // // Process the MCAP database // Delta = Time - pIfTask->McapDbMaintenanceTime; arpDoMcapDbMaintenance(pIF, Time, Delta, &fProcessed, pSR); if (fProcessed) { // // Update the last "McapDbMaintenance" time. // pIfTask->McapDbMaintenanceTime = Time; } // // Process Remote IPs // Delta = Time - pIfTask->RemoteIpMaintenanceTime; arpDoRemoteIpMaintenance(pIF, Time, Delta, &fProcessed, pSR); if (fProcessed) { // // Update the last "RemoteIpMaintenance" time. // pIfTask->RemoteIpMaintenanceTime = Time; } // // Process Remote Eths // Delta = Time - pIfTask->RemoteEthMaintenanceTime; arpDoRemoteEthMaintenance(pIF, Time, Delta, &fProcessed, pSR); if (fProcessed) { // // Update the last "RemoteIpMaintenance" time. // pIfTask->RemoteEthMaintenanceTime = Time; } // // Process Local IPs // Delta = Time - pIfTask->LocalIpMaintenanceTime; arpDoLocalIpMaintenance(pIF, Time, Delta, &fProcessed, pSR); if (fProcessed) { // // Update the last "LocalIpMaintenance" time. // pIfTask->LocalIpMaintenanceTime = Time; } // // Process DhcpTableEntries // Delta = Time - pIfTask->DhcpTableMaintainanceTime;; arpDoDhcpTableMaintenance(pIF, Time, Delta, &fProcessed, pSR); if (fProcessed) { // // Update the last "LocalIpMaintenance" time. // pIfTask->DhcpTableMaintainanceTime= Time; } // Now we wait again... // RmSuspendTask(pTask, STAGE_ResumeDelayed, pSR); RmResumeTaskDelayed( pTask, 0, 1000 * pIfTask->Delay, &pIfTask->Timer, pSR ); Status = NDIS_STATUS_PENDING; } break; case STAGE_End: { NDIS_HANDLE BindContext; LOCKOBJ(pIF, pSR); if (pIF->pMaintenanceTask == pTask) { // We're the official ics test task, we clear ourselves from // the interface object and do any initialization required. // DBG_DELASSOC( &pIF->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_IF_MAINTENANCE_TASK, // AssociationID pSR ); pIF->pMaintenanceTask = NULL; UNLOCKOBJ(pIF, pSR); } else { // We're not the official IF maintenance task. // Nothing else to do. // UNLOCKOBJ(pIF, pSR); break; } } break; default: { ASSERTEX(!"Unknown task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } VOID arpStartIfMaintenanceTask( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT PRM_STACK_RECORD pSR ) { PRM_TASK pTask; NDIS_STATUS Status; ENTER("arpStartIfMaintenanceTask", 0xb987276b) RM_ASSERT_NOLOCKS(pSR); // // Allocate and start an instance of the arpTaskIfMaintenance task. // Status = arpAllocateTask( &pIF->Hdr, // pParentObject arpTaskIfMaintenance, // pfnHandler 0, // Timeout "Task: IF Maintenance", // szDescription &pTask, pSR ); if (FAIL(Status)) { TR_WARN(("couldn't alloc IF maintenance task!\n")); } else { (VOID)RmStartTask( pTask, 0, // UserParam (unused) pSR ); } EXIT() } NDIS_STATUS arpTryStopIfMaintenanceTask( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN PRM_TASK pTask, // task to pend until M task completes IN UINT PendCode, // Pend code to suspend task. PRM_STACK_RECORD pSR ) /*++ Status : PENDING means task has been suspended, non PENDING means operation has completed synchronously. --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PTASK_IF_MAINTENANCE pIfTask; ENTER("arpTryStopIfMaintenanceTask", 0xb987276b) LOCKOBJ(pIF, pSR); pIfTask = (PTASK_IF_MAINTENANCE) pIF->pMaintenanceTask; if (pIfTask != NULL) { pIfTask->Quit = TRUE; RmTmpReferenceObject(&pIfTask->TskHdr.Hdr, pSR); } UNLOCKOBJ(pIF, pSR); // // Resume the maintenance task if it's waiting -- it will then quit // because we set the Quit field above. // if (pIfTask != NULL) { UINT TaskResumed; Status = RmPendTaskOnOtherTask( pTask, PendCode, &pIfTask->TskHdr, pSR ); if (Status == NDIS_STATUS_SUCCESS) { RmResumeDelayedTaskNow( &pIfTask->TskHdr, &pIfTask->Timer, &TaskResumed, pSR ); Status = NDIS_STATUS_PENDING; // We've GOT to return pending! } else { ASSERT(FALSE); Status = NDIS_STATUS_FAILURE; } RmTmpDereferenceObject(&pIfTask->TskHdr.Hdr, pSR); } RM_ASSERT_NOLOCKS(pSR) EXIT() return Status; } VOID arpDoLocalIpMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ) { ENTER("LocalIpMaintenance", 0x1a39fc89) if (SecondsSinceLastMaintenance < 10) { TR_INFO(("Skipping Local Ip maintenance (delay=%lu).\n", SecondsSinceLastMaintenance )); *pfProcessed = FALSE; return; // EARLY RETURN; } *pfProcessed = TRUE; TR_INFO(("Actually doing Local Ip maintenance.\n")); RmWeakEnumerateObjectsInGroup( &pIF->LocalIpGroup, arpMaintainOneLocalIp, NULL, // Context pSR ); EXIT() } VOID arpDoRemoteIpMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ) { ENTER("RemoteIpMaintenance", 0x1ae00035) if (SecondsSinceLastMaintenance < 15) { TR_INFO(("Skipping Remote Ip maintenance (delay=%lu).\n", SecondsSinceLastMaintenance )); *pfProcessed = FALSE; return; // EARLY RETURN; } *pfProcessed = TRUE; TR_INFO(("Actually doing Remote Ip maintenance.\n")); RmWeakEnumerateObjectsInGroup( &pIF->RemoteIpGroup, arpMaintainArpCache, NULL, // Context pSR ); EXIT() } VOID arpDoRemoteEthMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ) { ENTER("RemoteEthMaintenance", 0x6c496b7f) if (SecondsSinceLastMaintenance < 15) { TR_INFO(("Skipping Eth Ip maintenance (delay=%lu).\n", SecondsSinceLastMaintenance )); *pfProcessed = FALSE; return; // EARLY RETURN; } *pfProcessed = TRUE; TR_INFO(("Actually doing Remote Eth maintenance.\n")); RmWeakEnumerateObjectsInGroup( &pIF->RemoteEthGroup, arpMaintainOneRemoteEth, NULL, // Context pSR ); EXIT() } VOID arpDoDhcpTableMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ) { ENTER("DhcpMaintenance", 0x1a39fc89) if (SecondsSinceLastMaintenance < 120) { TR_INFO(("Skipping Local Ip maintenance (delay=%lu).\n", SecondsSinceLastMaintenance )); *pfProcessed = FALSE; return; // EARLY RETURN; } *pfProcessed = TRUE; TR_INFO(("Actually doing Dhcp maintenance.\n")); RmWeakEnumerateObjectsInGroup( &pIF->EthDhcpGroup, arpMaintainOneDhcpEntry, NULL, // Context pSR ); EXIT() } // Enum function // INT arpMaintainOneDhcpEntry( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ) { ENTER("arpMaintainOneDhcpEntry", 0xc7604372) NDIS_STATUS Status; ARP1394_ETH_DHCP_ENTRY *pEntry; PARP1394_INTERFACE pIF; pEntry = (ARP1394_ETH_DHCP_ENTRY *) pHdr; pIF = (PARP1394_INTERFACE )RM_PARENT_OBJECT (pEntry); RM_ASSERT_NOLOCKS(pSR); do { UINT CurrentTime = arpGetSystemTime(); #define ARP_PURGE_DHCP_TABLE_TIME 90 // Arp entry timeout. // // NOTE: we don't bother to get the lock with dealing with // sendinfo.TimeLastChecked -- this is ok. // if (pEntry->TimeLastChecked==0) { // Set this field to the current time. It will be cleared back to 0 // when the next packet is sent to this remote Eth. // pEntry->TimeLastChecked = CurrentTime; } else if ((CurrentTime - pEntry->TimeLastChecked) >= ARP_PURGE_DHCP_TABLE_TIME ) { // // We should clean up this dhcp entry. this is the only code path // from which an entry is ever deleted. // RmFreeObjectInGroup( &pIF->EthDhcpGroup, &(pEntry->Hdr), NULL, // NULL pTask == synchronous. pSR ); break; } } while (FALSE); RM_ASSERT_NOLOCKS(pSR) return TRUE; // Continue to enumerate. } // Enum function // INT arpMaintainOneLocalIp( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ) { ENTER("MaintainOneLocalIp", 0x1ae00035) PARPCB_LOCAL_IP pLocalIp; IP_ADDRESS LocalAddr; PARP1394_INTERFACE pIF; UINT Channel; pLocalIp = (PARPCB_LOCAL_IP) pHdr; LocalAddr = pLocalIp->IpAddress; pIF = IF_FROM_LOCALIP(pLocalIp); RM_ASSERT_NOLOCKS(pSR); do { ARPCB_DEST *pDest; ARP_DEST_PARAMS DestParams; // Skip if we can't do MCAP on this address. // LOCKOBJ(pLocalIp, pSR); if (!CHECK_LOCALIP_MCAP(pLocalIp, ARPLOCALIP_MCAP_CAPABLE)) { UNLOCKOBJ(pLocalIp, pSR); break; } UNLOCKOBJ(pLocalIp, pSR); // // Find a channel mapping to this address, if any. // Channel = arpFindAssignedChannel( pIF, LocalAddr, 0, // TODO -- pass in current time. pSR ); // // NOTE: Special return value NIC1394_BROADCAST_CHANNEL is returned if // this address is mapped to no specific channel. // ARP_ZEROSTRUCT(&DestParams); DestParams.HwAddr.AddressType = NIC1394AddressType_Channel; DestParams.HwAddr.Channel = Channel; DestParams.ReceiveOnly = TRUE; DestParams.AcquireChannel = FALSE; arpUpdateLocalIpDest(pIF, pLocalIp, &DestParams, pSR); } while (FALSE); RM_ASSERT_NOLOCKS(pSR) return TRUE; // Continue to enumerate. } // Enum function // INT arpMaintainOneRemoteIp( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ) #if 0 for each RIP send VC if !marked dirty mark dirty if linked to channel pdest check if channel is still mapped to group if not, unlink. if required initiate link to new pdest (possibly channel) else //expired unlink from pdest and get rid of it #endif // 0 { ENTER("MaintainOneRemoteIp", 0x1ae00035) NDIS_STATUS Status; PARPCB_REMOTE_IP pRemoteIp; PARP1394_INTERFACE pIF; pRemoteIp = (PARPCB_REMOTE_IP) pHdr; pIF = IF_FROM_LOCALIP(pRemoteIp); RM_ASSERT_NOLOCKS(pSR); do { IP_ADDRESS IpAddr; UINT Channel; ARP_DEST_PARAMS DestParams; ARPCB_DEST *pDest; BOOLEAN AcquireChannel; UINT CurrentTime = arpGetSystemTime(); IpAddr = pRemoteIp->Key.IpAddress; #define ARP_PURGE_REMOTEIP_TIME 300 // Arp entry timeout. // // NOTE: we don't bother to get the lock with dealing with // sendinfo.TimeLastChecked -- this is ok. // if (pRemoteIp->sendinfo.TimeLastChecked==0) { if (CHECK_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_DYNAMIC) || CHECK_REMOTEIP_RESOLVE_STATE (pRemoteIp, ARPREMOTEIP_UNRESOLVED)) { // Set this field to the current time. It will be cleared back to 0 // when the next packet is sent to this remote ip. // pRemoteIp->sendinfo.TimeLastChecked = CurrentTime; } } else if ((CurrentTime - pRemoteIp->sendinfo.TimeLastChecked) >= ARP_PURGE_REMOTEIP_TIME) { // // We should clean up this remote ip. // arpDeinitRemoteIp(pRemoteIp, pSR); break; } #if ARP_ENABLE_MCAP_SEND // // We'll now see if we need to re-set which destination this // pRemoteIp points to. // // Skip if we can't do MCAP on this address. // LOCKOBJ(pRemoteIp, pSR); if (!CHECK_REMOTEIP_MCAP(pRemoteIp, ARPREMOTEIP_MCAP_CAPABLE)) { UNLOCKOBJ(pRemoteIp, pSR); break; } UNLOCKOBJ(pRemoteIp, pSR); // // Find a channel mapping to this address, if any. // Channel = arpFindAssignedChannel( pIF, pRemoteIp->Key.IpAddress, 0, pSR ); // // NOTE: Special return value NIC1394_BROADCAST_CHANNEL is returned if // this address is mapped to no specific channel. // AcquireChannel = FALSE; #if 0 // Let's not enable this just yet -- instead if (Channel == NIC1394_BROADCAST_CHANNEL) { // // Hmm... let's get aggressive and try to grab a channel. // Channel = arpFindFreeChannel(pIF, pSR); if (Channel != NIC1394_BROADCAST_CHANNEL) { // // Got one! // AcquireChannel = TRUE; } } else { // // There is already a channel allocated by someone to be used // for this ip address. Let's use it. // } #endif // 0 ARP_ZEROSTRUCT(&DestParams); DestParams.HwAddr.AddressType = NIC1394AddressType_Channel; DestParams.HwAddr.Channel = Channel; DestParams.AcquireChannel = AcquireChannel; arpUpdateRemoteIpDest(pIF, pRemoteIp, &DestParams, pSR); #endif // ARP_ENABLE_MCAP_SEND } while (FALSE); RM_ASSERT_NOLOCKS(pSR) return TRUE; // Continue to enumerate. } // Enum function // INT arpMaintainOneRemoteEth( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ) { ENTER("MaintainOneRemoteEth", 0x21807796) NDIS_STATUS Status; PARPCB_REMOTE_ETH pRemoteEth; PARP1394_INTERFACE pIF; pRemoteEth = (PARPCB_REMOTE_ETH) pHdr; pIF = IF_FROM_LOCALIP(pRemoteEth); RM_ASSERT_NOLOCKS(pSR); do { UINT CurrentTime = arpGetSystemTime(); #define ARP_PURGE_REMOTEETH_TIME 300 // Arp entry timeout. // // NOTE: we don't bother to get the lock with dealing with // sendinfo.TimeLastChecked -- this is ok. // if (pRemoteEth->TimeLastChecked==0) { // Set this field to the current time. It will be cleared back to 0 // when the next packet is sent to this remote Eth. // pRemoteEth->TimeLastChecked = CurrentTime; } else if ((CurrentTime - pRemoteEth->TimeLastChecked) >= ARP_PURGE_REMOTEETH_TIME) { // // We should clean up this remote eth. // arpDeinitRemoteEth(pRemoteEth, pSR); break; } } while (FALSE); RM_ASSERT_NOLOCKS(pSR) return TRUE; // Continue to enumerate. } UINT arpFindAssignedChannel( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN IP_ADDRESS IpAddress, IN UINT CurrentTime, // OPTIONAL PRM_STACK_RECORD pSR ) /*++ NOTE: Special return value NIC1394_BROADCAST_CHANNEL is returned if this address is mapped to no specific channel. --*/ { ENTER("FindAssignedChannel", 0xd20a216b) UINT Channel = NIC1394_BROADCAST_CHANNEL; UINT u; LOCKOBJ(pIF, pSR); if (CurrentTime == 0) { CurrentTime = arpGetSystemTime(); } // // Run down the channel info array, looking for a matching IP address. // for (u = 0; u < ARP_NUM_CHANNELS; u++) { PMCAP_CHANNEL_INFO pMci; pMci = &pIF->mcapinfo.rgChannelInfo[u]; if ( IpAddress == pMci->GroupAddress && arpIsActiveMcapChannel(pMci, CurrentTime)) { ASSERT(pMci->Channel == u); Channel = u; TR_WARN(("Found Matching channel %lu for ip address 0x%lu.\n", Channel, IpAddress )); break; } } UNLOCKOBJ(pIF, pSR); return Channel; EXIT() } VOID arpUpdateLocalIpDest( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN PARPCB_LOCAL_IP pLocalIp, IN PARP_DEST_PARAMS pDestParams, PRM_STACK_RECORD pSR ) /*++ Make pLocalIp point to a des with params pDestParams. Create a pDest if required. If pLocalIp is pointing to some other pDest, cleanup that other pDest if no one else is refering to it. --*/ { ENTER("UpdateLocalIpDest", 0x3f2dcaa7) ARPCB_DEST *pOldDest = NULL; RM_ASSERT_NOLOCKS(pSR); // pLocalIp uses it's parent's (pIF's) lock. // RM_ASSERT_SAME_LOCK_AS_PARENT(pLocalIp); do { PCHAR szDescription; INT fCreated = FALSE; PRM_TASK pMakeCallTask; UINT Channel; NDIS_STATUS Status; ARPCB_DEST *pDest; // // Currently, only Channel Dests are supported. // if (pDestParams->HwAddr.AddressType != NIC1394AddressType_Channel) { ASSERT(FALSE); break; } else { Channel = pDestParams->HwAddr.Channel; } LOCKOBJ(pIF, pSR); RM_DBG_ASSERT_LOCKED(&pLocalIp->Hdr, pSR); // same lock as pIF; pDest = pLocalIp->pDest; if (pDest != NULL) { RM_DBG_ASSERT_LOCKED(&pDest->Hdr, pSR); // same lock as pIF; if (pDest->Params.HwAddr.AddressType == NIC1394AddressType_Channel) { if (pDest->Params.HwAddr.Channel == Channel) { // // We're already linked to this channel. Nothing more to do. // UNLOCKOBJ(pIF, pSR); break; } } else { // // Shouldn't get here -- MCAP_CAPABLE addresses shouldn't be // linked to non-channel destinations (for NOW anyway). // ASSERT(!"pLocalIp linked to non-channel pDest."); UNLOCKOBJ(pIF, pSR); break; } // // We're linked to some other pDest currently. We'll have // to unlink ourselves from pDest, and get rid of the other // pDest if no one is using it. // RmTmpReferenceObject(&pDest->Hdr, pSR); arpUnlinkLocalIpFromDest(pLocalIp, pSR); } pOldDest = pDest; pDest = NULL; ASSERT(pLocalIp->pDest == NULL); // // SPECIAL CASE: If the channel is the broadcast channel, we don't // need to do anything more, because the broadcast channel is always // active. // if (Channel == NIC1394_BROADCAST_CHANNEL) { UNLOCKOBJ(pIF, pSR); break; } // // Now link to a new dest and if required initiate a call on it. // // Now create a destination item for this structure. // Status = RmLookupObjectInGroup( &pIF->DestinationGroup, RM_CREATE, // Create if required pDestParams, // Key pDestParams, // pParams (RM_OBJECT_HEADER**) &pDest, &fCreated, pSR ); if (FAIL(Status)) { UNLOCKOBJ(pIF, pSR); OBJLOG1( pIF, "FATAL: Couldn't create local-ip dest type %d.\n", pDestParams->HwAddr.AddressType); break; } Status = arpAllocateTask( &pDest->Hdr, // pParentObject arpTaskMakeCallToDest, // pfnHandler 0, // Timeout "Task: MakeCallToDest (local ip)", &pMakeCallTask, pSR ); if (FAIL(Status)) { UNLOCKOBJ(pIF, pSR); // NOTE: Even on failure, we leave the newly-created // special dest object. It will get cleaned up when // the interface is unloaded. // } else { arpLinkLocalIpToDest(pLocalIp, pDest, pSR); UNLOCKOBJ(pIF, pSR); (VOID)RmStartTask( pMakeCallTask, 0, // UserParam (unused) pSR ); } RmTmpDereferenceObject(&pDest->Hdr, pSR); // Added by RmLookupObjectIn.. } while (FALSE); // // If required, get rid of pOldDest. // if (pOldDest != NULL) { arpDeinitDestination(pOldDest, TRUE, pSR); // TRUE == only if unused. RmTmpDereferenceObject(&pOldDest->Hdr, pSR); } RM_ASSERT_NOLOCKS(pSR); } UINT arpFindFreeChannel( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT PRM_STACK_RECORD pSR ) /*++ NOTE: Special return value NIC1394_BROADCAST_CHANNEL is returned if we couldn't find a free channel. Also there's no guarantee that this channel is really free. --*/ { ENTER("FindAssignedChannel", 0xd20a216b) UINT Channel = NIC1394_BROADCAST_CHANNEL; UINT u; LOCKOBJ(pIF, pSR); // // Run down the channel info array, looking for an empty slot. // for (u = 0; u < ARP_NUM_CHANNELS; u++) { PMCAP_CHANNEL_INFO pMci; pMci = &pIF->mcapinfo.rgChannelInfo[u]; if (pMci->GroupAddress == 0) { ASSERT(pMci->Channel == 0); // pMci->Channel = u; Channel = u; TR_WARN(("Found Free channel %lu.\n", Channel )); break; } } UNLOCKOBJ(pIF, pSR); return Channel; EXIT() } VOID arpUpdateRemoteIpDest( IN PARP1394_INTERFACE pIF, // NOLOCKIN NOLOCKOUT IN PARPCB_REMOTE_IP pRemoteIp, IN PARP_DEST_PARAMS pDestParams, PRM_STACK_RECORD pSR ) { ENTER("UpdateRemoteIpDest", 0x3f2dcaa7) ARPCB_DEST *pOldDest = NULL; RM_ASSERT_NOLOCKS(pSR); // pRemoteIp uses it's parent's (pIF's) lock. // RM_ASSERT_SAME_LOCK_AS_PARENT(pRemoteIp); do { PCHAR szDescription; INT fCreated = FALSE; PRM_TASK pMakeCallTask; UINT Channel; NDIS_STATUS Status; ARPCB_DEST *pDest; // // Lookup/Create Remote Destination // NOTE/WARNING: We'll create a new destination even if one exists for // the same uniqueID but different FIFO-address -- this is by design. // What should happen is that the old pDest should be eventually removed. // Status = RmLookupObjectInGroup( &pIF->DestinationGroup, RM_CREATE, //NOT RM_NEW (could be existing) pDestParams, pDestParams, // pParams (RM_OBJECT_HEADER**) &pDest, &fCreated, pSR ); if (FAIL(Status)) { OBJLOG1( pIF, "Couldn't add dest entry with hw addr 0x%lx\n", (UINT) pDestParams->HwAddr.FifoAddress.UniqueID // Truncation ); // // We'll leave the RemoteIp entry around -- it will be cleaned up later. // #if 0 // We do have to deref the tmpref added when looking it up. // RmTmpDereferenceObject(&pRemoteIp->Hdr, pSR); #endif // 0 break; } LOCKOBJ(pIF, pSR); if (pRemoteIp->pDest != pDest) { // If required, unlink any existing destination from pIP. // if (pRemoteIp->pDest != NULL) { pOldDest = pRemoteIp->pDest; RmTmpReferenceObject(&pOldDest->Hdr, pSR); arpUnlinkRemoteIpFromDest( pRemoteIp, // LOCKIN LOCKOUT pSR ); ASSERT(pRemoteIp->pDest == NULL); } // Set the pRemoteIp state to reflect that it is FIFO/Channel // and DYNAMIC. // { // (Dbg only) Change lock scope from pIF to pLocalIp, because // we're altering pLocalIp's state below... // RmDbgChangeLockScope( &pIF->Hdr, &pRemoteIp->Hdr, 0x1385053b, // LocID pSR ); if (pDestParams->HwAddr.AddressType == NIC1394AddressType_FIFO) { SET_REMOTEIP_FCTYPE(pRemoteIp, ARPREMOTEIP_FIFO); } else { SET_REMOTEIP_FCTYPE(pRemoteIp, ARPREMOTEIP_CHANNEL); } SET_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_DYNAMIC); // (Dbg only) Change lock scope back to pIF. // RmDbgChangeLockScope( &pRemoteIp->Hdr, &pIF->Hdr, 0x315d28a1, // LocID pSR ); } // Link pRemoteIp to pDest. // // // We've created both RemoteIp and Destination entries. Now link them. // (We still have the IF lock, which is the same as the RemoteIP and // desination locks for now). // // TODO: will need to change this when pRemoteIp gets its own lock. // RM_ASSERT_SAME_LOCK_AS_PARENT(pRemoteIp); RM_ASSERT_SAME_LOCK_AS_PARENT(pDest); arpLinkRemoteIpToDest( pRemoteIp, pDest, pSR ); } UNLOCKOBJ(pIF, pSR); RmTmpDereferenceObject(&pDest->Hdr, pSR); } while(FALSE); // // If required, get rid of pOldDest. // if (pOldDest != NULL) { arpDeinitDestination(pOldDest, TRUE, pSR); // TRUE == only if unused. RmTmpDereferenceObject(&pOldDest->Hdr, pSR); } RM_ASSERT_NOLOCKS(pSR); } VOID arpDeinitRemoteIp( PARPCB_REMOTE_IP pRemoteIp, PRM_STACK_RECORD pSR ) /*++ Unload a remote ip. --*/ { ENTER("arpDeinitRemoteIp", 0xea0a2662) PRM_TASK pTask; NDIS_STATUS Status; RM_ASSERT_NOLOCKS(pSR); #if DBG { IP_ADDRESS IpAddress = pRemoteIp->Key.IpAddress; TR_WARN(("Deiniting RemoteIp %d.%d.%d.%d\n", ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3])); } #endif // DBG Status = arpAllocateTask( &pRemoteIp->Hdr, // pParentObject, arpTaskUnloadRemoteIp, // pfnHandler, 0, // Timeout, "Task: Unload Remote Ip", // szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pRemoteIp, ("FATAL: couldn't alloc unload pRemoteIp task!\n")); } else { (VOID) RmStartTask( pTask, 0, // UserParam (unused) pSR ); } } VOID arpDeinitRemoteEth( PARPCB_REMOTE_ETH pRemoteEth, PRM_STACK_RECORD pSR ) /*++ Unload a remote ip. --*/ { ENTER("arpDeinitRemoteEth", 0x72dd17e7) PRM_TASK pTask; NDIS_STATUS Status; RM_ASSERT_NOLOCKS(pSR); #if DBG { IP_ADDRESS IpAddress = pRemoteEth->IpAddress; TR_WARN(("Deiniting RemoteEth %d.%d.%d.%d\n", ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3])); } #endif // DBG Status = arpAllocateTask( &pRemoteEth->Hdr, // pParentObject, arpTaskUnloadRemoteEth, // pfnHandler, 0, // Timeout, "Task: Unload Remote Eth", // szDescription &pTask, pSR ); if (FAIL(Status)) { OBJLOG0(pRemoteEth, ("FATAL: couldn't alloc unload pRemoteIp task!\n")); } else { (VOID) RmStartTask( pTask, 0, // UserParam (unused) pSR ); } } VOID arpDoMcapDbMaintenance( PARP1394_INTERFACE pIF, UINT CurrentTime, UINT SecondsSinceLastMaintenance, MYBOOL *pfProcessed, PRM_STACK_RECORD pSR ) /*++ Go through the mcap database, zeroing out all entries marked "NotRecentlyUpdated", and marking all others "NotRecentlyUpdated." Also send out an mcap advertisements for all channels we've locally allocated. --*/ { UINT u; UINT NumLocallyAllocated =0; PNDIS_PACKET pNdisPacket; NDIS_STATUS Status; ENTER("McapDbMaintenance", 0x1ae00035) if (SecondsSinceLastMaintenance < 10) { TR_INFO(("Skipping McapDb maintenance (delay=%lu).\n", SecondsSinceLastMaintenance )); *pfProcessed = FALSE; return; // EARLY RETURN; } *pfProcessed = TRUE; TR_INFO(("Actually doing Mcap Db maintenance.\n")); LOCKOBJ(pIF, pSR); // // Run down the channel info array, looking for and zapping stale channel // assignments. // for (u = 0; u < ARP_NUM_CHANNELS; u++) { PMCAP_CHANNEL_INFO pMci; MYBOOL fOk; pMci = &pIF->mcapinfo.rgChannelInfo[u]; if (pMci->GroupAddress == 0) continue; // An empty record. fOk = arpIsActiveMcapChannel(pMci, CurrentTime); if (!fOk) { TR_WARN(("McapDB: clearing stale channel %lu.\n", pMci->Channel )); ASSERT(pMci->Channel == u); ARP_ZEROSTRUCT(pMci); continue; } if (pMci->Flags & MCAP_CHANNEL_FLAGS_LOCALLY_ALLOCATED) { NumLocallyAllocated++; } } // If required, send an mcap advertisement packet. // do { IP1394_MCAP_PKT_INFO PktInfo; PIP1394_MCAP_GD_INFO pGdi; UINT cb = NumLocallyAllocated * sizeof(*pGdi); UINT v; if (NumLocallyAllocated==0) break; ASSERT(FALSE); if (cb <= sizeof(PktInfo.GdiSpace)) { pGdi = PktInfo.GdiSpace; } else { NdisAllocateMemoryWithTag(&pGdi, cb, MTAG_MCAP_GD); if (pGdi == NULL) { TR_WARN(("Allocation Failure")); break; } } PktInfo.pGdis = pGdi; // Now go through the mcap list, picking up locally allocated // channels. // for (u=0, v=0; u < ARP_NUM_CHANNELS; u++) { PMCAP_CHANNEL_INFO pMci; pMci = &pIF->mcapinfo.rgChannelInfo[u]; if (pMci->Flags & MCAP_CHANNEL_FLAGS_LOCALLY_ALLOCATED) { if (v >= NumLocallyAllocated) { ASSERT(FALSE); break; } if (pMci->ExpieryTime > CurrentTime) { pGdi->Expiration = pMci->ExpieryTime - CurrentTime; } else { pGdi->Expiration = 0; } pGdi->Channel = pMci->Channel; pGdi->SpeedCode = pMci->SpeedCode; pGdi->GroupAddress = pMci->GroupAddress; v++; pGdi++; } } UNLOCKOBJ(pIF, pSR); PktInfo.NumGroups = v; PktInfo.SenderNodeID = 0; // TODO PktInfo.OpCode = IP1394_MCAP_OP_ADVERTISE; // // Now we must actually allocate and send the advertisement. // Status = arpCreateMcapPkt( pIF, &PktInfo, &pNdisPacket, pSR ); if (FAIL(Status)) break; TR_WARN(("Attempting to send MCAP ADVERTISE PKT." "NumGoups=%lu Group0-1 == 0x%08lx->%lu 0x%08lx->%lu.\n", PktInfo.NumGroups, PktInfo.pGdis[0].GroupAddress, PktInfo.pGdis[0].Channel, PktInfo.pGdis[1].GroupAddress, PktInfo.pGdis[1].Channel )); ARP_FASTREADLOCK_IF_SEND_LOCK(pIF); // Actually send the packet (this will silently fail and free the pkt // if we're not in a position to send the pkt.) // arpSendControlPkt( pIF, // LOCKIN NOLOCKOUT (IF send lk) pNdisPacket, pIF->pBroadcastDest, pSR ); RM_ASSERT_NOLOCKS(pSR); RmTmpDereferenceObject(&pIF->Hdr, pSR); } while (FALSE); UNLOCKOBJ(pIF, pSR); EXIT() } #if DBG VOID arpDbgDisplayMapping( IP_ADDRESS IpAddress, PNIC1394_DESTINATION pHwAddr, char * szPrefix ) { ENTER("MAP", 0x0) if (pHwAddr == NULL) { TR_WARN(("%s %d.%d.%d.%d --> \n", szPrefix, ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3])); } else if (pHwAddr->AddressType == NIC1394AddressType_FIFO) { PUCHAR puc = (PUCHAR) &pHwAddr->FifoAddress; TR_WARN(("%s %d.%d.%d.%d --> FIFO %02lx-%02lx-%02lx-%02lx-%02lx-%02lx-%02lx-%02lx.\n", szPrefix, ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3], puc[0], puc[1], puc[2], puc[3], puc[4], puc[5], puc[6], puc[7])); } else if (pHwAddr->AddressType == NIC1394AddressType_Channel) { TR_WARN(("%s %d.%d.%d.%d --> CHANNEL %d.\n", szPrefix, ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3], pHwAddr->Channel)); } else { TR_WARN(("%s %d.%d.%d.%d --> Special dest 0x%08lx.\n", szPrefix, ((PUCHAR)(&IpAddress))[0], ((PUCHAR)(&IpAddress))[1], ((PUCHAR)(&IpAddress))[2], ((PUCHAR)(&IpAddress))[3], pHwAddr->Channel)); } EXIT() } #endif // DBG PRM_OBJECT_HEADER arpRemoteDestCreate( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) /*++ Routine Description: Allocate and initialize an object of type ARPCB_REMOTE_IP. Arguments: pParentObject - Actually a pointer to the interface (ARP1394_INTERFACE) pCreateParams - Actually the IP address (not a pointer to the IP address) to associate with this remote IP object. Return Value: Pointer to the allocated and initialized object on success. NULL otherwise. --*/ { ENTER ("arpRemoteDestCreate", 0xa896311a) ARPCB_REMOTE_IP *pRemoteIp; PRM_OBJECT_HEADER pHdr; PREMOTE_DEST_KEY pKey = (PREMOTE_DEST_KEY)pCreateParams; NDIS_STATUS Status; Status = ARP_ALLOCSTRUCT(pRemoteIp, MTAG_REMOTE_IP); if (Status != NDIS_STATUS_SUCCESS || pRemoteIp == NULL) { return NULL; } ARP_ZEROSTRUCT(pRemoteIp); pHdr = (PRM_OBJECT_HEADER) pRemoteIp; ASSERT(pHdr == &pRemoteIp->Hdr); // We expect the parent object to be the IF object! // ASSERT(pParentObject->Sig == MTAG_INTERFACE); if (pHdr) { RmInitializeHeader( pParentObject, pHdr, MTAG_REMOTE_IP, pParentObject->pLock, &ArpGlobal_RemoteIpStaticInfo, NULL, // szDescription pSR ); TR_INFO( ("New RemoteDest Key %x %x %x %x %x %x \n", pKey->ENetAddress.addr[0], pKey->ENetAddress.addr[1], pKey->ENetAddress.addr[2], pKey->ENetAddress.addr[3], pKey->ENetAddress.addr[4], pKey->ENetAddress.addr[5])); // set up the remote key REMOTE_DEST_KEY_INIT(&pRemoteIp->Key); pRemoteIp->Key = *((PREMOTE_DEST_KEY) pCreateParams); pRemoteIp->IpAddress = ((PREMOTE_DEST_KEY) pCreateParams)->IpAddress; // Initialize various other stuff... InitializeListHead(&pRemoteIp->sendinfo.listSendPkts); if ((IS_REMOTE_DEST_IP_ADDRESS(&pRemoteIp->Key) == TRUE) && arpCanTryMcap(pRemoteIp->IpAddress)) { SET_REMOTEIP_MCAP(pRemoteIp, ARPREMOTEIP_MCAP_CAPABLE); } } // // Add a backup task that could potentially be used to delete this Remote Ip // arpAddBackupTasks (&ArpGlobals, 1); EXIT() return pHdr; } VOID arpRemoteDestDelete( PRM_OBJECT_HEADER pHdr, PRM_STACK_RECORD pSR ) /*++ Routine Description: Free an object of type ARPCB_REMOTE_IP. Arguments: pHdr - Actually a pointer to the remote ip object to be freed. --*/ { ARPCB_REMOTE_IP *pRemoteIp = (ARPCB_REMOTE_IP *) pHdr; ASSERT(pRemoteIp->Hdr.Sig == MTAG_REMOTE_IP); pRemoteIp->Hdr.Sig = MTAG_FREED; ARP_FREE(pHdr); // // Remove a backup task that was added when RemoteIp was created // arpRemoveBackupTasks (&ArpGlobals, 1); } // Enum function // INT arpMaintainArpCache( PRM_OBJECT_HEADER pHdr, PVOID pvContext, // Unused PRM_STACK_RECORD pSR ) #if 0 for each RIP send VC if !marked dirty mark dirty if linked to channel pdest check if channel is still mapped to group if not, unlink. if required initiate link to new pdest (possibly channel) else //expired unlink from pdest and get rid of it #endif // 0 { ENTER("arpMaintainArpCache", 0xefc55765) NDIS_STATUS Status; PARPCB_REMOTE_IP pRemoteIp; PARP1394_INTERFACE pIF; pRemoteIp = (PARPCB_REMOTE_IP) pHdr; pIF = IF_FROM_LOCALIP(pRemoteIp); RM_ASSERT_NOLOCKS(pSR); do { IP_ADDRESS IpAddr; UINT Channel; ARP_DEST_PARAMS DestParams; ARPCB_DEST *pDest; BOOLEAN AcquireChannel; UINT CurrentTime = arpGetSystemTime(); UINT TimeSinceLastCheck; IpAddr = pRemoteIp->Key.IpAddress; #define ARP_PURGE_REMOTEIP_TIME 300 // Arp entry timeout. #define ARP_REFRESH_REMOTEIP_TIME (ARP_PURGE_REMOTEIP_TIME - 60) // Arp Refresh time TimeSinceLastCheck = CurrentTime - pRemoteIp->sendinfo.TimeLastChecked ; // // NOTE: we don't bother to get the lock with dealing with // sendinfo.TimeLastChecked -- this is ok. // if (pRemoteIp->sendinfo.TimeLastChecked==0) { if (CHECK_REMOTEIP_SDTYPE(pRemoteIp, ARPREMOTEIP_DYNAMIC) || CHECK_REMOTEIP_RESOLVE_STATE (pRemoteIp, ARPREMOTEIP_UNRESOLVED)) { // Set this field to the current time. It will be cleared back to 0 // when the next packet is sent to this remote ip. // pRemoteIp->sendinfo.TimeLastChecked = CurrentTime; } } else if (TimeSinceLastCheck >= ARP_REFRESH_REMOTEIP_TIME && TimeSinceLastCheck <= ARP_PURGE_REMOTEIP_TIME) { arpRefreshArpEntry(pRemoteIp, pSR); } else if (TimeSinceLastCheck >= ARP_PURGE_REMOTEIP_TIME) { // // We should clean up this remote ip. // arpDeinitRemoteIp(pRemoteIp, pSR); break; } #if ARP_ENABLE_MCAP_SEND // // We'll now see if we need to re-set which destination this // pRemoteIp points to. // // Skip if we can't do MCAP on this address. // LOCKOBJ(pRemoteIp, pSR); if (!CHECK_REMOTEIP_MCAP(pRemoteIp, ARPREMOTEIP_MCAP_CAPABLE)) { UNLOCKOBJ(pRemoteIp, pSR); break; } UNLOCKOBJ(pRemoteIp, pSR); // // Find a channel mapping to this address, if any. // Channel = arpFindAssignedChannel( pIF, pRemoteIp->Key.IpAddress, 0, pSR ); // // NOTE: Special return value NIC1394_BROADCAST_CHANNEL is returned if // this address is mapped to no specific channel. // AcquireChannel = FALSE; #if 0 // Let's not enable this just yet -- instead if (Channel == NIC1394_BROADCAST_CHANNEL) { // // Hmm... let's get aggressive and try to grab a channel. // Channel = arpFindFreeChannel(pIF, pSR); if (Channel != NIC1394_BROADCAST_CHANNEL) { // // Got one! // AcquireChannel = TRUE; } } else { // // There is already a channel allocated by someone to be used // for this ip address. Let's use it. // } #endif // 0 ARP_ZEROSTRUCT(&DestParams); DestParams.HwAddr.AddressType = NIC1394AddressType_Channel; DestParams.HwAddr.Channel = Channel; DestParams.AcquireChannel = AcquireChannel; arpUpdateRemoteIpDest(pIF, pRemoteIp, &DestParams, pSR); #endif // ARP_ENABLE_MCAP_SEND } while (FALSE); RM_ASSERT_NOLOCKS(pSR) return TRUE; // Continue to enumerate. } VOID arpRefreshArpEntry( PARPCB_REMOTE_IP pRemoteIp, PRM_STACK_RECORD pSR ) { ENTER("arpRefreshArpEntry",0x2e19af0b) NDIS_STATUS Status = NDIS_STATUS_FAILURE; PRM_TASK pTask = NULL; do { PUCHAR pIpAddress; // // We do not refresh Ip addresses ending in 0xff because they are broadcast // packets and we are only concernetd with maintaining unicast destinations // pIpAddress = (PUCHAR)&pRemoteIp->IpAddress; if (pIpAddress[3] == 0xff) { break; } // // We do not need to hold the lock as we are gauranteed that only one instance // of the original timer function is going to fire. By implication, all calls to // this function are serialized // if (pRemoteIp->pResolutionTask != NULL) { // There is already another task trying to resolve this Ip Address // so exit break; } Status = arpAllocateTask( &pRemoteIp->Hdr, // pParentObject, arpTaskResolveIpAddress, // pfnHandler, 0, // Timeout "Task: ResolveIpAddress", // szDescription &pTask, pSR ); if (FAIL(Status)) { pTask = NULL; break; } RmStartTask (pTask,0,pSR); }while (FALSE); EXIT() } NDIS_STATUS arpTaskUnloadEthDhcpEntry( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) /*++ This task is responsible for shuttingdown and eventually deleting a Dhcp Entry It goes through the following stages: simply calls RmFreeObject in Group as there is no asynchronous unload work to be done. UserParam for (Code == RM_TASKOP_START) : unused --*/ { ENTER("TaskUnloadRemoteEth", 0xf42aaa68) NDIS_STATUS Status = NDIS_STATUS_FAILURE; ARP1394_ETH_DHCP_ENTRY * pDhcpEntry = (ARP1394_ETH_DHCP_ENTRY*) RM_PARENT_OBJECT(pTask); ARP1394_INTERFACE *pIF = (ARP1394_INTERFACE*) RM_PARENT_OBJECT(pDhcpEntry ); // Following are the list of pending states for this task. // enum { PEND_OtherUnloadComplete }; switch(Code) { case RM_TASKOP_START: { LOCKOBJ(pDhcpEntry, pSR); // First check if pDhcpEntry is still allocated, if not we go away. // if (RM_IS_ZOMBIE(pDhcpEntry)) { Status = NDIS_STATUS_SUCCESS; break; } // // pDhcpEntry is allocated. Now check if there is already a // shutdown task attached to pDhcpEntry. // if (pDhcpEntry ->pUnloadTask != NULL) { // // There is a shutdown task. We pend on it. // PRM_TASK pOtherTask = pDhcpEntry->pUnloadTask; TR_WARN(("Unload task %p exists; pending on it.\n", pOtherTask)); RmTmpReferenceObject(&pOtherTask->Hdr, pSR); UNLOCKOBJ(pDhcpEntry , pSR); RmPendTaskOnOtherTask( pTask, PEND_OtherUnloadComplete, pOtherTask, pSR ); RmTmpDereferenceObject(&pOtherTask->Hdr, pSR); Status = NDIS_STATUS_PENDING; break; } // // There is no unload task going on. Let's // make this task THE unload task. // pDhcpEntry->pUnloadTask = pTask; // // Since we're THE unload task, add an association to pDhcpEntry, // which will only get cleared when the pDhcpEntry->pUnloadTask field // above is cleared. // DBG_ADDASSOC( &pDhcpEntry->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_ETHDHCP_UNLOAD_TASK, // AssociationID " Official unload task 0x%p (%s)\n", // szFormat pSR ); // // 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_OtherUnloadComplete: { // // There was another unload task going when we started, and // it's now complete. Nothing for us to do... // // TODO need standard way to propagate the error code. // Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { LOCKOBJ(pDhcpEntry, pSR); // // We're done. There should be no async activities left to do. // // // If we're THE unload task, we go on and deallocate the object. // if (pDhcpEntry ->pUnloadTask == pTask) { // // pDhcpEntry had better not be in a zombie state -- THIS task // is the one responsible for deallocating the object! // ASSERTEX(!RM_IS_ZOMBIE(pDhcpEntry ), pDhcpEntry ); pDhcpEntry ->pUnloadTask = NULL; RmFreeObjectInGroup( &pIF->EthDhcpGroup, &(pDhcpEntry ->Hdr), NULL, // NULL pTask == synchronous. pSR ); ASSERTEX(RM_IS_ZOMBIE(pDhcpEntry ), pDhcpEntry ); // Delete the association we added when we set // pDhcpEntry->pUnloadTask to pTask. // DBG_DELASSOC( &pDhcpEntry ->Hdr, // pObject pTask, // Instance1 pTask->Hdr.szDescription, // Instance2 ARPASSOC_ETHDHCP_UNLOAD_TASK, // AssociationID pSR ); UNLOCKOBJ(pDhcpEntry, pSR); } else { // // We weren't THE unload task, nothing left to do. // The object had better be in the zombie state.. // ASSERTEX( pDhcpEntry->pUnloadTask == NULL && RM_IS_ZOMBIE(pDhcpEntry), pDhcpEntry ); Status = NDIS_STATUS_SUCCESS; } Status = (NDIS_STATUS) UserParam; } break; // RM_TASKOP_END: default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RmUnlockAll(pSR); EXIT() return Status; }