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