windows-nt/Source/XPSP1/NT/net/1394/nic/sys/driver.c
2020-09-26 16:20:57 +08:00

672 lines
13 KiB
C

//--------------------------------------------------------//
// //
// //
// 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
Arguments:
Return Value:
--*/
{
//
// The BufferSize always has to be greater than SizeReturned
//
NdisMoveMemory (pAdapterName,
&pAdapter->AdapterName[0],
pAdapter->AdapterNameSize * sizeof (WCHAR));
if (pSizeReturned != NULL)
{
*pSizeReturned = pAdapter->AdapterNameSize ;
}
}
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)
{
// BRIDGE START
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)
{
// BRIDGE STOP
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;
NdisZeroMemory (&pAdapter->LoadArp, sizeof(pAdapter->LoadArp));
InitializeListHead(&pAdapter->LoadArp.Queue);
pAdapter->LoadArp.bInitialized = TRUE;
NdisInitializeWorkItem (&pAdapter->LoadArp.WorkItem,
nicProcessNotificationForArp,
pAdapter);
nicGetAdapterName (pAdapter,
pEthCmd->AdapterName,
sizeof(pEthCmd->AdapterName)-sizeof(WCHAR),
&Size );
pEthCmd->AdapterName[Size/2]=0;
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 timer
//
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;
}