reactos/drivers/network/ndisuio/protocol.c

557 lines
17 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS NDIS User I/O driver
* FILE: protocol.c
* PURPOSE: Protocol stuff
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
*/
#include "ndisuio.h"
#define NDEBUG
#include <debug.h>
VOID
NTAPI
NduOpenAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
NDIS_STATUS Status,
NDIS_STATUS OpenStatus)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter open completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
VOID
NTAPI
NduCloseAdapterComplete(NDIS_HANDLE ProtocolBindingContext,
NDIS_STATUS Status)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter close completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
NDIS_STATUS
NTAPI
NduNetPnPEvent(NDIS_HANDLE ProtocolBindingContext,
PNET_PNP_EVENT NetPnPEvent)
{
PNDIS_DEVICE_POWER_STATE PowerState;
DPRINT("NetPnPEvent\n");
switch (NetPnPEvent->NetEvent)
{
case NetEventQueryRemoveDevice:
/* Nothing to do */
DPRINT1("NetPnPEvent: QueryRemoveDevice\n");
return NDIS_STATUS_SUCCESS;
case NetEventSetPower:
ASSERT(NetPnPEvent->BufferLength >= sizeof(*PowerState));
PowerState = NetPnPEvent->Buffer;
switch (*PowerState)
{
case NdisDeviceStateD0:
DPRINT1("NetPnPEvent: SetPower D0\n");
return NDIS_STATUS_SUCCESS;
default:
DPRINT1("NetPnPEvent: SetPower state %d not supported\n", *PowerState);
return NDIS_STATUS_FAILURE;
}
case NetEventQueryPower:
DPRINT1("NetPnPEvent: QueryPower\n");
return NDIS_STATUS_SUCCESS;
case NetEventCancelRemoveDevice:
DPRINT1("NetPnPEvent: CancelRemoveDevice\n");
return NDIS_STATUS_SUCCESS;
case NetEventReconfigure:
DPRINT1("NetPnPEvent: Reconfigure\n");
return NDIS_STATUS_SUCCESS;
case NetEventBindList:
DPRINT1("NetPnPEvent: BindList\n");
return NDIS_STATUS_SUCCESS;
case NetEventBindsComplete:
DPRINT("NetPnPEvent: BindsComplete\n");
return NDIS_STATUS_SUCCESS;
case NetEventPnPCapabilities:
DPRINT1("NetPnPEvent: PnPCapabilities\n");
return NDIS_STATUS_SUCCESS;
default:
DPRINT1("NetPnPEvent unimplemented for net event 0x%x\n", NetPnPEvent->NetEvent);
return NDIS_STATUS_FAILURE;
}
}
VOID
NTAPI
NduSendComplete(NDIS_HANDLE ProtocolBindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter send completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
VOID
NTAPI
NduTransferDataComplete(NDIS_HANDLE ProtocolBindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status,
UINT BytesTransferred)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter transfer completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
VOID
NTAPI
NduResetComplete(NDIS_HANDLE ProtocolBindingContext,
NDIS_STATUS Status)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter reset completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
VOID
NTAPI
NduRequestComplete(NDIS_HANDLE ProtocolBindingContext,
PNDIS_REQUEST NdisRequest,
NDIS_STATUS Status)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
DPRINT("Asynchronous adapter request completed\n");
/* Store the final status and signal the event */
AdapterContext->AsyncStatus = Status;
KeSetEvent(&AdapterContext->AsyncEvent, IO_NO_INCREMENT, FALSE);
}
NDIS_STATUS
NTAPI
NduReceive(NDIS_HANDLE ProtocolBindingContext,
NDIS_HANDLE MacReceiveContext,
PVOID HeaderBuffer,
UINT HeaderBufferSize,
PVOID LookAheadBuffer,
UINT LookaheadBufferSize,
UINT PacketSize)
{
PNDISUIO_ADAPTER_CONTEXT AdapterContext = ProtocolBindingContext;
PNDISUIO_PACKET_ENTRY PacketEntry;
PVOID PacketBuffer;
PNDIS_PACKET Packet;
NDIS_STATUS Status;
UINT BytesTransferred;
DPRINT("Received a %d byte packet\n", PacketSize);
/* Discard if nobody is waiting for it */
if (AdapterContext->OpenCount == 0)
return NDIS_STATUS_NOT_ACCEPTED;
/* Allocate a buffer to hold the packet data and header */
PacketBuffer = ExAllocatePool(NonPagedPool, PacketSize + HeaderBufferSize);
if (!PacketBuffer)
return NDIS_STATUS_NOT_ACCEPTED;
/* Allocate the packet descriptor and buffer */
Packet = CreatePacketFromPoolBuffer(AdapterContext,
(PUCHAR)PacketBuffer + HeaderBufferSize,
PacketSize);
if (!Packet)
{
ExFreePool(PacketBuffer);
return NDIS_STATUS_NOT_ACCEPTED;
}
/* Transfer the packet data into our data buffer */
if (LookaheadBufferSize == PacketSize)
{
NdisCopyLookaheadData((PVOID)((PUCHAR)PacketBuffer + HeaderBufferSize),
LookAheadBuffer,
PacketSize,
AdapterContext->MacOptions);
BytesTransferred = PacketSize;
}
else
{
NdisTransferData(&Status,
AdapterContext->BindingHandle,
MacReceiveContext,
0,
PacketSize,
Packet,
&BytesTransferred);
if (Status == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&AdapterContext->AsyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
Status = AdapterContext->AsyncStatus;
}
if (Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("Failed to transfer data with status 0x%x\n", Status);
CleanupAndFreePacket(Packet, FALSE);
ExFreePool(PacketBuffer);
return NDIS_STATUS_NOT_ACCEPTED;
}
}
/* Copy the header data */
RtlCopyMemory(PacketBuffer, HeaderBuffer, HeaderBufferSize);
/* Free the packet descriptor and buffers
but not the pool because we still need it */
CleanupAndFreePacket(Packet, FALSE);
/* Allocate a packet entry from pool */
PacketEntry = ExAllocatePool(NonPagedPool, sizeof(NDISUIO_PACKET_ENTRY) + BytesTransferred + HeaderBufferSize - 1);
if (!PacketEntry)
{
ExFreePool(PacketBuffer);
return NDIS_STATUS_RESOURCES;
}
/* Initialize the packet entry and copy in packet data */
PacketEntry->PacketLength = BytesTransferred + HeaderBufferSize;
RtlCopyMemory(PacketEntry->PacketData, PacketBuffer, PacketEntry->PacketLength);
/* Free the old buffer */
ExFreePool(PacketBuffer);
/* Insert the packet on the adapter's packet list */
ExInterlockedInsertTailList(&AdapterContext->PacketList,
&PacketEntry->ListEntry,
&AdapterContext->Spinlock);
/* Signal the read event */
KeSetEvent(&AdapterContext->PacketReadEvent,
IO_NETWORK_INCREMENT,
FALSE);
return NDIS_STATUS_SUCCESS;
}
VOID
NTAPI
NduReceiveComplete(NDIS_HANDLE ProtocolBindingContext)
{
/* No op */
}
VOID
NTAPI
NduStatus(NDIS_HANDLE ProtocolBindingContext,
NDIS_STATUS GeneralStatus,
PVOID StatusBuffer,
UINT StatusBufferSize)
{
/* FIXME: Implement status tracking */
}
VOID
NTAPI
NduStatusComplete(NDIS_HANDLE ProtocolBindingContext)
{
/* FIXME: Implement status tracking */
}
static
NDIS_STATUS
UnbindAdapterByContext(PNDISUIO_ADAPTER_CONTEXT AdapterContext)
{
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PNDISUIO_OPEN_ENTRY OpenEntry;
PNDISUIO_PACKET_ENTRY PacketEntry;
NDIS_STATUS Status;
DPRINT("Unbinding adapter %wZ\n", &AdapterContext->DeviceName);
/* FIXME: We don't do anything with outstanding reads */
/* Remove the adapter context from the global list */
KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
RemoveEntryList(&AdapterContext->ListEntry);
KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
/* Free the device name string */
RtlFreeUnicodeString(&AdapterContext->DeviceName);
/* Invalidate all handles to this adapter */
CurrentEntry = AdapterContext->OpenEntryList.Flink;
while (CurrentEntry != &AdapterContext->OpenEntryList)
{
OpenEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_OPEN_ENTRY, ListEntry);
/* Make sure the entry is sane */
ASSERT(OpenEntry->FileObject);
/* Remove the adapter context pointer */
ASSERT(AdapterContext == OpenEntry->FileObject->FsContext);
OpenEntry->FileObject->FsContext = NULL;
AdapterContext->OpenCount--;
/* Remove the open entry pointer */
ASSERT(OpenEntry == OpenEntry->FileObject->FsContext2);
OpenEntry->FileObject->FsContext2 = NULL;
/* Move to the next entry */
CurrentEntry = CurrentEntry->Flink;
/* Free the open entry */
ExFreePool(OpenEntry);
}
/* If this fails, we have a refcount mismatch somewhere */
ASSERT(AdapterContext->OpenCount == 0);
/* Free all pending packet entries */
CurrentEntry = AdapterContext->PacketList.Flink;
while (CurrentEntry != &AdapterContext->PacketList)
{
PacketEntry = CONTAINING_RECORD(CurrentEntry, NDISUIO_PACKET_ENTRY, ListEntry);
/* Move to the next entry */
CurrentEntry = CurrentEntry->Flink;
/* Free the packet entry */
ExFreePool(PacketEntry);
}
/* Send the close request */
NdisCloseAdapter(&Status,
AdapterContext->BindingHandle);
/* Wait for a pending close */
if (Status == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&AdapterContext->AsyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
Status = AdapterContext->AsyncStatus;
}
/* Free the context */
ExFreePool(AdapterContext);
return Status;
}
static
NDIS_STATUS
BindAdapterByName(PNDIS_STRING DeviceName)
{
NDIS_STATUS OpenErrorStatus;
PNDISUIO_ADAPTER_CONTEXT AdapterContext;
NDIS_MEDIUM SupportedMedia[1] = {NdisMedium802_3};
UINT SelectedMedium;
NDIS_STATUS Status;
NDIS_REQUEST Request;
/* Allocate the adapter context */
AdapterContext = ExAllocatePool(NonPagedPool, sizeof(*AdapterContext));
if (!AdapterContext)
{
return NDIS_STATUS_RESOURCES;
}
/* Set up the adapter context */
RtlZeroMemory(AdapterContext, sizeof(*AdapterContext));
KeInitializeEvent(&AdapterContext->AsyncEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&AdapterContext->PacketReadEvent, SynchronizationEvent, FALSE);
KeInitializeSpinLock(&AdapterContext->Spinlock);
InitializeListHead(&AdapterContext->PacketList);
InitializeListHead(&AdapterContext->OpenEntryList);
AdapterContext->OpenCount = 0;
AdapterContext->DeviceName.Length =
AdapterContext->DeviceName.MaximumLength = DeviceName->Length;
AdapterContext->DeviceName.Buffer = ExAllocatePool(NonPagedPool, DeviceName->Length);
if (!AdapterContext->DeviceName.Buffer)
{
ExFreePool(AdapterContext);
return NDIS_STATUS_RESOURCES;
}
/* Copy the device name into the adapter context */
RtlCopyMemory(AdapterContext->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
DPRINT("Binding adapter %wZ\n", &AdapterContext->DeviceName);
/* Create the buffer pool */
NdisAllocateBufferPool(&Status,
&AdapterContext->BufferPoolHandle,
50);
if (Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("Failed to allocate buffer pool with status 0x%x\n", Status);
RtlFreeUnicodeString(&AdapterContext->DeviceName);
ExFreePool(AdapterContext);
return Status;
}
/* Create the packet pool */
NdisAllocatePacketPool(&Status,
&AdapterContext->PacketPoolHandle,
25,
PROTOCOL_RESERVED_SIZE_IN_PACKET);
if (Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("Failed to allocate packet pool with status 0x%x\n", Status);
NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
RtlFreeUnicodeString(&AdapterContext->DeviceName);
ExFreePool(AdapterContext);
return Status;
}
/* Send the open request */
NdisOpenAdapter(&Status,
&OpenErrorStatus,
&AdapterContext->BindingHandle,
&SelectedMedium,
SupportedMedia,
1,
GlobalProtocolHandle,
AdapterContext,
DeviceName,
0,
NULL);
/* Wait for a pending open */
if (Status == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&AdapterContext->AsyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
Status = AdapterContext->AsyncStatus;
}
/* Check the final status */
if (Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("Failed to open adapter for bind with status 0x%x\n", Status);
NdisFreePacketPool(AdapterContext->PacketPoolHandle);
NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
RtlFreeUnicodeString(&AdapterContext->DeviceName);
ExFreePool(AdapterContext);
return Status;
}
/* Get the MAC options */
Request.RequestType = NdisRequestQueryInformation;
Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
Request.DATA.QUERY_INFORMATION.InformationBuffer = &AdapterContext->MacOptions;
Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG);
NdisRequest(&Status,
AdapterContext->BindingHandle,
&Request);
/* Wait for a pending request */
if (Status == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&AdapterContext->AsyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
Status = AdapterContext->AsyncStatus;
}
/* Check the final status */
if (Status != NDIS_STATUS_SUCCESS)
{
NDIS_STATUS CloseStatus;
DPRINT1("Failed to get MAC options with status 0x%x\n", Status);
NdisCloseAdapter(&CloseStatus,
AdapterContext->BindingHandle);
if (CloseStatus == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&AdapterContext->AsyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
NdisFreePacketPool(AdapterContext->PacketPoolHandle);
NdisFreeBufferPool(AdapterContext->BufferPoolHandle);
RtlFreeUnicodeString(&AdapterContext->DeviceName);
ExFreePool(AdapterContext);
return Status;
}
/* Add the adapter context to the global list */
ExInterlockedInsertTailList(&GlobalAdapterList,
&AdapterContext->ListEntry,
&GlobalAdapterListLock);
return STATUS_SUCCESS;
}
VOID
NTAPI
NduBindAdapter(PNDIS_STATUS Status,
NDIS_HANDLE BindContext,
PNDIS_STRING DeviceName,
PVOID SystemSpecific1,
PVOID SystemSpecific2)
{
/* Use our helper function to create a context for this adapter */
*Status = BindAdapterByName(DeviceName);
}
VOID
NTAPI
NduUnbindAdapter(PNDIS_STATUS Status,
NDIS_HANDLE ProtocolBindingContext,
NDIS_HANDLE UnbindContext)
{
/* This is forced unbind. UnbindAdapterByContext() will take care of
* invalidating file handles pointer to this adapter for us */
*Status = UnbindAdapterByContext(ProtocolBindingContext);
}