File:  [WindowsNT SDKs] / ntddk / src / network / tdi / info.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1989-1993 Microsoft Corporation

Module Name:

    info.c

Abstract:

    This module contains code which performs the following TDI services:

        o   TdiQueryInformation
        o   TdiSetInformation

Environment:

    Kernel mode

Revision History:

--*/

#include "st.h"


//
// Useful macro to obtain the total length of an MDL chain.
//

#define StGetMdlChainLength(Mdl, Length) { \
    PMDL _Mdl = (Mdl); \
    *(Length) = 0; \
    while (_Mdl) { \
        *(Length) += MmGetMdlByteCount(_Mdl); \
        _Mdl = _Mdl->Next; \
    } \
}

//
// Local functions used to satisfy various requests.
//

VOID
StStoreProviderStatistics(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PTDI_PROVIDER_STATISTICS ProviderStatistics
    );

VOID
StStoreAdapterStatus(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PUCHAR SourceRouting,
    IN UINT SourceRoutingLength,
    IN PVOID StatusBuffer
    );

VOID
StStoreNameBuffers(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PVOID Buffer,
    IN ULONG BufferLength,
    IN ULONG NamesToSkip,
    OUT PULONG NamesWritten,
    OUT PULONG TotalNameCount OPTIONAL,
    OUT PBOOLEAN Truncated
    );


NTSTATUS
StTdiQueryInformation(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the TdiQueryInformation request for the transport
    provider.

Arguments:

    Irp - the Irp for the requested operation.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    NTSTATUS status;
    PIO_STACK_LOCATION irpSp;
    PVOID adapterStatus;
    PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
    PTA_NETBIOS_ADDRESS broadcastAddress;
    PTDI_PROVIDER_STATISTICS ProviderStatistics;
    PTDI_CONNECTION_INFO ConnectionInfo;
    ULONG TargetBufferLength;
    LARGE_INTEGER timeout = {0,0};
    PTP_CONNECTION Connection;
    ULONG NamesWritten, TotalNameCount, BytesWritten;
    BOOLEAN Truncated;

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

    irpSp = IoGetCurrentIrpStackLocation (Irp);

    query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;

    switch (query->QueryType) {

    case TDI_QUERY_CONNECTION_INFO:

        //
        // Connection info is queried on a connection,
        // verify this.
        //

        Connection = irpSp->FileObject->FsContext;

        status = StVerifyConnectionObject (Connection);

        if (!NT_SUCCESS (status)) {
            return status;
        }

        ConnectionInfo = ExAllocatePool (
                             NonPagedPool,
                             sizeof (TDI_CONNECTION_INFO));

        if (ConnectionInfo == NULL) {

            PANIC ("StQueryInfo: Cannot allocate connection info!\n");
            StWriteResourceErrorLog (DeviceContext, sizeof(TDI_CONNECTION_INFO), 6);
            status = STATUS_INSUFFICIENT_RESOURCES;

        } else if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {

            status = Connection->Status;
            ExFreePool (ConnectionInfo);

        } else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {

            status = STATUS_INVALID_CONNECTION;
            ExFreePool (ConnectionInfo);

        } else {

            RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));

            //
            // Fill in connection information here.
            //

            status = TdiCopyBufferToMdl (
                            (PVOID)ConnectionInfo,
                            0L,
                            sizeof(TDI_CONNECTION_INFO),
                            Irp->MdlAddress,
                            0,
                            &(Irp->IoStatus.Information));

            ExFreePool (ConnectionInfo);
        }

        StDereferenceConnection ("query connection info", Connection);

        break;

    case TDI_QUERY_BROADCAST_ADDRESS:

        //
        // for this provider, the broadcast address is a zero byte name,
        // contained in a Transport address structure.
        //

        broadcastAddress = ExAllocatePool (
                                NonPagedPool,
                                sizeof (TA_NETBIOS_ADDRESS));
        if (broadcastAddress == NULL) {
            PANIC ("StQueryInfo: Cannot allocate broadcast address!\n");
            StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 2);
            status = STATUS_INSUFFICIENT_RESOURCES;
        } else {

            broadcastAddress->TAAddressCount = 1;
            broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
            broadcastAddress->Address[0].AddressLength = 0;

            Irp->IoStatus.Information =
                    sizeof (broadcastAddress->TAAddressCount) +
                    sizeof (broadcastAddress->Address[0].AddressType) +
                    sizeof (broadcastAddress->Address[0].AddressLength);

            status = TdiCopyBufferToMdl (
                            (PVOID)broadcastAddress,
                            0L,
                            Irp->IoStatus.Information,
                            Irp->MdlAddress,
                            0,
                            &(Irp->IoStatus.Information));

            ExFreePool (broadcastAddress);
        }

        break;

    case TDI_QUERY_PROVIDER_INFO:

        status = TdiCopyBufferToMdl (
                    &(DeviceContext->Information),
                    0,
                    sizeof (TDI_PROVIDER_INFO),
                    Irp->MdlAddress,
                    0,
                    &Irp->IoStatus.Information);
        break;

    case TDI_QUERY_PROVIDER_STATISTICS:

        StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);

        if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {

            Irp->IoStatus.Information = 0;
            status = STATUS_BUFFER_OVERFLOW;

        } else {

            ProviderStatistics = ExAllocatePool(
                                   NonPagedPool,
                                   sizeof(TDI_PROVIDER_STATISTICS) +
                                     ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)));

            if (ProviderStatistics == NULL) {

                PANIC ("StQueryInfo: Cannot allocate provider statistics!\n");
                StWriteResourceErrorLog (DeviceContext, sizeof(TDI_PROVIDER_STATISTICS), 7);
                status = STATUS_INSUFFICIENT_RESOURCES;

            } else {

                StStoreProviderStatistics (DeviceContext, ProviderStatistics);

                status = TdiCopyBufferToMdl (
                                (PVOID)ProviderStatistics,
                                0L,
                                sizeof(TDI_PROVIDER_STATISTICS) +
                                  ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
                                Irp->MdlAddress,
                                0,
                                &(Irp->IoStatus.Information));

                ExFreePool (ProviderStatistics);
            }

        }

        break;

    case TDI_QUERY_SESSION_STATUS:

        status = STATUS_NOT_IMPLEMENTED;
        break;

    case TDI_QUERY_ADAPTER_STATUS:

        StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);

        //
        // Determine if this is a local or remote query. It is
        // local if there is no remote address specific at all,
        // or if it is equal to our reserved address.
        //

        if ((query->RequestConnectionInformation != NULL) &&
             (RtlCompareMemory(
                 ((PTA_NETBIOS_ADDRESS)(query->RequestConnectionInformation->RemoteAddress))->
                     Address[0].Address[0].NetbiosName,
                 DeviceContext->ReservedNetBIOSAddress,
                 NETBIOS_NAME_LENGTH) != NETBIOS_NAME_LENGTH)) {

            //
            // Remote, not supported here.
            //

            status = STATUS_NOT_IMPLEMENTED;

        } else {

            //
            // Local.
            //

            adapterStatus = ExAllocatePool (
                                NonPagedPool,
                                TargetBufferLength);

            if (adapterStatus == NULL) {
                PANIC("StQueryInfo: PANIC! Could not allocate adapter status buffer\n");
                StWriteResourceErrorLog (DeviceContext, TargetBufferLength, 3);
                return STATUS_INSUFFICIENT_RESOURCES;
            }

            StStoreAdapterStatus (
                DeviceContext,
                NULL,
                0,
                adapterStatus);

            StStoreNameBuffers (
                DeviceContext,
                (PUCHAR)adapterStatus + sizeof(ADAPTER_STATUS),
                TargetBufferLength - sizeof(ADAPTER_STATUS),
                0,
                &NamesWritten,
                &TotalNameCount,
                &Truncated);

            ((PADAPTER_STATUS)adapterStatus)->name_count = (WORD)TotalNameCount;

            BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));

            status = TdiCopyBufferToMdl (
                        adapterStatus,
                        0,
                        BytesWritten,
                        Irp->MdlAddress,
                        0,
                        &Irp->IoStatus.Information);

            if (Truncated) {
                 status = STATUS_BUFFER_OVERFLOW;
            }

            ExFreePool (adapterStatus);

        }

        break;

    case TDI_QUERY_FIND_NAME:

        //
        // Find name, not supported here.
        //

        status = STATUS_NOT_IMPLEMENTED;
        break;

    default:
        status = STATUS_INVALID_DEVICE_REQUEST;
        break;
    }

    return status;

} /* StTdiQueryInformation */

//
// Quick macros, assumes DeviceContext and ProviderStatistics exist.
//

#define STORE_RESOURCE_STATS_1(_ResourceNum,_ResourceId,_ResourceName) \
{ \
    PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
    RStats->ResourceId = (_ResourceId); \
    RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## MaxInUse; \
    if (DeviceContext->_ResourceName ## Samples > 0) { \
        RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Total / DeviceContext->_ResourceName ## Samples; \
    } else { \
        RStats->AverageResourceUsed = 0; \
    } \
    RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
}

#define STORE_RESOURCE_STATS_2(_ResourceNum,_ResourceId,_ResourceName) \
{ \
    PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
    RStats->ResourceId = (_ResourceId); \
    RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## Allocated; \
    RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Allocated; \
    RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
}


VOID
StStoreProviderStatistics(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PTDI_PROVIDER_STATISTICS ProviderStatistics
    )

/*++

Routine Description:

    This routine writes the TDI_PROVIDER_STATISTICS structure
    from the device context into ProviderStatistics.

Arguments:

    DeviceContext - a pointer to the device context.

    ProviderStatistics - The buffer that holds the result. It is assumed
        that it is long enough.

Return Value:

    None.

--*/

{

    ProviderStatistics->Version = 0x0100;

    //
    // Copy all the statistics from OpenConnections to WastedSpace
    // Packets in one move.
    //

    RtlCopyMemory(
        (PVOID)&(ProviderStatistics->OpenConnections),
        (PVOID)&(DeviceContext->OpenConnections),
        sizeof(TDI_PROVIDER_STATISTICS));

    //
    // Copy the resource statistics.
    //

    ProviderStatistics->NumberOfResources = ST_TDI_RESOURCES;

    STORE_RESOURCE_STATS_1 (0, 12, Address);
    STORE_RESOURCE_STATS_1 (1, 13, AddressFile);
    STORE_RESOURCE_STATS_1 (2, 14, Connection);
    STORE_RESOURCE_STATS_1 (3, 15, Request);

    STORE_RESOURCE_STATS_2 (4, 22, Packet);
    STORE_RESOURCE_STATS_2 (5, 23, ReceivePacket);
    STORE_RESOURCE_STATS_2 (6, 24, ReceiveBuffer);

}   /* StStoreProviderStatistics */


VOID
StStoreAdapterStatus(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PUCHAR SourceRouting,
    IN UINT SourceRoutingLength,
    IN PVOID StatusBuffer
    )

/*++

Routine Description:

    This routine writes the ADAPTER_STATUS structure for the
    device context into StatusBuffer. The name_count field is
    initialized to zero; StStoreNameBuffers is used to write
    name buffers.

Arguments:

    DeviceContext - a pointer to the device context.

    SourceRouting - If this is a remote request, the source
        routing information from the frame.

    SourceRoutingLength - The length of SourceRouting.

    StatusBuffer - The buffer that holds the result. It is assumed
        that it is at least sizeof(ADAPTER_STATUS) bytes long.

Return Value:

    None.

--*/

{

    PADAPTER_STATUS AdapterStatus = (PADAPTER_STATUS)StatusBuffer;
    UINT MaxUserData;

    RtlZeroMemory ((PVOID)AdapterStatus, sizeof(ADAPTER_STATUS));

    RtlCopyMemory (AdapterStatus->adapter_address, DeviceContext->LocalAddress.Address, 6);
    AdapterStatus->rev_major = 0x03;

    switch (DeviceContext->MacInfo.MediumType) {
        case NdisMedium802_5: AdapterStatus->adapter_type = 0xff; break;
        default: AdapterStatus->adapter_type = 0xfe; break;
    }

    AdapterStatus->frmr_recv = 0;
    AdapterStatus->frmr_xmit = 0;

    AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
    AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;

    AdapterStatus->xmit_success = (WORD)(DeviceContext->IFramesSent - DeviceContext->IFramesResent);
    AdapterStatus->recv_success = (WORD)DeviceContext->IFramesReceived;
    AdapterStatus->iframe_recv_err = (WORD)DeviceContext->IFramesRejected;
    AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->IFramesResent;

    AdapterStatus->t1_timeouts = 0;
    AdapterStatus->ti_timeouts = 0;
    AdapterStatus->xmit_aborts = 0;


    AdapterStatus->free_ncbs = 0xffff;
    AdapterStatus->max_cfg_ncbs = 0xffff;
    AdapterStatus->max_ncbs = 0xffff;
    AdapterStatus->pending_sess = (WORD)DeviceContext->OpenConnections;
    AdapterStatus->max_cfg_sess = 0xffff;
    AdapterStatus->max_sess = 0xffff;


    MacReturnMaxDataSize(
        &DeviceContext->MacInfo,
        SourceRouting,
        SourceRoutingLength,
        DeviceContext->MaxSendPacketSize,
        &MaxUserData);

    AdapterStatus->max_dgram_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
    AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - sizeof(ST_HEADER));

    return;

}   /* StStoreAdapterStatus */


VOID
StStoreNameBuffers(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PVOID Buffer,
    IN ULONG BufferLength,
    IN ULONG NamesToSkip,
    OUT PULONG NamesWritten,
    OUT PULONG TotalNameCount OPTIONAL,
    OUT PBOOLEAN Truncated
    )

/*++

Routine Description:

    This routine writes NAME_BUFFER structures for the
    device context into NameBuffer. It can skip a specified
    number of names at the beginning, and returns the number
    of names written into NameBuffer. If a name will only
    partially fit, it is not written.

Arguments:

    DeviceContext - a pointer to the device context.

    NameBuffer - The buffer to write the names into.

    NameBufferLength - The length of NameBuffer.

    NamesToSkip - The number of names to skip.

    NamesWritten - Returns the number of names written.

    TotalNameCount - Returns the total number of names available,
        if specified.

    Truncated - More names are available than were written.

Return Value:

    None.

--*/

{

    ULONG NameCount = 0;
    ULONG BytesWritten = 0;
    KIRQL oldirql;
    PLIST_ENTRY p;
    PNAME_BUFFER NameBuffer = (PNAME_BUFFER)Buffer;
    PTP_ADDRESS address;


    //
    // Spin through the address list for this device context.
    //

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

    p = DeviceContext->AddressDatabase.Flink;

    for (p = DeviceContext->AddressDatabase.Flink;
         p != &DeviceContext->AddressDatabase;
         p = p->Flink) {

        address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);

        //
        // Ignore addresses that are shutting down.
        //

        if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
            continue;
        }

        //
        // Ignore the broadcast address.
        //

        if (address->NetworkName == NULL) {
            continue;
        }

        //
        // Ignore the reserved address.
        //

        if ((address->NetworkName->NetbiosName[0] == 0) &&
            (RtlCompareMemory(
                 address->NetworkName->NetbiosName,
                 DeviceContext->ReservedNetBIOSAddress,
                 NETBIOS_NAME_LENGTH) == NETBIOS_NAME_LENGTH)) {

            continue;
        }

        //
        // Check if we are still skipping.
        //

        if (NameCount < NamesToSkip) {
             ++NameCount;
             continue;
        }

        //
        // Make sure we still have room.
        //

        if (BytesWritten + sizeof(NAME_BUFFER) > BufferLength) {
            break;
        }

        RtlCopyMemory(
            NameBuffer->name,
            address->NetworkName->NetbiosName,
            NETBIOS_NAME_LENGTH);

        ++NameCount;
        NameBuffer->name_num = (UCHAR)NameCount;

        NameBuffer->name_flags = REGISTERED;
        if (address->Flags & ADDRESS_FLAGS_GROUP) {
            NameBuffer->name_flags |= GROUP_NAME;
        }

        // BUGBUG: name_flags should be done more accurately.

        BytesWritten += sizeof(NAME_BUFFER);
        ++NameBuffer;

    }

    *NamesWritten = NameBuffer - (PNAME_BUFFER)Buffer;

    if (p == &DeviceContext->AddressDatabase) {

        *Truncated = FALSE;
        if (ARGUMENT_PRESENT(TotalNameCount)) {
            *TotalNameCount = NameCount;
        }

    } else {

        *Truncated = TRUE;

        //
        // If requested, continue through the list and count
        // all the addresses.
        //

        if (ARGUMENT_PRESENT(TotalNameCount)) {

            for ( ;
                 p != &DeviceContext->AddressDatabase;
                 p = p->Flink) {

                address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);

                //
                // Ignore addresses that are shutting down.
                //

                if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
                    continue;
                }

                //
                // Ignore the broadcast address.
                //

                if (address->NetworkName == NULL) {
                    continue;
                }

                //
                // Ignore the reserved address, since we count it no matter what.
                //

                if ((address->NetworkName->NetbiosName[0] == 0) &&
                    (RtlCompareMemory(
                         address->NetworkName->NetbiosName,
                         DeviceContext->ReservedNetBIOSAddress,
                         NETBIOS_NAME_LENGTH) == NETBIOS_NAME_LENGTH)) {

                    continue;
                }

                ++NameCount;

            }

            *TotalNameCount = NameCount;

        }

    }


    RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);

    return;

}   /* StStoreNameBuffers */


NTSTATUS
StTdiSetInformation(
    IN PIRP Irp
    )

/*++

Routine Description:

    This routine performs the TdiSetInformation request for the transport
    provider.

Arguments:

    Irp - the Irp for the requested operation.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    UNREFERENCED_PARAMETER (Irp);

    return STATUS_NOT_IMPLEMENTED;

} /* StTdiQueryInformation */


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.