// Copyright (c) 2000-2002, Microsoft Corporation, all rights reserved // // driver.c // // IEEE1394 mini-port/call-manager driver // // // Loads and unload the ARP module when the // bridge is activated // // Created by Adube // //--------------------------------------------------------// // // // // // ZwLoadDriver is locally declared because if I try // // and include ZwApi.h there are conflicts with // // structures defined in wdm.h // // // // // //--------------------------------------------------------// #include "precomp.h" NDIS_STRING ArpName = NDIS_STRING_CONST("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ARP1394"); //----------------------------------------------------------// // Local Prototypes // //----------------------------------------------------------// NTSYSAPI NTSTATUS NTAPI ZwLoadDriver( IN PUNICODE_STRING DriverServiceName ); NTSYSAPI NTSTATUS NTAPI ZwUnloadDriver( IN PUNICODE_STRING DriverServiceName ); VOID nicEthStartArpWorkItem ( PNDIS_WORK_ITEM pWorkItem, IN PVOID Context ); NTSYSAPI NTSTATUS NTAPI ZwDeviceIoControlFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG IoControlCode, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength ); VOID nicSetupIoctlToLoadArp ( IN PADAPTERCB pAdapter, IN PARP_INFO pArpInfo ); VOID nicSetupAndSendIoctlToArp ( IN PADAPTERCB pAdapter, IN PARP_INFO pArpInfo ); //----------------------------------------------------------// // Functions // //----------------------------------------------------------// VOID nicSendIoctlToArp( PARP1394_IOCTL_COMMAND pCmd ) /*++ Routine Description: Send the start Ioctl to the ARp module Arguments: Return Value: --*/ { BOOLEAN fRet = FALSE; PUCHAR pc; HANDLE DeviceHandle; ULONG BytesReturned; OBJECT_ATTRIBUTES Atts; NDIS_STRING strArp1394 = NDIS_STRING_CONST ("\\Device\\Arp1394"); HANDLE Handle; NTSTATUS status = STATUS_UNSUCCESSFUL; IO_STATUS_BLOCK ioStatusBlock; do { InitializeObjectAttributes(&Atts, &strArp1394, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwCreateFile(&Handle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &Atts, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); if (!NT_SUCCESS(status)) { Handle = NULL; break; } // // Submit the request to the forwarder // status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &ioStatusBlock, ARP_IOCTL_CLIENT_OPERATION, pCmd, sizeof(*pCmd), pCmd, sizeof(*pCmd)); // // Close the device. // ZwClose(Handle); if (!NT_SUCCESS(status)) { ASSERT (status == STATUS_SUCCESS); break; } } while (FALSE); } VOID nicLoadArpDriver () /*++ Routine Description: Load the arp module Arguments: Return Value: --*/ { ZwLoadDriver(&ArpName); TRACE (TL_T, TM_Mp,("Loaded the Arp Module %p\n", &ArpName)); } VOID nicGetAdapterName ( IN PADAPTERCB pAdapter, IN WCHAR* pAdapterName, IN ULONG BufferSize, IN PULONG pSizeReturned ) /*++ Routine Description: Get the Adapter Name From NDIS. All sizes are in bytes Arguments: Return Value: --*/ { // // The BufferSize always has to be greater than SizeReturned // if (BufferSize > pAdapter->AdapterNameSize) { NdisMoveMemory (pAdapterName, &pAdapter->AdapterName[0], pAdapter->AdapterNameSize); if (pSizeReturned != NULL) { *pSizeReturned = pAdapter->AdapterNameSize ; } } else { // // The else case cannot be hit because the size of the AdapterName buffer // is 1 less than the sizeof pEthCmd->AdapterName[]. if this is ever changed, // the Assert will be hit. // ASSERT (BufferSize > pAdapter->AdapterNameSize); *pSizeReturned = 0; } } VOID nicSetupIoctlToArp ( IN PADAPTERCB pAdapter, IN PARP_INFO pArpInfo ) /*++ Routine Description: Sets up the Ioctl to be sent to the Arp module Arguments: Return Value: --*/ { PARP1394_IOCTL_ETHERNET_NOTIFICATION pEthCmd = &pAdapter->ArpIoctl.EthernetNotification; ADAPTER_ACQUIRE_LOCK(pAdapter); if (BindArp == pArpInfo->Action || LoadArp == pArpInfo->Action) { pEthCmd->Hdr.Op = ARP1394_IOCTL_OP_ETHERNET_START_EMULATION; pAdapter->fIsArpStarted = TRUE; ADAPTER_SET_FLAG(pAdapter,fADAPTER_BridgeMode); } if (UnloadArp == pArpInfo->Action || UnloadArpNoRequest== pArpInfo->Action) { pEthCmd->Hdr.Op = ARP1394_IOCTL_OP_ETHERNET_STOP_EMULATION; pAdapter->fIsArpStarted = FALSE; ADAPTER_CLEAR_FLAG(pAdapter,fADAPTER_BridgeMode); } ADAPTER_RELEASE_LOCK(pAdapter); } VOID nicSetupAndSendIoctlToArp ( IN PADAPTERCB pAdapter, PARP_INFO pArpInfo ) /*++ Routine Description: Sets up an Ioctl and Sends it to the Arp module Arguments: Return Value: --*/ { nicSetupIoctlToArp (pAdapter, pArpInfo); nicSendIoctlToArp(&pAdapter->ArpIoctl); } VOID nicSendNotificationToArp( IN PADAPTERCB pAdapter, IN PARP_INFO pArpInfo ) /*++ Routine Description: Send the notification to the arp module Arguments: Return Value: --*/ { PNDIS_REQUEST pRequest = NULL; ULONG Start = FALSE; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; ARP1394_IOCTL_COMMAND ArpIoctl; // // Extract our variables from the workitem // TRACE (TL_T, TM_Mp, ("==>nicEthStartArpWorkItem Start %x", Start )); do { // // First complete the request, so that protocols can start sending new // requests . Notes 11/30/00 // if (pArpInfo->Action == LoadArp || pArpInfo->Action == UnloadArp) { // // in either of these cases, it is a request that has initiated the action. // // if (pRequest == NULL) { // // This came in through our CL SetInformation Handler // NdisMSetInformationComplete (pAdapter->MiniportAdapterHandle, NdisStatus ); } else { NdisMCoRequestComplete ( NdisStatus , pAdapter->MiniportAdapterHandle, pRequest); } } // // "arp13 -bstart adapter" // If we are asked to Load Arp, we verify that the arp hasn't // already been started // if (pArpInfo->Action == LoadArp && pAdapter->fIsArpStarted == FALSE)// we are turning ON { // // Load the driver // nicLoadArpDriver (); // // Send it an IOCTL to open the nic1394 adapter // } if (pArpInfo->Action == BindArp && pAdapter->fIsArpStarted == FALSE) { // // if the arp module has not been started and we are asking to bind, // then it means that an unload was ahead of us in the queue and // unbound nic1394 from arp1394. This thread can exit. // break; } // // Send the Ioctl to the Arp module // nicSetupAndSendIoctlToArp (pAdapter, pArpInfo); } while (FALSE); // // end of function // FREE_NONPAGED (pArpInfo); TRACE (TL_T, TM_Mp, ("<==nicEthStartArpWorkItem fLoadArp %x", pArpInfo->Action)); return; } VOID nicProcessNotificationForArp( IN PNDIS_WORK_ITEM pWorkItem, IN PVOID Context ) /*++ Routine Description: This function extracts the notification from the workitem and sends the Load/Unload/ BInd notfication to ARp 1394 Arguments: Return Value: --*/ { PADAPTERCB pAdapter = (PADAPTERCB) Context; ADAPTER_ACQUIRE_LOCK (pAdapter); // // Empty the Queue indicating as many packets as possible // while (IsListEmpty(&pAdapter->LoadArp.Queue)==FALSE) { PARP_INFO pArpInfo; PLIST_ENTRY pLink; NDIS_STATUS NdisStatus; pAdapter->LoadArp.PktsInQueue--; pLink = RemoveHeadList(&pAdapter->LoadArp.Queue); ADAPTER_RELEASE_LOCK (pAdapter); // // Extract the send context // if (pLink != NULL) { pArpInfo = CONTAINING_RECORD( pLink, ARP_INFO, Link); nicSendNotificationToArp(pAdapter, pArpInfo); } ADAPTER_ACQUIRE_LOCK (pAdapter); } // // clear the flag // ASSERT (pAdapter->LoadArp.PktsInQueue==0); ASSERT (IsListEmpty(&pAdapter->LoadArp.Queue)); pAdapter->LoadArp.bTimerAlreadySet = FALSE; ADAPTER_RELEASE_LOCK (pAdapter); NdisInterlockedDecrement (&pAdapter->OutstandingWorkItems); } VOID nicInitializeLoadArpStruct( PADAPTERCB pAdapter ) /*++ Routine Description: This function initializes the LoadArp struct in _ADAPTERCB Arguments: Return Value: --*/ { if (pAdapter->LoadArp.bInitialized == FALSE) { PARP1394_IOCTL_ETHERNET_NOTIFICATION pEthCmd = &pAdapter->ArpIoctl.EthernetNotification; ULONG Size; // // Initialize the Load Arp struct // NdisZeroMemory (&pAdapter->LoadArp, sizeof(pAdapter->LoadArp)); InitializeListHead(&pAdapter->LoadArp.Queue); pAdapter->LoadArp.bInitialized = TRUE; NdisInitializeWorkItem (&pAdapter->LoadArp.WorkItem, nicProcessNotificationForArp, pAdapter); // // Initialize the AdapterName, this will ensure that the string is // NULL terminated // NdisZeroMemory( pEthCmd->AdapterName, sizeof(pEthCmd->AdapterName)); nicGetAdapterName (pAdapter, pEthCmd->AdapterName, sizeof(pEthCmd->AdapterName)-sizeof(WCHAR), &Size ); pEthCmd->Hdr.Version = ARP1394_IOCTL_VERSION; } } NDIS_STATUS nicQueueRequestToArp( PADAPTERCB pAdapter, ARP_ACTION Action, PNDIS_REQUEST pRequest ) /*++ Routine Description: This function inserts a request to load/unload or bind the Arp module 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 --*/ { NDIS_STATUS Status = NDIS_STATUS_FAILURE; BOOLEAN fSetWorkItem = FALSE; PARP_INFO pArpInfo; do { pArpInfo = ALLOC_NONPAGED(sizeof (ARP_INFO), MTAG_DEFAULT); if (pArpInfo == NULL) { break; } ADAPTER_ACQUIRE_LOCK (pAdapter); // // Find out if this thread needs to fire the timer // pArpInfo->Action = Action; pArpInfo->pRequest = pRequest; if (pAdapter->LoadArp.bTimerAlreadySet == FALSE) { fSetWorkItem = TRUE; pAdapter->LoadArp.bTimerAlreadySet = TRUE; } InsertTailList( &pAdapter->LoadArp.Queue, &pArpInfo->Link ); pAdapter->LoadArp.PktsInQueue++; ADAPTER_RELEASE_LOCK (pAdapter); // // Now queue the workitem // if (fSetWorkItem== TRUE) { PNDIS_WORK_ITEM pWorkItem; // // Initialize the timer // pWorkItem = &pAdapter->LoadArp.WorkItem; TRACE( TL_V, TM_Recv, ( " Set Timer ")); NdisInterlockedIncrement(&pAdapter->OutstandingWorkItems); NdisScheduleWorkItem (pWorkItem); } Status = NDIS_STATUS_SUCCESS; } while (FALSE); ASSERT (Status == NDIS_STATUS_SUCCESS); return Status; }