windows-nt/Source/XPSP1/NT/net/nwlink/fwd/ddreqs.c
2020-09-26 16:20:57 +08:00

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;
}