mirror of
https://github.com/reactos/reactos.git
synced 2024-08-06 03:14:36 +00:00
1496 lines
45 KiB
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 */
|