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

1356 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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++;
pRt->AddFl[i].NoOfRcvIrps = 0; //Why wasn't this initialized before?
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) = UlongToPtr(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;
#ifdef SUNDOWN
ULONG_PTR Index;
#else
ULONG Index;
#endif
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;
#ifdef SUNDOWN
ULONG_PTR Index;
#else
ULONG Index;
#endif
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;
#ifdef SUNDOWN
ULONG_PTR Index;
#else
ULONG Index;
#endif
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;
#ifdef SUNDOWN
ULONG_PTR Index;
#else
ULONG Index;
#endif
#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 = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
if (!pRtBuffer) {
status = STATUS_INSUFFICIENT_RESOURCES;
CTEFreeLock (&pRt->Lock, OldIrq);
IpxDereferenceRt(pRtInfo, RT_IRPIN);
break;
}
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);
// 301920
status = STATUS_UNSUCCESSFUL;
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 = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
if (!pRtBuffer) {
CopyLength = 0;
status = STATUS_INSUFFICIENT_RESOURCES;
} else {
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;
#ifdef SUNDOWN
ULONG_PTR Index;
#else
ULONG Index;
#endif
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 */