// // Copyright (c) 1998-1999, Microsoft Corporation, all rights reserved // // mp.c // // IEEE1394 mini-port/call-manager driver // // Mini-port routines // // 12/28/1998 JosephJ Created, // #include #include "mp.h" #pragma hdrstop //----------------------------------------------------------------------------- // Data used in processing requests //----------------------------------------------------------------------------- NDIS_OID SupportedOids[] = { OID_GEN_CO_SUPPORTED_LIST, OID_GEN_CO_HARDWARE_STATUS, OID_GEN_CO_MEDIA_SUPPORTED, OID_GEN_CO_MEDIA_IN_USE, OID_GEN_CO_LINK_SPEED, OID_GEN_CO_VENDOR_ID, OID_GEN_CO_VENDOR_DESCRIPTION, OID_GEN_CO_DRIVER_VERSION, OID_GEN_CO_PROTOCOL_OPTIONS, OID_GEN_CO_MEDIA_CONNECT_STATUS, OID_GEN_CO_MAC_OPTIONS, OID_GEN_CO_VENDOR_DRIVER_VERSION, OID_GEN_CO_MINIMUM_LINK_SPEED, OID_GEN_CO_XMIT_PDUS_OK, OID_GEN_CO_RCV_PDUS_OK, OID_GEN_CO_XMIT_PDUS_ERROR, OID_GEN_CO_RCV_PDUS_ERROR, OID_GEN_CO_RCV_PDUS_NO_BUFFER, OID_1394_LOCAL_NODE_INFO, OID_1394_VC_INFO, OID_1394_NICINFO, OID_1394_IP1394_CONNECT_STATUS, OID_1394_ENTER_BRIDGE_MODE, OID_1394_EXIT_BRIDGE_MODE, OID_1394_ISSUE_BUS_RESET, OID_802_3_CURRENT_ADDRESS, OID_GEN_MAXIMUM_LOOKAHEAD, OID_GEN_MAXIMUM_FRAME_SIZE, OID_GEN_MAXIMUM_TOTAL_SIZE, OID_GEN_LINK_SPEED, OID_GEN_TRANSMIT_BUFFER_SPACE, OID_GEN_RECEIVE_BUFFER_SPACE, OID_GEN_TRANSMIT_BLOCK_SIZE, OID_GEN_RECEIVE_BLOCK_SIZE, OID_GEN_MAXIMUM_SEND_PACKETS, OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_CURRENT_LOOKAHEAD, OID_802_3_PERMANENT_ADDRESS, OID_802_3_MULTICAST_LIST, OID_802_3_MAXIMUM_LIST_SIZE, OID_802_3_RCV_ERROR_ALIGNMENT, OID_802_3_XMIT_ONE_COLLISION, OID_802_3_XMIT_MORE_COLLISIONS, OID_GEN_PROTOCOL_OPTIONS, OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_CURRENT_LOOKAHEAD, OID_GEN_PHYSICAL_MEDIUM, OID_PNP_QUERY_POWER, OID_PNP_SET_POWER, OID_1394_QUERY_EUID_NODE_MAP }; //----------------------------------------------------------------------------- // Locally used function prototypes //----------------------------------------------------------------------------- NDIS_STATUS nicAllocateLoopbackPacketPool ( IN PADAPTERCB pAdapter ); VOID nicFreeLoopbackPacketPool ( IN PADAPTERCB pAdapter ); VOID nicLoopbackPacket( IN VCCB* pVc, IN PNDIS_PACKET pPacket ); VOID nicQueryEuidNodeMacMap ( IN PADAPTERCB pAdapter, IN PNDIS_REQUEST pRequest ); VOID nicRemoveRemoteNodeFromNodeTable( IN PNODE_TABLE pNodeTable, IN PREMOTE_NODE pRemoteNode ); NDIS_STATUS nicSetPower ( IN PADAPTERCB pAdapter, IN NET_DEVICE_POWER_STATE DeviceState ); //----------------------------------------------------------------------------- // Mini-port handlers //----------------------------------------------------------------------------- NDIS_STATUS NicMpInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext ) /*++ Routine Description: Standard 'MiniportInitialize' routine called by NDIS to initialize a new adapter. See DDK doc. The driver will receive no requests until this initialization has completed. Arguments: See DDK docs Return Value: Appropriate Status --*/ { NDIS_STATUS NdisStatus; NTSTATUS NtStatus; PADAPTERCB pAdapter= NULL; PDEVICE_OBJECT pNextDeviceObject = NULL; LARGE_INTEGER LocalHostUniqueId; REMOTE_NODE *p1394RemoteNodePdoCb = NULL; UINT64 u64LocalHostUniqueId =0; BOOLEAN FreeAdapter = FALSE; BOOLEAN DequeueAdapter = FALSE; ULONG Generation; ULONG InitStatus; // // This is the order with which the initialize routine is done. // enum { NoState, AllocatedAdapter, AdapterQueued, InitializedEvents, InitializedBcr, RegisteredResetCallback, AddedConfigRom, RegisteredEnumerator, InitializedLookasideList, InitializedPktLog, InitializedRcvThread, InitializedSendThread, InitializedReassembly, InitializedLoopbackPool }; STORE_CURRENT_IRQL TIMESTAMP_ENTRY("==>IntializeHandler"); TIMESTAMP_INITIALIZE(); TRACE( TL_T, TM_Init, ( "==>NicMpInitialize" ) ); InitStatus = NoState; NdisStatus = *OpenErrorStatus = NDIS_STATUS_SUCCESS; // Find the medium index in the array of media, looking for the only one // we support, 'NdisMedium1394'. // { UINT i; for (i = 0; i < MediumArraySize; ++i) { if (MediumArray[ i ] == g_ulMedium ) { break; } } if (i >= MediumArraySize) { TRACE( TL_A, TM_Init, ( "medium?" ) ); return NDIS_STATUS_FAILURE; } *SelectedMediumIndex = i; } // Allocate and zero a control block for the new adapter. // pAdapter = ALLOC_NONPAGED( sizeof(ADAPTERCB), MTAG_ADAPTERCB ); TRACE( TL_N, TM_Init, ( "Acb=$%p", pAdapter ) ); if (!pAdapter) { return NDIS_STATUS_RESOURCES; } FreeAdapter = TRUE; InitStatus = AllocatedAdapter; NdisZeroMemory (pAdapter, sizeof(*pAdapter) ); // Add a reference that will eventually be removed by an NDIS call to // the nicFreeAdapter handler. // nicReferenceAdapter (pAdapter, "MpInitialize" ); // Set a marker for easier memory dump browsing and future assertions. // pAdapter->ulTag = MTAG_ADAPTERCB; // Save the NDIS handle associated with this adapter for use in future // NdisXxx calls. // pAdapter->MiniportAdapterHandle = MiniportAdapterHandle; // Initialize the adapter-wide lock. // NdisAllocateSpinLock( &pAdapter->lock ); // Initialize the various lists of top-level resources. // pAdapter->HardwareStatus = NdisHardwareStatusInitializing; // // The enumerator and bus1394 have asked us to load, therefore media // should be connected // pAdapter->MediaConnectStatus = NdisMediaStateDisconnected; InitializeListHead( &pAdapter->AFList ); InitializeListHead( &pAdapter->PDOList ); // // Default initialization values // pAdapter->Speed = SPEED_FLAGS_400; pAdapter->SpeedMbps = 4 * 1000000; pAdapter->SCode = SCODE_400_RATE; do { // Read this adapter's registry settings. // NdisStatus = nicGetRegistrySettings( WrapperConfigurationContext, pAdapter ); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; } // Inform NDIS of the attributes of our adapter. Set the // 'MiniportAdapterContext' returned to us by NDIS when it calls our // handlers to the address of our adapter control block. Turn off // hardware oriented timeouts. // NdisMSetAttributesEx( MiniportAdapterHandle, (NDIS_HANDLE)pAdapter, (UINT)0, NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT | NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT | NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK, NdisInterfaceInternal ); NdisStatus = nicMCmRegisterAddressFamily (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { // // If we fail, Let the next entrant try the same thing // break; } ADAPTER_SET_FLAG (pAdapter,fADAPTER_RegisteredAF); // // Insert into global list of adapters. So we will be ready to receive notifications // from the enumerator // NdisAcquireSpinLock ( &g_DriverLock); InsertHeadList (&g_AdapterList, &pAdapter->linkAdapter); DequeueAdapter = TRUE; InitStatus = AdapterQueued; NdisReleaseSpinLock (&g_DriverLock); pAdapter->HardwareStatus = NdisHardwareStatusReady; // // Set up linkages. Get the PDO for the device from Ndis // NdisMGetDeviceProperty( MiniportAdapterHandle, NULL, NULL, &pNextDeviceObject, NULL, NULL ); ASSERT (pNextDeviceObject != NULL); pAdapter->Generation = 0; // // Update data structure with the local hosts VDO // pAdapter->pNextDeviceObject = pNextDeviceObject; TRACE( TL_I, TM_Mp, ( " LocalHost VDO %x", pNextDeviceObject) ); nicInitializeAllEvents (pAdapter); InitStatus = InitializedEvents; // // Initialize the BCM so it is ready to handle Resets // NdisStatus = nicInitializeBroadcastChannelRegister (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK( TM_Init, ( "nicMpInitialize - nicInitializeBroadcastChannelRegister ") ); } InitStatus = InitializedBcr; // // Initialize the generation count , reset callback and config rom // NdisStatus = nicGetGenerationCount (pAdapter, &Generation); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Init, ("Initialize Handler - nicGetGeneration Failed" ) ); } pAdapter->Generation = Generation; // // request notification of bus resets // NdisStatus = nicBusResetNotification (pAdapter, REGISTER_NOTIFICATION_ROUTINE, nicResetNotificationCallback, pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Init, ("Initialize Handler - nicBusResetNotification Failed" ) ); } InitStatus = RegisteredResetCallback; // // add ip/1394 to the config rom // NdisStatus = nicAddIP1394ToConfigRom (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Init, ("Initialize Handler - nicAddIP1394ToConfigRom Failed" ) ); } InitStatus = AddedConfigRom; // // Lets find out our MaxRec. // NdisStatus = nicGetReadWriteCapLocalHost(pAdapter, &pAdapter->ReadWriteCaps); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; } pAdapter->MaxRec = nicGetMaxRecFromBytes(pAdapter->ReadWriteCaps.MaxAsyncWriteRequest); TRACE (TL_V, TM_Mp, (" MaxRec %x\n", pAdapter->MaxRec ) ); // // Update the Local Speed. If we fail now, we will get it again // after a Reset. // nicUpdateLocalHostSpeed (pAdapter); TRACE (TL_V, TM_Mp, (" SCode %x", pAdapter->SCode) ); // // Bus Reset - used to kick off the BCM algorithm // nicIssueBusReset (pAdapter,BUS_RESET_FLAGS_FORCE_ROOT ); // // Register this adapter with the enumerator. // if (NdisEnum1394DeregisterAdapter != NULL) { NtStatus = NdisEnum1394RegisterAdapter((PVOID)pAdapter, pNextDeviceObject, &pAdapter->EnumAdapterHandle, &LocalHostUniqueId); if (NtStatus != STATUS_SUCCESS) { ADAPTER_SET_FLAG(pAdapter, fADAPTER_FailedRegisteration); // // Don;t Bail Out // //NdisStatus = NDIS_STATUS_FAILURE; BREAK( TM_Init, ( "nicMpInitialize - NdisEnum1394RegisterAdapter FAILED ") ); } else { ADAPTER_SET_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator); InitStatus = RegisteredEnumerator; } } else { GET_LOCAL_HOST_INFO1 Uid; // // Enum is not loaded get the Unique Id // NdisStatus = nicGetLocalHostUniqueId (pAdapter, &Uid ); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK( TM_Init, ( " nicMpInitialize - nicGetLocalHostUniqueId FAILED ") ); } else { LocalHostUniqueId = Uid.UniqueId; } } // // Validate the Local Adapter's Unique Id // if (LocalHostUniqueId.QuadPart == (UINT64)(0) ) { nicWriteErrorLog (pAdapter,NDIS_ERROR_CODE_HARDWARE_FAILURE, NIC_ERROR_CODE_INVALID_UNIQUE_ID_0); NdisStatus = NDIS_STATUS_FAILURE; break; } if (LocalHostUniqueId.QuadPart == (UINT64)(-1) ) { nicWriteErrorLog (pAdapter,NDIS_ERROR_CODE_HARDWARE_FAILURE,NIC_ERROR_CODE_INVALID_UNIQUE_ID_FF); NdisStatus = NDIS_STATUS_FAILURE; break; } #ifdef PKT_LOG nic1394AllocPktLog (pAdapter); if (pAdapter->pPktLog == NULL) { NdisStatus = NDIS_STATUS_FAILURE; BREAK (TM_Init, ("nicMpInitialize - Could not allocate packetlog" ) ); } nic1394InitPktLog(pAdapter->pPktLog); InitStatus = InitializedPktLog; #endif // // Initialize the reassembly timers // nicInitSerializedReassemblyStruct(pAdapter); // cannot fail InitStatus = InitializedReassembly; // // This swap is done so that the byte reported by the bus driver matches that // which is used in the notification of add nodes, remove nodes and make call // LocalHostUniqueId.LowPart = SWAPBYTES_ULONG (LocalHostUniqueId.LowPart ); LocalHostUniqueId.HighPart = SWAPBYTES_ULONG (LocalHostUniqueId.HighPart ); u64LocalHostUniqueId = LocalHostUniqueId.QuadPart; pAdapter->UniqueId = u64LocalHostUniqueId; pAdapter->HardwareStatus = NdisHardwareStatusReady; // // Get Our local Fake Mac address // nicGetFakeMacAddress (&u64LocalHostUniqueId, &pAdapter->MacAddressEth); // // Initialize the lookaside lists // nicInitializeAdapterLookasideLists (pAdapter); InitStatus = InitializedLookasideList; // // Initialize the remote node table // nicUpdateRemoteNodeTable (pAdapter); // // initialize the gasp header // nicMakeGaspHeader (pAdapter, &pAdapter->GaspHeader); // // Assign a MAC address to this Adapter // { AdapterNum++; // // generate a locally // administered address by manipulating the first two bytes. // } // // Allocate the loopback pools // NdisStatus= nicAllocateLoopbackPacketPool (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { BREAK (TM_Init, ("nicMpInitialize - nicAllocateLoopbackPacketPool FAILED" ) ); } InitStatus = InitializedLoopbackPool; ADAPTER_SET_FLAG (pAdapter, fADAPTER_DoStatusIndications); pAdapter->PowerState = NetDeviceStateD0; } while (FALSE); if (NdisStatus != NDIS_STATUS_SUCCESS) { NDIS_STATUS FailureStatus = NDIS_STATUS_FAILURE; // Failed, so undo whatever portion succeeded. // TRACE( TL_I, TM_Init, ( "NicMpInitialize FAILING InitStatus %x", InitStatus) ); ADAPTER_SET_FLAG (pAdapter, fADAPTER_FailedInit); ADAPTER_CLEAR_FLAG (pAdapter, fADAPTER_DoStatusIndications); // // This is in reverse order of the init and there are no breaks here. // The implicit assumption is that if the code failed at a certain point // it will have to undo whatever was previously allocated // switch (InitStatus) { case InitializedLoopbackPool: { nicFreeLoopbackPacketPool(pAdapter); FALL_THROUGH; } case InitializedLookasideList: { nicDeleteAdapterLookasideLists(pAdapter); FALL_THROUGH; } case InitializedReassembly: { nicDeInitSerializedReassmblyStruct(pAdapter); FALL_THROUGH; } case InitializedSendThread: { FALL_THROUGH; } case InitializedRcvThread: { FALL_THROUGH; } case InitializedPktLog: { #ifdef PKT_LOG nic1394DeallocPktLog(pAdapter); #endif FALL_THROUGH } case RegisteredEnumerator: { // // If we registered with the enumerator , then deregister // if ((NdisEnum1394DeregisterAdapter != NULL) && ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator)) { // // deregister this adapter with enumerator // TRACE( TL_V, TM_Init, ( " Deregistering with the Enum %x", pAdapter->EnumAdapterHandle) ); NdisEnum1394DeregisterAdapter(pAdapter->EnumAdapterHandle); ADAPTER_CLEAR_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator | fADAPTER_FailedRegisteration); } FALL_THROUGH } case AddedConfigRom: { TRACE( TL_V, TM_Init, ( " removing config rom handle %x", pAdapter->hCromData ) ); FailureStatus = nicSetLocalHostPropertiesCRom(pAdapter, (PUCHAR)&Net1394ConfigRom, sizeof(Net1394ConfigRom), SLHP_FLAG_REMOVE_CROM_DATA, &pAdapter->hCromData, &pAdapter->pConfigRomMdl); FALL_THROUGH } case RegisteredResetCallback: { TRACE( TL_V, TM_Init, ( " Deregistering reset callback ") ); // // Deregeister the reset callback // FailureStatus = nicBusResetNotification (pAdapter, DEREGISTER_NOTIFICATION_ROUTINE, nicResetNotificationCallback, pAdapter) ; FALL_THROUGH } case InitializedBcr: case InitializedEvents: { TRACE( TL_V, TM_Init, ( " Freeing BCR ") ); nicFreeBroadcastChannelRegister(pAdapter); NdisWaitEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent, WAIT_INFINITE); FALL_THROUGH } case AdapterQueued: { NdisAcquireSpinLock ( &g_DriverLock); nicRemoveEntryList (&pAdapter->linkAdapter); NdisReleaseSpinLock (&g_DriverLock); FALL_THROUGH } case AllocatedAdapter: { nicDereferenceAdapter(pAdapter, "NicMpInitialize"); break; } default : { ASSERT (0); } } } TRACE( TL_T, TM_Init, ( "<==NicMpInitialize=$%08x", NdisStatus ) ); MATCH_IRQL; TRACE( TL_I, TM_Init, ( "NicMpInitialize Status %x, pAdapter %p", NdisStatus,pAdapter ) ); TIMESTAMP_EXIT("<==IntializeHandler"); return NdisStatus; } VOID NicMpHalt( IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: Standard 'MiniportHalt' routine called by NDIS to deallocate all resources attached to the adapter. NDIS does not make any other calls for this mini-port adapter during or after this call. NDIS will not call this routine when packets indicated as received have not been returned, or when any VC is created and known to NDIS. Runs at PASSIVE IRQL. Arguments: Return Value: --*/ { PADAPTERCB pAdapter = (PADAPTERCB) MiniportAdapterContext; BOOLEAN TimerCancelled = FALSE; STORE_CURRENT_IRQL TIMESTAMP_ENTRY("==>Haltandler"); TRACE( TL_T, TM_Mp, ( "==>NicMpHalt" ) ); TRACE( TL_I, TM_Mp, ( " Adapter %x Halted", pAdapter ) ); if (pAdapter->ulTag != MTAG_ADAPTERCB) { ASSERT( !"Atag?" ); return; } ADAPTER_CLEAR_FLAG (pAdapter, fADAPTER_DoStatusIndications); // // Unload the Arp module if necessary. This is necessary if // the nic is forced to operate in a non-power managed environment // by the user. // if (pAdapter->fIsArpStarted == TRUE) { nicQueueRequestToArp(pAdapter, UnloadArpNoRequest, NULL); } ADAPTER_SET_FLAG (pAdapter, fADAPTER_Halting); // // Stop the reassembly timer // nicDeInitSerializedReassmblyStruct(pAdapter); // // Deallocating the packet log // #ifdef PKT_LOG nic1394DeallocPktLog(pAdapter); #endif // // remove the config rom // nicSetLocalHostPropertiesCRom(pAdapter, (PUCHAR)&Net1394ConfigRom, sizeof(Net1394ConfigRom), SLHP_FLAG_REMOVE_CROM_DATA, &pAdapter->hCromData, &pAdapter->pConfigRomMdl); pAdapter->hCromData = NULL; // // free the apapter packet pool nicFreeLoopbackPacketPool(pAdapter); // // Free the BCR // nicFreeBroadcastChannelRegister(pAdapter); TRACE (TL_V, TM_Mp, ("About to Wait for Free AddressRange\n" ) ); NdisWaitEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent, WAIT_INFINITE); TRACE (TL_V, TM_Mp, ("Wait Completed for Free AddressRange\n" ) ); nicBusResetNotification (pAdapter, DEREGISTER_NOTIFICATION_ROUTINE, nicResetNotificationCallback, pAdapter); // // deregister this adapter with enumerator // if ((NdisEnum1394DeregisterAdapter != NULL) && ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator)) { // // deregister this adapter with enumerator // NdisEnum1394DeregisterAdapter(pAdapter->EnumAdapterHandle); ADAPTER_CLEAR_FLAG(pAdapter, fADAPTER_RegisteredWithEnumerator | fADAPTER_FailedRegisteration); } // // No more Irps on this adapter's VDO // ADAPTER_SET_FLAG (pAdapter, fADAPTER_VDOInactive); // // Cancel Outstanding Timer // ADAPTER_SET_FLAG (pAdapter, fADAPTER_FreedTimers); // // Cancel Outstanding WorItems // while (pAdapter->OutstandingWorkItems != 0) { NdisMSleep (10000); } ADAPTER_SET_FLAG (pAdapter, fADAPTER_DeletedWorkItems); // Remove this adapter from the global list of adapters. // NdisAcquireSpinLock(&g_DriverLock); nicRemoveEntryList(&pAdapter->linkAdapter); NdisReleaseSpinLock(&g_DriverLock); ADAPTER_ACQUIRE_LOCK (pAdapter); // do Adapter Specific Work here pAdapter->HardwareStatus = NdisHardwareStatusClosing; // // Free all lookaside lists // nicDeleteAdapterLookasideLists (pAdapter); ADAPTER_SET_FLAG (pAdapter, fADAPTER_DeletedLookasideLists); ADAPTER_RELEASE_LOCK (pAdapter); NdisFreeSpinLock (&pAdapter->lock); while (pAdapter->lRef != 1) { // // sleep for 1 second waiting for outstanding operations to complete // NdisMSleep (1000); } nicDereferenceAdapter( pAdapter, "nicMpHalt" ); //ASSERT (g_AdapterFreed == TRUE); TRACE( TL_T, TM_Mp, ( "<==NicMpHalt " ) ); TIMESTAMP_EXIT("<==Haltandler"); TIMESTAMP_HALT(); TRACE( TL_I, TM_Init, ( "Nic1394 Halted %p ", pAdapter ) ); MATCH_IRQL } NDIS_STATUS NicMpReset( OUT PBOOLEAN AddressingReset, IN NDIS_HANDLE MiniportAdapterContext ) /*++ Routine Description: Do Nothing Arguments: Return Value: --*/ { TRACE( TL_T, TM_Mp, ( "NicMpReset" ) ); return NDIS_STATUS_SUCCESS; } NDIS_STATUS NicMpCoActivateVc( IN NDIS_HANDLE MiniportVcContext, IN OUT PCO_CALL_PARAMETERS CallParameters ) /*++ Routine Description: Do Nothing Standard 'MiniportCoActivateVc' routine called by NDIS in response to a protocol's request to activate a virtual circuit. The only "protocol" to call us is our call manager half, which knows exactly what it's doing and so we don't have to do anything here. It does expect us to return success synchronously. Arguments: Return Value: Always Succeed --*/ { return NDIS_STATUS_SUCCESS; } NDIS_STATUS NicMpCoDeactivateVc( IN NDIS_HANDLE MiniportVcContext ) /*++ Routine Description: Standard 'MiniportCoDeactivateVc' routine called by NDIS in response to a protocol's request to de-activate a virtual circuit. The only "protocol" to call us is our call manager half, which knows exactly what it's doing and so we don't have to do anything here. It does expect us to return success synchronously. Arguments: Return Value: --*/ { return NDIS_STATUS_SUCCESS; } VOID NicMpCoSendPackets( IN NDIS_HANDLE MiniportVcContext, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) /*++ Routine Description: Co Send Handler for the Miniport Any broadcast packets have to be looped back as 1394 does not loop back packets sent on a channel Arguments: See DDK Return Value: None: After the first failure, call NdisMCoSendComplete(..) on all packets --*/ { UINT i; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; NDIS_PACKET** ppPacket; VCCB* pVc; extern UINT NicSends; TRACE( TL_V, TM_Send, ( "==>NicMpCoSendPackets(%d), Vc %.8x", NumberOfPackets, MiniportVcContext ) ); pVc = (VCCB* )MiniportVcContext; ASSERT( pVc->Hdr.ulTag == MTAG_VCCB ); for (i = 0, ppPacket = PacketArray; i < NumberOfPackets; ++i, ++ppPacket) { NDIS_PACKET* pPacket = *ppPacket; // SendPacket sends the packet and eventually calls // NdisMCoSendComplete to notify caller of the result. // NDIS_SET_PACKET_STATUS( pPacket, NDIS_STATUS_PENDING ); nicIncrementSends (pVc); nicDumpPkt (pPacket , "Sending "); // // Loopback the packet it is a broadcast packet // if (pVc->Hdr.VcType == NIC1394_SendRecvChannel || pVc->Hdr.VcType == NIC1394_MultiChannel || pVc->Hdr.VcType == NIC1394_SendChannel) { nicLoopbackPacket(pVc, pPacket); } nicUpdatePacketState (pPacket, NIC1394_TAG_IN_SEND); NdisStatus = pVc->Hdr.VcHandlers.SendPackets (pVc, pPacket); if (NT_SUCCESS (NdisStatus) == FALSE) { TRACE( TL_N, TM_Send, ( "SendHandler failed Status %.8x", NdisStatus ) ); break; } } // If the call to the VC's Send handler was not successful // Indicate failure for that packet and all packets following it // if (NT_SUCCESS(NdisStatus) == FALSE) // can pend also { // Start from the packet which caused the break and indicate // Failure (call the completion handler for each packet // for ( ; i < NumberOfPackets;++i,++ppPacket) { TRACE( TL_V, TM_Send, ( "Calling NdisCoSendComplete, status %x, VcHandle %x, pPkt %x", NDIS_STATUS_FAILURE , pVc->Hdr.NdisVcHandle, *ppPacket ) ); nicMpCoSendComplete (NDIS_STATUS_FAILURE, pVc,*ppPacket); } } TRACE( TL_T, TM_Send, ( "<==NicMpCoSendPackets " ) ); } NDIS_STATUS NicMpCoRequest( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_HANDLE MiniportVcContext, IN OUT PNDIS_REQUEST NdisRequest ) /*++ Routine Description: Standard CoRequest handler. It branches off into a Query function and a Set Function. Arguments: See DDK Return Value: --*/ { ADAPTERCB* pAdapter; VCCB* pVc; NDIS_STATUS status; TRACE( TL_T, TM_Mp, ( "NicMpCoReq, Request %.8x", NdisRequest ) ); pAdapter = (ADAPTERCB* )MiniportAdapterContext; if (pAdapter->ulTag != MTAG_ADAPTERCB) { ASSERT( !"Atag?" ); return NDIS_STATUS_INVALID_DATA; } pVc = (VCCB* )MiniportVcContext; if (pVc && pVc->Hdr.ulTag != MTAG_VCCB) { ASSERT( !"Vtag?" ); return NDIS_STATUS_INVALID_DATA; } switch (NdisRequest->RequestType) { case NdisRequestQueryStatistics: case NdisRequestQueryInformation: { status = nicQueryInformation( pAdapter, pVc, NdisRequest ); break; } case NdisRequestSetInformation: { status = nicSetInformation( pAdapter, pVc, NdisRequest ); break; } default: { status = NDIS_STATUS_NOT_SUPPORTED; TRACE( TL_V, TM_Mp, ( "type=%d?", NdisRequest->RequestType ) ); break; } } TRACE( TL_T, TM_Mp, ( "NicMpCoReq, Status=$%x", status ) ); return status; } //----------------------------------------------------------------------------- // Mini-port utility routines (alphabetically) // Some are used externally //----------------------------------------------------------------------------- VOID nicDereferenceAdapter( IN PADAPTERCB pAdapter, IN PCHAR pDebugPrint ) /*++ Routine Description: Dereferences the Adapter, If the Ref is zero, it will free the adapter object. It expects that this will happen in the Halt Handler. The Ref Count cannot bounce back up from zero because the last refernce is Dereferenced only after no new operations can be started on the adapter. Arguments: Adapter DebugString Return Value: --*/ { LONG lRef; lRef = NdisInterlockedDecrement( &pAdapter->lRef ); TRACE( TL_V, TM_Ref, ( "**nicDereferenceAdapter pAdapter %x, to %d, %s ", pAdapter, pAdapter->lRef, pDebugPrint ) ); ASSERT( lRef >= 0 ); if (lRef == 0) { nicFreeAdapter( pAdapter ); } } VOID nicFreeAdapter( IN ADAPTERCB* pAdapter ) /*++ Routine Description: Free the memory for the adapter structure Arguments: Return Value: --*/ { pAdapter->ulTag = MTAG_FREED; ASSERT (pAdapter->lRef == 0); FREE_NONPAGED( pAdapter ); g_AdapterFreed = TRUE; } NDIS_STATUS nicGetRegistrySettings( IN NDIS_HANDLE WrapperConfigurationContext, IN ADAPTERCB * pAdapter ) /*++ Routine Description: nic1394 reads 1 registry parameter and that is the name of the NDIS miniport so that it can be used if the miniport is ever set into Bridge mode Arguments: Return Value: --*/ { NDIS_STATUS status; NDIS_HANDLE hCfg; NDIS_CONFIGURATION_PARAMETER* pncp; PNDIS_CONFIGURATION_PARAMETER pNameConfig; NDIS_STRING strMiniportName = NDIS_STRING_CONST("MiniportName"); ULONG AdapterNameSizeInBytes = 0; NdisOpenConfiguration( &status, &hCfg, WrapperConfigurationContext ); if (status != NDIS_STATUS_SUCCESS) return status; do { // // Read the Miniport Name. First setup the buffer // NdisReadConfiguration(&status, &pNameConfig, hCfg, &strMiniportName, NdisParameterString); if (status != NDIS_STATUS_SUCCESS) { break; } AdapterNameSizeInBytes = pNameConfig->ParameterData.StringData.Length; // // Only Copy the Adapter name if the size of the string from the registry // is smaller than the size we have allocated in the adapter structure. // There should also be room for the trailing L'\0' character. // if ((ADAPTER_NAME_SIZE*sizeof(WCHAR)) > (AdapterNameSizeInBytes+2)) { PUCHAR pAdapterName = (PUCHAR)&pAdapter->AdapterName[0]; pAdapter->AdapterNameSize = AdapterNameSizeInBytes; NdisMoveMemory (pAdapterName, // Destination pNameConfig->ParameterData.StringData.Buffer, // Source AdapterNameSizeInBytes ); // number of characters // // NULL - terminate the string by adding the L'\0' Unicode character // pAdapterName[AdapterNameSizeInBytes]= 0; pAdapterName[AdapterNameSizeInBytes+1]= 0; } } while (FALSE); NdisCloseConfiguration( hCfg ); TRACE( TL_N, TM_Init, ( "Reg: Name %s", &pAdapter->AdapterName)); return status; } NDIS_STATUS nicQueryInformation( IN ADAPTERCB* pAdapter, IN VCCB* pVc, IN OUT PNDIS_REQUEST NdisRequest ) /*++ Routine Description: NOTE: this function can be called in at least two contexts: 1: in the context of an NdisRequest 2: in the context of our own work item, if the request needs to be completed at passive. Arguments: Return Value: --*/ { NDIS_STATUS status; ULONG ulInfo; VOID* pInfo; ULONG ulInfoLen; USHORT usInfo; NDIS_OID Oid; PVOID InformationBuffer; ULONG InformationBufferLength; PULONG BytesWritten; PULONG BytesNeeded; NDIS_CO_LINK_SPEED CoLinkSpeed; NIC1394_LOCAL_NODE_INFO LocalNodeInfo; NIC1394_VC_INFO VcInfo; NDIS_PNP_CAPABILITIES PnpCaps; NIC1394_NICINFO NicInfo; Oid = NdisRequest->DATA.QUERY_INFORMATION.Oid; InformationBuffer = NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer; InformationBufferLength = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength; BytesWritten = &NdisRequest->DATA.QUERY_INFORMATION.BytesWritten; BytesNeeded = &NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded; // The next variables are used to setup the data structures that are // used to respond to the OIDs they correspond to // TRACE( TL_T, TM_Init, ( "==>nicQueryInformation, Adapter %.8x, Vc %.8x, Oid %.8x",pAdapter, pVc, Oid )); // The cases in this switch statement find or create a buffer containing // the requested information and point 'pInfo' at it, noting it's length // in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo' // buffer is set up as the default. // ulInfo = 0; pInfo = &ulInfo; ulInfoLen = sizeof(ulInfo); status = NDIS_STATUS_SUCCESS; switch (Oid) { case OID_GEN_CO_SUPPORTED_LIST: { pInfo = &SupportedOids[0]; ulInfoLen = sizeof(SupportedOids); break; } case OID_GEN_CO_HARDWARE_STATUS: { // // Copy the hardware status into the users buffer. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_HARDWARE_STATUS)" ) ); NdisAcquireSpinLock (&pAdapter->lock); pInfo = (PUCHAR) &pAdapter->HardwareStatus; NdisReleaseSpinLock (&pAdapter->lock); ulInfoLen = sizeof(pAdapter->HardwareStatus); break; } case OID_GEN_MAXIMUM_LOOKAHEAD: { // Report the maximum number of bytes we can always provide as // lookahead data on receive indications. We always indicate full // packets so this is the same as the receive block size. And // since we always allocate enough for a full packet, the receive // block size is the same as the frame size. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_LOOKAHEAD)" ) ); ulInfo = Nic1394_MaxFrameSize; break; } case OID_GEN_CO_MAC_OPTIONS: { // Report a bitmask defining optional properties of the driver. // // NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA promises that our receive // buffer is not on a device-specific card. // // NDIS_MAC_OPTION_TRANSFERS_NOT_PEND promises we won't return // NDIS_STATUS_PENDING from our TransferData handler which is true // since we don't have one. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_MAC_OPTIONS)" ) ); ulInfo = 0; break; } case OID_GEN_CO_MEDIA_SUPPORTED: case OID_GEN_CO_MEDIA_IN_USE: { // // We support 1394. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_MEDIA_SUPPORTED or OID_GEN_CO_MEDIA_IN_USE)" ) ); ulInfo = g_ulMedium; break; } case OID_GEN_CO_MINIMUM_LINK_SPEED: { // // Link speed depends upon the type of adapter. We will need to // add support for different speeds and so forth // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_MINIMUM_LINK_SPEED or OID_GEN_CO_LINK_SPEED)" ) ); CoLinkSpeed.Inbound = CoLinkSpeed.Outbound = pAdapter->SpeedMbps; //10 Mbps ???? pInfo = (PUCHAR)&CoLinkSpeed; ulInfoLen = sizeof(CoLinkSpeed); TRACE( TL_V, TM_Mp, ( "Link Speed %x" ,CoLinkSpeed.Outbound ) ); break; } case OID_GEN_CO_VENDOR_ID: { // // We need to add the appropriate vendor id for the nic1394 // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_VENDOR_ID)" ) ); ulInfo = 0xFFFFFFFF; break; } case OID_GEN_CO_VENDOR_DESCRIPTION: { TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_VENDOR_DESCRIPTION)" ) ); pInfo = (PUCHAR)pnic1394DriverDescription; ulInfoLen = strlen(pnic1394DriverDescription); break; } case OID_GEN_VENDOR_DRIVER_VERSION: { pInfo =(PVOID) &nic1394DriverGeneration; ulInfoLen = sizeof(nic1394DriverGeneration); break; } case OID_GEN_CO_DRIVER_VERSION: { // // Return the version of NDIS that we expect. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_DRIVER_VERSION)" ) ); usInfo = ((NDIS_MajorVersion << 8) | NDIS_MinorVersion); pInfo = (PUCHAR)&usInfo; ulInfoLen = sizeof(USHORT); break; } case OID_GEN_CO_PROTOCOL_OPTIONS: { // // We don't support protocol options. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_PROTOCOL_OPTIONS)" ) ); ulInfo = 0; break; } case OID_GEN_CO_MEDIA_CONNECT_STATUS: { // // Return our true state only if we have ever received a // remote node in this boot. // TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CO_MEDIA_CONNECT_STATUS)" ) ); if (ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RemoteNodeInThisBoot) == FALSE) { ulInfo = NdisMediaStateConnected; } else { ulInfo = pAdapter->MediaConnectStatus; } break; } case OID_1394_IP1394_CONNECT_STATUS: { // // Return whether or not we have a link. This is used by the Arp // module to set connectivity // TRACE( TL_V, TM_Mp, ( "QInfo(OID_1394_IP1394_CONNECT_STATUS)" ) ); ulInfo = pAdapter->MediaConnectStatus; break; } case OID_1394_LOCAL_NODE_INFO: { // This Oid return information about the local node // on the machine // Need to change this with real values that will be present // in the header structures // TRACE( TL_V, TM_Mp, ( "QInfo(OID_1394_LOCAL_NODE_INFO)" ) ); ADAPTER_ACQUIRE_LOCK (pAdapter); LocalNodeInfo.UniqueID = pAdapter->UniqueId; LocalNodeInfo.BusGeneration = pAdapter->Generation; LocalNodeInfo.NodeAddress = pAdapter->NodeAddress; LocalNodeInfo.MaxRecvBlockSize = pAdapter->MaxRec; LocalNodeInfo.MaxRecvSpeed = pAdapter->SCode; ADAPTER_RELEASE_LOCK (pAdapter); pInfo = &LocalNodeInfo; ulInfoLen = sizeof(LocalNodeInfo); break; } case OID_1394_VC_INFO: { // Returns information about the VC that is being queried // TRACE( TL_V, TM_Mp, ("QInfo(OID_1394_VC_INFO)") ); if (pVc != NULL) { VcInfo.Destination = pVc->Hdr.Nic1394MediaParams.Destination; pInfo = &VcInfo; ulInfoLen = sizeof(VcInfo); } else { status = NDIS_STATUS_FAILURE; } break; } case OID_1394_NICINFO: { if (InformationBufferLength >= sizeof(NicInfo)) { // // We need to call nicFillNicInfo at passive, so we switch // to a work item context. // if (KeGetCurrentIrql() > PASSIVE_LEVEL) { PNIC_WORK_ITEM pNicWorkItem; pNicWorkItem = ALLOC_NONPAGED (sizeof(NIC_WORK_ITEM), MTAG_WORKITEM); if (pNicWorkItem != NULL) { NdisZeroMemory(pNicWorkItem, sizeof(*pNicWorkItem)); pNicWorkItem->RequestInfo.pNdisRequest = NdisRequest; pNicWorkItem->RequestInfo.pVc = NULL; NdisInitializeWorkItem ( &pNicWorkItem->NdisWorkItem, (NDIS_PROC) nicQueryInformationWorkItem, (PVOID) pAdapter); TRACE( TL_V, TM_Cm, ( "Scheduling QueryInformation WorkItem" ) ); nicReferenceAdapter (pAdapter, "nicFillBusInfo "); NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems); NdisScheduleWorkItem (&pNicWorkItem->NdisWorkItem); status = NDIS_STATUS_PENDING; } else { status = NDIS_STATUS_RESOURCES; } } else { status = nicFillNicInfo ( pAdapter, (PNIC1394_NICINFO) InformationBuffer, // Input &NicInfo // Output ); ASSERT(status != NDIS_STATUS_PENDING); } } pInfo = &NicInfo; ulInfoLen = sizeof(NicInfo); break; } case OID_1394_QUERY_EUID_NODE_MAP: { if (sizeof (EUID_TOPOLOGY) <= InformationBufferLength ) { nicQueryEuidNodeMacMap (pAdapter, NdisRequest); status = NDIS_STATUS_PENDING; } else { // // This will cause NDIS_STATUS_INVALID_LENGTH to be returned // ulInfoLen = sizeof (EUID_TOPOLOGY); } break; } case OID_GEN_CO_XMIT_PDUS_OK: { ulInfo = pAdapter->AdaptStats.ulXmitOk; break; } case OID_GEN_CO_RCV_PDUS_OK: { ulInfo = pAdapter->AdaptStats.ulRcvOk; break; } case OID_GEN_CO_XMIT_PDUS_ERROR: { ulInfo = pAdapter->AdaptStats.ulXmitError; break; } case OID_GEN_CO_RCV_PDUS_ERROR: { ulInfo = pAdapter->AdaptStats.ulRcvError; break; } case OID_GEN_CO_RCV_PDUS_NO_BUFFER: { ulInfo = 0; break; } case OID_GEN_PHYSICAL_MEDIUM: { TRACE( TL_V, TM_Mp, ( " OID_GEN_PHYSICAL_MEDIUM" ) ); ulInfo = NdisPhysicalMedium1394; break; } case OID_1394_ISSUE_BUS_RESET: { TRACE( TL_V, TM_Mp, ( " OID_1394_ISSUE_BUS_RESET" ) ); // // The ndistester is currently the only user of this oid and does not set the flag // if (InformationBufferLength == sizeof(ULONG)) { nicIssueBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT ); } break; } case OID_PNP_CAPABILITIES: { TRACE( TL_V, TM_Mp, ("QInfo(OID_PNP_CAPABILITIES)") ); PnpCaps.Flags = 0; PnpCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; PnpCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; PnpCaps.WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; pInfo = &PnpCaps; ulInfoLen = sizeof (PnpCaps); break; } case OID_PNP_QUERY_POWER: { // // The miniport is always ready to go into low power state. // *BytesWritten = sizeof (NDIS_DEVICE_POWER_STATE ); *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE ); status = NDIS_STATUS_SUCCESS; break; } // // Now do the Ethernet OIDS // case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_MAXIMUM_FRAME_SIZE: case OID_GEN_MAXIMUM_TOTAL_SIZE: case OID_GEN_TRANSMIT_BLOCK_SIZE: case OID_GEN_RECEIVE_BLOCK_SIZE: case OID_GEN_MAXIMUM_SEND_PACKETS: case OID_GEN_TRANSMIT_BUFFER_SPACE: case OID_GEN_RECEIVE_BUFFER_SPACE: case OID_802_3_PERMANENT_ADDRESS: case OID_802_3_CURRENT_ADDRESS: case OID_802_3_MULTICAST_LIST: case OID_802_3_MAXIMUM_LIST_SIZE: case OID_802_3_RCV_ERROR_ALIGNMENT: case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: case OID_GEN_LINK_SPEED: case OID_GEN_CURRENT_PACKET_FILTER: { status = NicEthQueryInformation((NDIS_HANDLE)pAdapter, Oid, InformationBuffer, InformationBufferLength, BytesWritten, BytesNeeded ); if (status == NDIS_STATUS_SUCCESS) { pInfo = InformationBuffer; ulInfoLen = *BytesWritten; } else { if (status == NDIS_STATUS_INVALID_LENGTH) { ulInfoLen = *BytesNeeded; } else { status = NDIS_STATUS_NOT_SUPPORTED; TRACE( TL_V, TM_Mp, ( "Q-OID=$%08x?", Oid ) ); } } break; } default: { TRACE( TL_V, TM_Mp, ( "Q-OID=$%08x?", Oid ) ); status = NDIS_STATUS_NOT_SUPPORTED; ulInfoLen = 0; break; } } if (ulInfoLen > InformationBufferLength) { // Caller's buffer is too small. Tell him what he needs. // *BytesNeeded = ulInfoLen; *BytesWritten = 0; status = NDIS_STATUS_INVALID_LENGTH; } else { // // If the request has not been pended then, fill // out the retuen values // if (status == NDIS_STATUS_SUCCESS ) { // Copy the found result to caller's buffer. // if (ulInfoLen > 0) { NdisMoveMemory( InformationBuffer, pInfo, ulInfoLen ); DUMPDW( TL_V, TM_Mp, pInfo, ulInfoLen ); } *BytesNeeded = *BytesWritten = ulInfoLen; } } TRACE( TL_N, TM_Mp, ( " Q-OID=$%08x, Status %x, Bytes Written %x", Oid, status, *BytesWritten ) ); TRACE( TL_T, TM_Init, ( "<==nicQueryInformation, Status %.8x", status )); return status; } VOID nicReferenceAdapter( IN ADAPTERCB* pAdapter , IN PCHAR pDebugPrint ) /*++ Routine Description: Arguments: Return Value: --*/ // Adds areference to the adapter block, 'pAdapter'. // { LONG lRef; lRef = NdisInterlockedIncrement( &pAdapter->lRef ); TRACE( TL_V, TM_Ref, ( "**nicReferenceAdapter pAdapter %x, to %d, %s ", pAdapter, pAdapter->lRef, pDebugPrint ) ); } NDIS_STATUS nicSetInformation( IN ADAPTERCB* pAdapter, IN VCCB* pVc, IN OUT PNDIS_REQUEST NdisRequest ) /*++ Routine Description: Handle SetInformation requests. Arguments are as for the standard NDIS 'MiniportQueryInformation' handler except this routine does not count on being serialized with respect to other requests. Arguments: Return Value: --*/ { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; ULONG ulInfo = 0; VOID* pInfo= NULL; ULONG ulInfoLen= 0; USHORT usInfo = 0; NDIS_OID Oid; PVOID InformationBuffer; ULONG InformationBufferLength; PULONG BytesRead; PULONG BytesNeeded; // // Initialize the REquest Variables // Oid = NdisRequest->DATA.SET_INFORMATION.Oid; InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer; InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength; BytesRead = &NdisRequest->DATA.SET_INFORMATION.BytesRead; BytesNeeded = &NdisRequest->DATA.SET_INFORMATION.BytesNeeded; TRACE( TL_T, TM_Init, ( "==>nicSetInformation , Adapter %.8x, Vc %.8x, Oid %.8x",pAdapter, pVc, Oid )); Status = NDIS_STATUS_SUCCESS; switch (Oid) { case OID_GEN_CURRENT_PACKET_FILTER: { ULONG Filter; if (InformationBufferLength < sizeof (ULONG)) { Status = NDIS_STATUS_INVALID_LENGTH; break; } else { *BytesNeeded = sizeof (ULONG); } // // Store the new value. // NdisMoveMemory(&Filter, InformationBuffer, sizeof(ULONG)); // // Don't allow promisc mode, because we can't support that. // if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) { Status = NDIS_STATUS_FAILURE; break; } pAdapter->CurPacketFilter = Filter; Status = NDIS_STATUS_SUCCESS; ulInfoLen = sizeof (ULONG); break; } case OID_1394_ENTER_BRIDGE_MODE: { *BytesNeeded = 0; nicInitializeLoadArpStruct(pAdapter); Status = nicQueueRequestToArp (pAdapter, LoadArp, // Load Arp Module NdisRequest); if (Status == NDIS_STATUS_SUCCESS) { // // we have successfully queued a Workitem // so this request needs to be pended // Status = NDIS_STATUS_PENDING; } ulInfoLen = sizeof (ULONG); break; } case OID_1394_EXIT_BRIDGE_MODE: { *BytesNeeded = 0; if (pAdapter->fIsArpStarted == TRUE) { Status = nicQueueRequestToArp (pAdapter, UnloadArp, //Unload Arp Module NdisRequest); if (Status == NDIS_STATUS_SUCCESS) { // // we have successfully queued a Workitem // so this request needs to be pended // Status = NDIS_STATUS_PENDING; } ulInfoLen = sizeof (ULONG); } else { Status = NDIS_STATUS_SUCCESS; ulInfoLen = sizeof (ULONG); } break; } case OID_802_3_MULTICAST_LIST: case OID_GEN_CURRENT_LOOKAHEAD: case OID_GEN_NETWORK_LAYER_ADDRESSES: { Status = NicEthSetInformation(pAdapter, Oid, InformationBuffer, InformationBufferLength, BytesRead , BytesNeeded ); break; } case OID_1394_ISSUE_BUS_RESET: { TRACE( TL_V, TM_Mp, ( " OID_1394_ISSUE_BUS_RESET" ) ); // // The ndistester is currently the only user of this oid and does not set the flag // if (InformationBufferLength == sizeof(ULONG)) { nicIssueBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT ); } break; } case OID_PNP_SET_POWER: TRACE( TL_V, TM_Mp, ( "QInfo OID_PNP_SET_POWER %x", Oid ) ); *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE ); *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE ); if (InformationBufferLength >= sizeof (NDIS_DEVICE_POWER_STATE)) { NDIS_DEVICE_POWER_STATE PoState; NdisMoveMemory (&PoState,InformationBuffer,sizeof (PoState)); Status = nicSetPower(pAdapter,PoState); } break; default: { TRACE( TL_A, TM_Mp, ( "S-OID=$%08x?", Oid ) ); Status = NDIS_STATUS_NOT_SUPPORTED; *BytesRead = *BytesNeeded = 0; break; } } if (*BytesNeeded > InformationBufferLength) { // Caller's buffer is too small. Tell him what he needs. // *BytesRead = 0; Status = NDIS_STATUS_INVALID_LENGTH; } else { *BytesNeeded = *BytesRead = ulInfoLen; } TRACE( TL_A, TM_Mp, ( " S-OID=$%08x, Status %x, Bytes Read %x", Oid, Status, *BytesRead ) ); TRACE( TL_T, TM_Init, ( "<==nicSetInformation, Status %.8x", Status )); return Status; } //------------------------------------------------------------------------------ // C O N N E C T I O N L E S S F U N T I O N S S T A R T H E R E // NDIS_STATUS NicEthSetInformation( IN NDIS_HANDLE MiniportAdapterContext, NDIS_OID Oid, PVOID InformationBuffer, ULONG InformationBufferLength, PULONG BytesRead, PULONG BytesNeeded ) /*++ Routine Description: This is the Set information that will be used by the CL edge Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; UINT BytesLeft = InformationBufferLength; PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer); UINT OidLength; ULONG LookAhead; ULONG Filter; PADAPTERCB pAdapter; BOOLEAN IsShuttingDown; STORE_CURRENT_IRQL; pAdapter = (PADAPTERCB)MiniportAdapterContext; TRACE( TL_T, TM_Init, ( "==>nicEthSetInformation , Adapter %.8x, Oid %.8x",pAdapter, Oid )); // // IS the adapter shutting down // ADAPTER_ACQUIRE_LOCK (pAdapter); IsShuttingDown = (! ADAPTER_ACTIVE(pAdapter)) ; ADAPTER_RELEASE_LOCK (pAdapter); if (IsShuttingDown) { TRACE( TL_T, TM_Init, ( " nicSetInformation Shutting Down , Adapter %.8x, Oid %.8x",pAdapter, Oid )); *BytesRead = 0; *BytesNeeded = 0; NdisStatus = NDIS_STATUS_SUCCESS; return (NdisStatus); } // // Get Oid and Length of request // OidLength = BytesLeft; switch (Oid) { case OID_802_3_MULTICAST_LIST: if (OidLength % sizeof(MAC_ADDRESS)) { NdisStatus = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; *BytesNeeded = 0; break; } if (OidLength > (MCAST_LIST_SIZE * sizeof(MAC_ADDRESS))) { NdisStatus= NDIS_STATUS_MULTICAST_FULL; *BytesRead = 0; *BytesNeeded = 0; break; } NdisZeroMemory( &pAdapter->McastAddrs[0], MCAST_LIST_SIZE * sizeof(MAC_ADDRESS) ); NdisMoveMemory( &pAdapter->McastAddrs[0], InfoBuffer, OidLength ); pAdapter->McastAddrCount = OidLength / sizeof(MAC_ADDRESS); break; case OID_GEN_CURRENT_PACKET_FILTER: // // Verify length // if (OidLength != sizeof(ULONG)) { NdisStatus = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; *BytesNeeded = sizeof(ULONG); break; } // // Store the new value. // NdisMoveMemory(&Filter, InfoBuffer, sizeof(ULONG)); // // Don't allow promisc mode, because we can't support that. // if (Filter & NDIS_PACKET_TYPE_PROMISCUOUS) { NdisStatus = NDIS_STATUS_NOT_SUPPORTED; break; } ADAPTER_ACQUIRE_LOCK (pAdapter); pAdapter->CurPacketFilter = Filter; ADAPTER_RELEASE_LOCK (pAdapter); break; case OID_GEN_CURRENT_LOOKAHEAD: // // Verify length // if (OidLength != 4) { NdisStatus = NDIS_STATUS_INVALID_LENGTH; *BytesRead = 0; *BytesNeeded = 0; break; } // // Store the new value. // NdisMoveMemory(&LookAhead, InfoBuffer, sizeof(LookAhead)); pAdapter->CurLookAhead = LookAhead; break; case OID_GEN_NETWORK_LAYER_ADDRESSES: NdisStatus = NDIS_STATUS_SUCCESS; *BytesRead = InformationBufferLength; *BytesNeeded = InformationBufferLength; break; case OID_PNP_SET_POWER: TRACE( TL_V, TM_Mp, ( "QInfo OID_PNP_SET_POWER %x", Oid ) ); *BytesRead = sizeof (NDIS_DEVICE_POWER_STATE ); *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE ); if (InformationBufferLength >= sizeof (NDIS_DEVICE_POWER_STATE)) { NDIS_DEVICE_POWER_STATE PoState; NdisMoveMemory (&PoState,InformationBuffer,sizeof (PoState)); NdisStatus = nicSetPower(pAdapter,PoState); } break; case OID_1394_ISSUE_BUS_RESET: { TRACE( TL_V, TM_Mp, ( " OID_1394_ISSUE_BUS_RESET" ) ); if (InformationBufferLength == sizeof(ULONG)) { nicIssueBusReset (pAdapter, (*(PULONG)InformationBuffer)); } else { nicIssueBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT ); } break; } default: NdisStatus = NDIS_STATUS_INVALID_OID; *BytesRead = 0; *BytesNeeded = 0; break; } if (NdisStatus == NDIS_STATUS_SUCCESS) { DUMPDW( TL_V, TM_Mp, InformationBuffer, InformationBufferLength ); *BytesRead = BytesLeft; *BytesNeeded = 0; } TRACE( TL_T, TM_Init, ( "<==NicEthSetInformation , Adapter %.8x, Oid %.8x, NdisStatus %x",pAdapter, Oid, NdisStatus )); MATCH_IRQL; return NdisStatus; } NDIS_STATUS NicEthQueryInformation( IN NDIS_HANDLE MiniportAdapterContext, IN NDIS_OID Oid, IN PVOID InformationBuffer, IN ULONG InformationBufferLength, OUT PULONG BytesWritten, OUT PULONG BytesNeeded ) /*++ Routine Description: This is the Query information that will be used by the CL edge Arguments: Return Value: --*/ { UINT BytesLeft = InformationBufferLength; PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer); NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; NDIS_MEDIA_STATE MediaState; NDIS_MEDIUM Medium; PADAPTERCB pAdapter; ULONG GenericULong; USHORT GenericUShort; UCHAR GenericArray[6]; UINT MoveBytes = sizeof(GenericULong); PVOID MoveSource = (PVOID)(&GenericULong); ULONG i; STORE_CURRENT_IRQL; pAdapter = (PADAPTERCB)MiniportAdapterContext; TRACE( TL_T, TM_Init, ( "==>NicEthQueryInformation , Adapter %.8x, Oid %.8x",pAdapter, Oid )); // // Switch on request type // switch (Oid) { case OID_GEN_MAC_OPTIONS: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAC_OPTIONS)" ) ); GenericULong = NDIS_MAC_OPTION_NO_LOOPBACK; break; case OID_GEN_SUPPORTED_LIST: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_SUPPORTED_LIST)" ) ); MoveSource = (PVOID)(SupportedOids); MoveBytes = sizeof(SupportedOids); break; case OID_GEN_HARDWARE_STATUS: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_HARDWARE_STATUS)" ) ); HardwareStatus = NdisHardwareStatusReady; MoveSource = (PVOID)(&HardwareStatus); MoveBytes = sizeof(NDIS_HARDWARE_STATUS); break; case OID_GEN_MEDIA_CONNECT_STATUS: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MEDIA_CONNECT_STATUS)" ) ); if (ADAPTER_TEST_FLAG(pAdapter, fADAPTER_RemoteNodeInThisBoot) == FALSE) { MediaState = NdisMediaStateConnected; } else { MediaState = pAdapter->MediaConnectStatus; } MoveSource = (PVOID)(&MediaState); MoveBytes = sizeof(NDIS_MEDIA_STATE); break; case OID_GEN_MEDIA_SUPPORTED: case OID_GEN_MEDIA_IN_USE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MEDIA_SUPPORTED)" ) ); Medium = g_ulMedium; MoveSource = (PVOID) (&Medium); MoveBytes = sizeof(NDIS_MEDIUM); break; case OID_GEN_MAXIMUM_LOOKAHEAD: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_LOOKAHEAD)" ) ); GenericULong = pAdapter->MaxRecvBufferSize; break; case OID_GEN_CURRENT_LOOKAHEAD: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CURRENT_LOOKAHEAD)" ) ); GenericULong = pAdapter->MaxRecvBufferSize; break; case OID_GEN_MAXIMUM_FRAME_SIZE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_FRAME_SIZE)" ) ); GenericULong = IP1394_RFC_FRAME_SIZE; //pAdapter->MaxRecvBufferSize; break; case OID_GEN_MAXIMUM_TOTAL_SIZE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_TOTAL_SIZE)" ) ); GenericULong = IP1394_RFC_FRAME_SIZE; //pAdapter->MaxRecvBufferSize; break; case OID_GEN_TRANSMIT_BLOCK_SIZE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_TRANSMIT_BLOCK_SIZE)" ) ); GenericULong = pAdapter->MaxRecvBufferSize - sizeof (NDIS1394_UNFRAGMENTED_HEADER); break; case OID_GEN_RECEIVE_BLOCK_SIZE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_RECEIVE_BLOCK_SIZE)" ) ); GenericULong = pAdapter->MaxRecvBufferSize - sizeof (NDIS1394_UNFRAGMENTED_HEADER); break; case OID_GEN_MAXIMUM_SEND_PACKETS: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_MAXIMUM_SEND_PACKETS)" ) ); GenericULong = 32; // XXX What is our limit? From adapter? break; case OID_GEN_LINK_SPEED: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_LINK_SPEED)" ) ); GenericULong = pAdapter->SpeedMbps; break; case OID_GEN_TRANSMIT_BUFFER_SPACE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_TRANSMIT_BUFFER_SPACE)" ) ); GenericULong = pAdapter->MaxSendBufferSize;; break; case OID_GEN_RECEIVE_BUFFER_SPACE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_RECEIVE_BUFFER_SPACE)" ) ); GenericULong = pAdapter->MaxRecvBufferSize; break; case OID_GEN_VENDOR_ID: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_VENDOR_ID)" ) ); GenericULong = 0xFFFFFFFF; break; case OID_GEN_VENDOR_DESCRIPTION: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_VENDOR_DESCRIPTION)" ) ); MoveSource = pnic1394DriverDescription; MoveBytes = strlen(pnic1394DriverDescription); break; case OID_GEN_DRIVER_VERSION: case OID_GEN_VENDOR_DRIVER_VERSION: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_DRIVER_VERSION)" ) ); GenericULong = 2; break; case OID_802_3_PERMANENT_ADDRESS: case OID_802_3_CURRENT_ADDRESS: TRACE( TL_V, TM_Mp, ( "QInfo(OID_802_3_CURRENT_ADDRESS)" ) ); NdisMoveMemory((PCHAR)GenericArray, &pAdapter->MacAddressEth, sizeof(MAC_ADDRESS)); MoveSource = (PVOID)(GenericArray); MoveBytes = sizeof(MAC_ADDRESS); break; case OID_802_3_MULTICAST_LIST: TRACE( TL_V, TM_Mp, ( "QInfo(OID_802_3_MULTICAST_LIST)" ) ); MoveSource = (PVOID) &pAdapter->McastAddrs[0]; MoveBytes = pAdapter->McastAddrCount * sizeof(MAC_ADDRESS); break; case OID_802_3_MAXIMUM_LIST_SIZE: TRACE( TL_V, TM_Mp, ( "QInfo(OID_802_3_MAXIMUM_LIST_SIZE)" ) ); GenericULong = MCAST_LIST_SIZE; break; case OID_GEN_XMIT_OK: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_XMIT_OK)" ) ); GenericULong = pAdapter->AdaptStats.ulXmitOk;; break; case OID_GEN_RCV_OK: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_RCV_OK)" ) ); GenericULong = pAdapter->AdaptStats.ulRcvOk ; break; case OID_GEN_CURRENT_PACKET_FILTER: TRACE( TL_V, TM_Mp, ( "QInfo(OID_GEN_CURRENT_PACKET_FILTER)" ) ); GenericULong = pAdapter->CurPacketFilter ; break; case OID_GEN_XMIT_ERROR: case OID_GEN_RCV_ERROR: case OID_GEN_RCV_NO_BUFFER: case OID_802_3_RCV_ERROR_ALIGNMENT: case OID_802_3_XMIT_ONE_COLLISION: case OID_802_3_XMIT_MORE_COLLISIONS: GenericULong = 0; TRACE( TL_V, TM_Mp, ( "QInfo oid %x", Oid ) ); break; case OID_PNP_QUERY_POWER: TRACE( TL_V, TM_Mp, ( "QInfo OID_PNP_QUERY_POWER %x", Oid ) ); *BytesWritten = sizeof (NDIS_DEVICE_POWER_STATE ); *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE ); NdisStatus = NDIS_STATUS_SUCCESS; break; default: NdisStatus = NDIS_STATUS_INVALID_OID; break; } if (NdisStatus == NDIS_STATUS_SUCCESS) { if (MoveBytes > BytesLeft) { // // Not enough room in InformationBuffer. Punt // *BytesNeeded = MoveBytes; NdisStatus = NDIS_STATUS_INVALID_LENGTH; } else { // // Store result. // NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes); //(*BytesWritten) += MoveBytes; *BytesWritten = MoveBytes; DUMPDW( TL_V, TM_Mp, InfoBuffer, *BytesWritten); } } TRACE( TL_T, TM_Init, ( "<==NicEthQueryInformation , Adapter %.8x, Oid %.8x, Status %x Bytes Written %x ",pAdapter, Oid, NdisStatus, *BytesWritten )); //MATCH_IRQL; return NdisStatus; } VOID NicMpSendPackets( IN NDIS_HANDLE MiniportAdapterContext, IN PPNDIS_PACKET PacketArray, IN UINT NumberOfPackets ) /*++ Routine Description: The is the SendPacket handler used by the ConnectionLess interface The Bridge Protocol will send packets here and this function will wrap the data into a new NDIS_PACKET and indicate it up on the Ethernet VC to the ARP module Arguments: Return Value: --*/ { PADAPTERCB pAdapter = (PADAPTERCB)MiniportAdapterContext; PETHERNET_VCCB pEthernetVc = NULL; BOOLEAN fVcActive = FALSE; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; NDIS_STATUS IndicatedStatus = NDIS_STATUS_FAILURE; ULONG i; TRACE( TL_T, TM_Init, ( "==> NicMpSendPackets , Adapter %.8x, ppPacket %x, Num %x",pAdapter, PacketArray, NumberOfPackets )); do { if (pAdapter->pEthernetVc == NULL) { break; } ADAPTER_ACQUIRE_LOCK (pAdapter); pEthernetVc = pAdapter->pEthernetVc; fVcActive = VC_ACTIVE(pEthernetVc); if (fVcActive == TRUE) { for (i =0 ; i < NumberOfPackets; i++) { // // Reference the Vc for each packet // nicReferenceCall((PVCCB)pEthernetVc, "NicMpSendPackets"); } } ADAPTER_RELEASE_LOCK (pAdapter); if (fVcActive) { // //Set resource and indicate the packet array up to ndis // for (i =0 ; i < NumberOfPackets; i++) { PNDIS_PACKET pMyPacket = NULL, pPacket = NULL; PPKT_CONTEXT pPktContext = NULL; pPacket = PacketArray[i]; // // Now allocate a new packet // nicAllocatePacket (&NdisStatus, &pMyPacket, &pEthernetVc->PacketPool); if (NdisStatus != NDIS_STATUS_SUCCESS) { pMyPacket = NULL; break; } // // Set the original packet as the packet context // pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReservedEx; pPktContext->EthernetSend.pOrigPacket = pPacket; IndicatedStatus = NDIS_STATUS_RESOURCES; NDIS_SET_PACKET_STATUS (pMyPacket, IndicatedStatus); // // Chain the NdisBuffers // pMyPacket->Private.Head = pPacket->Private.Head; pMyPacket->Private.Tail = pPacket->Private.Tail; // // Dump the packet // { nicDumpPkt (pMyPacket, "Conn Less Send "); nicCheckForEthArps (pMyPacket); } // // We are in Ndis' context so we do not need a timer // NdisMCoIndicateReceivePacket(pEthernetVc->Hdr.NdisVcHandle, &pMyPacket,NumberOfPackets ); if (IndicatedStatus == NDIS_STATUS_RESOURCES) { // // Return Packets work // pPktContext = (PPKT_CONTEXT)&pMyPacket->MiniportReservedEx; ASSERT ( pPacket == pPktContext->EthernetSend.pOrigPacket ); // // Free the locally allocated packet // nicFreePacket(pMyPacket, &pEthernetVc->PacketPool); } } NdisMCoReceiveComplete(pAdapter->MiniportAdapterHandle); } }while (FALSE); // // Regardless of success, we need to complete the sends // for ( i = 0 ; i < NumberOfPackets; i++) { if (fVcActive == TRUE) { nicDereferenceCall ((PVCCB)pEthernetVc, "NicMpSendPackets" ); } NdisMSendComplete ( pAdapter->MiniportAdapterHandle, PacketArray[i], NDIS_STATUS_SUCCESS); } TRACE( TL_T, TM_Init, ( "<== NicMpSendPackets ")); } //---------------------------------------------------------------------------- // R E M O T E N O D E F U N C T I O N S S T A R T H E R E // NTSTATUS nicAddRemoteNode( IN PVOID Nic1394AdapterContext, // Nic1394 handle for the local host adapter IN PVOID Enum1394NodeHandle, // Enum1394 handle for the remote node IN PDEVICE_OBJECT RemoteNodePhysicalDeviceObject, // physical device object for the remote node IN ULONG UniqueId0, // unique ID Low for the remote node IN ULONG UniqueId1, // unique ID High for the remote node OUT PVOID * pNic1394NodeContext // Nic1394 context for the remote node ) /*++ Routine Description: This function does updates all the required nic1394 data structures to signal the arrival of a new remote node. Inserts itself into the correct list and allocates an address range for itself. The calls to AddRemoteNode and RemoveRemoteNode are serialized because they only happen in the when enum1394 gets a Start and Stop Arguments: Explained above Return Value: --*/ { NTSTATUS Status = STATUS_SUCCESS; REMOTE_NODE *pRemoteNode = NULL; PADAPTERCB pAdapter = (PADAPTERCB)Nic1394AdapterContext; UINT64 RemoteNodeUniqueId; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; BOOLEAN fNeedToRequestResetNotification = FALSE; ULONG Generation = 0; BOOLEAN fIsOnlyNode = FALSE; STORE_CURRENT_IRQL; RemoteNodeUniqueId = 0; RemoteNodeUniqueId = UniqueId0; RemoteNodeUniqueId = RemoteNodeUniqueId<<32; RemoteNodeUniqueId = RemoteNodeUniqueId | UniqueId1 ; TRACE( TL_N, TM_Mp, ( "** nicAddRemoteNode Remote %.8x, UniqueId %I64x", RemoteNodePhysicalDeviceObject, RemoteNodeUniqueId) ); // Initialize a PdoCb with the 1394 Pdo and insert it into the Pdo list // do { NdisStatus = nicInitializeRemoteNode(&pRemoteNode, RemoteNodePhysicalDeviceObject, RemoteNodeUniqueId); *pNic1394NodeContext = pRemoteNode; if (NdisStatus!=NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Mp, ( "NicMpInitializePdoCb FAILED %.8x", RemoteNodePhysicalDeviceObject) ); break; } pRemoteNode->pAdapter = pAdapter; pRemoteNode->Enum1394NodeHandle = Enum1394NodeHandle; pAdapter->MediaConnectStatus = NdisMediaStateConnected; // // We need to go through the RecvFiFo List and get allocate any address ranges on this pdo as well // ADAPTER_ACQUIRE_LOCK (pAdapter); // // Increment the Refcount. This signifies that the pRemoteNode has been created and will // be derefed only when the nic gets a notification of removal. // pRemoteNode->pAdapter = pAdapter; // // Add a reference to the adapter as the Pdo Block, now has a pointer to it // Will be derefed in the RemoveRemoteNode // nicReferenceAdapter (pAdapter, "nicAddRemoteNode"); // // Figure out if there are no remote node in the Adapter's list. that will make this node the only remote node // and we will have to kickstart the BCM algorithm // fIsOnlyNode = IsListEmpty (&pAdapter->PDOList); TRACE( TL_V, TM_Mp, ( " nicAddRemoteNode: fIsOnlyNode %x", fIsOnlyNode ) ); // // Insert the PDO into the adapter's RemoteNode List // InsertTailList (&pAdapter->PDOList, &pRemoteNode->linkPdo); NdisInterlockedIncrement (&pAdapter->AdaptStats.ulNumRemoteNodes); // // Increment the ref on the Pdo block as the adapter, now has a pointer to it // Will be derefed whereve the remote node is popped of the list // nicReferenceRemoteNode (pRemoteNode, AddRemoteNode); // // Now set the flag that the Pdo Block is activated, and that // it is ready to receive Irps // REMOTE_NODE_SET_FLAG (pRemoteNode, PDO_Activated); ADAPTER_RELEASE_LOCK (pAdapter); { NODE_ADDRESS RemoteNodeAddress; NdisStatus = nicGet1394AddressOfRemoteNode( pRemoteNode, &RemoteNodeAddress, 0 ); if (NdisStatus == NDIS_STATUS_SUCCESS) { TRACE( TL_V, TM_Mp, ( " RemoteNode %x , NodeAddress %", pRemoteNode, RemoteNodeAddress.NA_Node_Number) ); ADAPTER_ACQUIRE_LOCK (pAdapter); pAdapter->NodeTable.RemoteNode[RemoteNodeAddress.NA_Node_Number] = pRemoteNode; pRemoteNode->RemoteAddress = RemoteNodeAddress; ADAPTER_RELEASE_LOCK (pAdapter); } else { ASSERT (!" Unable to get Address from remote node"); // // Do not fail the Add Node // REMOTE_NODE_SET_FLAG (pRemoteNode, PDO_NotInsertedInTable); NdisStatus = NDIS_STATUS_SUCCESS; } } // // Update the local host's speed values // nicUpdateLocalHostSpeed (pAdapter); // // Update the remote node's cached caps. // { UINT SpeedTo; UINT EffectiveMaxBufferSize; UINT MaxRec; // Specifying FALSE (!from cache) below causes pRemoteNode's cached caps // to be refreshed. Ignore return value. // (VOID) nicQueryRemoteNodeCaps (pAdapter, pRemoteNode, &SpeedTo, &EffectiveMaxBufferSize, &MaxRec ); } // // We have received a remote node in this boot. // Set the flag. No need to hold the lock // ADAPTER_SET_FLAG(pAdapter, fADAPTER_RemoteNodeInThisBoot); // // Kick start the BCM algorithm if this is the only node in the Adapter's list. also need to initialize the BCR // if necessary. All done in this BCMAddRemoteNode function // nicBCMAddRemoteNode (pAdapter, fIsOnlyNode ); // // Inform the protocols of this new node, so that // it can query us for a new Euid Map // nicInformProtocolsOfReset(pAdapter); }while (FALSE); TRACE( TL_T, TM_Mp, ("<==nicAddRemoteNode Remote %.8x, Status %.8x", RemoteNodePhysicalDeviceObject, Status)); MATCH_IRQL; return NdisStatus; } VOID nicDeleteLookasideList ( IN OUT PNIC_NPAGED_LOOKASIDE_LIST pLookasideList ) /*++ Routine Description: Deletes a nic1394 Lookaside list Arguments: Return Value: --*/ { TRACE( TL_T, TM_Cm, ( "==> nicDeleteLookasideList pLookaside List %x", pLookasideList ) ); if (pLookasideList) { ASSERT (pLookasideList->OutstandingPackets == 0); NdisDeleteNPagedLookasideList (&pLookasideList->List); } TRACE( TL_T, TM_Cm, ( "<== nicDeleteLookasideList pLookaside List %x", pLookasideList) ); } NDIS_STATUS nicFreeRemoteNode( IN REMOTE_NODE *pRemoteNode ) /*++ Routine Description: Frees a Remote Node when the refcount goes to zero Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; TRACE( TL_T, TM_Mp, ( "==>nicFreeRemoteNodepRemoteNode %.8x", pRemoteNode ) ); ASSERT (pRemoteNode->Ref.ReferenceCount == 0); nicFreeNicSpinLock (&pRemoteNode->ReassemblyLock); pRemoteNode->pPdo = NULL; pRemoteNode->ulTag = MTAG_FREED; FREE_NONPAGED (pRemoteNode); TRACE( TL_T, TM_Mp, ( "<==nicFreeRemoteNode" ) ); return NdisStatus; } VOID nicInitializeLookasideList( IN OUT PNIC_NPAGED_LOOKASIDE_LIST pLookasideList, ULONG Size, ULONG Tag, USHORT Depth ) /*++ Routine Description: Allocates and initializes a nic Lookaside list Arguments: Return Value: --*/ { TRACE( TL_T, TM_Cm, ( "==> nicInitializeLookasideList pLookaside List %x, size %x, Tag %x, Depth %x, ", pLookasideList, Size, Tag, Depth) ); NdisInitializeNPagedLookasideList( &pLookasideList->List, NULL, //Allocate NULL, // Free 0, // Flags Size, MTAG_CBUF, Depth ); // Depth pLookasideList->Size = Size; TRACE( TL_T, TM_Cm, ( "<== nicInitializeLookasideList " ) ); } NDIS_STATUS nicInitializeRemoteNode( OUT REMOTE_NODE **ppRemoteNode, IN PDEVICE_OBJECT p1394DeviceObject, IN UINT64 UniqueId ) /*++ Routine Description: This function allocates and initializes a control block for the Device Object that is being passed . Also sets the initalize flag and, intialized the Vc List Copies the unique id, Initializes the reassembly structures ( lock and list) Arguments: pRemoteNode - Pointer to remote node that was allocated pDevice Object for the remote node Unique Id - UID of the remote node Return Value: Resources - if the Allocation failed Success - otherwise --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; PREMOTE_NODE pRemoteNode = NULL; TRACE( TL_T, TM_Mp, ( "==>NicInitializeRemoteNode PDO %.8x UniqueId %I64x", p1394DeviceObject, UniqueId) ); do { pRemoteNode = ALLOC_NONPAGED( sizeof(REMOTE_NODE), MTAG_REMOTE_NODE); if (pRemoteNode == NULL) { TRACE( TL_A, TM_Mp, ( "Memory Allocation for Pdo Block FAILED" ) ); *ppRemoteNode = NULL; NdisStatus = NDIS_STATUS_RESOURCES; break; } // // Zero out the strcuture // NdisZeroMemory ( pRemoteNode , sizeof(REMOTE_NODE) ); // // Set up the tag // pRemoteNode ->ulTag = MTAG_REMOTE_NODE; // // Set up the remote device's PDO // pRemoteNode ->pPdo = p1394DeviceObject; // // Set up the Unique ID // pRemoteNode ->UniqueId = UniqueId; // // Set up a Fake Mac Address for the Unique ID // nicGetMacAddressFromEuid(&UniqueId, &pRemoteNode->ENetAddress) ; // // Initialize the VC that are open on this Remote Node // InitializeListHead ( &(pRemoteNode->VcList)); // // Initialize the ref count // nicInitializeRef (&pRemoteNode->Ref); // // allocate the spin lock to control reassembly // nicInitializeNicSpinLock (&(pRemoteNode ->ReassemblyLock)); // // list for all reassemblies happenning on the remote node // InitializeListHead (&pRemoteNode->ReassemblyList); *ppRemoteNode = pRemoteNode ; } while (FALSE); TRACE( TL_T, TM_Mp, ( "<==NicInitializeRemoteNode, Status %.8x, pRemoteNode %.8x", NdisStatus, *ppRemoteNode) ); return NdisStatus; } VOID nicNoRemoteNodesLeft ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Called from the RemoveRemote Node codepath This means that the last node has gone away. Indicate a Media Disconnect. Arguments: Return Value: --*/ { BOOLEAN fBCMInProgress; ADDRESS_RANGE_CONTEXT BCRAddressRange; TRACE( TL_T, TM_Bcm, ( "==>nicNoRemoteNodesLeft pAdapter %x ",pAdapter ) ); pAdapter->MediaConnectStatus = NdisMediaStateDisconnected; if (ADAPTER_TEST_FLAG( pAdapter, fADAPTER_Halting) == FALSE) { nicMIndicateStatus ( pAdapter,NDIS_STATUS_MEDIA_DISCONNECT, NULL,0); } TRACE( TL_T, TM_Bcm, ( "<==nicNoRemoteNodesLeft pAdapter %x ",pAdapter ) ); } VOID nicReallocateChannels ( IN PNDIS_WORK_ITEM pWorkItem, IN PVOID Context ) /*++ Routine Description: Walk through all the channel VCs and reallocate all the previously allocated channels except the BCM channel . The BCM will reallocate this Tell the protocol that the 1394 bus has been reset. after all the channels have been allocated Arguments: Return Value: --*/ { ULONGLONG ChannelsAllocatedByLocalHost = 0; ULONG Channel = 0; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PADAPTERCB pAdapter = (PADAPTERCB) Context; ULONGLONG One = 1; TRACE( TL_T, TM_Mp, ( "==>nicReallocateChannels pAdpater %x", pAdapter) ); TRACE( TL_V, TM_Mp, (" nicReallocateChannels ChannelsAllocatedByLocalHost %I64x ", ChannelsAllocatedByLocalHost) ); Channel =0; while (Channel < NIC1394_MAX_NUMBER_CHANNELS ) { // // Does the channel 'i' need to be allocated // ADAPTER_ACQUIRE_LOCK (pAdapter); ChannelsAllocatedByLocalHost = pAdapter->ChannelsAllocatedByLocalHost ; ADAPTER_RELEASE_LOCK (pAdapter); if ( (( g_ullOne<OutstandingWorkItems); nicDereferenceAdapter(pAdapter, "nicResetReallocateChannels "); FREE_NONPAGED(pWorkItem); TRACE( TL_T, TM_Mp, ( "<==nicReallocateChannels " ) ); } NDIS_STATUS nicRemoteNodeRemoveVcCleanUp( IN REMOTE_NODE *pRemoteNode ) /*++ Routine Description: This function walks through the Pdo's Vc list annd closes the calls on each of them. These are SendFIFO VCs. Channel VC's will not be closed when the remote node is removed. This is typically called from a remove remote node function Arguments: PdoCb Pdo Control block that is getting removed Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PVCCB pVc = NULL; PLIST_ENTRY pVcList = NULL; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Mp, ( "==>nicRemoteNodeRemoveVcCleanUp pRemoteNode %.8x", pRemoteNode ) ); pVcList = ListNext (&pRemoteNode->VcList); while (pVcList != &pRemoteNode->VcList) { pVc = (VCCB*) CONTAINING_RECORD (pVcList, VCHDR, SinglePdoVcLink); // // move to the next Vc in the list // pVcList = ListNext (pVcList); TRACE( TL_V, TM_Mp, ( " nicRemoteNodeRemoveVcCleanUp VcType %x",pVc->Hdr.VcType ) ); switch(pVc->Hdr.VcType) { case NIC1394_SendRecvChannel: case NIC1394_RecvChannel: case NIC1394_SendChannel: { PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc; PREMOTE_NODE pNewChannelNode = NULL; // // Nothing to do here now // break; } case NIC1394_SendFIFO: { // // We know that it is a Send FIFO and the call needs to be closed // VC_SET_FLAG (pVc, VCBF_VcDispatchedCloseCall); // // This is to guarantee that we have the Vc Structure around at the end of the call // nicReferenceVc (pVc); REMOTE_NODE_RELEASE_LOCK (pRemoteNode); TRACE( TL_V, TM_Mp, ( "Dispatching a close call for Vc%.8x ",pVc ) ); NdisMCmDispatchIncomingCloseCall (NDIS_STATUS_SUCCESS, pVc->Hdr.NdisVcHandle, NULL, 0 ); REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode); // // Deref the ref made above. // nicDereferenceVc (pVc); break; } default: { // // There should be no other VC types here // TRACE( TL_A, TM_Mp, ( " Invalid VC %x Type nicRemoteNodeRemoveVcCleanUp ", pVc ) ); ASSERT (0); } } } MATCH_IRQL; TRACE( TL_T, TM_Mp, ( "<==nicRemoteNodeRemoveVcCleanUp " ) ); return NDIS_STATUS_SUCCESS; } NTSTATUS nicRemoveRemoteNode( IN PVOID Nic1394NodeContext // Nic1394 context for the remote node ) /*++ Routine Description: This function does all the hard work when the nic gets notification of a remote node going away. Closes all calls on the Pdo , Removes the Remote Node from the adapter's listPdo frees all the reassemblies on this node and then waits for the refcount to go to zero The calls to AddRemoteNode and RemoveRemoteNode are serialized because they only happen in the when enum1394 gets a Start and Stop Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; NTSTATUS Status = STATUS_SUCCESS; PREMOTE_NODE pRemoteNode = (REMOTE_NODE *)Nic1394NodeContext; PADAPTERCB pAdapter = pRemoteNode->pAdapter; PLIST_ENTRY pVcListEntry = NULL; PVCCB pVc = NULL; BOOLEAN FreeAddressRange = TRUE; BOOLEAN fIsPdoListEmpty = FALSE; LIST_ENTRY ReassemblyList; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Mp, ( " ** nicRemoveRemoteNode Node Context %x , Pdo %x",Nic1394NodeContext, pRemoteNode->pPdo ) ); do { pAdapter->pLastRemoteNode = pRemoteNode; REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode); // // We should tell everyone that the Pdo is being removed. However keep the node active // because there are Vc's which might need to submit Irps // REMOTE_NODE_SET_FLAG (pRemoteNode, PDO_Removed); // // Dispatch Close call requests for active calls on this Pdo. // However, keep the VCs in the pdocb's list // The NicCmCloseCall is the only function that removes Pdo's from the list // Will need to free the address range for any recv Vcs seperately // NdisStatus = nicRemoteNodeRemoveVcCleanUp (pRemoteNode); // // Remove the remote node from the RemoteNode Table // // nicRemoveRemoteNodeFromNodeTable(&pAdapter->NodeTable,pRemoteNode); // // Free All reassembly operations on this remopte node // nicFreeReassembliesOnRemoteNode (pRemoteNode, &ReassemblyList); // // Dereference the ref that was added when the Pdo block was inserted in the Adapter's list // The actual removal will take place later. We still have close calls to be completed and they // will need the PdoCb. So it remains in the adapter's queue // nicDereferenceRemoteNode (pRemoteNode, RemoveRemoteNode); // // Need to Deref the Reference made in NicInitializeRemoteNode function // nicDereferenceRemoteNode (pRemoteNode, RemoveRemoteNode); // // Dequeue the remote node here // nicRemoveEntryList (&pRemoteNode->linkPdo); NdisInterlockedDecrement (&pAdapter->AdaptStats.ulNumRemoteNodes); // // If this was the last remote node, then some special cleaning will be done // fIsPdoListEmpty = IsListEmpty (&pAdapter->PDOList); TRACE( TL_T, TM_Mp, ( " nicRemoveRemoteNode fIsOnlyNode %x ",fIsPdoListEmpty ) ); REMOTE_NODE_RELEASE_LOCK (pRemoteNode); // // Now, we wait forever for all the reference to go away // TRACE( TL_V, TM_Mp, ( "About ot Wait RemoteNode Ref's to go to zero" ) ); NdisWaitEvent (&pRemoteNode->Ref.RefZeroEvent, WAIT_INFINITE); TRACE( TL_V, TM_Mp, ( "Wait Succeeded Ref == 0, pRemoteNode %.8x, RefCount %.8x ", pRemoteNode, pRemoteNode->Ref.ReferenceCount) ); // // If this was the last node, and the remote node list is empty, we need to clean up the BCR // if (fIsPdoListEmpty == TRUE) { nicNoRemoteNodesLeft (pAdapter); } // // Delete the reassemblies that belong to this remote node and free them // if (IsListEmpty (&ReassemblyList) == FALSE) { nicAbortReassemblyList (&ReassemblyList); } nicFreeRemoteNode(pRemoteNode); // // Now update the speed on the adapter // nicUpdateLocalHostSpeed(pAdapter); // // Inform the protocols of the node removal, so that // it can query us for a new Euid Map // nicInformProtocolsOfReset(pAdapter); // // Careful this could cause the adapter refcounts to go to zero // nicDereferenceAdapter(pAdapter, "nicRemoveRemoteNode "); } while (FALSE); TRACE( TL_T, TM_Mp, ( "<== nicRemoveRemoteNode Status %.8x ", NdisStatus ) ); MATCH_IRQL; return NDIS_STATUS_SUCCESS; } VOID nicResetNotificationCallback ( IN PVOID pContext ) /*++ Routine Description: This routine will be called whenever the bus is reset. It will be called at DISPATCH Level Arguments: Context : a Remote Node Return Value: --*/ { PADAPTERCB pAdapter = (PADAPTERCB) pContext; BOOLEAN fNeedToQueueBCMWorkItem = FALSE; TRACE( TL_T, TM_Mp, ( "==>nicResetNotificationCallback Context %.8x ", pContext ) ); NdisInterlockedIncrement (&pAdapter->AdaptStats.ulNumResetCallbacks); pAdapter->AdaptStats.ulResetTime = nicGetSystemTime(); TRACE( TL_I, TM_Mp, ( " BUS RESET Callback Context %x, Old Gen %x ", pContext , pAdapter->Generation) ); // // Restart the BCM // nicResetRestartBCM (pAdapter); // // reallocate all channels that were opened by this node // nicResetReallocateChannels( pAdapter); // // Invalidate all pending reassemblies // nicFreeAllPendingReassemblyStructures(pAdapter); TRACE( TL_T, TM_Mp, ( "<==nicResetNotificationCallback " ) ); } VOID nicResetReallocateChannels ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Fires off a workitem to reallocate channels. ONLY To be called from a reset. Once all the channels have been re-allocated, it causes an indication to the protocols, Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PNDIS_WORK_ITEM pResetChannelWorkItem; TRACE( TL_T, TM_Mp, ( "==>nicResetReallocateChannels " ) ); // // reference the adapter as it is going to passed to a workiter. // decremented in the workitem // nicReferenceAdapter(pAdapter, "nicResetReallocateChannels"); do { pResetChannelWorkItem = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM); if (pResetChannelWorkItem== NULL) { TRACE( TL_A, TM_Cm, ( "nicResetReallocateChannels : Local Alloc failed for WorkItem" ) ); NdisStatus = NDIS_STATUS_RESOURCES; break; } else { // // From here on, this function cannot fail. // NdisStatus = NDIS_STATUS_SUCCESS; } NdisInitializeWorkItem ( pResetChannelWorkItem, (NDIS_PROC) nicReallocateChannels , (PVOID) pAdapter); TRACE( TL_V, TM_Cm, ( "Scheduling Channels WorkItem" ) ); NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems); NdisScheduleWorkItem (pResetChannelWorkItem); } while (FALSE); TRACE( TL_T, TM_Mp, ( "<==nicResetReallocateChannels %x ", NdisStatus ) ); } VOID nicResetRestartBCM ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Clean up the adapter's data structure and restart the BCM algorithm Arguments: Return Value: --*/ { TRACE( TL_T, TM_Mp, ( "==>nicResetRestartBCM pAdpater %x", pAdapter ) ); // // Now set up the data structures so we can restart the BCM for this generation // ADAPTER_ACQUIRE_LOCK(pAdapter); pAdapter->BCRData.LocalHostBCRBigEndian = BCR_IMPLEMENTED_BIG_ENDIAN; pAdapter->BCRData.IRM_BCR.NC_One = 1; pAdapter->BCRData.IRM_BCR.NC_Valid = 0; pAdapter->BCRData.IRM_BCR.NC_Channel = 0x3f; // // Clear the flags that are only valid through a single run of the BCM algorithm // BCR_CLEAR_FLAG (pAdapter, BCR_BCMFailed | BCR_LocalHostBCRUpdated | BCR_ChannelAllocated | BCR_LocalHostIsIRM); // // This will inform any BCM algorithm that a new reset happened // ADAPTER_SET_FLAG (pAdapter, fADAPTER_InvalidGenerationCount); // // We might have a thread waiting in FindIrmAmongRemoteNodes. .. Let it go and make it // abort the BCM // pAdapter->BCRData.BCRWaitForNewRemoteNode.EventCode = nic1394EventCode_BusReset; NdisSetEvent (&pAdapter->BCRData.BCRWaitForNewRemoteNode.NdisEvent); ADAPTER_RELEASE_LOCK(pAdapter); // // Now reschedule a work item to do the BCM algorithm // TRACE( TL_A, TM_Bcm , ("Reset - scheduling the BCM" ) ); nicScheduleBCMWorkItem(pAdapter); TRACE( TL_T, TM_Mp, ( "<==nicResetRestartBCM " ) ); } VOID nicBusResetWorkItem( NDIS_WORK_ITEM* pResetWorkItem, IN PVOID Context ) /*++ Routine Description: Calls nicBusReset and exits Arguments: Return Value: --*/ { PADAPTERCB pAdapter= (PADAPTERCB) Context; TRACE( TL_T, TM_Mp, ( "==>nicBusResetWorkItem " ) ); nicBusReset (pAdapter, BUS_RESET_FLAGS_FORCE_ROOT ); NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems); nicDereferenceAdapter(pAdapter, "nicBusResetWorkItem"); TRACE( TL_T, TM_Mp, ( "<==nicBusResetWorkItem" ) ); FREE_NONPAGED (pResetWorkItem); } VOID nicIssueBusReset ( PADAPTERCB pAdapter, ULONG Flags ) /*++ Routine Description: Picks up a PDO and issues a bus reset on that PDO As this can come down through an NdisRequest, it can be at IRQL <=DISPATCH_LEVEL Arguments: Return Value: --*/ { PREMOTE_NODE pRemoteNode = NULL; TRACE( TL_T, TM_Mp, ( "==> nicIssueBusReset %x ",Flags ) ); if (PASSIVE_LEVEL == KeGetCurrentIrql () ) { nicBusReset (pAdapter, Flags); } else { // // Dereferenced in the workitem // nicReferenceAdapter (pAdapter, "nicIssueBusReset "); do { PNDIS_WORK_ITEM pReset; NDIS_STATUS NdisStatus; pReset = ALLOC_NONPAGED (sizeof(NDIS_WORK_ITEM), MTAG_WORKITEM); if (pReset == NULL) { TRACE( TL_A, TM_Cm, ( "Local Alloc failed for WorkItem" ) ); break; } NdisInitializeWorkItem ( pReset, (NDIS_PROC)nicBusResetWorkItem, (PVOID)pAdapter); TRACE( TL_A, TM_Cm, ( "Setting WorkItem" ) ); NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems); NdisScheduleWorkItem (pReset); }while (FALSE); } TRACE( TL_T, TM_Mp, ( "<== nicIssueBusReset " ) ); } VOID nicUpdateLocalHostSpeed ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Updates the speed for the local host and updates the payload for all ChannelVCs This also updates the SCode that goes to the ARP module.. The SCode will never be updated unless this function is called via the BCM algorithm Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PREMOTE_NODE pRemoteNode = NULL; PDEVICE_OBJECT PdoTable[MAX_LOCAL_NODES]; ULONG Num = 0; ULONG SpeedMbps = 10000000; ULONG PrevSpeed = pAdapter->Speed; ULONG Speed =0; ULONG MaxRecvBufferSize = 0; ULONG MaxSendBufferSize = 0; ULONG SCode = 0; TRACE( TL_T, TM_Bcm, ( "==> nicUpdateLocalHostSpeed " ) ); do { PLIST_ENTRY pRemoteNodeList; NODE_ADDRESS RemoteNodeAddress; NODE_TABLE RefNodeTable; ULONG NumRemoteNodes = 0; NdisZeroMemory (&RefNodeTable, sizeof(RefNodeTable)); NumRemoteNodes = 0; ADAPTER_ACQUIRE_LOCK (pAdapter); pRemoteNodeList = ListNext (&pAdapter->PDOList); // // Walk through the entire list and make a copy of the current list. // Reference each remote node on the list. // The lock will ensure that the list is valid and that no removed remote nodes // get into our RefNodeTable list. // while (pRemoteNodeList != &pAdapter->PDOList) { pRemoteNode = CONTAINING_RECORD (pRemoteNodeList, REMOTE_NODE, linkPdo); // // Reference the remote node. This guarantees that the remote node will // remain valid and in the list until it is dereferenced (deref happens below) // nicReferenceRemoteNode (pRemoteNode, UpdateLocalHostSpeed); RefNodeTable.RemoteNode[NumRemoteNodes] = pRemoteNode; ASSERT (REMOTE_NODE_TEST_FLAG (pRemoteNode,PDO_Removed) == FALSE); // // Increment the Cursors and go to the next RemoteNode // pRemoteNodeList = ListNext (pRemoteNodeList); NumRemoteNodes++; // // We only do 63 nodes . // if (NumRemoteNodes > (NIC1394_MAX_NICINFO_NODES - 1)) { break; } } //while (pRemoteNodeList != &pAdapter->PDOList) ADAPTER_RELEASE_LOCK (pAdapter); // // Now Create the Array of Remote Node PDOs that will be send down into the // bus driver // NdisZeroMemory (&PdoTable[0], sizeof (PdoTable) ); Num = 0; while (Num < NumRemoteNodes) { PdoTable[Num] = RefNodeTable.RemoteNode[Num]->pPdo; Num++; } // // Now send the Array down to the Bus Driver and get the speed of // the 1394 network. // NdisStatus = nicGetMaxSpeedBetweenDevices( pAdapter, Num, PdoTable, &Speed); // // Now Dereference all the Remote Nodes that were referenced above // ADAPTER_ACQUIRE_LOCK(pAdapter) // // We're done, Now Dereference the Remote Node References Made above // { USHORT RefIndex=0; PREMOTE_NODE pCurrRemoteNode; // // Initialize the structures // pCurrRemoteNode = RefNodeTable.RemoteNode[0]; RefIndex =0; while (pCurrRemoteNode != NULL) { nicDereferenceRemoteNode(pCurrRemoteNode, UpdateRemoteNodeTable); RefIndex++; pCurrRemoteNode = RefNodeTable.RemoteNode[RefIndex]; } } ADAPTER_RELEASE_LOCK (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; } // // By looking at the speed constants 1 -> 100Mbps // SpeedMbps = Speed*1000000; // // update the scode -- default 400. // As 400+ hardware is prototype from WinXP, we default to 400 for now // SCode = SCODE_400_RATE; if (Speed > SPEED_FLAGS_400) { Speed = SPEED_FLAGS_400; } switch (Speed) { case SPEED_FLAGS_400 : { SCode = SCODE_400_RATE ; MaxRecvBufferSize = ISOCH_PAYLOAD_400_RATE; MaxSendBufferSize = ASYNC_PAYLOAD_400_RATE; break; } case SPEED_FLAGS_100 : { SCode = SCODE_100_RATE; MaxRecvBufferSize = ISOCH_PAYLOAD_100_RATE; MaxSendBufferSize = ASYNC_PAYLOAD_100_RATE; break; } case SPEED_FLAGS_200 : { SCode = SCODE_200_RATE; MaxRecvBufferSize = ISOCH_PAYLOAD_200_RATE; MaxSendBufferSize = ASYNC_PAYLOAD_200_RATE; break; } default: { SCode = SCODE_400_RATE ; MaxRecvBufferSize = ISOCH_PAYLOAD_400_RATE; MaxSendBufferSize = ASYNC_PAYLOAD_400_RATE; break; } } ADAPTER_ACQUIRE_LOCK(pAdapter); pAdapter->Speed = Speed; pAdapter->SpeedMbps = SpeedMbps; pAdapter->SCode = SCode; pAdapter->MaxRecvBufferSize = MaxRecvBufferSize; pAdapter->MaxSendBufferSize = MaxSendBufferSize; ADAPTER_RELEASE_LOCK (pAdapter); TRACE( TL_V, TM_Mp, ( " nicUpdateLocalHostSpeed Speed returned %d",SpeedMbps ) ); // // Now update the speed value in all the channel VC's as they are dependent on this parameter // if (Speed == PrevSpeed || Speed > SPEED_FLAGS_1600 ) { // // either the speed has not changed or it has invalid value, break out // TRACE (TL_V, TM_Init, ("Will not update - Speed %x, Prev Speed %x", Speed, PrevSpeed) ); break; } // // The speed and the payload have changed. Update all the channel Vc's // and Recv FIFOVc's payload // nicUpdateSpeedInAllVCs (pAdapter, Speed ); } while (FALSE); TRACE( TL_T, TM_Mp, ( "<== nicUpdateLocalHostSpeed SpeedCode %x, Num %x" , pAdapter->Speed, Num) ); } VOID nicUpdateSpeedInAllVCs ( PADAPTERCB pAdapter, ULONG Speed ) /*++ Routine Description: This routine updates the speed flag in all Channel Vcs It assumes that the new speed is different from the old speed Arguments: pAdapter- Local Adapter intance Speed - new speed Return Value: --*/ { PAFCB pAfcb = NULL; PVCCB pVc = NULL; PLIST_ENTRY pAfEntry = NULL; PLIST_ENTRY pVcEntry = NULL; ULONG MaxPayload = 0; ULONG SCode = 0; TRACE( TL_T, TM_Mp, ( "==> nicUpdateSpeedInAllVCs ") ); switch (Speed) { case SPEED_FLAGS_100 : { SCode = SCODE_100_RATE; MaxPayload = ISOCH_PAYLOAD_100_RATE; break; } case SPEED_FLAGS_200 : { SCode = SCODE_200_RATE; MaxPayload = ISOCH_PAYLOAD_200_RATE ; break; } case SPEED_FLAGS_400 : { SCode = SCODE_400_RATE; MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } case SPEED_FLAGS_800 : { SCode = SCODE_800_RATE; MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } case SPEED_FLAGS_1600 : { SCode = SCODE_1600_RATE; MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } case SPEED_FLAGS_3200 : { SCode = SCODE_1600_RATE; MaxPayload = ISOCH_PAYLOAD_400_RATE; break; } default : { ASSERT (Speed <= SPEED_FLAGS_3200 && Speed != 0 ); break; } } ADAPTER_ACQUIRE_LOCK (pAdapter); pAfEntry = ListNext (&pAdapter->AFList); // // Walk through all the Vc and set the value on the channelVcs // while (pAfEntry != &pAdapter->AFList) { pAfcb = CONTAINING_RECORD (pAfEntry, AFCB, linkAFCB); pAfEntry = ListNext (pAfEntry); pVcEntry = ListNext (&pAfcb->AFVCList); // // Now walk through the VCs on the Af // while (pVcEntry != &pAfcb->AFVCList) { pVc = (PVCCB) CONTAINING_RECORD (pVcEntry, VCHDR, linkAFVcs ); pVcEntry = ListNext ( pVcEntry ); // // If it is a channel Send Vc update the Speed and Payload // if (pVc->Hdr.VcType == NIC1394_SendRecvChannel || pVc->Hdr.VcType == NIC1394_SendChannel) { PCHANNEL_VCCB pChannelVc = (PCHANNEL_VCCB)pVc; pChannelVc->Speed = Speed; pVc->Hdr.MaxPayload = MaxPayload; } } //while (pVcEntry != &pAfcb->AFVCList) } //while (pAfEntry != &pAdapter->AFList) pAdapter->SCode = SCode; ADAPTER_RELEASE_LOCK (pAdapter); TRACE( TL_T, TM_Mp, ( "<== nicUpdateSpeedInAllVCs ") ); } VOID nicInitializeAllEvents ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Self Explanatory Arguments: Return Value: --*/ // Function Description: // Initialize all the events in the adapter block // // Arguments // pAdapter - The local host in question. // // Return Value: // None { TRACE( TL_T, TM_Mp, ( "==> nicInitializeAllEvents " ) ); NdisInitializeEvent (&pAdapter->RecvFIFOEvent); NdisInitializeEvent (&pAdapter->WaitForRemoteNode.NdisEvent); pAdapter->WaitForRemoteNode.EventCode = Nic1394EventCode_InvalidEventCode; NdisInitializeEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent); pAdapter->BCRData.MakeCallWaitEvent.EventCode = Nic1394EventCode_InvalidEventCode; NdisInitializeEvent (&pAdapter->BCRData.BCRWaitForNewRemoteNode.NdisEvent); pAdapter->BCRData.BCRWaitForNewRemoteNode.EventCode = Nic1394EventCode_InvalidEventCode; NdisInitializeEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent); pAdapter->BCRData.BCRFreeAddressRange.EventCode = Nic1394EventCode_InvalidEventCode; TRACE( TL_T, TM_Mp, ( "<== nicInitializeAllEvents " ) ); } VOID nicInitializeAdapterLookasideLists ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Initialize all the lookaside lists in the adapter block Arguments: Return Value: --*/ { USHORT DefaultDepth = 15; TRACE( TL_T, TM_Mp, ( "==> nicInitializeAdapterLookasideLists pAdpater %x ", pAdapter ) ); nicInitializeLookasideList ( &pAdapter->SendLookasideList100, sizeof (PAYLOAD_100_LOOKASIDE_BUFFER), MTAG_CBUF, DefaultDepth ); pAdapter->SendLookasideList100.MaxSendSize = PAYLOAD_100; TRACE( TL_V, TM_Mp, ( " SendLookasideList100 Payload %x", PAYLOAD_100) ); nicInitializeLookasideList ( &pAdapter->SendLookasideList2K, sizeof (PAYLOAD_2K_LOOKASIDE_BUFFER), MTAG_CBUF, DefaultDepth ); pAdapter->SendLookasideList2K.MaxSendSize = PAYLOAD_2K; TRACE( TL_V, TM_Mp, ( " SendLookasideList2K Payload %x", PAYLOAD_2K) ); TRACE( TL_T, TM_Mp, ( "<== nicInitializeAdapterLookasideLists " ) ); } VOID nicDeleteAdapterLookasideLists ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Delete all the lookaside lists in the adapter block Arguments: Return Value: --*/ { TRACE( TL_T, TM_Mp, ( "==> nicDeleteAdapterLookasideLists pAdapter %x ", pAdapter ) ); TRACE( TL_T, TM_Mp, ( " Delete NonFragmentationLookasideList %x ", &pAdapter->SendLookasideList2K) ); nicDeleteLookasideList (&pAdapter->SendLookasideList2K); TRACE( TL_T, TM_Mp, ( " Delete FragmentationLookasideList %x ", &pAdapter->SendLookasideList100) ); nicDeleteLookasideList (&pAdapter->SendLookasideList100); TRACE( TL_T, TM_Mp, ( "<== nicDeleteAdapterLookasideLists " ) ); } VOID ReassemblyTimerFunction ( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ) /*++ Routine Description: Walk through all the pending reassembly operations and take out the ones that need to be freed (Have been untouched since the timer last fired) Append the ToBeFreed reassemblies into a seperate linked list and free them after releasing the spin locks If the there are any pending reassemblies then the timer requeues itself Arguments: Return Value: --*/ { PREMOTE_NODE pRemoteNode = NULL; PLIST_ENTRY pRemoteNodeList = NULL; PLIST_ENTRY pReassemblyList = NULL; LIST_ENTRY ToBeFreedList; PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL; PADAPTERCB pAdapter = (PADAPTERCB) FunctionContext; ULONG RefValue = 0; STORE_CURRENT_IRQL; ( TL_T, TM_Mp, ( "==> ReassemblyTimerFunction pAdapter %x", pAdapter ) ); InitializeListHead(&ToBeFreedList); ADAPTER_ACQUIRE_LOCK (pAdapter); pRemoteNodeList = ListNext (&pAdapter->PDOList); pAdapter->Reassembly.PktsInQueue =0; // // Walking through the remote nodes // while (pRemoteNodeList != &pAdapter->PDOList) { pRemoteNode = CONTAINING_RECORD(pRemoteNodeList, REMOTE_NODE, linkPdo); pRemoteNodeList = ListNext (pRemoteNodeList); RefValue = pRemoteNode->Ref.ReferenceCount; ; // // Reference the remote node, so we can guarantee its presence // if (REMOTE_NODE_ACTIVE (pRemoteNode) == FALSE) { // // The remote node is going away. Skip this remote node // continue; } if (nicReferenceRemoteNode (pRemoteNode, ReassemblyTimer )== FALSE ) { // // The remote node is going away. Skip this remote node // continue; } REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK (pRemoteNode); // // Now walking through all the reassembly structures on that remote node // pReassemblyList = ListNext(&pRemoteNode->ReassemblyList); while (pReassemblyList != &pRemoteNode->ReassemblyList) { pReassembly = CONTAINING_RECORD (pReassemblyList, NDIS1394_REASSEMBLY_STRUCTURE, ReassemblyListEntry); pReassemblyList = ListNext(pReassemblyList); // // If the reassembly has not been touched since the last timer it needs to be freed. // Other threads can ask us to free the reassembly by setting the aborted flag // if (REASSEMBLY_TEST_FLAG (pReassembly, REASSEMBLY_FREED) == TRUE) { continue; } if (REASSEMBLY_TEST_FLAG (pReassembly, (REASSEMBLY_NOT_TOUCHED| REASSEMBLY_ABORTED)) == TRUE) { REASSEMBLY_SET_FLAG (pReassembly, REASSEMBLY_FREED); // // We have the lock, so we can remove this reassembly structure from the remote node // TRACE( TL_V, TM_Reas, ( "Removing Reassembly %x", pReassembly) ); RemoveEntryList(&pReassembly->ReassemblyListEntry); // // dereference the remote node . ref was made when the reassembly was added // to the remote node // nicDereferenceRemoteNode (pRemoteNode, ReassemblyTimer_Removing ); nicDereferenceReassembly (pReassembly, "ReassemblyTimerFunction - Removing reassembly"); // // add this reassembly to the to be freed list. // InsertTailList(&ToBeFreedList,&pReassembly->ReassemblyListEntry); } else { // // Mark the Reassembly as Not Touched. If a fragment is received, it will clear the flag // REASSEMBLY_SET_FLAG (pReassembly, REASSEMBLY_NOT_TOUCHED); pAdapter->Reassembly.PktsInQueue ++; } }// while (pReassemblyList != &pRemoteNode->ReassemblyList) REMOTE_NODE_REASSEMBLY_RELEASE_LOCK(pRemoteNode); nicDereferenceRemoteNode(pRemoteNode , ReassemblyTimer ); } //while (pRemoteNodeList != &pAdapter->PDOList) // // Clear the timer set flag , so that any new reassenblies will restart the timer // pAdapter->Reassembly.bTimerAlreadySet = FALSE; ADAPTER_RELEASE_LOCK (pAdapter); // // Now we walk the ToBeFreedList and free each of the reasembly structures // if (IsListEmpty (&ToBeFreedList) == FALSE) { nicAbortReassemblyList (&ToBeFreedList); } if (pAdapter->Reassembly.PktsInQueue > 0) { // // Requeue the timer, as there are still fragments remaining in the list. // This will fail in the case, that the adapter is being halted or Set // To Low Power // ASSERT (ADAPTER_TEST_FLAG (pAdapter, fADAPTER_NoMoreReassembly) == FALSE); nicQueueReassemblyTimer(pAdapter, FALSE); } pAdapter->Reassembly.CompleteEvent.EventCode = nic1394EventCode_ReassemblyTimerComplete; NdisSetEvent (&pAdapter->Reassembly.CompleteEvent.NdisEvent); TRACE( TL_T, TM_Mp, ( "<== ReassemblyTimerFunction " ) ); MATCH_IRQL; } NDIS_STATUS nicAddIP1394ToConfigRom ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Adds thE IP1394 Config Rom entry to the OHCI device. Arguments: Return Value: --*/ { HANDLE hCromData = NULL; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; PMDL pConfigRomMdl = NULL; TRACE( TL_T, TM_Mp, ( "==> nicAddIP1394ToConfigRom pAdapter %x", pAdapter ) ); NdisStatus = nicSetLocalHostPropertiesCRom(pAdapter, (PUCHAR)&Net1394ConfigRom, sizeof(Net1394ConfigRom), SLHP_FLAG_ADD_CROM_DATA, &hCromData, &pConfigRomMdl); ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); if (NdisStatus == NDIS_STATUS_SUCCESS) { pAdapter->hCromData = hCromData; pAdapter->pConfigRomMdl = pConfigRomMdl; } TRACE( TL_T, TM_Mp, ( "<== nicAddIP1394ToConfigRom pAdapter %x", pAdapter ) ); return NdisStatus; } NDIS_STATUS nicMCmRegisterAddressFamily ( IN PADAPTERCB pAdapter ) /*++ Routine Description: This function will only be called once per local host This will cause the ARP module to send Create Vc's etc Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; BOOLEAN fDoRegister = TRUE; TRACE( TL_T, TM_Mp, ( "==> nicCmRegisterAddressFamily pAdapter %x", pAdapter ) ); do { // Register the address family of our call manager with NDIS for the // newly bound adapter. We use the mini-port form of // RegisterAddressFamily instead of the protocol form because // we are a miniport/callmanager combo. The mini-port form // causes the call manager VC context to // automatically map to the mini-port VC context, which is exactly // what we want. // // NDIS notifies all call manager clients of the new family we // register. // { NDIS_CALL_MANAGER_CHARACTERISTICS ncmc; CO_ADDRESS_FAMILY family; NdisZeroMemory( &family, sizeof(family) ); family.MajorVersion = NDIS_MajorVersion; family.MinorVersion = NDIS_MinorVersion; family.AddressFamily = CO_ADDRESS_FAMILY_1394; NdisZeroMemory( &ncmc, sizeof(ncmc) ); ncmc.MajorVersion = NDIS_MajorVersion; ncmc.MinorVersion = NDIS_MinorVersion; ncmc.CmCreateVcHandler = NicCmCreateVc; ncmc.CmDeleteVcHandler = NicCmDeleteVc; ncmc.CmOpenAfHandler = NicCmOpenAf; ncmc.CmCloseAfHandler = NicCmCloseAf; ncmc.CmRegisterSapHandler = nicRegisterSapHandler; ncmc.CmDeregisterSapHandler = nicDeregisterSapHandler; ncmc.CmMakeCallHandler = NicCmMakeCall; ncmc.CmCloseCallHandler = NicCmCloseCall; // NEW for 1394 no ncmc.CmIncomingCallCompleteHandler ncmc.CmAddPartyHandler = nicCmAddPartyHandler; ncmc.CmDropPartyHandler = nicCmDropPartyHandler; // no CmDropPartyHandler // NEW for 1394 no ncmc.CmActivateVcCompleteHandler // NEW for 1394 no ncmc.CmDeactivateVcCompleteHandler ncmc.CmModifyCallQoSHandler = NicCmModifyCallQoS; ncmc.CmRequestHandler = NicCmRequest; // no CmRequestCompleteHandler TRACE( TL_I, TM_Cm, ( "NdisMCmRegAf" ) ); NdisStatus = NdisMCmRegisterAddressFamily (pAdapter->MiniportAdapterHandle, &family, &ncmc, sizeof(ncmc) ); TRACE( TL_I, TM_Cm, ( "NdisMCmRegAf=$%x", NdisStatus ) ); } } while (FALSE); TRACE( TL_T, TM_Mp, ( "<== nicCmRegisterAddressFamily NdisStatus %x", NdisStatus ) ); return NdisStatus; } VOID nicFreeReassembliesOnRemoteNode ( IN PREMOTE_NODE pRemoteNode, PLIST_ENTRY pToBeFreedList ) /*++ Routine Description: Free All reassemblies that are on this remote node. Acquires the reassembly Lock , pops the reassemblies off the list and then aborts them This functions is an exception to our reassembly garbage collection. algorithm as the context of this function requires immediate freeing of the reassembly structures Expects the remote node lock to be held Arguments: pRemote Node - Remote Node that is being pulled out Return Value: --*/ { ULONG NumFreed=0; PLIST_ENTRY pReassemblyList = NULL; PNDIS1394_REASSEMBLY_STRUCTURE pReassembly = NULL; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Mp, ( "==> nicFreeReassembliesOnRemoteNode pRemoteNode %x", pRemoteNode) ); InitializeListHead(pToBeFreedList); // // Now walking through all the reassembly structures on that remote node // // // If the remtoe node is in the list, it is fair game for us to extract it // REMOTE_NODE_REASSEMBLY_ACQUIRE_LOCK (pRemoteNode); pReassemblyList = ListNext(&pRemoteNode->ReassemblyList); while (pReassemblyList != &pRemoteNode->ReassemblyList) { pReassembly = CONTAINING_RECORD (pReassemblyList, NDIS1394_REASSEMBLY_STRUCTURE, ReassemblyListEntry); pReassemblyList = ListNext(pReassemblyList); // // Once the reassembly has been marked as free, it should no longer be in the remote // node's list . // ASSERT (REASSEMBLY_TEST_FLAG (pReassembly, REASSEMBLY_FREED) == FALSE); REASSEMBLY_SET_FLAG (pReassembly, REASSEMBLY_FREED); // // We have the lock, so we can remove this reassembly structure from the remote node // TRACE( TL_V, TM_Mp, ( "Removing Reassembly %x", pReassembly) ); RemoveEntryList(&pReassembly->ReassemblyListEntry); // // dereference the remote node . ref was made when the reassembly was added // to the remote node // nicDereferenceRemoteNode (pRemoteNode, FreeReassembliesOnRemoteNode ); nicDereferenceReassembly(pReassembly, "nicFreeReassembliesOnRemoteNode " ); // // add this reassembly to the to be freed list. // InsertTailList(pToBeFreedList,&pReassembly->ReassemblyListEntry); }// while (pReassemblyList != &pRemoteNode->ReassemblyList) REMOTE_NODE_REASSEMBLY_RELEASE_LOCK(pRemoteNode); TRACE( TL_T, TM_Mp, ( "<== nicFreeReassembliesOnRemoteNode NumFreed %x",NumFreed ) ); MATCH_IRQL; } UCHAR nicGetMaxRecFromBytes( IN ULONG ByteSize ) /*++ Routine Description: Converts Size in bytes to MaxRec 512 - 8 1024 - 9 Arguments: ULONG Bytes Size Return Value: --*/ { TRACE( TL_T ,TM_Mp, ( "==>nicGetMaxRecFromBytes ByteSize %x",ByteSize) ); if (ByteSize == ASYNC_PAYLOAD_100_RATE) return MAX_REC_100_RATE; if (ByteSize == ASYNC_PAYLOAD_200_RATE) return MAX_REC_200_RATE; if (ByteSize == ASYNC_PAYLOAD_400_RATE) return MAX_REC_400_RATE; if (ByteSize == ASYNC_PAYLOAD_800_RATE_LOCAL) return MAX_REC_800_RATE_LOCAL; if (ByteSize == ASYNC_PAYLOAD_1600_RATE_LOCAL) return MAX_REC_1600_RATE_LOCAL; if (ByteSize == ASYNC_PAYLOAD_3200_RATE_LOCAL) return MAX_REC_3200_RATE_LOCAL; // // Default to 400 for all greater values // return MAX_REC_400_RATE; } UCHAR nicGetMaxRecFromSpeed( IN ULONG Scode ) /*++ Routine Description: Converts Speed to MaxRec Arguments: ULONG Bytes Size Return Value: --*/ { TRACE( TL_T ,TM_Mp, ( "==>nicGetMaxRecFromSpeed Scode %x",Scode) ); if (Scode == SPEED_FLAGS_100) return MAX_REC_100_RATE; if (Scode == SPEED_FLAGS_200 ) return MAX_REC_200_RATE; if (Scode == SPEED_FLAGS_400 ) return MAX_REC_400_RATE; if (Scode == SPEED_FLAGS_800 ) return MAX_REC_800_RATE_LOCAL ; if (Scode == SPEED_FLAGS_1600 ) return MAX_REC_1600_RATE_LOCAL ; if (Scode == SPEED_FLAGS_3200 ) return MAX_REC_3200_RATE_LOCAL ; // // default // return MAX_REC_400_RATE; } PREMOTE_NODE nicGetRemoteNodeFromTable ( ULONG NodeNumber, PADAPTERCB pAdapter ) /*++ Routine Description: Looks up the remote node in a locked table , references the remote node and returns Arguments: ULONG NodeNumber Return Value: pRemoteNode --*/ { PREMOTE_NODE pRemoteNode = NULL; ADAPTER_ACQUIRE_LOCK (pAdapter); pRemoteNode = pAdapter->NodeTable.RemoteNode[NodeNumber]; if (pRemoteNode != NULL) { nicReferenceRemoteNode (pRemoteNode, GetRemoteNodeFromTable); } ADAPTER_RELEASE_LOCK (pAdapter); return pRemoteNode; } NDIS_STATUS nicFillNicInfo ( IN PADAPTERCB pAdapter, PNIC1394_NICINFO pInNicInfo, PNIC1394_NICINFO pOutNicInfo ) /*++ Routine Description: Takes the Buffer passed in, makes sure that it is big enough and then puts all our statistics into that buffer Arguments: Return Value: --*/ { NDIS_STATUS Status = NDIS_STATUS_INVALID_DATA; do { // // First check internal version // if (pInNicInfo->Hdr.Version != NIC1394_NICINFO_VERSION) { TRACE( TL_A, TM_Mp, ( " NICINFO.Version mismatch. Want %lu got %lu\n", NIC1394_NICINFO_VERSION, pInNicInfo->Hdr.Version )); break; } // // Struct-copy the old to the new. It's wasteful, but we don't want // to dig into how much of the in buffer contains valid data. // *pOutNicInfo = *pInNicInfo; // // Rest is op-specific // switch(pOutNicInfo->Hdr.Op) { case NIC1394_NICINFO_OP_BUSINFO: Status = nicFillBusInfo(pAdapter, &pOutNicInfo->BusInfo); break; case NIC1394_NICINFO_OP_REMOTENODEINFO: Status = nicFillRemoteNodeInfo(pAdapter, &pOutNicInfo->RemoteNodeInfo); break; case NIC1394_NICINFO_OP_CHANNELINFO: Status = nicFillChannelInfo(pAdapter, &pOutNicInfo->ChannelInfo); break; case NIC1394_NICINFO_OP_RESETSTATS: Status = nicResetStats (pAdapter, &pOutNicInfo->ResetStats); default: TRACE( TL_A, TM_Mp, ( " NICINFO.Op (%lu) is unknown.\n", pInNicInfo->Hdr.Op )); break; } } while (FALSE); return Status; } NDIS_STATUS nicResetStats ( IN PADAPTERCB pAdapter, PNIC1394_RESETSTATS pResetStats ) /*++ Routine Description: Self explanatory Arguments: Return Value: --*/ { NdisZeroMemory (&pAdapter->AdaptStats.TempStats, sizeof (pAdapter->AdaptStats.TempStats) ); return NDIS_STATUS_SUCCESS; } NDIS_STATUS nicFillBusInfo( IN PADAPTERCB pAdapter, IN OUT PNIC1394_BUSINFO pBi ) /*++ Routine Description: Colpied all the statistics that we have into the buffer that was passed in. Arguments: Return Value: --*/ { ULARGE_INTEGER BusMap, ActiveMap; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; NIC_SEND_RECV_STATS* pNicStats = NULL; PADAPT_STATS pAdaptStats = &pAdapter->AdaptStats; // // Fill with Dummy data // pBi->NumBusResets = pAdaptStats->ulNumResetCallbacks; pBi->SecondsSinceBusReset = nicGetSystemTime() - pAdaptStats->ulResetTime; pBi->Flags = (BCR_TEST_FLAG( pAdapter, BCR_LocalHostIsIRM) == TRUE ) ? NIC1394_BUSINFO_LOCAL_IS_IRM : 0; // // CHANNEL RELATED INFORMATION // NdisStatus = nicQueryChannelMap( pAdapter, &BusMap); if (NdisStatus == NDIS_STATUS_SUCCESS) { pBi->Channel.BusMap = BusMap.QuadPart; } // // For now // ActiveMap.QuadPart = pAdapter->ChannelsAllocatedByLocalHost; // // First zero out some info // NdisZeroMemory( &pBi->Channel.SendPktStats, sizeof (pBi->Channel.SendPktStats )); NdisZeroMemory( &pBi->Fifo.SendPktStats, sizeof (pBi->Fifo.SendPktStats) ) ; // // Now go through each Vc and extract the relevant information // ADAPTER_ACQUIRE_LOCK (pAdapter); #define GARBAGE 9999 pBi->Channel.Bcr = *((PULONG) &pAdapter->BCRData.IRM_BCR); pBi->LocalNodeInfo.UniqueID = pAdapter->UniqueId; // This node's 64-bit Unique ID. pBi->LocalNodeInfo.BusGeneration = pAdapter->Generation; // 1394 Bus generation ID. pBi->LocalNodeInfo.NodeAddress = pAdapter->NodeAddress; pBi->LocalNodeInfo.MaxRecvBlockSize = pAdapter->MaxRec; pBi->LocalNodeInfo.MaxRecvSpeed = pAdapter->SCode; // // Fill up Recv Vc Stats // if (pAdapter->pRecvFIFOVc != NULL) { PRECVFIFO_VCCB pRecvVc = pAdapter->pRecvFIFOVc; pBi->Fifo.Recv_Off_Low = pRecvVc->VcAddressRange.AR_Off_Low; pBi->Fifo.Recv_Off_High = pRecvVc ->VcAddressRange.AR_Off_High; nicCopyPacketStats(&pBi->Fifo.RecvPktStats ,pAdapter->AdaptStats.TempStats.Fifo.ulRecv, GARBAGE , GARBAGE , GARBAGE); pBi->Fifo.NumFreeRecvBuffers = pRecvVc->NumAllocatedFifos - pRecvVc->NumIndicatedFifos; pBi->Fifo.MinFreeRecvBuffers = GARBAGE ; // todo } // // Fifo Send Stats // pNicStats = &pAdaptStats->TempStats.Fifo; nicCopyPacketStats ( &pBi->Fifo.SendPktStats, pNicStats->ulSendNicSucess, pNicStats->ulSendNicFail, pNicStats->ulSendBusSuccess, pNicStats->ulSendBusFail ); nicCopyPacketStats ( &pBi->Fifo.RecvPktStats, pNicStats->ulRecv, 0, 0, 0); // // Channel Send Stats // pNicStats = &pAdapter->AdaptStats.TempStats.Channel; nicCopyPacketStats ( &pBi->Channel.SendPktStats, pNicStats->ulSendNicSucess, pNicStats->ulSendNicFail, pNicStats->ulSendBusSuccess, pNicStats->ulSendBusFail ); // // Broadcast channel data - same as channel // nicCopyPacketStats ( &pBi->Channel.BcSendPktStats, pNicStats->ulSendNicSucess, pNicStats->ulSendNicFail, pNicStats->ulSendBusSuccess, pNicStats->ulSendBusFail ); // // Recv Channels // nicCopyPacketStats ( &pBi->Channel.BcRecvPktStats , pNicStats->ulRecv, 0, 0, 0); ADAPTER_RELEASE_LOCK (pAdapter); pBi->Channel.ActiveChannelMap= ActiveMap.QuadPart; pBi->Fifo.NumOutstandingReassemblies = pAdaptStats->TempStats.ulNumOutstandingReassemblies; pBi->Fifo.MaxOutstandingReassemblies =pAdaptStats->TempStats.ulMaxOutstandingReassemblies; //pBi->Fifo.NumAbortedReassemblies = ReassemblyCompleted; // // Information about remote nodes. More information about each of these nodes // may be queried using *OP_REMOTE_NODEINFO // pBi->NumRemoteNodes = pAdaptStats->ulNumRemoteNodes; ADAPTER_ACQUIRE_LOCK (pAdapter); { UINT i = 0; PLIST_ENTRY pRemoteEntry = ListNext(&pAdapter->PDOList); while (pRemoteEntry != &pAdapter->PDOList) { PREMOTE_NODE pRemote = CONTAINING_RECORD (pRemoteEntry, REMOTE_NODE, linkPdo); pRemoteEntry = ListNext(pRemoteEntry); pBi->RemoteNodeUniqueIDS[i] = pRemote->UniqueId; i++; } } ADAPTER_RELEASE_LOCK (pAdapter); return NDIS_STATUS_SUCCESS; } NDIS_STATUS nicFillChannelInfo( IN PADAPTERCB pAdapter, IN OUT PNIC1394_CHANNELINFO pCi ) /*++ Routine Description: Simply return success. Arguments: Return Value: --*/ { return NDIS_STATUS_SUCCESS; } NDIS_STATUS nicFillRemoteNodeInfo( IN PADAPTERCB pAdapter, IN OUT PNIC1394_REMOTENODEINFO pRni ) /*++ Routine Description: Captures the information from our Remote Nodes. Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus; REMOTE_NODE *pRemoteNode = NULL; do { // // First let's find the remote node, based on the unique ID. // nicFindRemoteNodeFromAdapter refs pRemoteNode on success. // NdisStatus = nicFindRemoteNodeFromAdapter(pAdapter, NULL, // pPDO OPTIONAL pRni->UniqueID, &pRemoteNode); if (NdisStatus != NDIS_STATUS_SUCCESS) { pRemoteNode = NULL; break; } NdisStatus = nicQueryRemoteNodeCaps (pAdapter, pRemoteNode, &pRni->MaxSpeedBetweenNodes, &pRni->EffectiveMaxBlockSize, &pRni->MaxRec ); REMOTE_NODE_ACQUIRE_LOCK (pRemoteNode); pRni->NodeAddress = *(PUSHORT) &pRemoteNode->RemoteAddress; if (REMOTE_NODE_ACTIVE (pRemoteNode)) { pRni->Flags = NIC1394_REMOTEINFO_ACTIVE; } else { pRni->Flags = NIC1394_REMOTEINFO_UNLOADING; // we assume it's unloading. } REMOTE_NODE_RELEASE_LOCK (pRemoteNode); // // Don't support the following yet. // NdisZeroMemory (&pRni->SendFifoPktStats, sizeof (pRni->SendFifoPktStats) ); NdisZeroMemory (&pRni->SendFifoPktStats, sizeof (pRni->SendFifoPktStats)); NdisZeroMemory (&pRni->RecvFifoPktStats, sizeof (pRni->SendFifoPktStats)); NdisZeroMemory (&pRni->RecvChannelPktStats , sizeof (pRni->SendFifoPktStats)); } while (FALSE); if (pRemoteNode != NULL) { nicDereferenceRemoteNode(pRemoteNode, FillRemoteNodeInfo); } return NdisStatus; } VOID nicCopyPacketStats ( NIC1394_PACKET_STATS* pStats, UINT TotNdisPackets, // Total number of NDIS packets sent/indicated UINT NdisPacketsFailures,// Number of NDIS packets failed/discarded UINT TotBusPackets, // Total number of BUS-level reads/writes UINT BusPacketFailures // Number of BUS-level failures(sends)/discards(recv) ) /*++ Routine Description: Self Explanatory Arguments: Return Value: --*/ { pStats->TotNdisPackets= TotNdisPackets; // Total number of NDIS packets sent/indicated pStats->NdisPacketsFailures= NdisPacketsFailures;// Number of NDIS packets failed/discarded pStats->TotBusPackets = TotBusPackets; // Total number of BUS-level reads/writes pStats->TotBusPackets = BusPacketFailures; // Number of BUS-level failures(sends)/discards(recv) } VOID nicAddPacketStats( NIC1394_PACKET_STATS* pStats, UINT TotNdisPackets, // Total number of NDIS packets sent/indicated UINT NdisPacketsFailures,// Number of NDIS packets failed/discarded UINT TotBusPackets, // Total number of BUS-level reads/writes UINT BusPacketFailures // Number of BUS-level failures(sends)/discards(recv) ) /*++ Routine Description: Self Explanatory Arguments: Return Value: --*/ { pStats->TotNdisPackets+= TotNdisPackets; // Total number of NDIS packets sent/indicated pStats->NdisPacketsFailures+= NdisPacketsFailures;// Number of NDIS packets failed/discarded pStats->TotBusPackets += TotBusPackets; // Total number of BUS-level reads/writes pStats->TotBusPackets += BusPacketFailures; // Number of BUS-level failures(sends)/discards(recv) } VOID nicInformProtocolsOfReset( IN PADAPTERCB pAdapter ) /*++ Routine Description: Informs protocols of reset. Does an NdisMCoIndicateStatus with a locally allocated structure which includes the new Local Node Address and Generation Arguments: Return Value: --*/ { NIC1394_STATUS_BUFFER StatusBuffer; NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; TRACE( TL_T, TM_Mp, ( "==> nicInformProtocolsOfReset ") ); do { NdisZeroMemory (&StatusBuffer, sizeof (StatusBuffer) ); StatusBuffer.Signature = NIC1394_MEDIA_SPECIFIC; StatusBuffer.Event = NIC1394_EVENT_BUS_RESET; NdisMCoIndicateStatus(pAdapter->MiniportAdapterHandle, NULL, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, &StatusBuffer, sizeof(StatusBuffer)); } while (FALSE); TRACE( TL_T, TM_Mp, ( "<== nicInformProtocolsOfReset ") ); } VOID nicUpdateRemoteNodeCaps( PADAPTERCB pAdapter ) /*++ Routine Description: Update the caps (maxrec, maxspeed-to, max effective buffer size) for all nodes that we have connections to. Arguments: Return Value: --*/ { ULONG i = 0; ULONG NumNodes = 0; PREMOTE_NODE pRemoteNode = NULL; NODE_ADDRESS NodeAddress; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; for (i=0; iNodeTable.RemoteNode[i] == NULL) { continue; // ******************* CONTINUE **************** } ADAPTER_ACQUIRE_LOCK (pAdapter); pRemoteNode = pAdapter->NodeTable.RemoteNode[i]; // We check again, with the lock held. // if (pRemoteNode == NULL || !REMOTE_NODE_ACTIVE (pRemoteNode)) { ADAPTER_RELEASE_LOCK (pAdapter); continue; // ******************* CONTINUE **************** } nicReferenceRemoteNode (pRemoteNode, UpdateRemoteNodeCaps); ADAPTER_RELEASE_LOCK (pAdapter); // Specifying FALSE (!from cache) below causes pRemoteNode's cached caps // to be refreshed. // NdisStatus = nicQueryRemoteNodeCaps (pAdapter, pRemoteNode, &SpeedTo, &EffectiveMaxBufferSize, &MaxRec ); if (NdisStatus != NDIS_STATUS_SUCCESS) { TRACE( TL_A, TM_Mp, ( "nicUpdateRemoteNodeCaps couldn't update caps fo node %x", pRemoteNode)); } nicDereferenceRemoteNode (pRemoteNode, UpdateRemoteNodeCaps); } } VOID nicQueryInformationWorkItem( IN PNDIS_WORK_ITEM pWorkItem, IN PVOID Context ) /*++ Routine Description: This is the WorkItem that we have allocated for our querying information. Arguments: Return Value: --*/ { PADAPTERCB pAdapter= (PADAPTERCB) Context; PNIC_WORK_ITEM pNicWorkItem = (PNIC_WORK_ITEM) pWorkItem; NDIS_STATUS Status; Status = nicQueryInformation( pAdapter, pNicWorkItem->RequestInfo.pVc, pNicWorkItem->RequestInfo.pNdisRequest ); // // We call at passive, so we should never be pending here. // ASSERT(Status != NDIS_STATUS_PENDING); // // Asynchronously complete the work item. // NdisMCoRequestComplete( Status, pAdapter->MiniportAdapterHandle, pNicWorkItem->RequestInfo.pNdisRequest ); // // Deref the work item adapter reference. // FREE_NONPAGED (pWorkItem); NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems); nicDereferenceAdapter(pAdapter, "nicQueryInfoWorkItem"); } VOID nicMIndicateStatus( IN PADAPTERCB pAdapter , IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) /*++ Routine Description: This function inserts a packet into the send queue. If there is no timer servicing the queue then it queues a timer to dequeue the packet in Global Event's context Arguments: Self explanatory Return Value: Success - if inserted into the the queue --*/ { if (ADAPTER_TEST_FLAG (pAdapter, fADAPTER_DoStatusIndications) == FALSE) { return; } NdisMCoIndicateStatus (pAdapter->MiniportAdapterHandle , NULL, GeneralStatus, StatusBuffer, StatusBufferSize ); } NDIS_STATUS nicAllocateLoopbackPacketPool ( IN PADAPTERCB pAdapter ) /*++ Routine Description: allocate a packet and buffer pool for loopback packet Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; do { // // Allocate a packet pool to indicate loopback receives from. // NdisAllocatePacketPoolEx( &NdisStatus, &pAdapter->LoopbackPool.Handle, 32, 32, sizeof(LOOPBACK_RSVD) ); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; } pAdapter->LoopbackPool.AllocatedPackets = 0; NdisAllocateBufferPool( &NdisStatus, &pAdapter->LoopbackBufferPool, 64 ); if (NdisStatus != NDIS_STATUS_SUCCESS) { break; } } while (FALSE); return NdisStatus; } VOID nicFreeLoopbackPacketPool ( IN PADAPTERCB pAdapter ) /*++ Routine Description: free the packet and buffer pool for loopback packet Arguments: Return Value: --*/ { if (pAdapter->LoopbackPool.Handle != NULL) { nicFreePacketPool (&pAdapter->LoopbackPool); } if (pAdapter->LoopbackBufferPool != NULL) { NdisFreeBufferPool(pAdapter->LoopbackBufferPool); pAdapter->LoopbackBufferPool = NULL; } } VOID nicLoopbackPacket( IN VCCB* pVc, IN PNDIS_PACKET pPacket ) /*++ Routine Description: Allocate a packet and indicate it up on the Broadcast vc Arguments: Return Value: --*/ { NDIS_STATUS Status; PNDIS_BUFFER pFirstBuffer; ULONG TotalLength; PNDIS_PACKET pLoopbackPacket; PUCHAR pCopyBuf; PNDIS_BUFFER pLoopbackBuffer; ULONG BytesCopied; ADAPTERCB* pAdapter; PLOOPBACK_RSVD pLoopbackRsvd; pAdapter = pVc->Hdr.pAF->pAdapter; TRACE( TL_T, TM_Recv, ("NIC1394: loopback pkt %p on VC %p, type %d\n", pPacket, pVc, pVc->Hdr.VcType)); pLoopbackPacket = NULL; pLoopbackBuffer = NULL; pCopyBuf = NULL; do { nicAllocatePacket(&Status, &pLoopbackPacket, &pAdapter->LoopbackPool); if (Status != NDIS_STATUS_SUCCESS) { break; } NdisQueryPacket( pPacket, NULL, NULL, &pFirstBuffer, &TotalLength ); pCopyBuf = ALLOC_NONPAGED (TotalLength, MTAG_RBUF); if (pCopyBuf == NULL) { Status = NDIS_STATUS_RESOURCES; break; } NdisAllocateBuffer( &Status, &pLoopbackBuffer, pAdapter->LoopbackBufferPool, pCopyBuf, TotalLength ); if (Status != NDIS_STATUS_SUCCESS) { break; } pLoopbackBuffer->Next = NULL; NdisChainBufferAtFront(pLoopbackPacket, pLoopbackBuffer); NdisCopyFromPacketToPacket( pLoopbackPacket, 0, TotalLength, pPacket, 0, &BytesCopied ); // // Make sure we can reclaim the packet after the receive indicate // returns. // // If the status is made async, then the loopback Tag will // break in the return packet handler // NDIS_SET_PACKET_STATUS(pLoopbackPacket, NDIS_STATUS_RESOURCES); // Set the Loopback Tag. pLoopbackRsvd = (PLOOPBACK_RSVD) pLoopbackPacket->ProtocolReserved; pLoopbackRsvd->LoopbackTag = NIC_LOOPBACK_TAG; NdisSetPacketFlags (pLoopbackPacket, NDIS_FLAGS_IS_LOOPBACK_PACKET); NdisMCoIndicateReceivePacket( pVc->Hdr.NdisVcHandle, &pLoopbackPacket, 1); NdisFreeBuffer(pLoopbackBuffer); nicFreePacket(pLoopbackPacket, &pAdapter->LoopbackPool); FREE_NONPAGED(pCopyBuf); } while (FALSE); if (Status != NDIS_STATUS_SUCCESS) { if (pCopyBuf) { FREE_NONPAGED(pCopyBuf); } if (pLoopbackBuffer) { NdisFreeBuffer(pLoopbackBuffer); } if (pLoopbackPacket) { nicFreePacket(pLoopbackPacket, &pAdapter->LoopbackPool); } } } VOID nicWriteErrorLog ( IN PADAPTERCB pAdapter, IN NDIS_ERROR_CODE ErrorCode, IN ULONG ErrorValue ) /*++ Routine Description: Self Explanatory - See DDK Arguments: Return Value: --*/ { NdisWriteErrorLogEntry( pAdapter->MiniportAdapterHandle, ErrorCode, 1, ErrorValue ); } VOID nicUpdateRemoteNodeTable ( IN PADAPTERCB pAdapter ) /*++ Routine Description: Go through all the remote nodes in the system and query its Node Address Make two tables, one contains all the remote nodes that have been refed. The other contains the Nodes according to their Node Addresses(TempNodeTable). Simple algorithm: Take a snapshot of the current RemoteNodes List into RefNodeTable Ref all the remote nodes in a local structure. Get their new remote node addresses (TempNodeTable) Copy the TempNodeTable into the Adapter Structure - it is now official Update the address in the remote node themselves Dereference the Ref made above Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; PNODE_TABLE pNodeTable = &pAdapter->NodeTable; PLIST_ENTRY pRemoteNodeList; NODE_ADDRESS RemoteNodeAddress; NODE_TABLE RefNodeTable; NODE_TABLE TempNodeTable; ULONG NumRemoteNodes = 0; ULONG MaxNumRefNodeTable = 0; USHORT RefIndex=0; PREMOTE_NODE pCurrRemoteNode; STORE_CURRENT_IRQL; TRACE( TL_T, TM_Mp, ( " ==>nicUpdateRemoteNodeTable pAdapter %x, TempNodeTable%x", pAdapter , &TempNodeTable) ); NdisZeroMemory (&TempNodeTable, sizeof (NODE_TABLE) ); NdisZeroMemory (&RefNodeTable, sizeof(RefNodeTable)); NumRemoteNodes = 0; ADAPTER_ACQUIRE_LOCK (pAdapter); pRemoteNodeList = ListNext (&pAdapter->PDOList); // // Walk through the entire list and make a copy of the current list. // Reference each remote node on the list. // The lock will ensure that the list is valid and that no removed remote nodes // get into our RefNodeTable list. // while (pRemoteNodeList != &pAdapter->PDOList) { PREMOTE_NODE pRemoteNode; pRemoteNode = CONTAINING_RECORD (pRemoteNodeList, REMOTE_NODE, linkPdo); // // Reference the remote node. This guarantees that the remote node will // remain valid and in the list until it is dereferenced (deref happens below) // nicReferenceRemoteNode (pRemoteNode, UpdateRemoteNodeTable); RefNodeTable.RemoteNode[MaxNumRefNodeTable] = pRemoteNode; ASSERT (REMOTE_NODE_TEST_FLAG (pRemoteNode,PDO_Removed) == FALSE); // // Increment the Cursors and go to the next RemoteNode // pRemoteNodeList = ListNext (pRemoteNodeList); MaxNumRefNodeTable++; } //while (pRemoteNodeList != &pAdapter->PDOList) ADAPTER_RELEASE_LOCK (pAdapter); // // Without the lock, call into the Bus Driver to get the remote address // of each remote node // { // // Initialize the structures // pCurrRemoteNode = RefNodeTable.RemoteNode[0]; RefIndex =0; while (pCurrRemoteNode != NULL) { // Get the Node Address of the current Remote Node // NdisStatus = nicGet1394AddressOfRemoteNode (pCurrRemoteNode, &RemoteNodeAddress, 0); if (NdisStatus == NDIS_STATUS_SUCCESS) { // // Fill in the Temp Remote Node Table // PREMOTE_NODE *ppRemoteNode; ppRemoteNode = &TempNodeTable.RemoteNode[RemoteNodeAddress.NA_Node_Number]; if (*ppRemoteNode == NULL) { // // Update the value in the table // *ppRemoteNode = pCurrRemoteNode; NumRemoteNodes ++; } } // Move to the next node in our local RefNodeTable // RefIndex++; pCurrRemoteNode = RefNodeTable.RemoteNode[RefIndex]; } } ADAPTER_ACQUIRE_LOCK(pAdapter) // // Use the results of our queries to update our internal structures // Regardless of success or failure, copy the temp node table over // into the adapter // NdisMoveMemory (&pAdapter->NodeTable, &TempNodeTable, sizeof (NODE_TABLE) ); pAdapter->NumRemoteNodes = NumRemoteNodes; // // Update the node address within each of these remote nodes // { ULONG NumUpdated = 0; USHORT i=0; // // Update the Remote Node structures with their new Node Addresses // while (NumUpdated != NumRemoteNodes) { if (i >= (sizeof(TempNodeTable.RemoteNode)/sizeof(TempNodeTable.RemoteNode[0]))) { // We've gone past the end of the array. Should never do that. // ASSERT(!"Walked off the end of the NodeTable"); break; } if (TempNodeTable.RemoteNode[i] != NULL) { TempNodeTable.RemoteNode[i]->RemoteAddress.NA_Node_Number = i; NumUpdated ++; } i++; // Use i to check if we have walked off the end of the table TRACE( TL_V, TM_Mp, ( " UpdatingRemoteNodeAddresses NumUpdated %x, i %x, NumRemoteNodes %x", NumUpdated, i, NumRemoteNodes) ); } // while (TRUE) } // // We're done, Now Dereference the Remote Node References Made above // pCurrRemoteNode = RefNodeTable.RemoteNode[0]; RefIndex =0; while (pCurrRemoteNode != NULL) { if (REMOTE_NODE_TEST_FLAG (pCurrRemoteNode, PDO_Removed) ) { // // If the node is being removed, then do not re-insert it // into the node table, by clearing it out of the NodeTable // ULONG CurrNodeNumber = pCurrRemoteNode->RemoteAddress.NA_Node_Number; RefNodeTable.RemoteNode[RefIndex] = NULL; if (pAdapter->NodeTable.RemoteNode[CurrNodeNumber] == pCurrRemoteNode) { pAdapter->NodeTable.RemoteNode[CurrNodeNumber] = NULL; } } nicDereferenceRemoteNode(pCurrRemoteNode, UpdateRemoteNodeTable); RefIndex++; pCurrRemoteNode = RefNodeTable.RemoteNode[RefIndex]; } ADAPTER_RELEASE_LOCK (pAdapter); TRACE( TL_T, TM_Mp, ( "<== nicUpdateRemoteNodeTable pAdapter %x, NumRemoteNodes %x", pAdapter, NumRemoteNodes ) ); MATCH_IRQL; } VOID nicRemoveRemoteNodeFromNodeTable( IN PNODE_TABLE pNodeTable, IN PREMOTE_NODE pRemoteNode ) /*++ Routine Description: Remove the Remove Node from the Table and decrement any refcounts associated with it. Arguments: Return Value: --*/ { // // This function assumes that the adapter lock is held. // PPREMOTE_NODE ppRemoteNode = NULL; // // find the remote node and delete it from the node table. // // // The RemoteNode is probably already in the correct place in the Node Table. We'll look there first // ppRemoteNode = &pNodeTable->RemoteNode[pRemoteNode->RemoteAddress.NA_Node_Number] ; if (*ppRemoteNode != pRemoteNode) { // //We did not find the remote node, now we need to go through all the entries and see // if the remote node is there // UINT i =0; while (iRemoteNode[i]; if (*ppRemoteNode == pRemoteNode) { // // we have found the remote node in the node table-- remove it // *ppRemoteNode = NULL; } i++; // try the next node } // while () } // // if we were able to find the remote node either by the // node number or through our iterative search // then remove it from the Node Table // if (*ppRemoteNode == pRemoteNode) { *ppRemoteNode = NULL; } } VOID nicVerifyEuidTopology( IN PADAPTERCB pAdapter, IN PEUID_TOPOLOGY pEuidMap ) /*++ Routine Description: Update THe node address of each remote node and then fills up the euid Map structre Arguments: Return Value: --*/ { EUID_TOPOLOGY EuidTopology; PLIST_ENTRY pRemoteNodeList; PREMOTE_NODE pRemoteNode = NULL; // // Requery each remote node for its latest HW address // nicUpdateRemoteNodeTable (pAdapter); // // Recreate the list and verify that the topology has not changed from under us. // NdisZeroMemory (pEuidMap, sizeof(*pEuidMap)); ADAPTER_ACQUIRE_LOCK(pAdapter); pRemoteNodeList = ListNext (&pAdapter->PDOList); // // Walk through the entire list and fire of a request for each RemoteNode // The lock will ensure that the list is valid // while (pRemoteNodeList != &pAdapter->PDOList) { USHORT NodeNumber; pEuidMap->NumberOfRemoteNodes++; pRemoteNode = CONTAINING_RECORD (pRemoteNodeList, REMOTE_NODE, linkPdo); pRemoteNodeList = ListNext (pRemoteNodeList); NodeNumber = pRemoteNode->RemoteAddress.NA_Node_Number; pEuidMap->Node[NodeNumber].Euid = pRemoteNode->UniqueId; pEuidMap->Node[NodeNumber].ENetAddress = pRemoteNode->ENetAddress; } //while (pRemoteNodeList != &pAdapter->PDOList) ADAPTER_RELEASE_LOCK (pAdapter); } nicVerifyEuidMapWorkItem ( NDIS_WORK_ITEM* pWorkItem, IN PVOID Context ) /*++ Routine Description: This routine is a workitem routine. It is called whenever we are asked to report back our Mapping and is always called in the context of the miniport getting a request from arp1394.sys. Arguments: pAdapter Local host Return Value: --*/ { PNIC_WORK_ITEM pNicWorkItem = (PNIC_WORK_ITEM )pWorkItem; PNDIS_REQUEST pRequest = pNicWorkItem->RequestInfo.pNdisRequest; PADAPTERCB pAdapter = (PADAPTERCB)Context; PEUID_TOPOLOGY pEuidMap = (PEUID_TOPOLOGY) pRequest->DATA.QUERY_INFORMATION.InformationBuffer; // // Verify the contents of the Euid Map // nicVerifyEuidTopology(pAdapter,pEuidMap); // // As we atleast have the old data (before verification), // we should always succeed the request // NdisMCoRequestComplete(NDIS_STATUS_SUCCESS, pAdapter->MiniportAdapterHandle, pRequest); FREE_NONPAGED (pNicWorkItem); NdisInterlockedDecrement(&pAdapter->OutstandingWorkItems); } VOID nicQueryEuidNodeMacMap ( IN PADAPTERCB pAdapter, IN PNDIS_REQUEST pRequest ) /*++ Routine Description: Goes through all the remote nodes and extracts their Euid, Node Number and Mac address. This function first tries to query each remote node to get its latest address either via by directly asking the remote node or thorough a work item. If that fails, then it takes the last known good values and reports it to the Arp module. Arguments: Return Value: --*/ { PLIST_ENTRY pRemoteNodeList; PREMOTE_NODE pRemoteNode; NDIS_STATUS Status = NDIS_STATUS_FAILURE; PEUID_TOPOLOGY pEuidMap = (PEUID_TOPOLOGY) pRequest->DATA.QUERY_INFORMATION.InformationBuffer; PNIC_WORK_ITEM pUpdateTableWorkItem = NULL; NdisZeroMemory (pEuidMap, sizeof (*pEuidMap)); Status = NDIS_STATUS_SUCCESS; do { if (KeGetCurrentIrql() == PASSIVE_LEVEL) { // // This thread queries and completes the request // nicVerifyEuidTopology(pAdapter, pEuidMap); break; } // // We need to update the generation count // pUpdateTableWorkItem = ALLOC_NONPAGED (sizeof(NIC_WORK_ITEM), MTAG_WORKITEM); if (pUpdateTableWorkItem !=NULL) { // // Set the Workitem // NdisInitializeWorkItem ( &pUpdateTableWorkItem->NdisWorkItem, (NDIS_PROC)nicVerifyEuidMapWorkItem, (PVOID)pAdapter ); pUpdateTableWorkItem->RequestInfo.pNdisRequest = pRequest; NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems); NdisScheduleWorkItem (&pUpdateTableWorkItem->NdisWorkItem); // // Only code path that pends the request -because of the workitem // Status = NDIS_STATUS_PENDING; } else { // // Allocation failure - We report the results without verifying them. // ADAPTER_ACQUIRE_LOCK(pAdapter); pRemoteNodeList = ListNext (&pAdapter->PDOList); // // Walk through the entire list and fire of a request for each RemoteNode // The lock will ensure that the list is valid // while (pRemoteNodeList != &pAdapter->PDOList) { USHORT NodeNumber; pEuidMap->NumberOfRemoteNodes++; pRemoteNode = CONTAINING_RECORD (pRemoteNodeList, REMOTE_NODE, linkPdo); pRemoteNodeList = ListNext (pRemoteNodeList); NodeNumber = pRemoteNode->RemoteAddress.NA_Node_Number; pEuidMap->Node[NodeNumber].Euid = pRemoteNode->UniqueId; pEuidMap->Node[NodeNumber].ENetAddress = pRemoteNode->ENetAddress; } //while (pRemoteNodeList != &pAdapter->PDOList) ADAPTER_RELEASE_LOCK (pAdapter); // // This thread completes the request with possibly stale data. // break; } }while (FALSE); if (NDIS_STATUS_PENDING != Status) { NdisMCoRequestComplete(Status, pAdapter->MiniportAdapterHandle, pRequest); } } NDIS_STATUS nicSetPower ( IN PADAPTERCB pAdapter, IN NET_DEVICE_POWER_STATE DeviceState ) /*++ Routine Description: if PowerState is LowPower, then we 1) there are no outstanding VCs or AFs open in the miniport 2) free the Broadcast Channel Register, If the PowerState is On, then 1) we reallocate the BroadcastChannel Register 2) if we are in bridge mode, Start the Arp module Arguments: Return Value: --*/ { NDIS_STATUS NdisStatus = NDIS_STATUS_FAILURE; switch (DeviceState) { case NetDeviceStateD0: { // // Initialize the BCM so it is ready to handle Resets // ADAPTER_CLEAR_FLAG(pAdapter, fADAPTER_LowPowerState); NdisStatus = nicInitializeBroadcastChannelRegister (pAdapter); if (NdisStatus != NDIS_STATUS_SUCCESS) { nicFreeBroadcastChannelRegister(pAdapter); break; } ASSERT (NdisStatus == NDIS_STATUS_SUCCESS); nicScheduleBCMWorkItem (pAdapter); // // If we are in bridge mode, then start the arp module // if (ADAPTER_TEST_FLAG (pAdapter, fADAPTER_BridgeMode) == TRUE) { nicQueueRequestToArp(pAdapter, BindArp, NULL); } // // Re-initialize the Reassembly Timer // nicInitSerializedReassemblyStruct(pAdapter); // cannot fail NdisStatus = NDIS_STATUS_SUCCESS; } break; case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: { // // Free the Broadcast Channel Register // nicFreeBroadcastChannelRegister(pAdapter); // // Wait for the Free to complete. // NdisWaitEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent,0); NdisResetEvent (&pAdapter->BCRData.BCRFreeAddressRange.NdisEvent); ADAPTER_SET_FLAG(pAdapter, fADAPTER_LowPowerState); // // ReStart any pending broadcast channel make calls // pAdapter->BCRData.MakeCallWaitEvent.EventCode = nic1394EventCode_FreedAddressRange; NdisSetEvent (&pAdapter->BCRData.MakeCallWaitEvent.NdisEvent); // // Wait for Outstanding WorItems and timers // nicDeInitSerializedReassmblyStruct(pAdapter); while (pAdapter->OutstandingWorkItems != 0) { NdisMSleep (10000); } NdisStatus = NDIS_STATUS_SUCCESS; } break; default: { ASSERT (0); break; } } ASSERT (NDIS_STATUS_SUCCESS == NdisStatus); pAdapter->PowerState = DeviceState; return NdisStatus; }