Unfortunately, because of the "open" architecture of Windows NT it is absolutely impossible to implement intermediate drivers using the information provided in DDK. Many aspects of the problem are completely uncovered there; and thanks God there are several examples of intermediate drivers which you can use as a starting point for an intermediate driver.
Unfortunately again, those examples work only for network cards such as Ethernet, Fddi and Token-Ring; trying to use them for NdisWan (this is microsoft's acronym for RAS pseudo-"network cards") fails. The main reason for this is that RAS uses a proprietary interface (aside of the "standard" NDIS interface). The following instructions are how to make an intermediate driver that will accomplish this proprietary interface; however the following was tested only with NetBIOS transport, but TCP/IP transport should work this way too.
Here are the instructions how to adapt a intermediate driver that works with network cards to make it work with RAS:
{"IntermediateTransport ndisWanAdapterDialIn non non 100", +
"IntermediateTransport ndisWanAdapterDialOut non non 100", +
"IntermediateTransport ndisWanAdapterDialInIP non non 100", +
"IntermediateTransport ndisWanAdapterDialOutIP non non 100"}
NTSTATUS NdisWanIoctl (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
// If this is a request for \Device\NdisWan, process it
if (DeviceObject != NdisWanHookDevice)
return -1;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
// copy the IRP into the stack location for next driver
*nextIrpStack = *IrpStack;
if (IrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
// Get the pointer to the input/output buffer and it's length
PVOID inputBuffer = Irp->AssociatedIrp.SystemBuffer;
PVOID outputBuffer = Irp->UserBuffer;
ULONG inputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG outputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG IoCode = (IrpStack->Parameters.DeviceIoControl.IoControlCode & 0x3ffc) >> 2;
ULONG IoId = IrpStack->Parameters.DeviceIoControl.IoControlCode >> 16;
if (IoId == 0x30)
switch (IoCode)
{
case 3: // ActivateRoute
{
struct ActivateRoute
{
ULONG Unknown1; // 0x00000001
USHORT Protocol; // 0x80d5
USHORT DeviceNameLength; // 0x0010
K_CHAR DeviceName [100]; // "\DEVICE\NDISWAN4"
} *Parm = (ActivateRoute *)inputBuffer;
// If device name is specified, replace it by underlying MP
if (Parm->DeviceNameLength != 0xffff)
{
K_STRING Name = { Parm->DeviceNameLength * 2, Parm->DeviceNameLength * 2, Parm->DeviceName };
// Look through NdisWan intermediate drivers
NdisAcquireSpinLock (&NdisWanAdapterChainLock);
AdapterControlBlock *cur = NdisWanAdapterChain;
while (cur)
{
if (!RtlCompareUnicodeString (&Name, &cur->IMDeviceName, TRUE))
{
// Copy the underlaying MP device name into buffer
RtlMoveMemory (&Parm->DeviceName, cur->MPDeviceName.Buffer,
cur->MPDeviceName.Length);
Name.Length = Name.MaximumLength = cur->MPDeviceName.Length;
Parm->DeviceNameLength = cur->MPDeviceName.Length / 2;
RtlUpcaseUnicodeString (&Name, &Name, FALSE);
break;
}
cur = cur->NextNdisWan;
}
NdisReleaseSpinLock (&NdisWanAdapterChainLock);
}
break;
}
}
}
return IoCallDriver (NdisWanDevice, Irp);
}
That's it.