223 lines
5.6 KiB
C
223 lines
5.6 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ntos\tdi\isn\fwd\ddreqs.c
|
|
|
|
Abstract:
|
|
Management of demand dial request queues
|
|
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
LIST_ENTRY ConnectionIrpQueue;
|
|
LIST_ENTRY ConnectionRequestQueue;
|
|
|
|
/*++
|
|
Q u e u e C o n n e c t i o n R e q u e s t
|
|
|
|
Routine Description:
|
|
Adds request to connected the interface to the queue
|
|
|
|
Arguments:
|
|
ifCB - control block of the interface that needs to be
|
|
connected
|
|
packet - packet that prompted the connection request
|
|
data - pointer to actual data in the packet
|
|
oldIRQL - IRQL at which interface lock was acquired
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Note that interface lock must be acquired before calling this
|
|
routine which will release it
|
|
|
|
--*/
|
|
VOID
|
|
QueueConnectionRequest (
|
|
PINTERFACE_CB ifCB,
|
|
PNDIS_PACKET packet,
|
|
PUCHAR data,
|
|
KIRQL oldIRQL
|
|
) {
|
|
KIRQL cancelIRQL;
|
|
|
|
IoAcquireCancelSpinLock (&cancelIRQL);
|
|
SET_IF_CONNECTING (ifCB);
|
|
if (!IsListEmpty (&ConnectionIrpQueue)) {
|
|
ULONG ulBytes = 0;
|
|
PIRP irp = CONTAINING_RECORD (
|
|
ConnectionIrpQueue.Flink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry);
|
|
PIO_STACK_LOCATION irpStack=IoGetCurrentIrpStackLocation(irp);
|
|
RemoveEntryList (&irp->Tail.Overlay.ListEntry);
|
|
ASSERT (irpStack->Parameters.DeviceIoControl.IoControlCode
|
|
==IOCTL_FWD_GET_DIAL_REQUEST);
|
|
ASSERT ((irpStack->Parameters.DeviceIoControl.IoControlCode&3)
|
|
==METHOD_BUFFERED);
|
|
IoSetCancelRoutine (irp, NULL);
|
|
IoReleaseCancelSpinLock (cancelIRQL);
|
|
|
|
FillConnectionRequest (
|
|
ifCB->ICB_Index,
|
|
packet,
|
|
data,
|
|
(PFWD_DIAL_REQUEST)irp->AssociatedIrp.SystemBuffer,
|
|
irpStack->Parameters.DeviceIoControl.OutputBufferLength,
|
|
&ulBytes);
|
|
irp->IoStatus.Information = ulBytes;
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
|
|
IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
|
|
("IpxFwd: Passing dial request for if %ld (icb:%08lx) with %d bytes of data.\n",
|
|
ifCB->ICB_Index, ifCB, irp->IoStatus.Information));
|
|
IoCompleteRequest (irp, IO_NO_INCREMENT);
|
|
}
|
|
else {
|
|
InsertTailList (&ConnectionRequestQueue, &ifCB->ICB_ConnectionLink);
|
|
IoReleaseCancelSpinLock (cancelIRQL);
|
|
ifCB->ICB_ConnectionPacket = packet;
|
|
ifCB->ICB_ConnectionData = data;
|
|
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
D e q u e u e C o n n e c t i o n R e q u e s t
|
|
|
|
Routine Description:
|
|
Removes conection requset for the interface from the queue
|
|
|
|
Arguments:
|
|
ifCB - control block of the interface that needs to be
|
|
removed
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
VOID
|
|
DequeueConnectionRequest (
|
|
PINTERFACE_CB ifCB
|
|
) {
|
|
KIRQL cancelIRQL;
|
|
IoAcquireCancelSpinLock (&cancelIRQL);
|
|
if (IsListEntry (&ifCB->ICB_ConnectionLink)) {
|
|
RemoveEntryList (&ifCB->ICB_ConnectionLink);
|
|
InitializeListEntry (&ifCB->ICB_ConnectionLink);
|
|
}
|
|
IoReleaseCancelSpinLock (cancelIRQL);
|
|
}
|
|
|
|
/*++
|
|
F i l l C o n n e c t i o n R e q u e s t
|
|
|
|
Routine Description:
|
|
Fills the provided buffer with index of interface that needs
|
|
to be connected and packet that prompted the request
|
|
|
|
Arguments:
|
|
index - if index
|
|
packet - packet that prompted the request
|
|
data - pointer to IPX data (IPX header) inside of the packet
|
|
request - request buffer to fill
|
|
reqSize - size of request buffer
|
|
bytesCopied - bytesCopied into the request buffer
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS - array was filled successfully
|
|
This routine assumes that there it is called only when there
|
|
are outstanding requests in the request queue
|
|
|
|
--*/
|
|
VOID
|
|
FillConnectionRequest (
|
|
IN ULONG index,
|
|
IN PNDIS_PACKET packet,
|
|
IN PUCHAR data,
|
|
IN OUT PFWD_DIAL_REQUEST request,
|
|
IN ULONG reqSize,
|
|
OUT PULONG bytesCopied
|
|
) {
|
|
PNDIS_BUFFER buf;
|
|
|
|
*bytesCopied = 0;
|
|
request->IfIndex = index;
|
|
NdisQueryPacket (packet, NULL, NULL, &buf, NULL);
|
|
do {
|
|
PVOID va;
|
|
UINT length;
|
|
|
|
NdisQueryBuffer (buf, &va, &length);
|
|
if (((PUCHAR)va<=data)
|
|
&& ((PUCHAR)va+length>data)) {
|
|
TdiCopyMdlToBuffer (buf,
|
|
(ULONG)(data-(PUCHAR)va),
|
|
request,
|
|
FIELD_OFFSET (FWD_DIAL_REQUEST, Packet),
|
|
reqSize,
|
|
bytesCopied);
|
|
*bytesCopied += FIELD_OFFSET (FWD_DIAL_REQUEST, Packet);
|
|
break;
|
|
}
|
|
NdisGetNextBuffer (buf, &buf);
|
|
}
|
|
while (buf!=NULL);
|
|
}
|
|
|
|
/*++
|
|
F a i l C o n n e c t i o n R e q u e s t s
|
|
|
|
Routine Description:
|
|
Cleans up on connection request failure
|
|
|
|
Arguments:
|
|
InterfaceIndex - index of interface that could not be connected
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS - clean up was successfull
|
|
STATUS_UNSUCCESSFUL - interface with this index does not exist
|
|
|
|
--*/
|
|
NTSTATUS
|
|
FailConnectionRequest (
|
|
IN ULONG InterfaceIndex
|
|
) {
|
|
PINTERFACE_CB ifCB;
|
|
KIRQL oldIRQL;
|
|
|
|
ASSERT (InterfaceIndex!=FWD_INTERNAL_INTERFACE_INDEX);
|
|
|
|
ifCB = GetInterfaceReference (InterfaceIndex);
|
|
if (ifCB!=NULL) {
|
|
IpxFwdDbgPrint (DBG_DIALREQS, DBG_WARNING,
|
|
("IpxFwd: Dial request failed for if %ld (icb:%08lx).\n",
|
|
ifCB->ICB_Index, ifCB));
|
|
ProcessInternalQueue (ifCB);
|
|
ProcessExternalQueue (ifCB);
|
|
KeAcquireSpinLock (&ifCB->ICB_Lock, &oldIRQL);
|
|
if (IS_IF_CONNECTING (ifCB)) {
|
|
SET_IF_NOT_CONNECTING (ifCB);
|
|
DequeueConnectionRequest (ifCB);
|
|
}
|
|
KeReleaseSpinLock (&ifCB->ICB_Lock, oldIRQL);
|
|
ReleaseInterfaceReference (ifCB);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|