summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/ipx/rt.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/ipx/rt.c')
-rw-r--r--private/ntos/tdi/isn/ipx/rt.c1311
1 files changed, 1311 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/ipx/rt.c b/private/ntos/tdi/isn/ipx/rt.c
new file mode 100644
index 000000000..8881f03fa
--- /dev/null
+++ b/private/ntos/tdi/isn/ipx/rt.c
@@ -0,0 +1,1311 @@
+/*++
+
+Copyright (c) 1989-1994 Microsoft Corporation
+
+Module Name;
+
+ Rt.c
+
+Abstract;
+
+
+Author;
+
+
+Revision History;
+
+TODO: Get rid of ref/Deref since the RTINFO structure will not be destroyed
+ Use a common alloc/free function (with the rest of ipx)
+ Allocate tagged memory
+ Optimize code more
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// function prototypes
+//
+
+VOID
+RtIrpCancel(
+ IN PDEVICE_OBJECT Device,
+ IN PIRP pIrp
+ );
+
+
+PVOID
+RtAllocMem(
+ IN ULONG Size
+ );
+
+VOID
+RtFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size
+ );
+
+NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN PDEVICE pDevice
+ );
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength);
+
+NTSTATUS
+CleanupRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp);
+
+NTSTATUS
+CloseRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp);
+
+NTSTATUS
+SendIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+
+NTSTATUS
+RcvIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ );
+NTSTATUS
+PassDgToRt (
+ IN PDEVICE pDevice,
+ IN PIPX_DATAGRAM_OPTIONS2 pContext,
+ IN ULONG Index,
+ IN VOID UNALIGNED *pDgrm,
+ IN ULONG uNumBytes
+ );
+
+VOID
+IpxDerefRt(
+ PRT_INFO pRt
+ );
+
+VOID
+IpxRefRt(
+ PRT_INFO pRt
+ );
+
+VOID
+IpxDestroyRt(
+ IN PRT_INFO pRt
+ );
+
+#define ALLOC_PRAGMA 1
+#define CTEMakePageable(x, y) alloc_text(x,y)
+
+#define AllocMem(_BytesToAlloc) IpxAllocateMemory(_BytesToAlloc, MEMORY_PACKET, "RT MEMORY")
+
+#define FreeMem(_Memory, _BytesAllocated) IpxFreeMemory(_Memory, _BytesAllocated, MEMORY_PACKET, "RT MEMORY")
+
+
+#define IpxVerifyRt(pRt) // \
+ // if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) { return STATUS_INVALID_ADDRESS; }
+
+
+//******************* Pageable Routine Declarations ****************
+#ifdef ALLOC_PRAGMA
+#pragma CTEMakePageable(PAGERT, CloseRtAddress)
+#pragma CTEMakePageable(PAGERT, CleanupRtAddress)
+#pragma CTEMakePageable(PAGERT, RcvIrpFromRt)
+#pragma CTEMakePageable(PAGERT, SendIrpFromRt)
+#pragma CTEMakePageable(PAGERT, PassDgToRt)
+#pragma CTEMakePageable(PAGERT, RtIrpCancel)
+#pragma CTEMakePageable(PAGERT, NTCheckSetCancelRoutine)
+#pragma CTEMakePageable(PAGERT, NTIoComplete)
+#pragma CTEMakePageable(PAGERT, RtFreeMem)
+#pragma CTEMakePageable(PAGERT, RtAllocMem)
+#pragma CTEMakePageable(PAGERT, IpxRefRt)
+#pragma CTEMakePageable(PAGERT, IpxDerefRt)
+#pragma CTEMakePageable(PAGERT, IpxDestroyRt)
+#endif
+//******************* Pageable Routine Declarations ****************
+
+
+HANDLE IpxRtDiscardableCodeHandle={0};
+
+PRT_INFO pRtInfo; //contains info about all rt opened end points
+
+
+NTSTATUS
+OpenRtAddress(
+ IN PDEVICE pDevice,
+ IN PREQUEST pIrp
+ )
+{
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ NTSTATUS status;
+ ULONG SaveReqCode;
+
+
+ IpxPrint0("OpenRtAddress - entered\n");
+
+ //
+ // if the RTINFO endpoint structure is not allocated, then allocate it
+ // and initialize it. But first get the device lock. This gurantees that
+ // we can not have two irps doing the creation at the same time
+ //
+ CTEGetLock(&pDevice->Lock, &OldIrq);
+ if (!pRtInfo)
+ {
+
+ pRt = AllocMem(sizeof(RT_INFO));
+
+ //
+ // Do this after locking the pagable rtns.
+ //
+ // pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM,
+ // we can compare pRt passed in them with pRtInfo
+ if (pRt)
+ {
+ RtlZeroMemory(pRt,sizeof(RT_INFO));
+ IpxPrint1("OpenRtAddress: Initializing CompletedIrps for pRt=(%lx)\n", pRt);
+ pRt->RcvMemoryMax = RT_MAX_BUFF_MEM; // max. memory we can allocate
+ pRt->Type = IPX_RT_SIGNATURE;
+ pRt->Size = sizeof(RT_INFO);
+ pRt->pDevice = pDevice;
+ IpxPrint1("OpenRtAddress: pRtInfo=(%lx)\n", pRt);
+ IpxPrint1("Completed Irp list is (%lx)\n", IsListEmpty(&pRt->CompletedIrps));
+
+#if DBG
+ RtlCopyMemory(pRt->Signature, "RTIF", sizeof("RTIF") - 1);
+#endif
+ InitializeListHead(&pRt->CompletedIrps);
+ InitializeListHead(&pRt->HolderIrpsList);
+ }
+ CTEFreeLock(&pDevice->Lock, OldIrq);
+ }
+ else
+ {
+ pRt = pRtInfo;
+ CTEFreeLock(&pDevice->Lock, OldIrq);
+ IpxPrint1("OpenRtAddress: RTINFO found = (%lx)\n", pRtInfo);
+ }
+
+ if (pRt)
+ {
+
+ // Page in the Rt Code, if it hasn't already been paged in.
+ //
+ if (!IpxRtDiscardableCodeHandle)
+ {
+ IpxRtDiscardableCodeHandle = MmLockPagableCodeSection( CloseRtAddress );
+
+ pRtInfo = pRt; //store it in pRtInfo. When irps come down from RM,
+ // we can compare pRt passed in them with pRtInfo
+ }
+
+ //
+ // it could fail to lock the pages so check for that
+ //
+ if (IpxRtDiscardableCodeHandle)
+ {
+
+ ULONG i;
+ status = STATUS_SUCCESS;
+
+ IpxReferenceRt(pRtInfo, RT_CREATE);
+
+ //
+ // Find an empty slot and mark it open
+ //
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ for (i=0; i<IPX_RT_MAX_ADDRESSES; i++)
+ {
+ if (pRt->AddFl[i].State == RT_EMPTY)
+ {
+ break;
+ }
+ }
+ if (i < IPX_RT_MAX_ADDRESSES)
+ {
+ pRt->AddFl[i].State = RT_OPEN;
+ pRt->NoOfAdds++;
+ InitializeListHead(&pRt->AddFl[i].RcvList);
+ InitializeListHead(&pRt->AddFl[i].RcvIrpList);
+ }
+ else
+ {
+ CTEFreeLock(&pRt->Lock, OldIrq);
+ IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES);
+ IpxDereferenceRt(pRtInfo, RT_CREATE);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto RET;
+ }
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // Found an empty slot. Initialize all relevant info. and then
+ // open an address object.
+ //
+ SaveReqCode = REQUEST_CODE(pIrp);
+ REQUEST_CODE(pIrp) = MIPX_RT_CREATE;
+ status = IpxOpenAddressM(pDevice, pIrp, i);
+ REQUEST_CODE(pIrp) = SaveReqCode;
+
+ IpxPrint1("After IpxOpenAddressM: Completed Irp list is (%lx)\n", IsListEmpty(&pRtInfo->CompletedIrps));
+ if (status != STATUS_SUCCESS)
+ {
+ IpxPrint0("OpenRtAddress; Access Denied due to OpenAddress\n");
+ IpxDereferenceRt(pRtInfo, RT_CREATE);
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[i].State = RT_EMPTY;
+ pRt->NoOfAdds--;
+ CTEFreeLock(&pRt->Lock, OldIrq);
+ }
+ else
+ {
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[i].AddressFile = REQUEST_OPEN_CONTEXT(pIrp);
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // No need to put pRt since it is global. We stick with the addressfile here.
+ //
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)pRt;
+ REQUEST_OPEN_TYPE(pIrp) = (PVOID)(ROUTER_ADDRESS_FILE + i);
+ IpxPrint1("OpenRtAdd: Index = (%d)\n", RT_ADDRESS_INDEX(pIrp));
+ }
+ }
+ else
+ {
+ IpxPrint1("OpenRtAddress; All %d slots used up\n", IPX_RT_MAX_ADDRESSES);
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ IpxPrint0("OpenRtCreate; Couldn't allocate a RT_INFO structure\n");
+ CTEAssert(FALSE); //should never happen unless system is running
+ //out of non-paged pool
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+RET:
+ IpxPrint1("OpenRtAddress status prior to return= %X\n",status);
+ return(status);
+}
+
+
+NTSTATUS
+CleanupRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp)
+
+/*++
+Routine Description;
+
+ This Routine handles closing the Rt Object that is used by
+ by RT to send and receive name service datagrams on port 137.
+
+
+Arguments;
+
+ pIrp - a ptr to an IRP
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ ULONG Index;
+ PLIST_ENTRY pLE;
+ PIRP pTmpIrp;
+
+
+
+ IpxPrint0("CleanupRtAddress - entered\n");
+
+ //
+ // if the endpoint structure is allocated, then deallocate it
+ //
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("CleanupRtAdd: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+
+ do
+ {
+ PLIST_ENTRY pRcvEntry;
+ PRTRCV_BUFFER pRcv;
+ PRT_IRP pRtAddFl = &pRt->AddFl[Index];
+
+ CTEAssert(pRtAddFl->State == RT_OPEN);
+ IpxPrint1("CleanupRtAddress: Got AF handle = (%lx)\n", pRtAddFl);
+ IpxReferenceRt(pRt, RT_CLEANUP);
+ status = STATUS_SUCCESS;
+
+ CTEGetLock (&pRt->Lock, &OldIrq);
+
+ //
+ // prevent any more dgram getting queued up
+ //
+ pRtAddFl->State = RT_CLOSING;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ //
+ // free any rcv buffers that may be queued up
+ //
+ pHead = &pRtAddFl->RcvList;
+ while (pRcvEntry = ExInterlockedRemoveHeadList(pHead, &pRt->Lock))
+ {
+ pRcv = CONTAINING_RECORD(pRcvEntry,RTRCV_BUFFER,Linkage);
+
+ CTEAssert(pRcv);
+ IpxPrint1("CleanupRtAddress:Freeing buffer = (%lx)\n", pRcv);
+ RtFreeMem(pRcv,pRcv->TotalAllocSize);
+ }
+
+ //
+ // Complete all irps that are queued
+ //
+ while (pLE = ExInterlockedRemoveHeadList(&pRtAddFl->RcvIrpList, &pRt->Lock)) {
+
+ //
+ // The recv irp is here so copy the data to its buffer and
+ // pass it up to RT
+ //
+ pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+ IpxPrint1("CleanupRtAddress: Completing Rt rcv Irp from AdFl queue pIrp=%X\n" ,pTmpIrp);
+ pTmpIrp->IoStatus.Information = 0;
+ pTmpIrp->IoStatus.Status = STATUS_CANCELLED;
+
+ NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1);
+
+ } //end of while
+
+ //
+ // dequeue and complete any irps on the complete queue.
+ //
+
+ while (pLE = ExInterlockedRemoveHeadList(&pRt->CompletedIrps, &pRt->Lock))
+ {
+ pTmpIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+ if (RT_ADDRESS_INDEX(pTmpIrp) == Index)
+ {
+ IpxPrint1("CleanupRtAddress:Completing Rt rcv Irp from CompleteIrps queue pIrp=%X\n" ,pTmpIrp);
+
+ pTmpIrp->IoStatus.Information = 0;
+ pTmpIrp->IoStatus.Status = STATUS_CANCELLED;
+ NTIoComplete(pTmpIrp, (NTSTATUS)-1, (ULONG)-1);
+ }
+ else
+ {
+ ExInterlockedInsertHeadList(&pRt->HolderIrpsList, pLE, &pRt->Lock);
+ }
+ }
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ while(!IsListEmpty(&pRt->HolderIrpsList))
+ {
+ pLE = RemoveHeadList(&pRt->HolderIrpsList);
+ InsertHeadList(&pRt->CompletedIrps, pLE);
+ }
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // Store AF pointer in Irp since we will now be freeing the address file
+ // (in driver.c).
+ //
+
+ //
+ // We always have addressfile in the Irp
+ //
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtAddFl->AddressFile);
+
+ IpxDereferenceRt(pRt, RT_CLEANUP);
+ } while (FALSE);
+
+ IpxPrint0("CleanupRtAddress: Return\n");
+ return(status);
+}
+
+NTSTATUS
+CloseRtAddress(
+ IN PDEVICE pDevice,
+ IN PIRP pIrp)
+{
+
+ NTSTATUS status;
+ PRT_INFO pRt;
+ CTELockHandle OldIrq;
+ PLIST_ENTRY pHead;
+ ULONG Index;
+
+ IpxPrint0("CloseRtAddress - entered\n");
+
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("CloseRtAdd: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+ CTEAssert(pRt->AddFl[Index].State == RT_CLOSING);
+
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRt->AddFl[Index].AddressFile);
+ //REQUEST_OPEN_TYPE(pIrp) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ pRt->AddFl[Index].State = RT_EMPTY;
+ pRt->NoOfAdds--;
+ CTEFreeLock(&pRt->Lock, OldIrq);
+
+ //
+ // THis is a counter to the RT_CREATE
+ //
+ IpxDereferenceRt(pRt, RT_CLOSE);
+
+ return(STATUS_SUCCESS);
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+SendIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ )
+{
+ CTELockHandle OldIrq;
+ NTSTATUS Status;
+ ULONG Index;
+ PRT_INFO pRt;
+
+ IpxPrint0("SendIrpfromRt - entered\n");
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ do {
+ //
+ // Check if the add. file slot indicates that it is OPEN. If it is
+ // not open, then we should return STATUS_INVALID_HANDLE. The
+ // reason why it may not be open is if we got a cleanup/close before
+ // this irp.
+ //
+ CTEGetLock(&pRt->Lock, &OldIrq);
+ if (pRt->AddFl[Index].State != RT_OPEN)
+ {
+
+ //
+ // free the lock, set the status and break out
+ //
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+ //
+ // Let us reference the RtInfo structure so that it does not dissapear
+ // and also for some accounting
+ //
+ IpxReferenceRt(pRt, RT_SEND);
+
+
+ IpxPrint1("SendIrpFromRt: Index = (%d)\n", Index);
+
+ //
+ // Store the AF pointer since IpxTdiSendDatagram will use it. Free
+ // the device lock since we have nothing more to do with our structures
+ // here.
+ //
+ // REQUEST_OPEN_CONTEXT(pIrp) = (PVOID)(pRtInfo->AddFl[Index].AddressFile);
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ Status = IpxTdiSendDatagram(pDevice->DeviceObject, pIrp);
+
+ //
+ // All done with this send. Derefernce the RtInfo structure.
+ //
+ IpxDereferenceRt(pRtInfo, RT_SEND);
+ } while(FALSE);
+
+ IpxPrint0("SendIrpfromRt - leaving\n");
+ return(Status);
+}
+
+ NTSTATUS
+RcvIrpFromRt (
+ IN PDEVICE pDevice,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description;
+
+ This function takes the rcv irp posted by RT and decides if there are
+ any datagram queued waiting to go up to RT. If so then the datagram
+ is copied to the RT buffer and passed back up. Otherwise the irp is
+ held by Netbt until a datagram does come in.
+
+Arguments;
+
+ pDevice - not used
+ pIrp - Rt Rcv Irp
+
+Return Value;
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes;
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PRTRCV_BUFFER pBuffer;
+ PLIST_ENTRY pEntry;
+ CTELockHandle OldIrq;
+ PRT_INFO pRt;
+ PIPX_DATAGRAM_OPTIONS2 pRtBuffer;
+ PRT_IRP pRtAF;
+ ULONG Index;
+#if DBG
+ ULONG NoOfRcvIrp;
+#endif
+
+ IpxPrint0("RcvIrpfromRt - Entered\n");
+
+ // pRt = REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+
+ IpxPrint1("RcvIrpFromRt: Index = (%d)\n", Index);
+
+ IpxVerifyRt(pRt);
+ CTEAssert(pRt && (pRt == pRtInfo));
+ CTEAssert(Index < IPX_RT_MAX_ADDRESSES);
+
+ CTEGetLock (&pRt->Lock, &OldIrq);
+ do
+ {
+ pRtAF = &pRt->AddFl[Index];
+ if (pRtAF->State != RT_OPEN)
+ {
+ status = STATUS_INVALID_HANDLE;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ break;
+ }
+ IpxReferenceRt(pRt, RT_IRPIN);
+
+ if (!IsListEmpty(&pRtAF->RcvList))
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG UserBufferLengthToPass;
+ ULONG MdlLength;
+
+ //
+ // There is at least one datagram waiting to be received
+ //
+ pEntry = RemoveHeadList(&pRtAF->RcvList);
+
+ pBuffer = (PRTRCV_BUFFER)CONTAINING_RECORD(pEntry,RTRCV_BUFFER,
+ Linkage);
+
+ IpxPrint0("RcvIrpFromRt: Buffer dequeued\n");
+ //
+ // Copy the datagram and the source address to RT buffer and
+ // return to RT
+ //
+ pMdl = pIrp->MdlAddress;
+ IpxPrint2("RcvIrpFromRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl);
+ CTEAssert(pMdl);
+ if (!pMdl)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ IpxDereferenceRt(pRtInfo, RT_IRPIN);
+ break;
+
+ }
+ pRtBuffer = MmGetSystemAddressForMdl(pMdl);
+ MdlLength = MmGetMdlByteCount(pMdl);
+
+ UserBufferLengthToPass = pBuffer->UserBufferLengthToPass;
+
+ CopyLength = (UserBufferLengthToPass <= MdlLength) ? UserBufferLengthToPass : MdlLength;
+ IpxPrint0("RcvIrpFromRt: Copying Options\n");
+ RtlCopyMemory((PVOID)pRtBuffer,
+ (PVOID)&pBuffer->Options,
+ CopyLength);
+
+ //
+ // subtract from the total amount buffered for RT since we are
+ // passing a datagram up to RT now.
+ //
+ pRtInfo->RcvMemoryAllocated -= pBuffer->TotalAllocSize;
+ RtFreeMem(pBuffer, pBuffer->TotalAllocSize);
+
+ CTEAssert(pRtBuffer->DgrmOptions.LocalTarget.NicId);
+
+ //
+ // pass the irp up to RT
+ //
+ if (CopyLength < UserBufferLengthToPass)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+#if DBG
+ NoOfRcvIrp = pRtAF->NoOfRcvIrps;
+#endif
+
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+
+ IpxPrint3("Returning Rt rcv Irp immediately with queued dgram, status=%X,pIrp=%X. NoOfRcvIrp=(%d)\n" ,status,pIrp, NoOfRcvIrp);
+
+ pIrp->IoStatus.Information = CopyLength;
+ pIrp->IoStatus.Status = status;
+ }
+ else
+ {
+
+ status = NTCheckSetCancelRoutine(pIrp,RtIrpCancel,pDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ CTEFreeLock (&pRt->Lock, OldIrq);
+ }
+ else
+ {
+ if (pRtAF->NoOfRcvIrps++ > RT_IRP_MAX)
+ {
+ IpxPrint1("RcvIrpFromRt; REACHED LIMIT OF IRPS. NoOfRcvIrp=(%d)\n", pRtAF->NoOfRcvIrps);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ pRtAF->NoOfRcvIrps--;
+ CTEFreeLock (&pRt->Lock, OldIrq);
+
+ }
+ else
+ {
+ InsertTailList(&pRtAF->RcvIrpList,REQUEST_LINKAGE(pIrp));
+ IpxPrint2("IpxRt;Holding onto Rt Rcv Irp, pIrp =%Xstatus=%X\n", status,pIrp);
+
+ status = STATUS_PENDING;
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ }
+ }
+
+
+ }
+ IpxDereferenceRt(pRtInfo, RT_IRPIN);
+ } while(FALSE);
+
+ IpxPrint0("RcvIrpfromRt - Leaving\n");
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+PassDgToRt (
+ IN PDEVICE pDevice,
+ IN PIPX_DATAGRAM_OPTIONS2 pContext,
+ IN ULONG Index,
+ IN VOID UNALIGNED *pDgrm,
+ IN ULONG uNumBytes
+ )
+/*++
+
+Routine Description;
+
+ This function is used to allow NBT to pass name query service Pdu's to
+ RT. Rt posts a Rcv irp to Netbt. If the Irp is here then simply
+ copy the data to the irp and return it, otherwise buffer the data up
+ to a maximum # of bytes. Beyond that limit the datagrams are discarded.
+
+ If Retstatus is not success then the pdu will also be processed by
+ nbt. This allows nbt to process packets when wins pauses and
+ its list of queued buffers is exceeded.
+
+Arguments;
+
+ pDevice - card that the request can in on
+ pSrcAddress - source address
+ pDgrm - ptr to the datagram
+ uNumBytes - length of datagram
+
+Return Value;
+
+ STATUS_PENDING if the buffer is to be held on to , the normal case.
+
+Notes;
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPX_DATAGRAM_OPTIONS2 pRtBuffer;
+ PIRP pIrp;
+ CTELockHandle OldIrq;
+
+
+ IpxPrint0("PassDgToRt - Entered\n");
+
+ //
+ // Get the source port and ip address, since RT needs this information.
+ //
+ IpxPrint1("PassDgToRt: Index = (%d)\n", Index);
+ CTEGetLock(&pRtInfo->Lock,&OldIrq);
+
+ do
+ {
+ PRT_IRP pRtAF = &pRtInfo->AddFl[Index];
+ if (pRtAF->State != RT_OPEN)
+ {
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+ break;
+ }
+ IpxReferenceRt(pRtInfo, RT_BUFF);
+ if (IsListEmpty(&pRtAF->RcvIrpList))
+ {
+ IpxPrint0("PassDgToRt: No Rcv Irp\n");
+ if (pRtInfo->RcvMemoryAllocated < pRtInfo->RcvMemoryMax)
+ {
+ PRTRCV_BUFFER pBuffer;
+
+ pBuffer = RtAllocMem(uNumBytes + sizeof(RTRCV_BUFFER));
+ if (pBuffer)
+ {
+ pBuffer->TotalAllocSize = uNumBytes + sizeof(RTRCV_BUFFER);
+
+ //
+ // Copy the user data
+ //
+ RtlCopyMemory(
+ (PUCHAR)((PUCHAR)pBuffer + OFFSET_PKT_IN_RCVBUFF),
+ (PVOID)pDgrm,uNumBytes);
+
+
+ pBuffer->Options.DgrmOptions.LocalTarget.NicId =
+ pContext->DgrmOptions.LocalTarget.NicId;
+ pBuffer->Options.LengthOfExtraOpInfo = 0;
+
+ //
+ // total amount allocated for user
+ //
+ pBuffer->UserBufferLengthToPass = uNumBytes + OFFSET_PKT_IN_OPTIONS;
+
+ CTEAssert(pContext->DgrmOptions.LocalTarget.NicId);
+ IpxPrint2("PassDgToRt: Nic Id is (%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, uNumBytes);
+
+
+
+ //
+ // Keep track of the total amount buffered so that we don't
+ // eat up all non-paged pool buffering for RT
+ //
+ pRtInfo->RcvMemoryAllocated += pBuffer->TotalAllocSize;
+
+ IpxPrint0("IpxRt;Buffering Rt Rcv - no Irp, status=%X\n");
+ InsertTailList(&pRtAF->RcvList,&pBuffer->Linkage);
+ IpxPrint0("PassDgToRt: Buffer Queued\n");
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ IpxPrint0("PassDgToRt; Could not allocate buffer\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ // this ret status will allow netbt to process the packet.
+ //
+ IpxPrint0("PassDgToRt; Dropping Pkt\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+ }
+ else
+ {
+ PMDL pMdl;
+ ULONG CopyLength;
+ ULONG DgrmLength;
+ ULONG MdlBufferLength;
+ ULONG BytesToCopy;
+ PLIST_ENTRY pLE;
+
+ //
+ // The recv irp is here so copy the data to its buffer and
+ // pass it up to RT
+ //
+ pLE = RemoveHeadList(&pRtAF->RcvIrpList);
+ pIrp = CONTAINING_RECORD(pLE, IRP, Tail.Overlay.ListEntry);
+
+ (*(REQUEST_LINKAGE(pIrp))).Flink = NULL;
+ (*(REQUEST_LINKAGE(pIrp))).Blink = NULL;
+
+ //
+ // Copy the datagram and the source address to RT buffer and
+ // return to RT
+ //
+ pMdl = pIrp->MdlAddress;
+ IpxPrint2("PassDgToRt: Irp=(%lx); Mdl=(%lx)\n", pIrp, pMdl);
+ CTEAssert(pMdl);
+
+ pRtBuffer = MmGetSystemAddressForMdl(pIrp->MdlAddress);
+
+ MdlBufferLength = MmGetMdlByteCount(pMdl);
+ DgrmLength = uNumBytes;
+ BytesToCopy = DgrmLength + OFFSET_PKT_IN_OPTIONS;
+
+ CopyLength = (BytesToCopy <= MdlBufferLength) ? BytesToCopy : MdlBufferLength;
+ IpxPrint2("PassDgToRt: Copy Length = (%d); Mdl Buffer Length is (%d)\n", CopyLength, MdlBufferLength);
+
+ //
+ // Copy user datagram into pRtBuffer
+ //
+ RtlCopyMemory((PVOID)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS),
+ (PVOID)pDgrm,
+ CopyLength-OFFSET_PKT_IN_OPTIONS);
+
+ IpxPrint1("Data copied is (%.12s)\n", (PUCHAR)((PUCHAR)pRtBuffer + OFFSET_PKT_IN_OPTIONS + sizeof(IPX_HEADER)));
+
+ pRtBuffer->DgrmOptions.LocalTarget.NicId = pContext->DgrmOptions.LocalTarget.NicId;
+ pRtBuffer->LengthOfExtraOpInfo = 0;
+
+ IpxPrint3("PassDgToRt: Copy to RcvIrp;Nic Id is (%d/%d). BufferLength is (%lx)\n", pContext->DgrmOptions.LocalTarget.NicId, pRtBuffer->DgrmOptions.LocalTarget.NicId, uNumBytes);
+
+
+ CTEAssert(pContext->DgrmOptions.LocalTarget.NicId);
+
+ //
+ // pass the irp up to RT
+ //
+ if (CopyLength < BytesToCopy)
+ {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ InsertTailList(&pRtInfo->CompletedIrps, REQUEST_LINKAGE(pIrp));
+ pRtAF->NoOfRcvIrps--;
+ IpxPrint4("PassDgToRt;Returning Rt Rcv Irp - data from net, Length=%X,pIrp=%X; status = (%d). NoOfRcvIrp = (%d)\n" ,uNumBytes,pIrp, status, pRtAF->NoOfRcvIrps);
+
+ pIrp->IoStatus.Status = status;
+ pIrp->IoStatus.Information = CopyLength;
+ CTEFreeLock(&pRtInfo->Lock,OldIrq);
+
+ }
+ IpxDereferenceRt(pRtInfo, RT_BUFF);
+ } while (FALSE);
+
+
+ IpxPrint0("PassDgToRt - Entered\n");
+ return(status);
+
+}
+
+//----------------------------------------------------------------------------
+ VOID
+RtIrpCancel(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+/*++
+
+Routine Description;
+
+ This routine handles the cancelling a RtRcv Irp. It must release the
+ cancel spin lock before returning re; IoCancelIrp().
+
+Arguments;
+
+
+Return Value;
+
+ The final status from the operation.
+
+--*/
+{
+ KIRQL OldIrq;
+ PRT_INFO pRt;
+ PDEVICE pDevice = IpxDevice;
+ ULONG Index;
+ PIRP pTmpIrp;
+
+ IpxPrint0("RtIrpCancel;Got a Rt Irp Cancel !!! *****************\n");
+
+ Index = RT_ADDRESS_INDEX(pIrp);
+ IpxPrint1("RtIrpCancel: Index = (%d)\n", Index);
+ // pRt = (PRT_INFO)REQUEST_OPEN_CONTEXT(pIrp);
+ pRt = pRtInfo;
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ if ((pRt->Type != IPX_RT_SIGNATURE) || (pRt->Size != sizeof(RT_INFO))) {
+ return;
+ }
+
+
+ //
+ // Be sure that PassNamePduToRt has not taken the RcvIrp for a
+ // Rcv just now.
+ //
+ CTEGetLock(&pRt->Lock,&OldIrq);
+ if (pRt && (pRt == pRtInfo) && (*(REQUEST_LINKAGE(pIrp))).Flink != NULL)
+ {
+
+ PRT_IRP pRtAF = &pRt->AddFl[Index];
+
+ RemoveEntryList(REQUEST_LINKAGE(pIrp));
+
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ pRtAF->NoOfRcvIrps--;
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ IpxPrint1("RtIrpCancel;Completing Request. NoOfRcvIrp = (%d)\n", pRtAF->NoOfRcvIrps);
+ IoCompleteRequest(pIrp,IO_NETWORK_INCREMENT);
+ } else {
+ CTEFreeLock(&pRt->Lock,OldIrq);
+ }
+}
+//----------------------------------------------------------------------------
+ PVOID
+RtAllocMem(
+ IN ULONG Size
+ )
+
+/*++
+Routine Description;
+
+ This Routine handles allocating memory and keeping track of how
+ much has been allocated.
+
+Arguments;
+
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value;
+
+ ptr to the memory allocated
+
+--*/
+
+{
+ if (pRtInfo->RcvMemoryAllocated > pRtInfo->RcvMemoryMax)
+ {
+ return NULL;
+ }
+ else
+ {
+ pRtInfo->RcvMemoryAllocated += Size;
+ return (AllocMem(Size));
+ }
+}
+//----------------------------------------------------------------------------
+ VOID
+RtFreeMem(
+ IN PVOID pBuffer,
+ IN ULONG Size
+ )
+
+/*++
+Routine Description;
+
+ This Routine handles freeing memory and keeping track of how
+ much has been allocated.
+
+Arguments;
+
+ pBuffer - buffer to free
+ Size - number of bytes to allocate
+ Rcv - boolean that indicates if it is rcv or send buffering
+
+Return Value;
+
+ none
+
+--*/
+
+{
+ if (pRtInfo)
+ {
+ pRtInfo->RcvMemoryAllocated -= Size;
+ }
+
+ FreeMem(pBuffer, Size);
+}
+
+
+
+//----------------------------------------------------------------------------
+
+VOID
+NTIoComplete(
+ IN PIRP pIrp,
+ IN NTSTATUS Status,
+ IN ULONG SentLength)
+
+/*++
+Routine Description;
+
+ This Routine handles calling the NT I/O system to complete an I/O.
+
+Arguments;
+
+ status - a completion status for the Irp
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ KIRQL OldIrq;
+
+ if (Status != -1)
+ {
+ pIrp->IoStatus.Status = Status;
+ }
+ // use -1 as a flag to mean do not adjust the sent length since it is
+ // already set
+ if (SentLength != -1)
+ {
+ pIrp->IoStatus.Information = SentLength;
+ }
+
+#if DBG
+ if (SentLength != -1)
+ {
+ if ( (Status != STATUS_SUCCESS) &&
+ (Status != STATUS_PENDING) &&
+ (Status != STATUS_INVALID_DEVICE_REQUEST) &&
+ (Status != STATUS_INVALID_PARAMETER) &&
+ (Status != STATUS_IO_TIMEOUT) &&
+ (Status != STATUS_BUFFER_OVERFLOW) &&
+ (Status != STATUS_BUFFER_TOO_SMALL) &&
+ (Status != STATUS_INVALID_HANDLE) &&
+ (Status != STATUS_INSUFFICIENT_RESOURCES) &&
+ (Status != STATUS_CANCELLED) &&
+ (Status != STATUS_DUPLICATE_NAME) &&
+ (Status != STATUS_TOO_MANY_NAMES) &&
+ (Status != STATUS_TOO_MANY_SESSIONS) &&
+ (Status != STATUS_REMOTE_NOT_LISTENING) &&
+ (Status != STATUS_BAD_NETWORK_PATH) &&
+ (Status != STATUS_HOST_UNREACHABLE) &&
+ (Status != STATUS_CONNECTION_REFUSED) &&
+ (Status != STATUS_WORKING_SET_QUOTA) &&
+ (Status != STATUS_REMOTE_DISCONNECT) &&
+ (Status != STATUS_LOCAL_DISCONNECT) &&
+ (Status != STATUS_LINK_FAILED) &&
+ (Status != STATUS_SHARING_VIOLATION) &&
+ (Status != STATUS_UNSUCCESSFUL) &&
+ (Status != STATUS_ACCESS_VIOLATION) &&
+ (Status != STATUS_NONEXISTENT_EA_ENTRY) )
+ {
+ IpxPrint1("returning unusual status = %X\n",Status);
+ }
+ }
+#endif
+ IpxPrint1("Irp Status is %d\n", pIrp->IoStatus.Status);
+
+ //
+ // set the Irps cancel routine to null or the system may bugcheck
+ // with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
+ //
+ // refer to IoCancelIrp() ..\ntos\io\iosubs.c
+ //
+ IoAcquireCancelSpinLock(&OldIrq);
+ IoSetCancelRoutine(pIrp,NULL);
+ IoReleaseCancelSpinLock(OldIrq);
+
+ IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
+}
+
+
+//----------------------------------------------------------------------------
+ NTSTATUS
+NTCheckSetCancelRoutine(
+ IN PIRP pIrp,
+ IN PVOID CancelRoutine,
+ IN PDEVICE pDevice
+ )
+
+/*++
+Routine Description;
+
+ This Routine sets the cancel routine for an Irp.
+
+Arguments;
+
+ status - a completion status for the Irp
+
+Return Value;
+
+ NTSTATUS - status of the request
+
+--*/
+
+{
+ NTSTATUS status;
+
+ IpxPrint1("CheckSetCancelRoutine: Entered. Irp = (%lx)\n", pIrp);
+ //
+ // Check if the irp was cancelled yet and if not, then set the
+ // irp cancel routine.
+ //
+ IoAcquireCancelSpinLock(&pIrp->CancelIrql);
+ if (pIrp->Cancel)
+ {
+ pIrp->IoStatus.Status = STATUS_CANCELLED;
+ status = STATUS_CANCELLED;
+
+ }
+ else
+ {
+ // setup the cancel routine
+ IoMarkIrpPending(pIrp);
+ IoSetCancelRoutine(pIrp,CancelRoutine);
+ status = STATUS_SUCCESS;
+ }
+
+ IoReleaseCancelSpinLock(pIrp->CancelIrql);
+ return(status);
+
+}
+
+
+
+
+VOID
+IpxRefRt(
+ PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine increments the reference count on a device context.
+
+Arguments;
+
+ Binding - Pointer to a transport device context object.
+
+Return Value;
+
+ none.
+
+--*/
+
+{
+
+ (VOID)InterlockedIncrement (&pRt->ReferenceCount);
+// CTEAssert (pRt->ReferenceCount > 0); // not perfect, but...
+// IpxPrint1("RefRt: RefCount is (%d)\n", pRt->ReferenceCount);
+
+} /* IpxRefRt */
+
+
+VOID
+IpxDerefRt(
+ PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments;
+
+ Binding - Pointer to a transport device context object.
+
+Return Value;
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&pRt->ReferenceCount);
+// IpxPrint1("DerefRt: RefCount is (%d)\n", pRt->ReferenceCount);
+
+// CTEAssert (result >= 0);
+
+#if 0
+ if (result == 0) {
+ IpxDestroyRt (pRt);
+ }
+#endif
+
+} /* IpxDerefRt */
+
+
+
+
+VOID
+IpxDestroyRt(
+ IN PRT_INFO pRt
+ )
+
+/*++
+
+Routine Description;
+
+ This routine destroys a binding structure.
+
+Arguments;
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value;
+
+ None.
+
+--*/
+
+{
+ IpxPrint0("Destroying Rt\n");
+ FreeMem (pRt, sizeof(RT_INFO));
+ pRtInfo = NULL;
+ return;
+} /* IpxDestroyRt */
+