/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: rcv.c Abstract: This module contains code which performs the following TDI services: o TdiReceive o TdiReceiveDatagram Environment: Kernel mode Revision History: --*/ #include "st.h" NTSTATUS StTdiReceive( IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiReceive request for the transport provider. Arguments: Irp - I/O Request Packet for this request. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; PTP_CONNECTION connection; KIRQL oldirql, cancelirql; PTP_REQUEST tpRequest; LARGE_INTEGER timeout = {0,0}; PIO_STACK_LOCATION irpSp; PMDL ReceiveBuffer; ULONG ReceiveBufferLength; PTDI_REQUEST_KERNEL_RECEIVE parameters; // // verify that the operation is taking place on a connection. At the same // time we do this, we reference the connection. This ensures it does not // get removed out from under us. Note also that we do the connection // lookup within a try/except clause, thus protecting ourselves against // really bogus handles // irpSp = IoGetCurrentIrpStackLocation (Irp); connection = irpSp->FileObject->FsContext; status = StVerifyConnectionObject (connection); if (!NT_SUCCESS (status)) { return status; } // // Initialize bytes transferred here. // Irp->IoStatus.Information = 0; // reset byte transfer count. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)(&irpSp->Parameters); ReceiveBuffer = Irp->MdlAddress; ReceiveBufferLength =parameters->ReceiveLength; // // Queue up this receive to the connection object. // status = StCreateRequest ( Irp, // IRP for this request. connection, // context. REQUEST_FLAGS_CONNECTION, // partial flags. ReceiveBuffer, ReceiveBufferLength, timeout, &tpRequest); // // We have a request, now queue it. If the connection has gone south on us // while we were getting things going, we will avoid actually queing the // request. // if (NT_SUCCESS (status)) { // This reference is removed by StDestroyRequest. StReferenceConnection("TdiReceive request", connection); tpRequest->Owner = ConnectionType; IoAcquireCancelSpinLock(&cancelirql); ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql); if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) { RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); IoReleaseCancelSpinLock(cancelirql); StCompleteRequest ( tpRequest, connection->Status, 0); status = STATUS_PENDING; } else { // // Insert onto the receive queue, and make the IRP // cancellable. // InsertTailList (&connection->ReceiveQueue,&tpRequest->Linkage); RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql); // // If this IRP has been cancelled, then call the // cancel routine. // if (Irp->Cancel) { Irp->CancelIrql = cancelirql; StCancelReceive((PDEVICE_OBJECT)(connection->Provider), Irp); StDereferenceConnection ("IRP cancelled", connection); // release lookup hold. return STATUS_PENDING; } Irp->CancelRoutine = StCancelReceive; IoReleaseCancelSpinLock(cancelirql); AwakenReceive (connection); // awaken if sleeping. status = STATUS_PENDING; } } StDereferenceConnection("temp TdiReceive", connection); return status; } /* TdiReceive */ NTSTATUS StTdiReceiveDatagram( IN PIRP Irp ) /*++ Routine Description: This routine performs the TdiReceiveDatagram request for the transport provider. Receive datagrams just get queued up to an address, and are completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at the address. Arguments: Irp - I/O Request Packet for this request. Return Value: NTSTATUS - status of operation. --*/ { NTSTATUS status; KIRQL oldirql; PTP_ADDRESS address; PTP_ADDRESS_FILE addressFile; PTP_REQUEST tpRequest; LARGE_INTEGER timeout = {0,0}; PIO_STACK_LOCATION irpSp; PMDL ReceiveBuffer; ULONG ReceiveBufferLength; // // verify that the operation is taking place on an address. At the same // time we do this, we reference the address. This ensures it does not // get removed out from under us. Note also that we do the address // lookup within a try/except clause, thus protecting ourselves against // really bogus handles // irpSp = IoGetCurrentIrpStackLocation (Irp); addressFile = irpSp->FileObject->FsContext; status = StVerifyAddressObject (addressFile); if (!NT_SUCCESS (status)) { return status; } address = addressFile->Address; ReceiveBuffer = Irp->MdlAddress; ReceiveBufferLength = ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength; status = StCreateRequest ( Irp, // IRP for this request. address, // context REQUEST_FLAGS_ADDRESS, // partial flags. ReceiveBuffer, ReceiveBufferLength, timeout, &tpRequest); if (NT_SUCCESS (status)) { StReferenceAddress ("Receive datagram", address); tpRequest->Owner = AddressType; ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql); if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) { RELEASE_SPIN_LOCK (&address->SpinLock,oldirql); StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0); status = STATUS_PENDING; } else { InsertTailList (&addressFile->ReceiveDatagramQueue,&tpRequest->Linkage); RELEASE_SPIN_LOCK (&address->SpinLock,oldirql); } status = STATUS_PENDING; } StDereferenceAddress ("Temp rcv datagram", address); return status; } /* TdiReceiveDatagram */