/*++ 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; }