reactos/drivers/network/lan/lan/lan.c

1496 lines
45 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: datalink/lan.c
* PURPOSE: Local Area Network media routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISIONS:
* CSH 01/08-2000 Created
* arty -- Separate service 09/2004
*/
#include "precomp.h"
ULONG DebugTraceLevel = 0x7ffffff;
PDEVICE_OBJECT LanDeviceObject = NULL;
/*!
* @brief Send a request to NDIS
*
* @param Adapter = Pointer to a LAN_ADAPTER structure
* @param Type = Type of request (Set or Query)
* @param OID = Value to be set/queried for
* @param Buffer = Pointer to a buffer to use
* @param Length = Number of bytes in Buffer
*
* @return Status of operation
*/
NDIS_STATUS
NDISCall(
PLAN_ADAPTER Adapter,
NDIS_REQUEST_TYPE Type,
NDIS_OID OID,
PVOID Buffer,
UINT Length)
{
NDIS_REQUEST Request;
NDIS_STATUS NdisStatus;
Request.RequestType = Type;
if (Type == NdisRequestSetInformation)
{
Request.DATA.SET_INFORMATION.Oid = OID;
Request.DATA.SET_INFORMATION.InformationBuffer = Buffer;
Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
}
else
{
Request.DATA.QUERY_INFORMATION.Oid = OID;
Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
}
if (Adapter->State != LAN_STATE_RESETTING)
{
NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
}
else
{
NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
}
/* Wait for NDIS to complete the request */
if (NdisStatus == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&Adapter->Event,
UserRequest,
KernelMode,
FALSE,
NULL);
NdisStatus = Adapter->NdisStatus;
}
return NdisStatus;
}
/*!
* @brief Frees memory for a LAN_ADAPTER structure
*
* @param Adapter = Pointer to LAN_ADAPTER structure to free
*/
VOID
FreeAdapter(
PLAN_ADAPTER Adapter)
{
exFreePool(Adapter);
}
/*!
* @brief Called by NDIS to complete opening of an adapter
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param Status = Status of the operation
* @param OpenErrorStatus = Additional status information
*/
VOID
NTAPI
ProtocolOpenAdapterComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status,
NDIS_STATUS OpenErrorStatus)
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
KeSetEvent(&Adapter->Event, 0, FALSE);
}
/*!
* @brief Called by NDIS to complete closing an adapter
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param Status = Status of the operation
*/
VOID
NTAPI
ProtocolCloseAdapterComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status)
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
Adapter->NdisStatus = Status;
KeSetEvent(&Adapter->Event, 0, FALSE);
}
/*!
* @brief Called by NDIS to complete resetting an adapter
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param Status = Status of the operation
*/
VOID
NTAPI
ProtocolResetComplete(
NDIS_HANDLE BindingContext,
NDIS_STATUS Status)
{
LA_DbgPrint(MID_TRACE, ("Called.\n"));
}
/*!
* @brief Called by NDIS to complete a request
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param NdisRequest = Pointer to an object describing the request
* @param Status = Status of the operation
*/
VOID
NTAPI
ProtocolRequestComplete(
NDIS_HANDLE BindingContext,
PNDIS_REQUEST NdisRequest,
NDIS_STATUS Status)
{
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
/* Save status of request and signal an event */
Adapter->NdisStatus = Status;
KeSetEvent(&Adapter->Event, 0, FALSE);
}
/*!
* @brief Called by NDIS to complete sending process
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param Packet = Pointer to a packet descriptor
* @param Status = Status of the operation
*/
VOID
NTAPI
ProtocolSendComplete(
NDIS_HANDLE BindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status)
{
/*PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;*/
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
/*(*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);*/
LA_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
}
/*!
* @brief Called by NDIS to complete reception of data
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param Packet = Pointer to a packet descriptor
* @param Status = Status of the operation
* @param BytesTransferred = Number of bytes transferred
*
* @note If the packet was successfully received, determine the protocol
* type and pass it to the correct receive handler
*/
VOID
NTAPI
ProtocolTransferDataComplete(
NDIS_HANDLE BindingContext,
PNDIS_PACKET Packet,
NDIS_STATUS Status,
UINT BytesTransferred)
{
PLIST_ENTRY ListEntry, ReadListEntry;
PLAN_PROTOCOL Proto;
PLAN_PACKET_HEADER Header;
PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
UINT i;
UINT PacketType;
UINT ContigSize;
PIRP ReadIrp;
KIRQL OldIrql;
LAN_PACKET LPPacket;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
if (Status == NDIS_STATUS_SUCCESS)
{
PNDIS_BUFFER NdisBuffer;
NdisGetFirstBufferFromPacket(Packet,
&NdisBuffer,
&LPPacket.EthHeader,
&ContigSize,
&LPPacket.TotalSize);
LPPacket.TotalSize = BytesTransferred;
/* Determine which upper layer protocol that should receive
this packet and pass it to the correct receive handler */
/*OskitDumpBuffer(IPPacket.Header, BytesTransferred);*/
PacketType = LPPacket.EthHeader->EType;
LA_DbgPrint(DEBUG_DATALINK,
("Ether Type = %x Total = %d Packet %x Payload %x\n",
PacketType, LPPacket.TotalSize, LPPacket.EthHeader,
LPPacket.EthHeader + 1));
NdisBuffer->Next = NULL;
for (ListEntry = DeviceExt->ProtocolListHead.Flink;
ListEntry != &DeviceExt->ProtocolListHead;
ListEntry = ListEntry->Flink)
{
Proto = CONTAINING_RECORD(ListEntry, LAN_PROTOCOL, ListEntry);
LA_DbgPrint(MID_TRACE,("Examining protocol %x\n", Proto));
for (i = 0; i < Proto->NumEtherTypes; i++)
{
LA_DbgPrint(MID_TRACE,(".Accepts proto %x\n",
Proto->EtherType[i]));
if (Proto->EtherType[i] == PacketType &&
!IsListEmpty(&Proto->ReadIrpListHead))
{
ReadListEntry = RemoveHeadList(&Proto->ReadIrpListHead);
ReadIrp = CONTAINING_RECORD(ReadListEntry,
IRP,
Tail.Overlay.ListEntry);
LA_DbgPrint(MID_TRACE,("..Irp %x\n", ReadIrp));
_SEH2_TRY
{
Header = ReadIrp->AssociatedIrp.SystemBuffer;
LA_DbgPrint(MID_TRACE,
("Writing packet at %x\n", Header));
Header->Fixed.Adapter = Adapter->Index;
Header->Fixed.AddressType = Adapter->Media;
Header->Fixed.AddressLen = IEEE_802_ADDR_LENGTH;
Header->Fixed.PacketType = PacketType;
RtlCopyMemory(Header->Address,
LPPacket.EthHeader->SrcAddr,
IEEE_802_ADDR_LENGTH);
if (Proto->Buffered)
{
LA_DbgPrint(MID_TRACE,("Buffered copy\n"));
RtlCopyMemory(Header->Address + IEEE_802_ADDR_LENGTH,
LPPacket.EthHeader + 1,
LPPacket.TotalSize -
sizeof(*LPPacket.EthHeader) );
Header->Fixed.Mdl = NULL;
}
else
Header->Fixed.Mdl = NdisBuffer;
ReadIrp->IoStatus.Status = 0;
ReadIrp->IoStatus.Information =
(Header->Address + IEEE_802_ADDR_LENGTH +
LPPacket.TotalSize -
sizeof(*LPPacket.EthHeader)) -
(PCHAR)Header;
LA_DbgPrint(MID_TRACE,("Bytes returned %d\n",
ReadIrp->IoStatus.Information));
#error move this out of SEH!
IoCompleteRequest(ReadIrp, IO_NETWORK_INCREMENT);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
LA_DbgPrint(MIN_TRACE,
("Failed write to packet in client\n"));
ReadIrp->IoStatus.Status = STATUS_ACCESS_VIOLATION;
ReadIrp->IoStatus.Information = 0;
IoCompleteRequest(ReadIrp, IO_NETWORK_INCREMENT);
}
_SEH2_END;
break;
}
}
}
}
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
FreeNdisPacket(Packet);
}
/*!
* @brief Called by NDIS when a packet has been received on the physical link
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param MacReceiveContext = Handle used by underlying NIC driver
* @param HeaderBuffer = Pointer to a buffer containing the packet header
* @param HeaderBufferSize = Number of bytes in HeaderBuffer
* @param LookaheadBuffer = Pointer to a buffer containing buffered packet data
* @param LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
* @param PacketSize = Overall size of the packet (not including header)
*
* @return Status of operation
*/
NDIS_STATUS
NTAPI
ProtocolReceive(
NDIS_HANDLE BindingContext,
NDIS_HANDLE MacReceiveContext,
PVOID HeaderBuffer,
UINT HeaderBufferSize,
PVOID LookaheadBuffer,
UINT LookaheadBufferSize,
UINT PacketSize)
{
USHORT EType;
UINT PacketType, BytesTransferred;
PCHAR BufferData;
NDIS_STATUS NdisStatus;
PNDIS_PACKET NdisPacket;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
LA_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
if (Adapter->State != LAN_STATE_STARTED)
{
LA_DbgPrint(DEBUG_DATALINK, ("Adapter is stopped.\n"));
return NDIS_STATUS_NOT_ACCEPTED;
}
if (HeaderBufferSize < Adapter->HeaderSize)
{
LA_DbgPrint(DEBUG_DATALINK, ("Runt frame received.\n"));
return NDIS_STATUS_NOT_ACCEPTED;
}
PacketType = EType;
/* Get a transfer data packet */
KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
NdisStatus = AllocatePacketWithBuffer(&NdisPacket, NULL, Adapter->MTU);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
return NDIS_STATUS_NOT_ACCEPTED;
}
LA_DbgPrint(DEBUG_DATALINK,
("pretransfer LookaheadBufferSize %d packsize %d\n",
LookaheadBufferSize,PacketSize));
{
UINT temp;
temp = PacketSize;
GetDataPtr(NdisPacket, 0, &BufferData, &temp);
}
LA_DbgPrint(DEBUG_DATALINK,
("pretransfer LookaheadBufferSize %d HeaderBufferSize %d packsize %d\n",
LookaheadBufferSize,HeaderBufferSize,PacketSize));
/* Get the data */
NdisTransferData(&NdisStatus,
Adapter->NdisHandle,
MacReceiveContext,
0,
PacketSize + HeaderBufferSize,
NdisPacket,
&BytesTransferred);
LA_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
if (NdisStatus != NDIS_STATUS_PENDING)
{
ProtocolTransferDataComplete(BindingContext,
NdisPacket,
NdisStatus,
PacketSize + HeaderBufferSize);
}
/* Release the packet descriptor */
KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
LA_DbgPrint(DEBUG_DATALINK, ("leaving\n"));
return NDIS_STATUS_SUCCESS;
}
/*!
* @brief Called by NDIS when we're done receiving data
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
*/
VOID
NTAPI
ProtocolReceiveComplete(
NDIS_HANDLE BindingContext)
{
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}
/*!
* @brief Called by NDIS when the underlying driver has changed state
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
* @param GenerelStatus = A generel status code
* @param StatusBuffer = Pointer to a buffer with medium-specific data
* @param StatusBufferSize = Number of bytes in StatusBuffer
*/
VOID
NTAPI
ProtocolStatus(
NDIS_HANDLE BindingContext,
NDIS_STATUS GenerelStatus,
PVOID StatusBuffer,
UINT StatusBufferSize)
{
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}
/*!
* @brief Called by NDIS when a status-change has occurred
*
* @param BindingContext = Pointer to a device context (LAN_ADAPTER)
*/
VOID
NTAPI
ProtocolStatusComplete(
NDIS_HANDLE NdisBindingContext)
{
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}
/*!
* @brief Called by NDIS during NdisRegisterProtocol to set up initial
* bindings, and periodically thereafter as new adapters come online
*
* @param Status - Return value to NDIS
* @param BindContext - Handle provided by NDIS to track pending binding operations
* @param DeviceName - Name of the miniport device to bind to
* @param SystemSpecific1 - Pointer to a registry path with protocol-specific
* configuration information
* @param SystemSpecific2 - Unused & must not be touched
*/
VOID
NTAPI
ProtocolBindAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2)
{
/* XXX confirm that this is still true, or re-word the following comment */
/* we get to ignore BindContext because we will never pend an operation with NDIS */
LA_DbgPrint(DEBUG_DATALINK, ("Called with registry path %wZ\n", SystemSpecific1));
*Status = LANRegisterAdapter(DeviceName, SystemSpecific1);
}
/*!
* @brief Transmits a packet
* ARGUMENTS:
* @param Context = Pointer to context information (LAN_ADAPTER)
* @param NdisPacket = Pointer to NDIS packet to send
* @param LinkAddress = Pointer to link address of destination (NULL = broadcast)
* @param Type = LAN protocol type (LAN_PROTO_*)
*/
VOID
LANTransmit(
PLAN_ADAPTER Adapter,
PNDIS_PACKET NdisPacket,
PVOID LinkAddress,
USHORT Type)
{
NDIS_STATUS NdisStatus;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
if (Adapter->State == LAN_STATE_STARTED)
{
NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
if (NdisStatus != NDIS_STATUS_PENDING)
ProtocolSendComplete((NDIS_HANDLE)Adapter, NdisPacket, NdisStatus);
}
else
{
ProtocolSendComplete((NDIS_HANDLE)Adapter, NdisPacket, NDIS_STATUS_CLOSED);
}
}
/* For use internally */
UINT
LANTransmitInternal(PLAN_PACKET_HEADER ToWrite, UINT OverallLength)
{
NDIS_STATUS NdisStatus;
PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
PLAN_ADAPTER Adapter;
PETH_HEADER EthHeader;
KIRQL OldIrql;
PNDIS_PACKET NdisPacket;
UINT Size, PayloadSize = OverallLength -
((ToWrite->Address + ToWrite->Fixed.AddressLen) - (PCHAR)ToWrite);
NdisStatus = AllocatePacketWithBuffer(&NdisPacket, NULL,
PayloadSize + sizeof(ETH_HEADER));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
if (!NT_SUCCESS(NdisStatus)) goto end;
Adapter = FindAdapterByIndex(DeviceExt, ToWrite->Fixed.Adapter);
if (!Adapter) goto end;
GetDataPtr(NdisPacket, 0, (PCHAR *)&EthHeader, &Size);
if (!EthHeader) goto end;
LA_DbgPrint(MID_TRACE,("Writing %d bytes of Dst\n",
ToWrite->Fixed.AddressLen));
/* Handle broadcast for other media types here */
if (ToWrite->Fixed.AddressLen)
{
RtlCopyMemory(EthHeader->DstAddr,
ToWrite->Address,
ToWrite->Fixed.AddressLen);
}
else
memset(EthHeader->DstAddr, -1, sizeof(EthHeader->DstAddr));
LA_DbgPrint(MID_TRACE,
("Writing %d bytes of Src\n", Adapter->HWAddressLength));
RtlCopyMemory(EthHeader->SrcAddr,
Adapter->HWAddress,
Adapter->HWAddressLength);
LA_DbgPrint(MID_TRACE,
("Writing %d bytes of payload\n", PayloadSize));
EthHeader->EType = ToWrite->Fixed.PacketType;
RtlCopyMemory(EthHeader + 1,
ToWrite->Address + ToWrite->Fixed.AddressLen,
PayloadSize);
LANTransmit(Adapter,
NdisPacket,
ToWrite->Address,
ToWrite->Fixed.PacketType);
end:
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
return OverallLength;
}
/*!
* @brief Binds a LAN adapter to IP layer
*
* @param Adapter = Pointer to LAN_ADAPTER structure
*
* @note We set the lookahead buffer size, set the packet filter and
* bind the adapter to IP layer
*/
VOID
BindAdapter(PLAN_ADAPTER Adapter, PNDIS_STRING RegistryPath)
{
/*NDIS_STATUS NdisStatus;*/
/*ULONG Lookahead = LOOKAHEAD_SIZE;*/
/*NTSTATUS Status;*/
/*HANDLE RegHandle = 0;*/
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
}
/*!
* @brief Registers protocol with an NDIS adapter
*
* @param AdapterName = Pointer to string with name of adapter to register
* @param Adapter = Address of pointer to a LAN_ADAPTER structure
*
* @return Status of operation
*/
NDIS_STATUS
LANRegisterAdapter(
PNDIS_STRING AdapterName,
PNDIS_STRING RegistryPath)
{
PLAN_ADAPTER Adapter;
NDIS_MEDIUM MediaArray[MAX_MEDIA];
NDIS_STATUS NdisStatus;
NDIS_STATUS OpenStatus;
UINT MediaIndex;
UINT AddressOID;
UINT Speed;
PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
Adapter = exAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
if (!Adapter)
{
LA_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return NDIS_STATUS_RESOURCES;
}
RtlZeroMemory(Adapter, sizeof(LAN_ADAPTER));
/* Put adapter in stopped state */
Adapter->State = LAN_STATE_STOPPED;
Adapter->Index = DeviceExt->AdapterId++;
InitializeListHead(&Adapter->AddressList);
InitializeListHead(&Adapter->ForeignList);
/* Initialize protecting spin lock */
KeInitializeSpinLock(&Adapter->Lock);
KeInitializeEvent(&Adapter->Event, SynchronizationEvent, FALSE);
/* Initialize array with media IDs we support */
MediaArray[MEDIA_ETH] = NdisMedium802_3;
LA_DbgPrint(DEBUG_DATALINK,("opening adapter %wZ\n", AdapterName));
/* Open the adapter. */
NdisOpenAdapter(&NdisStatus,
&OpenStatus,
&Adapter->NdisHandle,
&MediaIndex,
MediaArray,
MAX_MEDIA,
DeviceExt->NdisProtocolHandle,
Adapter,
AdapterName,
0,
NULL);
/* Wait until the adapter is opened */
if (NdisStatus == NDIS_STATUS_PENDING)
KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);
else if (NdisStatus != NDIS_STATUS_SUCCESS)
{
exFreePool(Adapter);
return NdisStatus;
}
Adapter->Media = MediaArray[MediaIndex];
/* Fill LAN_ADAPTER structure with some adapter specific information */
switch (Adapter->Media)
{
case NdisMedium802_3:
Adapter->HWAddressLength = IEEE_802_ADDR_LENGTH;
Adapter->BCastMask = BCAST_ETH_MASK;
Adapter->BCastCheck = BCAST_ETH_CHECK;
Adapter->BCastOffset = BCAST_ETH_OFFSET;
Adapter->HeaderSize = sizeof(ETH_HEADER);
Adapter->MinFrameSize = 60;
AddressOID = OID_802_3_CURRENT_ADDRESS;
Adapter->PacketFilter =
NDIS_PACKET_TYPE_BROADCAST |
NDIS_PACKET_TYPE_DIRECTED |
NDIS_PACKET_TYPE_MULTICAST;
break;
default:
/* Unsupported media */
LA_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
exFreePool(Adapter);
return NDIS_STATUS_NOT_SUPPORTED;
}
/* Get maximum frame size */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_FRAME_SIZE,
&Adapter->MTU,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
exFreePool(Adapter);
return NdisStatus;
}
/* Get maximum packet size */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_TOTAL_SIZE,
&Adapter->MaxPacketSize,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
exFreePool(Adapter);
return NdisStatus;
}
/* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
OID_GEN_MAXIMUM_SEND_PACKETS,
&Adapter->MaxSendPackets,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
/* Legacy NIC drivers may not support this query, if it fails we
assume it can send at least one packet per call to NdisSend(Packets) */
Adapter->MaxSendPackets = 1;
}
/* Get current hardware address */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
AddressOID,
Adapter->HWAddress,
Adapter->HWAddressLength);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
exFreePool(Adapter);
return NdisStatus;
}
/* Get maximum link speed */
NdisStatus = NDISCall(Adapter,
NdisRequestQueryInformation,
OID_GEN_LINK_SPEED,
&Speed,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
exFreePool(Adapter);
return NdisStatus;
}
/* Convert returned link speed to bps (it is in 100bps increments) */
Adapter->Speed = Speed * 100L;
/* Add adapter to the adapter list */
ExInterlockedInsertTailList(&DeviceExt->AdapterListHead,
&Adapter->ListEntry,
&DeviceExt->Lock);
Adapter->RegistryPath.Buffer =
ExAllocatePool(NonPagedPool, RegistryPath->MaximumLength);
if (!Adapter->RegistryPath.Buffer)
return NDIS_STATUS_RESOURCES;
RtlCopyUnicodeString(&Adapter->RegistryPath, RegistryPath);
NdisStatus = NDISCall(Adapter,
NdisRequestSetInformation,
OID_GEN_CURRENT_LOOKAHEAD,
&Adapter->Lookahead,
sizeof(ULONG));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MID_TRACE,
("Could not set lookahead buffer size (0x%X).\n",
NdisStatus));
return NdisStatus;
}
/* Set packet filter so we can send and receive packets */
NdisStatus = NDISCall(Adapter,
NdisRequestSetInformation,
OID_GEN_CURRENT_PACKET_FILTER,
&Adapter->PacketFilter,
sizeof(UINT));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n",
NdisStatus));
return NdisStatus;
}
Adapter->State = LAN_STATE_STARTED;
LA_DbgPrint(DEBUG_DATALINK, ("Leaving.\n"));
return NDIS_STATUS_SUCCESS;
}
/*!
* @brief Unregisters protocol with NDIS adapter
*
* @param Adapter = Pointer to a LAN_ADAPTER structure
*
* @return Status of operation
*/
NDIS_STATUS
LANUnregisterAdapter(
PLAN_ADAPTER Adapter)
{
KIRQL OldIrql;
NDIS_HANDLE NdisHandle;
NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
/* Unlink the adapter from the list */
RemoveEntryList(&Adapter->ListEntry);
KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
NdisHandle = Adapter->NdisHandle;
if (NdisHandle)
{
Adapter->NdisHandle = NULL;
KeReleaseSpinLock(&Adapter->Lock, OldIrql);
NdisCloseAdapter(&NdisStatus, NdisHandle);
if (NdisStatus == NDIS_STATUS_PENDING)
{
KeWaitForSingleObject(&Adapter->Event,
UserRequest,
KernelMode,
FALSE,
NULL);
NdisStatus = Adapter->NdisStatus;
}
}
else
KeReleaseSpinLock(&Adapter->Lock, OldIrql);
FreeAdapter(Adapter);
return NDIS_STATUS_SUCCESS;
}
/*!
* @brief Registers this protocol driver with NDIS
*
* @param Name = Name of this protocol driver
*
* @return Status of operation
*/
NTSTATUS
LANRegisterProtocol(PNDIS_STRING Name)
{
NDIS_STATUS NdisStatus;
NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
InitializeListHead(&DeviceExt->AdapterListHead);
InitializeListHead(&DeviceExt->ProtocolListHead);
/* Set up protocol characteristics */
RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR;
ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR;
ProtChars.Name.Length = Name->Length;
ProtChars.Name.Buffer = Name->Buffer;
ProtChars.Name.MaximumLength = Name->MaximumLength;
ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;
ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
ProtChars.ResetCompleteHandler = ProtocolResetComplete;
ProtChars.RequestCompleteHandler = ProtocolRequestComplete;
ProtChars.SendCompleteHandler = ProtocolSendComplete;
ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
ProtChars.ReceiveHandler = ProtocolReceive;
ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete;
ProtChars.StatusHandler = ProtocolStatus;
ProtChars.StatusCompleteHandler = ProtocolStatusComplete;
ProtChars.BindAdapterHandler = ProtocolBindAdapter;
/* Try to register protocol */
NdisRegisterProtocol(&NdisStatus,
&DeviceExt->NdisProtocolHandle,
&ProtChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
LA_DbgPrint(MID_TRACE, ("NdisRegisterProtocol failed, status 0x%x\n", NdisStatus));
return (NTSTATUS)NdisStatus;
}
return STATUS_SUCCESS;
}
/*!
* @brief Unregisters this protocol driver with NDIS
* @note Does not care wether we are already registered
*/
VOID
LANUnregisterProtocol(VOID)
{
PLAN_DEVICE_EXT DeviceExt = LanDeviceObject->DeviceExtension;
LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
NDIS_STATUS NdisStatus;
PLIST_ENTRY CurrentEntry;
PLIST_ENTRY NextEntry;
PLAN_ADAPTER Current;
KIRQL OldIrql;
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
/* Search the list and remove every adapter we find */
CurrentEntry = DeviceExt->AdapterListHead.Flink;
while (CurrentEntry != &DeviceExt->AdapterListHead)
{
NextEntry = CurrentEntry->Flink;
Current = CONTAINING_RECORD(CurrentEntry, LAN_ADAPTER, ListEntry);
/* Unregister it */
LANUnregisterAdapter(Current);
CurrentEntry = NextEntry;
}
NdisDeregisterProtocol(&NdisStatus, DeviceExt->NdisProtocolHandle);
}
NTSTATUS
NTAPI
LanCreateProtocol(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_PROTOCOL Proto;
PFILE_FULL_EA_INFORMATION EaInfo;
PLAN_DEVICE_EXT DeviceExt = (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PCHAR ProtoNumbersToMatch;
UINT Size = sizeof(*Proto);
NTSTATUS Status = STATUS_SUCCESS;
EaInfo = Irp->AssociatedIrp.SystemBuffer;
Size += EaInfo->EaValueLength;
Proto = ExAllocatePool(NonPagedPool, Size);
if (!Proto)
{
Status = Irp->IoStatus.Status = STATUS_NO_MEMORY;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return Status;
}
RtlZeroMemory(Proto, Size);
Proto->Id = DeviceExt->ProtoId++;
Proto->NumEtherTypes = EaInfo->EaValueLength / sizeof(USHORT);
ProtoNumbersToMatch = EaInfo->EaName + EaInfo->EaNameLength + 1;
LA_DbgPrint(MID_TRACE,("NumEtherTypes: %d\n", Proto->NumEtherTypes));
RtlCopyMemory(Proto->EtherType,
ProtoNumbersToMatch,
sizeof(USHORT) * Proto->NumEtherTypes);
InitializeListHead(&Proto->ReadIrpListHead);
FileObject->FsContext = Proto;
LA_DbgPrint(MID_TRACE,("DeviceExt: %x, Proto %x\n", DeviceExt, Proto));
ExInterlockedInsertTailList(&DeviceExt->ProtocolListHead,
&Proto->ListEntry,
&DeviceExt->Lock);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
LA_DbgPrint(MID_TRACE,("Status %x\n", Irp->IoStatus.Status));
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
LanCloseProtocol(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_DEVICE_EXT DeviceExt = (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PLAN_PROTOCOL Proto = FileObject->FsContext;
KIRQL OldIrql;
PLIST_ENTRY ReadIrpListEntry;
PIRP ReadIrp;
NTSTATUS Status;
LA_DbgPrint(MID_TRACE,("Called\n"));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
while (!IsListEmpty(&Proto->ReadIrpListHead))
{
ReadIrpListEntry = RemoveHeadList(&Proto->ReadIrpListHead);
ReadIrp = CONTAINING_RECORD(ReadIrpListEntry,
IRP,
Tail.Overlay.ListEntry);
ReadIrp->IoStatus.Information = 0;
ReadIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest(ReadIrp, IO_NO_INCREMENT);
}
RemoveEntryList(&Proto->ListEntry);
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
LA_DbgPrint(MID_TRACE,("Deleting %x\n"));
ExFreePool(Proto);
Status = Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
PLAN_ADAPTER
FindAdapterByIndex(
PLAN_DEVICE_EXT DeviceExt,
UINT Index)
{
PLIST_ENTRY ListEntry;
PLAN_ADAPTER Current, Target = NULL;
for (ListEntry = DeviceExt->AdapterListHead.Flink;
ListEntry != &DeviceExt->AdapterListHead;
ListEntry = ListEntry->Flink)
{
Current = CONTAINING_RECORD(ListEntry, LAN_ADAPTER, ListEntry);
if (Current->Index == Index)
{
Target = Current;
break;
}
}
return Target;
}
/* Write data to an adapter:
* |<- 16 >| |<-- variable ... -->|
* [indx] [addrtype] [addrlen ] [ptype] [packet-data ...]
*/
NTSTATUS
NTAPI
LanWriteData(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_PACKET_HEADER ToWrite = Irp->AssociatedIrp.SystemBuffer;
NTSTATUS Status = STATUS_SUCCESS;
LA_DbgPrint(MID_TRACE,("Called\n"));
Irp->IoStatus.Information =
LANTransmitInternal(ToWrite, IrpSp->Parameters.Write.Length);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
LanReadData(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_DEVICE_EXT DeviceExt =
(PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PLAN_PROTOCOL Proto = FileObject->FsContext;
LA_DbgPrint(MID_TRACE,("Called on %x (%x)\n", Proto, Irp));
ExInterlockedInsertTailList(&Proto->ReadIrpListHead,
&Irp->Tail.Overlay.ListEntry,
&DeviceExt->Lock);
LA_DbgPrint(MID_TRACE,("List: %x %x\n",
Proto->ReadIrpListHead.Flink,
Irp->Tail.Overlay.ListEntry.Flink));
IoMarkIrpPending(Irp);
return STATUS_PENDING;
}
NTSTATUS
NTAPI
LanEnumAdapters(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLIST_ENTRY ListEntry;
PLAN_DEVICE_EXT DeviceExt = (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
NTSTATUS Status = STATUS_SUCCESS;
PLAN_ADAPTER Adapter;
UINT AdapterCount = 0;
PUINT Output = Irp->AssociatedIrp.SystemBuffer;
KIRQL OldIrql;
LA_DbgPrint(MID_TRACE,("Called\n"));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
for (ListEntry = DeviceExt->AdapterListHead.Flink;
ListEntry != &DeviceExt->AdapterListHead;
ListEntry = ListEntry->Flink)
{
AdapterCount++;
}
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
AdapterCount * sizeof(UINT))
{
for (ListEntry = DeviceExt->AdapterListHead.Flink;
ListEntry != &DeviceExt->AdapterListHead;
ListEntry = ListEntry->Flink)
{
Adapter = CONTAINING_RECORD(ListEntry, LAN_ADAPTER, ListEntry);
*Output++ = Adapter->Index;
}
}
else
Status = STATUS_BUFFER_TOO_SMALL;
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
LA_DbgPrint(MID_TRACE,("Ending\n"));
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = (PCHAR)Output -
(PCHAR)Irp->AssociatedIrp.SystemBuffer;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
LanAdapterInfo(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_DEVICE_EXT DeviceExt =
(PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
PLAN_ADAPTER Adapter;
PLAN_ADDRESS_C Address;
PUINT AdapterIndexPtr = Irp->AssociatedIrp.SystemBuffer;
PLIST_ENTRY ListEntry;
UINT BytesNeeded = sizeof(LAN_ADAPTER_INFO), AddrSize;
NTSTATUS Status = STATUS_SUCCESS;
PCHAR Writing = Irp->AssociatedIrp.SystemBuffer;
PLAN_ADAPTER_INFO_S Info;
KIRQL OldIrql;
LA_DbgPrint(MID_TRACE,("Called\n"));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(*AdapterIndexPtr))
Adapter = NULL;
else
Adapter = FindAdapterByIndex(DeviceExt, *AdapterIndexPtr);
if (Adapter)
{
/* Local Addresses */
for (ListEntry = Adapter->AddressList.Flink;
ListEntry != &Adapter->AddressList;
ListEntry = ListEntry->Flink)
{
Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, ListEntry);
BytesNeeded += LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
Address->ClientPart.HWAddressLen);
}
/* Foreign Addresses */
for (ListEntry = Adapter->ForeignList.Flink;
ListEntry != &Adapter->ForeignList;
ListEntry = ListEntry->Flink)
{
Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C, ListEntry);
BytesNeeded += LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
Address->ClientPart.HWAddressLen);
}
BytesNeeded += Adapter->RegistryPath.Length;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
BytesNeeded)
{
/* Write common info */
Info = (PLAN_ADAPTER_INFO_S)Writing;
Info->Index = Adapter->Index;
Info->Media = Adapter->Media;
Info->Speed = Adapter->Speed;
/* Ethernet specific XXX */
Info->AddressLen = IEEE_802_ADDR_LENGTH;
Info->Overhead = Adapter->HeaderSize;
Info->MTU = Adapter->MTU;
Info->RegKeySize = Adapter->RegistryPath.Length;
/* Copy the name */
Writing += sizeof(*Info);
RtlCopyMemory(Adapter->RegistryPath.Buffer,
Writing,
Adapter->RegistryPath.Length);
/* Write the address info */
Writing += Adapter->RegistryPath.Length;
for (ListEntry = Adapter->AddressList.Flink;
ListEntry != &Adapter->AddressList;
ListEntry = ListEntry->Flink)
{
Address = CONTAINING_RECORD(ListEntry, LAN_ADDRESS_C,
ListEntry);
AddrSize = LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
Address->ClientPart.HWAddressLen);
RtlCopyMemory(Writing, &Address->ClientPart, AddrSize);
Writing += AddrSize;
}
for (ListEntry = Adapter->ForeignList.Flink;
ListEntry != &Adapter->ForeignList;
ListEntry = ListEntry->Flink)
{
Address = CONTAINING_RECORD(ListEntry,
LAN_ADDRESS_C,
ListEntry);
AddrSize = LAN_ADDR_SIZE(Address->ClientPart.AddressLen,
Address->ClientPart.HWAddressLen);
RtlCopyMemory(Writing, &Address->ClientPart, AddrSize);
Writing += AddrSize;
}
ASSERT(BytesNeeded == Writing - Irp->AssociatedIrp.SystemBuffer);
}
else Status = STATUS_BUFFER_TOO_SMALL;
}
else Status = STATUS_NO_SUCH_DEVICE;
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
LA_DbgPrint(MID_TRACE,("Ending (%d bytes)\n", BytesNeeded));
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesNeeded;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
LanSetBufferedMode(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp)
{
PLAN_DEVICE_EXT DeviceExt = (PLAN_DEVICE_EXT)DeviceObject->DeviceExtension;
PFILE_OBJECT FileObject = IrpSp->FileObject;
PLAN_PROTOCOL Proto = FileObject->FsContext;
NTSTATUS Status = STATUS_SUCCESS;
KIRQL OldIrql;
LA_DbgPrint(MID_TRACE,("Called %x\n", Proto));
KeAcquireSpinLock(&DeviceExt->Lock, &OldIrql);
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >=
sizeof(Proto->Buffered))
RtlCopyMemory(&Proto->Buffered,
Irp->AssociatedIrp.SystemBuffer,
sizeof(Proto->Buffered));
else
Status = STATUS_INVALID_PARAMETER;
KeReleaseSpinLock(&DeviceExt->Lock, OldIrql);
LA_DbgPrint(MID_TRACE,("Set buffered for %x to %d\n", Proto->Buffered));
Status = Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
LanDispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status = STATUS_SUCCESS;
LA_DbgPrint(MID_TRACE,("LanDispatch: %d\n", IrpSp->MajorFunction));
if (IrpSp->MajorFunction != IRP_MJ_CREATE)
{
LA_DbgPrint(MID_TRACE,("FO %x, IrpSp->FO %x\n",
FileObject, IrpSp->FileObject));
ASSERT(FileObject == IrpSp->FileObject);
}
switch (IrpSp->MajorFunction)
{
/* opening and closing handles to the device */
case IRP_MJ_CREATE:
/* Mostly borrowed from the named pipe file system */
return LanCreateProtocol(DeviceObject, Irp, IrpSp);
case IRP_MJ_CLOSE:
/* Ditto the borrowing */
return LanCloseProtocol(DeviceObject, Irp, IrpSp);
/* write data */
case IRP_MJ_WRITE:
return LanWriteData(DeviceObject, Irp, IrpSp);
/* read data */
case IRP_MJ_READ:
return LanReadData(DeviceObject, Irp, IrpSp);
case IRP_MJ_DEVICE_CONTROL:
{
LA_DbgPrint(MID_TRACE,("DeviceIoControl: %x\n",
IrpSp->Parameters.DeviceIoControl.
IoControlCode));
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_IF_ENUM_ADAPTERS:
return LanEnumAdapters(DeviceObject, Irp, IrpSp);
case IOCTL_IF_BUFFERED_MODE:
return LanSetBufferedMode(DeviceObject, Irp, IrpSp);
case IOCTL_IF_ADAPTER_INFO:
return LanAdapterInfo(DeviceObject, Irp, IrpSp);
default:
Status = STATUS_NOT_IMPLEMENTED;
Irp->IoStatus.Information = 0;
LA_DbgPrint(MIN_TRACE, ("Unknown IOCTL (0x%x)\n",
IrpSp->Parameters.DeviceIoControl.
IoControlCode));
break;
}
break;
}
/* unsupported operations */
default:
Status = STATUS_NOT_IMPLEMENTED;
LA_DbgPrint(MIN_TRACE,
("Irp: Unknown Major code was %x\n",
IrpSp->MajorFunction));
break;
}
LA_DbgPrint(MID_TRACE, ("Returning %x\n", Status));
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return (Status);
}
/* Do i need a global here? I think i need to do this a different way XXX */
VOID
NTAPI
LanUnload(
PDRIVER_OBJECT DriverObject)
{
LANUnregisterProtocol();
CloseNdisPools();
}
NTSTATUS
NTAPI
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegsitryPath)
{
PDEVICE_OBJECT DeviceObject;
PLAN_DEVICE_EXT DeviceExt;
UNICODE_STRING wstrDeviceName = RTL_CONSTANT_STRING(L"\\Device\\Lan");
UNICODE_STRING LanString = RTL_CONSTANT_STRING(L"LAN");
NTSTATUS Status;
InitNdisPools();
/* register driver routines */
DriverObject->MajorFunction[IRP_MJ_CLOSE] = LanDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE] = LanDispatch;
DriverObject->MajorFunction[IRP_MJ_WRITE] = LanDispatch;
DriverObject->MajorFunction[IRP_MJ_READ] = LanDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = LanDispatch;
DriverObject->DriverUnload = LanUnload;
/* create lan device */
Status = IoCreateDevice(DriverObject,
sizeof(LAN_DEVICE_EXT),
&wstrDeviceName,
FILE_DEVICE_NAMED_PIPE,
0,
FALSE,
&DeviceObject);
/* failure */
if (!NT_SUCCESS(Status))
{
return (Status);
}
LanDeviceObject = DeviceObject;
DeviceExt = DeviceObject->DeviceExtension;
RtlZeroMemory(DeviceExt, sizeof(*DeviceExt));
InitializeListHead(&DeviceExt->AdapterListHead);
InitializeListHead(&DeviceExt->ProtocolListHead);
KeInitializeSpinLock(&DeviceExt->Lock);
LANRegisterProtocol(&LanString);
DeviceObject->Flags |= DO_BUFFERED_IO;
LA_DbgPrint(MID_TRACE,("Device created: object %x ext %x\n",
DeviceObject, DeviceExt));
return (Status);
}
/* EOF */