예제 #1
0
NTSTATUS
NbfTdiAction(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PIRP Irp
)

/*++

Routine Description:

    This routine performs the TdiAction request for the transport
    provider.

Arguments:

    DeviceContext - The device context for the operation

    Irp - the Irp for the requested operation.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    NTSTATUS status;
    PIO_STACK_LOCATION irpSp;
    PTDI_ACTION_HEADER ActionHeader;
    LARGE_INTEGER timeout = {0,0};
    PTP_REQUEST tpRequest;
    KIRQL oldirql, cancelirql;
    ULONG BytesRequired;

    //
    // what type of status do we want?
    //

    irpSp = IoGetCurrentIrpStackLocation (Irp);

    if ((!Irp->MdlAddress) ||
            (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(TDI_ACTION_HEADER))) {
        return STATUS_INVALID_PARAMETER;
    }

    ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

    if (!ActionHeader) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    //
    // Make sure we have required number of bytes for this type of request
    //

    switch (ActionHeader->ActionCode) {

    case QUERY_INDICATION_CODE:
        BytesRequired = sizeof(ACTION_QUERY_INDICATION);
        break;

    case DATAGRAM_INDICATION_CODE:
        BytesRequired = sizeof(ACTION_DATAGRAM_INDICATION);
        break;

    default:
        return STATUS_NOT_IMPLEMENTED;
    }

    if (MmGetMdlByteCount(Irp->MdlAddress) < BytesRequired) {
        return STATUS_INVALID_PARAMETER;
    }

    //
    // Here the request is one of QUERY_INDICATION or DATAGRAM_INDICATION
    //

    //
    // These two requests are sent by RAS to "MABF"
    //

    if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
        return STATUS_NOT_SUPPORTED;
    }

    //
    // They should be sent on the control channel
    //

    if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) {
        return STATUS_NOT_SUPPORTED;
    }


    //
    // Create a request to describe this.
    //

    status = NbfCreateRequest (
                 Irp,                           // IRP for this request.
                 DeviceContext,                 // context.
                 REQUEST_FLAGS_DC,              // partial flags.
                 Irp->MdlAddress,
                 MmGetMdlByteCount(Irp->MdlAddress),
                 timeout,
                 &tpRequest);

    if (NT_SUCCESS (status)) {

        NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
        tpRequest->Owner = DeviceContextType;
        tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;

        IoAcquireCancelSpinLock(&cancelirql);
        ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);

        //
        // Disallow these requests on a stopping device.
        //

        if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {

            RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
            IoReleaseCancelSpinLock(cancelirql);
            NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);

        } else {

            if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {

                InsertTailList (
                    &DeviceContext->QueryIndicationQueue,
                    &tpRequest->Linkage);

            } else {

                InsertTailList (
                    &DeviceContext->DatagramIndicationQueue,
                    &tpRequest->Linkage);

            }

            DeviceContext->IndicationQueuesInUse = TRUE;


            //
            // If this IRP has been cancelled, then call the
            // cancel routine.
            //

            if (Irp->Cancel) {
                RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
                Irp->CancelIrql = cancelirql;
                NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
                return STATUS_PENDING;
            }

            IoSetCancelRoutine(Irp, NbfCancelAction);

            RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
            IoReleaseCancelSpinLock(cancelirql);

        }

        status = STATUS_PENDING;

    }

    return status;

}
예제 #2
0
VOID
NbfActionDatagramIndication(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PNBF_HDR_CONNECTIONLESS UiFrame,
    IN ULONG Length
)

/*++

Routine Description:

    This routine is called after a datagram frame has been
    received. It checks if there is a DATAGRAM.INDICATION IRP
    waiting to be completed, and if so completes it.

Arguments:

    DeviceContext - Pointer to our device context.

    UiFrame - Pointer to the incoming frame. The first byte of
        information is the first byte of the NetBIOS connectionless
        header.

    Length - The length of the frame starting at UiFrame.

Return Value:

    None

--*/

{
    KIRQL oldirql, cancelirql;
    PTP_REQUEST Request;
    PLIST_ENTRY p;
    PACTION_DATAGRAM_INDICATION ActionHeader;
    PDATAGRAM_INDICATION DatagramIndication;
    ULONG CopyLength;
    PMDL Mdl;
    NTSTATUS Status;


    IoAcquireCancelSpinLock (&cancelirql);
    ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);

    if (!IsListEmpty (&DeviceContext->DatagramIndicationQueue)) {

        p = RemoveHeadList (&DeviceContext->DatagramIndicationQueue);
        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);

        Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
        IoSetCancelRoutine(Request->IoRequestPacket, NULL);
        IoReleaseCancelSpinLock(cancelirql);

        Mdl = Request->Buffer2;
        ActionHeader = (PACTION_DATAGRAM_INDICATION)
                       (MmGetSystemAddressForMdl(Mdl));
        DatagramIndication = &ActionHeader->DatagramIndication;

        //
        // Copy over data from frame (note that dest and source
        // address are copied with one call).
        //

        RtlCopyMemory ((PUCHAR)(DatagramIndication->DestinationName),
                       (PUCHAR)(UiFrame->DestinationName),
                       2 * NETBIOS_NAME_LENGTH);

        if ((Length-sizeof(NBF_HDR_CONNECTIONLESS)) <=
                (ULONG)DatagramIndication->DatagramBufferLength) {

            CopyLength = Length - sizeof(NBF_HDR_CONNECTIONLESS);
            Status = STATUS_SUCCESS;

        } else {

            CopyLength = DatagramIndication->DatagramBufferLength;
            Status = STATUS_BUFFER_OVERFLOW;

        }


        RtlCopyMemory(
            (PUCHAR)DatagramIndication->DatagramBuffer,
            ((PUCHAR)UiFrame) + sizeof(NBF_HDR_CONNECTIONLESS),
            CopyLength);
        DatagramIndication->DatagramBufferLength = (USHORT)CopyLength;

        NbfCompleteRequest (Request, Status, CopyLength +
                            FIELD_OFFSET (ACTION_DATAGRAM_INDICATION, DatagramIndication.DatagramBuffer[0]));

    } else {

        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
        IoReleaseCancelSpinLock(cancelirql);

    }
}
예제 #3
0
VOID
NbfActionQueryIndication(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PNBF_HDR_CONNECTIONLESS UiFrame
)

/*++

Routine Description:

    This routine is called after a UI frame of type NAME_QUERY,
    ADD_NAME_QUERY, or ADD_GROUP_NAME_QUERY has been processed.
    It checks if there is a QUERY.INDICATION IRP waiting to
    be completed, and if so completes it.

Arguments:

    DeviceContext - Pointer to our device context.

    UiFrame - Pointer to the incoming frame. The first byte of
        information is the first byte of the NetBIOS connectionless
        header.

Return Value:

    None

--*/

{
    KIRQL oldirql, cancelirql;
    PTP_REQUEST Request;
    PLIST_ENTRY p;
    PMDL Mdl;
    PACTION_QUERY_INDICATION ActionHeader;
    PQUERY_INDICATION QueryIndication;


    IoAcquireCancelSpinLock (&cancelirql);
    ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);

    if (!IsListEmpty (&DeviceContext->QueryIndicationQueue)) {

        p = RemoveHeadList (&DeviceContext->QueryIndicationQueue);
        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);

        Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
        IoSetCancelRoutine(Request->IoRequestPacket,NULL);
        IoReleaseCancelSpinLock(cancelirql);

        Mdl = Request->Buffer2;
        ActionHeader = (PACTION_QUERY_INDICATION)
                       (MmGetSystemAddressForMdl(Mdl));
        QueryIndication = &ActionHeader->QueryIndication;

        //
        // Copy over data from frame (note that dest and source
        // address are copied with one call).
        //

        QueryIndication->Command = UiFrame->Command;
        RtlCopyMemory ((PUCHAR)(&QueryIndication->Data2), (PUCHAR)(&UiFrame->Data2Low), 2);
        RtlCopyMemory ((PUCHAR)(QueryIndication->DestinationName),
                       (PUCHAR)(UiFrame->DestinationName),
                       2 * NETBIOS_NAME_LENGTH);

        NbfCompleteRequest (Request, STATUS_SUCCESS, sizeof(ACTION_QUERY_INDICATION));

    } else {

        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
        IoReleaseCancelSpinLock(cancelirql);

    }
}
예제 #4
0
VOID
NbfStopControlChannel(
    IN PDEVICE_CONTEXT DeviceContext,
    IN USHORT ChannelIdentifier
)

/*++

Routine Description:

    This routine is called when an MJ_CLEANUP IRP is received
    on a control channel. It walks the device context's list of
    pending action requests and cancels those associated with
    this channel (as identified by ChannelIdentifier.

Arguments:

    DeviceContext - Pointer to our device context.

    ChannelIdentifier - The identifier for this open of the control
        channel, which is stored in Request->FrameContext for requests
        made on this channel.

Return Value:

    None

--*/

{

    KIRQL oldirql, cancelirql;
    PTP_REQUEST Request;
    PLIST_ENTRY p;
    UINT i;
    BOOLEAN FoundRequest;
    PLIST_ENTRY QueueHead, QueueEnd;


    //
    // Scan both queues, looking for requests. Since the list
    // may change, we scan until we find one, then remove it
    // and complete it. We then start scanning at the beginning
    // again. We continue until we find none on the queue that
    // belong to this control channel.
    //
    // The outer loop only runs twice; the first time it
    // processes QueryIndicationQueue, the second time
    // DatagramIndicationQueue.
    //

    for (i = 0; i < 2; i++) {

        do {

            //
            // Loop until we do not find a request on this
            // pass through the queue.
            //

            FoundRequest = FALSE;

            IoAcquireCancelSpinLock(&cancelirql);
            ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);

            if (i == 0) {
                QueueHead = DeviceContext->QueryIndicationQueue.Flink;
                QueueEnd = &DeviceContext->QueryIndicationQueue;
            } else {
                QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
                QueueEnd = &DeviceContext->DatagramIndicationQueue;
            }


            //
            // Scan the appropriate queue for a request on this
            // channel.
            //

            for (p = QueueHead; p != QueueEnd; p = p->Flink) {

                Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
                if (Request->FrameContext == ChannelIdentifier) {

                    //
                    // Found it, remove it from the list here.
                    //

                    IoSetCancelRoutine(Request->IoRequestPacket, NULL);
                    RemoveEntryList (p);

                    FoundRequest = TRUE;
                    break;

                }

            }

            RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
            IoReleaseCancelSpinLock(cancelirql);

            //
            // If we found a request, then complete it and loop
            // back to the top of the while loop to rescan the
            // list. If not, then we will exit the while loop
            // now.
            //

            if (FoundRequest) {

                NbfCompleteRequest (Request, STATUS_CANCELLED, 0);

            }

        } while (FoundRequest);

    }

}
예제 #5
0
VOID
NbfCancelAction(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
)

/*++

Routine Description:

    This routine is called by the I/O system to cancel an Action.
    What is done to cancel it is specific to each action.

    NOTE: This routine is called with the CancelSpinLock held and
    is responsible for releasing it.

Arguments:

    DeviceObject - Pointer to the device object for this driver.

    Irp - Pointer to the request packet representing the I/O request.

Return Value:

    none.

--*/

{
    KIRQL oldirql;
    PIO_STACK_LOCATION IrpSp;
    PTP_REQUEST Request;
    PLIST_ENTRY p;
    BOOLEAN Found;
    PTDI_ACTION_HEADER ActionHeader;
    PLIST_ENTRY QueueHead, QueueEnd;

    PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;

    //
    // Get a pointer to the current stack location in the IRP.  This is where
    // the function codes and parameters are stored.
    //

    IrpSp = IoGetCurrentIrpStackLocation (Irp);

    ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
            (IrpSp->MinorFunction == TDI_ACTION));

    ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);

    if (!ActionHeader) {
        return;
    }

    switch (ActionHeader->ActionCode) {

    case QUERY_INDICATION_CODE:
    case DATAGRAM_INDICATION_CODE:

        //
        // Scan through the appropriate queue, looking for this IRP.
        // If we find it, we just remove it from the queue; there
        // is nothing else involved in cancelling.
        //

        ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);

        if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
            QueueHead = DeviceContext->QueryIndicationQueue.Flink;
            QueueEnd = &DeviceContext->QueryIndicationQueue;
        } else {
            QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
            QueueEnd = &DeviceContext->DatagramIndicationQueue;
        }

        Found = FALSE;
        for (p = QueueHead; p != QueueEnd; p = p->Flink) {

            Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
            if (Request->IoRequestPacket == Irp) {

                //
                // Found it, remove it from the list here.
                //

                RemoveEntryList (p);

                Found = TRUE;
                break;

            }

        }

        RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
        IoReleaseCancelSpinLock (Irp->CancelIrql);

        if (Found) {

            NbfCompleteRequest (Request, STATUS_CANCELLED, 0);

        } else {

#if DBG
            DbgPrint("NBF: Tried to cancel action %lx on %lx, not found\n",
                     Irp, DeviceContext);
#endif
        }

        break;

    default:

        IoReleaseCancelSpinLock (Irp->CancelIrql);
        break;

    }


}
예제 #6
0
VOID
NbfTdiRequestTimeoutHandler(
    IN PKDPC Dpc,
    IN PVOID DeferredContext,
    IN PVOID SystemArgument1,
    IN PVOID SystemArgument2
    )

/*++

Routine Description:

    This routine is executed as a DPC at DISPATCH_LEVEL when a request
    such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
    encounters a timeout.  This routine cleans up the activity and cancels it.

Arguments:

    Dpc - Pointer to a system DPC object.

    DeferredContext - Pointer to the TP_REQUEST block representing the
        request that has timed out.

    SystemArgument1 - Not used.

    SystemArgument2 - Not used.

Return Value:

    none.

--*/

{
    KIRQL oldirql;
    PTP_REQUEST Request;
    PTP_CONNECTION Connection;
#if DBG
    LARGE_INTEGER time, difference;
#endif
    PIO_STACK_LOCATION IrpSp;
    PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
    PDEVICE_CONTEXT DeviceContext;

    Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings

    ENTER_NBF;

    Request = (PTP_REQUEST)DeferredContext;

    IF_NBFDBG (NBF_DEBUG_REQUEST) {
        NbfPrint1 ("RequestTimeoutHandler:  Entered, Request %lx\n", Request);
    }

    ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
    Request->Flags &= ~REQUEST_FLAGS_TIMER;
    if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {

#if DBG
        KeQuerySystemTime (&time);
        difference.QuadPart = time.QuadPart - (Request->Time).QuadPart;
        NbfPrint1 ("RequestTimeoutHandler: Request timed out, queued for %ld seconds\n",
                difference.LowPart / SECONDS);
#endif

        //
        // find reason for timeout
        //

        IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
        if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
            switch (IrpSp->MinorFunction) {

                //
                // none of these should time out.
                //

            case TDI_SEND:
            case TDI_ACCEPT:
            case TDI_SET_INFORMATION:
            case TDI_SET_EVENT_HANDLER:
            case TDI_SEND_DATAGRAM:
            case TDI_RECEIVE_DATAGRAM:
            case TDI_RECEIVE:

#if DBG
                NbfPrint1 ("RequestTimeoutHandler: Request: %lx Timed out, and shouldn't have!\n",
                        Request);
#endif
                ASSERT (FALSE);
                RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
                NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
                break;


            case TDI_LISTEN:
            case TDI_CONNECT:

#if DBG
                NbfPrint2 ("RequestTimeoutHandler:  %s Failed, Request: %lx\n",
                            IrpSp->MinorFunction == TDI_LISTEN ?
                                "Listen" :
                                IrpSp->MinorFunction == TDI_CONNECT ?
                                    "Connect" : "Disconnect",
                            Request);
#endif
                Connection = (PTP_CONNECTION)(Request->Context);
                RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);

                //
                // Since these requests are part of the connection
                // itself, we just stop the connection and the
                // request will get torn down then. If we get the
                // situation where the request times out before
                // it is queued to the connection, then the code
                // that is about to queue it will check the STOPPING
                // flag and complete it then.
                //
                // Don't stop the connection if an automatic connection
                // is in progress.
                //

#ifdef RASAUTODIAL

#if DBG
                DbgPrint("RequestTimeoutHandler: AUTOCONNECTING=0x%x\n", Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING);
#endif
                if (!(Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING))
                    NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
                break;

#endif

            case TDI_DISCONNECT:

                //
                // We don't create requests for TDI_DISCONNECT any more.
                //

                ASSERT(FALSE);
                break;

            case TDI_QUERY_INFORMATION:

                DeviceContext = (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject;
                query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;

                IF_NBFDBG (NBF_DEBUG_DEVCTX) {
                    NbfPrint1 ("RequestTimeout: %lx:\n", DeviceContext);
                }

                //
                // Determine if the request is done, or if we should
                // requeue it.
                //

                --Request->Retries;

                if (Request->Retries > 0) {

                    RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);

                    //
                    // Send another packet out, and restart the timer.
                    //

                    if (query->QueryType == TDI_QUERY_FIND_NAME) {

                        NbfSendQueryFindName (
                            DeviceContext,
                            Request);

                    } else if (query->QueryType == TDI_QUERY_ADAPTER_STATUS) {

                        PUCHAR SingleSR;
                        UINT SingleSRLength;

                        //
                        // Send the STATUS_QUERY frames out as
                        // single-route source routing.
                        //
                        // On a second status query this should
                        // really be sent directed, but currently we
                        // don't record the address anywhere.
                        //

                        MacReturnSingleRouteSR(
                            &DeviceContext->MacInfo,
                            &SingleSR,
                            &SingleSRLength);

                        NbfSendStatusQuery (
                            DeviceContext,
                            Request,
                            &DeviceContext->NetBIOSAddress,
                            SingleSR,
                            SingleSRLength);

                    } else {

                        ASSERT (FALSE);

                    }

                } else {

                    RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);

                    //
                    // That's it, we retried enough, complete it.
                    //

                    ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
                    RemoveEntryList (&Request->Linkage);
                    RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);

                    if (Request->BytesWritten > 0) {

                        NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);

                    } else {

                        NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, Request->BytesWritten);

                    }


                }

                break;

            default:
#if DBG
                NbfPrint2 ("RequestTimeoutHandler:  Unknown Request Timed out, Request: %lx Type: %x\n",
                            Request, IrpSp->MinorFunction);
#endif
                RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
                break;

            }   // end of switch

        } else {