You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1355 lines
36 KiB
1355 lines
36 KiB
/*++
|
|
|
|
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 */
|
|
|