From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/tdi/isn/ipx/rt.c | 1311 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1311 insertions(+) create mode 100644 private/ntos/tdi/isn/ipx/rt.c (limited to 'private/ntos/tdi/isn/ipx/rt.c') 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; iAddFl[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 */ + -- cgit v1.2.3