#include "precomp.h"
#pragma hdrstop
#pragma NDIS_INIT_FUNCTION(DriverEntry)
NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
NDIS_MEDIUM MediumArray[3] =
{
NdisMedium802_3, // Ethernet
NdisMedium802_5, // Token-ring
NdisMediumFddi // Fddi
};
//
// g_GlobalLock - Protects resources
//
NDIS_SPIN_LOCK g_GlobalLock;
//
// g_ProtocolHandle - handle returned by NDIS when registering the protocol portion of the IM
//
NDIS_HANDLE g_ProtocolHandle = NULL;
//
// g_MiniportHandle - handle returned by NDIS when MP portion registers as LM
//
NDIS_HANDLE g_MiniportHandle = NULL;
//
// g_AdapterList - List of adapters to which the NetWall is bound
//
PADAPT g_AdapterList = NULL;
//
// g_DriverObject - pointer to NT driver and device objects
//
PDRIVER_OBJECT g_DriverObject = NULL;
/**
* Routine Description:
*
* This is the primary initialization routine for the NetWall IM driver.
* It is simply responsible for the intializing the wrapper and registering
* the Miniport and Protocol driver.
*
* Arguments:
*
* IN DriverObject - Pointer to driver object created by the system.
* IN RegistryPath - Registry path string for driver service key
*
* Return Value:
*
* The status of the operation.
*/
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NDIS_STATUS Status;
NDIS_PROTOCOL_CHARACTERISTICS PChars;
NDIS_MINIPORT_CHARACTERISTICS MChars;
NDIS_STRING protoName;
UNICODE_STRING ntDeviceName;
UNICODE_STRING win32DeviceName;
NDIS_HANDLE WrapperHandle;
UINT FuncIndex = 0;
DBGPRINT("===> NetWall - DriverEntry/n");
DbgPrint("=== RegistryPath is : %ws ===/n", RegistryPath->Buffer);
g_DriverObject = DriverObject;
//
// Initialize Global Lock
//
NdisAllocateSpinLock(&g_GlobalLock);
do
{
//
// 1. Register the miniport with NDIS. Note that it is the miniport
// which was started as a driver and not the protocol. Also the miniport
// must be registered prior to the protocol since the protocol's BindAdapter
// handler can be initiated anytime and when it is, it must be ready to
// start driver instances.
//
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, NULL);
//
// 2. Perform IM Driver's Miniport Initialization
//
NdisZeroMemory(&MChars, sizeof(NDIS_MINIPORT_CHARACTERISTICS));
MChars.MajorNdisVersion = 4;
MChars.MinorNdisVersion = 0;
MChars.InitializeHandler = MPInitialize;
MChars.QueryInformationHandler = MPQueryInformation;
MChars.SetInformationHandler = MPSetInformation;
MChars.ResetHandler = MPReset;
MChars.TransferDataHandler = MPTransferData;
MChars.HaltHandler = MPHalt;
//
// We will disable the check for hang timeout so we do not
// need a check for hang handler!
//
MChars.CheckForHangHandler = NULL;
MChars.SendHandler = MPSend;
MChars.ReturnPacketHandler = MPReturnPacket;
//
// Either the Send or the SendPackets handler should be specified.
// If SendPackets handler is specified, SendHandler is ignored
//
MChars.SendPacketsHandler = NULL;//MPSendPackets;
Status = NdisIMRegisterLayeredMiniport(WrapperHandle,
&MChars,
sizeof(MChars),
&g_MiniportHandle);
if (! NT_SUCCESS(Status))
{
DbgPrint("MPRegisterAsMiniport Failed! Status: 0x%x/n", Status);
NdisWriteErrorLogEntry(
DriverObject,
(ULONG)IM_ERROR_IM_REGISTER_FAILED,
0,
1,
(ULONG )Status);
break;
}
//
// 3. Perform initialization supported by WDM
//
// Create a control device object for this driver.
// Application can send an IOCTL to this device to get
// bound adapter information.
//
//
DBGPRINT("===> NetWall - NdisWDMInitialize/n");
NdisAcquireSpinLock(&g_GlobalLock); // sync
++g_MiniportCount;
if (1 == g_MiniportCount)
{
ASSERT(g_DeviceState != PS_DEVICE_STATE_CREATING); //
while (g_DeviceState != PS_DEVICE_STATE_READY)
{
NdisReleaseSpinLock(&g_GlobalLock);
NdisMSleep(1); // Waiting
NdisAcquireSpinLock(&g_GlobalLock);
}
g_DeviceState = PS_DEVICE_STATE_CREATING;
// Now Can Create Device, Call NdisMRegisterDevice
NdisReleaseSpinLock(&g_GlobalLock);
//
// Initialize The Driver's Default Device Function Handlers
// --------------------------------------------------------
// Actually, we are re-initializing the MajorFunction table that
// has already been initialized by the NDIS wrapper.
//
DriverObject->FastIoDispatch = NULL;
for (FuncIndex = 0; FuncIndex <= IRP_MJ_MAXIMUM_FUNCTION; FuncIndex++)
{
//
// Save The Original MajorFunction Table
// -------------------------------------
// At this point the NDIS wrapper has ALREADY initialized the
// g_DriverObject MajorFunction table and created a DeviceObject for
// the miniport. Save the NDIS MajorFunction table entries.
//
NdisFunctionTable[FuncIndex] = DriverObject->MajorFunction[FuncIndex];
//
// Setup Our MajorFunction Table
//
g_DriverObject->MajorFunction[FuncIndex] = NetWall_DefaultFunctionDispatch;
}
//
// Specify Functions To Dispatch Directly
//
g_DriverObject->MajorFunction[IRP_MJ_CREATE] = NetWall_DeviceCreate;
g_DriverObject->MajorFunction[IRP_MJ_CLOSE] = NetWall_DeviceClose;
g_DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NetWall_DeviceCleanup;
g_DriverObject->MajorFunction[IRP_MJ_WRITE] = NetWall_DeviceWrite;
g_DriverObject->MajorFunction[IRP_MJ_READ] = NetWall_DeviceRead;
g_DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NetWall_DeviceIoControl;
g_DriverObject->DriverUnload = NetWall_DeviceUnload;
RtlInitUnicodeString(&ntDeviceName, NETWALL_WDM_DEVICE_NAME_W);
RtlInitUnicodeString(&win32DeviceName, NETWALL_WDM_SYMBOLIC_LINK_W);
//
// Create The "WDM Interface"
// --------------------------
// Creating the driver device object and sumbolic link and implementing
// an I/O function dispatcher provides the mechanism for a Win32
// application to communicate with the driver. This is sometines
// described as a "WDM interface".
//
Status = NdisMRegisterDevice(WrapperHandle,
&ntDeviceName, // /Device/DeviceName
&win32DeviceName, // /DosDevices/SymbolicName
g_DriverObject->MajorFunction,
&g_DeviceObject,
&g_DeviceHandle
);
if (NT_SUCCESS(Status))
{
g_DeviceObject->Flags |= DO_BUFFERED_IO;
}
if (!NT_SUCCESS(Status))
{
DbgPrint("NdisMRegisterDevice Failed - %08x/n", Status);
g_DeviceObject = NULL;
break;
}
NdisAcquireSpinLock(&g_GlobalLock); // Acquire spin Lock
g_DeviceState = PS_DEVICE_STATE_READY;
}
NdisReleaseSpinLock(&g_GlobalLock);
DBGPRINT("<=== NetWall - NdisWDMInitialize /n");
NdisMRegisterUnloadHandler(WrapperHandle, PtUnload);
//
// 4. Perform IM Driver's Protocol Initialization
//
NdisZeroMemory(&PChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
PChars.MajorNdisVersion = 4;
PChars.MinorNdisVersion = 0;
//
// Make sure the protocol-name matches the service-name under which this protocol is installed.
// This is needed to ensure that NDIS can correctly determine the binding and call us to bind
// to miniports below.
//
NdisInitUnicodeString(&protoName, L"NetWall");
PChars.Name = protoName;
PChars.OpenAdapterCompleteHandler = PtOpenAdapterComplete;
PChars.CloseAdapterCompleteHandler = PtCloseAdapterComplete;
PChars.SendCompleteHandler = PtSendComplete;
PChars.TransferDataCompleteHandler = PtTransferDataComplete;
PChars.ResetCompleteHandler = PtResetComplete;
PChars.RequestCompleteHandler = PtRequestComplete;
PChars.ReceiveHandler = PtReceive;
PChars.ReceiveCompleteHandler = PtReceiveComplete;
PChars.StatusHandler = PtStatus;
PChars.StatusCompleteHandler = PtStatusComplete;
PChars.BindAdapterHandler = PtBindAdapter;
PChars.UnbindAdapterHandler = PtUnbindAdapter;
PChars.UnloadHandler = NULL;
PChars.ReceivePacketHandler = PtReceivePacket;
PChars.PnPEventHandler = PtPNPHandler;
NdisRegisterProtocol(&Status,
&g_ProtocolHandle,
&PChars,
sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
if (! NT_SUCCESS(Status))
{
DbgPrint("PtRegisterAsProtocol Failed! Status: 0x%x/n", Status);
NdisWriteErrorLogEntry(
DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
IM_ERROR_PROTOCOL_INIT,
1,
L"NETWALL",
sizeof(Status),
&Status);
break;
}
//
// 5. Associate Miniport & Protocol, informs NDIS that the specified lower and upper interfaces for miniport and protocol respectively belong to the same intermediate driver.
//
NdisIMAssociateMiniport(g_MiniportHandle, g_ProtocolHandle);
DBGPRINT("<=== NetWall - DriverEntry Success. ===/n");
return Status;
} while (FALSE);
//
// Cleanup after a error that causes DriverEntry to fail.
//
if (g_DeviceObject)
{
NdisMDeregisterDevice(g_DeviceHandle);
}
//
// Deregister the protocol; we should have no references that would cause
// this to pend
//
if (g_ProtocolHandle)
{
NdisDeregisterProtocol(&Status, g_ProtocolHandle);
if (Status == NDIS_STATUS_PENDING)
{
DbgPrint("Client DeregProto failed - %08X/n", Status);
}
}
//
// Terminate the wrapper
//
if (WrapperHandle)
{
NdisTerminateWrapper(WrapperHandle, NULL);
}
//
// Free our global locks
//
NdisFreeSpinLock(&g_GlobalLock);
DBGPRINT("<=== NetWall - DriverEntry Failed. ===/n");
return (STATUS_UNSUCCESSFUL);
}
------------------
#include "precomp.h"
#pragma hdrstop
/**
* Routine Description:
*
* PtReceive determines whether a received network packet is of
* interest to the protocol's client(s) and, if so, copies the indicated
* data and, possibly, calls NdisTransferData to retrieve the rest of
* the indicated packet.
*
* If the data passed to ProtocolReceive was indicated by a call to NdisMXxxIndicateReceive,
* the size of the lookahead buffer passed to ProtocolReceive is <= the size returned by a
* call to NdisRequest with OID_GEN_CURRENT_LOOKAHEAD. All data in the lookahead buffer is
* read-only to the intermediate driver. If the call to ProtocolReceive occurred because
* the underlying NIC driver set the status of one or more packets in a packet array to
* NDIS_STATUS_RESOURCES before calling NdisMIndicateReceivePacket, the size of the lookahead
* buffer will always be equal to the size of the full network packet so the intermediate
* driver need not call NdisTransferData.
*
* If PacketSize is less than or equal to the given LookaheadBufferSize,
* the lookahead buffer contains the entire packet. If the underlying
* driver made the indication with NdisMIndicateReceivePacket, the
* lookahead buffer always contains a full network packet.
* Otherwise, Protocol must call NdisTransferData to copy any remaining data .
*
* LBFO - need to use primary for all receives
*
* Arguments:
*
* IN ProtocolBindingContext - Pointer to the adapter
* IN MacReceiveContext - Specifies a context handle that the underlying NIC driver associates with the packet received from the network.
* IN HeaderBuffer - Points to the base virtual address of a range containing the buffered packet header.
* IN HeaderBufferSize - Specifies the number of bytes in the packet header.
* IN LookAheadBuffer - Points to the base virtual address of a range that contains LookaheadBufferSize bytes of buffered network packet data.
* IN LookAheadBufferSize - Specifies the number of bytes of network packet data in the lookahead buffer.
* IN PacketSize - Specifies the size, in bytes, of the network packet data. The length of the packet does not include the length of the header.
*
* Return Value:
*
* NDIS_STATUS
*
* Remarks :
*
* The ProtocolReceive function of an NDIS intermediate driver cannot simply
* forward receive indications to still higher-level protocols. Such an
* attempt can cause a deadlock.
*
* The NDIS intermediate driver must repackage the indication in a fresh
* packet descriptor.
*
* By default, ProtocolReceive runs at IRQL DISPATCH_LEVEL in an arbitrary
* thread context.
*/
NDIS_STATUS
PtReceive(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)
{
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
PNDIS_PACKET MyPacket, Packet;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NETWALL_RCV_FILTER_ACTION FilterAction = RCV_FILTER_ACTION_PASS_PACKET;
DBGPRINT("===> NetWall - PtReceive/n");
//-----------------------------------------------
if (! pAdapt->MiniportHandle)
{
Status = NDIS_STATUS_FAILURE;
}
else do
{
FilterAction = NetWall_FilterReceive(
pAdapt,
MacReceiveContext,
(PCHAR)HeaderBuffer,
HeaderBufferSize,
(PCHAR)LookAheadBuffer,
LookAheadBufferSize,
PacketSize,
NETWALL_DIRECTION_IN
);
if (FilterAction == RCV_FILTER_ACTION_REJECT_PACKET)
{
DBGPRINT("<=== NetWall - PtReceive -> RCV_FILTER_ACTION_REJECT_PACKET/n");
return NDIS_STATUS_NOT_ACCEPTED;
}
//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//
if (pAdapt->isSecondary)
{
DBGPRINT("NETWALL GETTING RECIEVES ON SECONDARY/n");
ASSERT(0);
}
//
// If this was indicated by the miniport below as a packet, then get that packet pointer and indicate
// it as a packet as well(with appropriate status). This way the OOB stuff is accessible to the
// transport above us.
//
Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
if (Packet != NULL)
{
DBGPRINT("===> NetWall - PtReceive RePacket.../n");
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status, &MyPacket, pAdapt->RecvPacketPoolHandle);
if (Status == NDIS_STATUS_SUCCESS)
{
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
//
// Get the original packet(it could be the same packet as one received or a different one
// based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
// correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
//
// Make sure the status is set to NDIS_STATUS_RESOURCES.
//
NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
ASSERT(NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES);
NdisDprFreePacket(MyPacket);
DBGPRINT("<=== NetWall - PtReceive RePacket/n");
break;
}
}
//
// Fall through if the miniport below us has either not indicated a packet or
// we could not allocate one
//
pAdapt->IndicateRcvComplete = TRUE;
switch (pAdapt->Medium)
{
case NdisMedium802_3:
NdisMEthIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize
);
break;
case NdisMedium802_5:
NdisMTrIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize
);
break;
case NdisMediumFddi:
NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize
);
break;
default:
ASSERT(0);
break;
}
} while (FALSE);
DBGPRINT("<=== NetWall - PtReceive/n");
return Status;
}
/**
* Routine Description:
*
* Called by the adapter below us when it is done indicating a batch of received buffers.
*
* Arguments:
*
* ProtocolBindingContext - Pointer to our adapter structure.
*
* Return Value:
*
* None
*/
VOID
PtReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
{
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
DBGPRINT("===> NetWall - PtReceiveComplete/n");
//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//
if (pAdapt->isSecondary)
{
DBGPRINT("NetWall GETTING RECEIVES ON SECONDARY/n");
ASSERT(0);
}
if ((pAdapt->MiniportHandle != NULL) && pAdapt->IndicateRcvComplete)
{
switch (pAdapt->Medium)
{
case NdisMedium802_3:
NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
case NdisMedium802_5:
NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
case NdisMediumFddi:
NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
break;
default:
ASSERT(0);
break;
}
}
pAdapt->IndicateRcvComplete = FALSE;
DBGPRINT("<=== NetWall - PtReceiveComplete/n");
}
/**
* Routine Description:
*
* ReceivePacket handler. Called up by the miniport below when it supports NDIS 4.0 style receives.
* Re-package the packet and hand it back to NDIS for protocols above us. The re-package part is
* important since NDIS uses the WrapperReserved part of the packet for its own book-keeping. Also
* the re-packaging works differently when packets flow-up or down. In the up-path(here) the protocol
* reserved is owned by the protocol above. We need to use the miniport reserved here.
*
* Arguments:
*
* ProtocolBindingContext - Pointer to our adapter structure.
* Packet - Pointer to the packet
*
* Return Value:
*
* == 0 -> We are done with the packet
* != 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
*/
INT
PtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)
{
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
PRSVD Resvd;
NETWALL_RCV_FILTER_ACTION FilterAction = RCV_FILTER_ACTION_PASS_PACKET;
DBGPRINT("===> NetWall - PtReceivePacket/n");
if (! pAdapt->MiniportHandle)
{
return 0;
}
//
// Filter packet
//
FilterAction = FilterReceivePacket(pAdapt, Packet, NETWALL_DIRECTION_IN);
if (FilterAction == RCV_FILTER_ACTION_REJECT_PACKET)
{
DBGPRINT("<=== NetWall - PtReceivePacket, but dropped by filter !/n");
return 0;
}
//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//
if (pAdapt->isSecondary)
{
DBGPRINT("NetWall GETTING RECEIVES ON SECONDARY/n");
ASSERT(0);
}
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&MyPacket,
pAdapt->RecvPacketPoolHandle
);
if (Status == NDIS_STATUS_SUCCESS)
{
Resvd = (PRSVD)(MyPacket->MiniportReserved);
Resvd->OriginalPkt = Packet;
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;
//
// Get the original packet(it could be the same packet as one received or a different one
// based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
// correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
Status = NDIS_GET_PACKET_STATUS(Packet);
NDIS_SET_PACKET_STATUS(MyPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
if (Status == NDIS_STATUS_RESOURCES)
{
NdisDprFreePacket(MyPacket);
}
DBGPRINT("<=== NetWall - PtReceivePacket/n");
//
// If it does return a nonzero value, the intermediate driver must subsequently
// call NdisReturnPackets with a pointer to this packet descriptor.
//
return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
//
// We are out of packets. Silently drop it. Alternatively we can deal with it:
// - By keeping separate send and receive pools
// - Dynamically allocate more pools as needed and free them when not needed
//
return(0);
}
DBGPRINT("<=== NetWall - PtReceivePacket/n");
}
/**
*
* Routine Description:
*
* Indicate receives with NdisMIndicateReceivePacket.
* It is called when PtReceivePacket return value > 0.
*
* Arguments:
*
* MiniportAdapterContext - Pointer to our adapter structure.
* Packet - Pointer to the packet
*
* Return Value:
*
* Node.
*
* Remarks :
*
* Packet points to an NDIS_PACKET structure that belongs to the virtual
* adapter, and must be re-cycled by calling NdisFreePacket function.
*
* If Packet was being used to "passthru" a packet that NETWALLIM received
* from a lower-level miniport driver, then the pOriginalPacket field
* of the private packet context structure points to the original packet.
* This packet must be returned to the lower-level miniport by calling
* NdisReturnPackets.
*
* Finally, Packet and any associated NDIS_BUFFERs that belong to this
* virtual adapter must be re-cycled for reuse by calling NdisFreePacket.
*
*/
VOID
MPReturnPacket(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet
)
{
PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
PNDIS_PACKET MyPacket;
PRSVD Resvd;
DBGPRINT("===> NetWall - MPReturnPacket/n");
Resvd = (PRSVD)(Packet->MiniportReserved);
MyPacket = Resvd->OriginalPkt;
NdisFreePacket(Packet);
NdisReturnPackets(&MyPacket, 1);
DBGPRINT("<=== NetWall - MPReturnPacket/n");
}