--- /dev/null
+/*
+ * 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;
+
+NDIS_STATUS NDISCall(
+ PLAN_ADAPTER Adapter,
+ NDIS_REQUEST_TYPE Type,
+ NDIS_OID OID,
+ PVOID Buffer,
+ UINT Length)
+/*
+ * FUNCTION: Send a request to NDIS
+ * ARGUMENTS:
+ * Adapter = Pointer to a LAN_ADAPTER structure
+ * Type = Type of request (Set or Query)
+ * OID = Value to be set/queried for
+ * Buffer = Pointer to a buffer to use
+ * Length = Number of bytes in Buffer
+ * RETURNS:
+ * Status of operation
+ */
+{
+ 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;
+}
+
+
+VOID FreeAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure to free
+ */
+{
+ exFreePool(Adapter);
+}
+
+
+VOID STDCALL ProtocolOpenAdapterComplete(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS Status,
+ NDIS_STATUS OpenErrorStatus)
+/*
+ * FUNCTION: Called by NDIS to complete opening of an adapter
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * Status = Status of the operation
+ * OpenErrorStatus = Additional status information
+ */
+{
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID STDCALL ProtocolCloseAdapterComplete(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete closing an adapter
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * Status = Status of the operation
+ */
+{
+ PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+ Adapter->NdisStatus = Status;
+
+ KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID STDCALL ProtocolResetComplete(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete resetting an adapter
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * Status = Status of the operation
+ */
+{
+ LA_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolRequestComplete(
+ NDIS_HANDLE BindingContext,
+ PNDIS_REQUEST NdisRequest,
+ NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete a request
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * NdisRequest = Pointer to an object describing the request
+ * Status = Status of the operation
+ */
+{
+ 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);
+}
+
+
+VOID STDCALL ProtocolSendComplete(
+ NDIS_HANDLE BindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete sending process
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * Packet = Pointer to a packet descriptor
+ * Status = Status of the operation
+ */
+{
+ /*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"));
+}
+
+
+VOID STDCALL ProtocolTransferDataComplete(
+ NDIS_HANDLE BindingContext,
+ PNDIS_PACKET Packet,
+ NDIS_STATUS Status,
+ UINT BytesTransferred)
+/*
+ * FUNCTION: Called by NDIS to complete reception of data
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * Packet = Pointer to a packet descriptor
+ * Status = Status of the operation
+ * BytesTransferred = Number of bytes transferred
+ * NOTES:
+ * If the packet was successfully received, determine the protocol
+ * type and pass it to the correct receive handler
+ */
+{
+ 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));
+ _SEH_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));
+
+ IoCompleteRequest( ReadIrp, IO_NETWORK_INCREMENT );
+ } _SEH_HANDLE {
+ 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 );
+ } _SEH_END;
+ break;
+ }
+ }
+ }
+ }
+
+ KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+ FreeNdisPacket( Packet );
+}
+
+
+NDIS_STATUS STDCALL ProtocolReceive(
+ NDIS_HANDLE BindingContext,
+ NDIS_HANDLE MacReceiveContext,
+ PVOID HeaderBuffer,
+ UINT HeaderBufferSize,
+ PVOID LookaheadBuffer,
+ UINT LookaheadBufferSize,
+ UINT PacketSize)
+/*
+ * FUNCTION: Called by NDIS when a packet has been received on the physical link
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * MacReceiveContext = Handle used by underlying NIC driver
+ * HeaderBuffer = Pointer to a buffer containing the packet header
+ * HeaderBufferSize = Number of bytes in HeaderBuffer
+ * LookaheadBuffer = Pointer to a buffer containing buffered packet data
+ * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
+ * PacketSize = Overall size of the packet (not including header)
+ * RETURNS:
+ * Status of operation
+ */
+{
+ 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 ) 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;
+}
+
+
+VOID STDCALL ProtocolReceiveComplete(
+ NDIS_HANDLE BindingContext)
+/*
+ * FUNCTION: Called by NDIS when we're done receiving data
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolStatus(
+ NDIS_HANDLE BindingContext,
+ NDIS_STATUS GenerelStatus,
+ PVOID StatusBuffer,
+ UINT StatusBufferSize)
+/*
+ * FUNCTION: Called by NDIS when the underlying driver has changed state
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ * GenerelStatus = A generel status code
+ * StatusBuffer = Pointer to a buffer with medium-specific data
+ * StatusBufferSize = Number of bytes in StatusBuffer
+ */
+{
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+
+VOID STDCALL ProtocolStatusComplete(
+ NDIS_HANDLE NdisBindingContext)
+/*
+ * FUNCTION: Called by NDIS when a status-change has occurred
+ * ARGUMENTS:
+ * BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+}
+
+VOID STDCALL ProtocolBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2)
+/*
+ * FUNCTION: Called by NDIS during NdisRegisterProtocol to set up initial
+ * bindings, and periodically thereafer as new adapters come online
+ * ARGUMENTS:
+ * Status: Return value to NDIS
+ * BindContext: Handle provided by NDIS to track pending binding operations
+ * DeviceName: Name of the miniport device to bind to
+ * SystemSpecific1: Pointer to a registry path with protocol-specific configuration information
+ * SystemSpecific2: Unused & must not be touched
+ */
+{
+ /* 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);
+}
+
+
+VOID LANTransmit(
+ PLAN_ADAPTER Adapter,
+ PNDIS_PACKET NdisPacket,
+ PVOID LinkAddress,
+ USHORT Type)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ * Context = Pointer to context information (LAN_ADAPTER)
+ * NdisPacket = Pointer to NDIS packet to send
+ * LinkAddress = Pointer to link address of destination (NULL = broadcast)
+ * Type = LAN protocol type (LAN_PROTO_*)
+ */
+{
+ 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;
+}
+
+VOID BindAdapter(PLAN_ADAPTER Adapter, PNDIS_STRING RegistryPath)
+/*
+ * FUNCTION: Binds a LAN adapter to IP layer
+ * ARGUMENTS:
+ * Adapter = Pointer to LAN_ADAPTER structure
+ * NOTES:
+ * We set the lookahead buffer size, set the packet filter and
+ * bind the adapter to IP layer
+ */
+{
+ /*NDIS_STATUS NdisStatus;*/
+ /*ULONG Lookahead = LOOKAHEAD_SIZE;*/
+ /*NTSTATUS Status;*/
+ /*HANDLE RegHandle = 0;*/
+
+ LA_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+
+}
+
+NDIS_STATUS LANRegisterAdapter( PNDIS_STRING AdapterName,
+ PNDIS_STRING RegistryPath)
+/*
+ * FUNCTION: Registers protocol with an NDIS adapter
+ * ARGUMENTS:
+ * AdapterName = Pointer to string with name of adapter to register
+ * Adapter = Address of pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ * Status of operation
+ */
+{
+ 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;
+}
+
+
+NDIS_STATUS LANUnregisterAdapter(
+ PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unregisters protocol with NDIS adapter
+ * ARGUMENTS:
+ * Adapter = Pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ * Status of operation
+ */
+{
+ 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;
+}
+
+NTSTATUS LANRegisterProtocol(PNDIS_STRING Name)
+/*
+ * FUNCTION: Registers this protocol driver with NDIS
+ * ARGUMENTS:
+ * Name = Name of this protocol driver
+ * RETURNS:
+ * Status of operation
+ */
+{
+ 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;
+}
+
+
+VOID LANUnregisterProtocol(VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+ 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 STDCALL
+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 STDCALL
+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 STDCALL
+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 STDCALL
+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 STDCALL
+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 STDCALL
+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 STDCALL
+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 STDCALL
+LanDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+
+ 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 STDCALL LanUnload(PDRIVER_OBJECT DriverObject) {
+ LANUnregisterProtocol();
+ CloseNdisPools();
+}
+
+NTSTATUS STDCALL DriverEntry( PDRIVER_OBJECT DriverObject,
+ PUNICODE_STRING RegsitryPath ) {
+ PDEVICE_OBJECT DeviceObject;
+ PLAN_DEVICE_EXT DeviceExt;
+ UNICODE_STRING wstrDeviceName, LanString;
+ 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 */
+ RtlRosInitUnicodeStringFromLiteral(&wstrDeviceName, L"\\Device\\Lan");
+ RtlRosInitUnicodeStringFromLiteral(&LanString, L"LAN");
+
+ 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 */