summaryrefslogblamecommitdiffstats
path: root/private/ntos/tdi/st/framesnd.c
blob: 0d9f5cff7baf6d2b9617692f8edbf63c0a399ad8 (plain) (tree)


















































































































































































































































































































































































                                                                                                     
/*++

Copyright (c) 1989-1993  Microsoft Corporation

Module Name:

    framesnd.c

Abstract:

    This module contains routines which build and send Sample transport
    frames for other modules.

Environment:

    Kernel mode

Revision History:

--*/

#include "st.h"



NTSTATUS
StSendConnect(
    IN PTP_CONNECTION Connection
    )

/*++

Routine Description:

    This routine sends a CONNECT frame of the appropriate type given the
    state of the specified connection.

Arguments:

    Connection - Pointer to a transport connection object.

Return Value:

    none.

--*/

{
    NTSTATUS Status;
    PDEVICE_CONTEXT DeviceContext;
    PUCHAR SourceRouting;
    UINT SourceRoutingLength;
    UINT HeaderLength;
    PSEND_PACKET_TAG SendTag;
    PTP_PACKET Packet;
    PST_HEADER StHeader;


    DeviceContext = Connection->Provider;

    //
    // Allocate a packet from the pool.
    //

    Status = StCreatePacket (DeviceContext, &Packet);
    if (!NT_SUCCESS (Status)) {                    // couldn't make frame.
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
    SendTag->Type = TYPE_C_FRAME;
    SendTag->Packet = Packet;
    SendTag->Owner = (PVOID)Connection;

    //
    // Build the MAC header.
    //

    //
    // CONNECT frames go out as
    // single-route source routing.
    //

    MacReturnSingleRouteSR(
        &DeviceContext->MacInfo,
        &SourceRouting,
        &SourceRoutingLength);

    MacConstructHeader (
        &DeviceContext->MacInfo,
        Packet->Header,
        DeviceContext->MulticastAddress.Address,
        DeviceContext->LocalAddress.Address,
        sizeof(ST_HEADER),
        SourceRouting,
        SourceRoutingLength,
        &HeaderLength);


    //
    // Build the header: 'C', dest, source
    //

    StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);

    StHeader->Signature = ST_SIGNATURE;
    StHeader->Command = ST_CMD_CONNECT;
    StHeader->Flags = 0;

    RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
    RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);

    HeaderLength += sizeof(ST_HEADER);

    //
    // Modify the packet length and send the it.
    //

    StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);

    StNdisSend (Packet);

    return STATUS_SUCCESS;
} /* StSendConnect */


NTSTATUS
StSendDisconnect(
    IN PTP_CONNECTION Connection
    )

/*++

Routine Description:

    This routine sends a DISCONNECT frame of the appropriate type given the
    state of the specified connection.

Arguments:

    Connection - Pointer to a transport connection object.

Return Value:

    none.

--*/

{
    NTSTATUS Status;
    PDEVICE_CONTEXT DeviceContext;
    PUCHAR SourceRouting;
    UINT SourceRoutingLength;
    UINT HeaderLength;
    PSEND_PACKET_TAG SendTag;
    PTP_PACKET Packet;
    PST_HEADER StHeader;


    DeviceContext = Connection->Provider;

    //
    // Allocate a packet from the pool.
    //

    Status = StCreatePacket (DeviceContext, &Packet);
    if (!NT_SUCCESS (Status)) {                    // couldn't make frame.
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
    SendTag->Type = TYPE_D_FRAME;
    SendTag->Packet = Packet;
    SendTag->Owner = (PVOID)Connection;

    //
    // Build the MAC header.
    //

    //
    // CONNECT frames go out as
    // single-route source routing.
    //

    MacReturnSingleRouteSR(
        &DeviceContext->MacInfo,
        &SourceRouting,
        &SourceRoutingLength);

    MacConstructHeader (
        &DeviceContext->MacInfo,
        Packet->Header,
        DeviceContext->MulticastAddress.Address,
        DeviceContext->LocalAddress.Address,
        sizeof(ST_HEADER),
        SourceRouting,
        SourceRoutingLength,
        &HeaderLength);


    //
    // Build the header: 'D', dest, source
    //

    StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);

    StHeader->Signature = ST_SIGNATURE;
    StHeader->Command = ST_CMD_DISCONNECT;
    StHeader->Flags = 0;

    RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
    RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);

    HeaderLength += sizeof(ST_HEADER);

    //
    // Modify the packet length and send the it.
    //

    StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);

    StNdisSend (Packet);

    return STATUS_SUCCESS;

} /* StSendDisconnect */


NTSTATUS
StSendAddressFrame(
    PTP_ADDRESS Address
    )

/*++

Routine Description:

    It is intended that this routine be used for sending datagrams and
    braodcast datagrams.

    The datagram to be sent is described in the NDIS packet contained
    in the Address. When the send completes, the send completion handler
    returns the NDIS buffer describing the datagram to the buffer pool and
    marks the address ndis packet as usable again. Thus, all datagram
    frames are sequenced through the address they are sent on.

Arguments:

    Address - pointer to the address from which to send this datagram.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    PDEVICE_CONTEXT DeviceContext;


    //
    // Send the packet.
    //

    DeviceContext = Address->Provider;

    INCREMENT_COUNTER (DeviceContext, PacketsSent);

    StNdisSend (Address->Packet);

    return STATUS_PENDING;
} /* StSendAddressFrame */


VOID
StSendDatagramCompletion(
    IN PTP_ADDRESS Address,
    IN PNDIS_PACKET NdisPacket,
    IN NDIS_STATUS NdisStatus
    )

/*++

Routine Description:

    This routine is called as an I/O completion handler at the time a
    StSendUIMdlFrame send request is completed.  Because this handler is only
    associated with StSendUIMdlFrame, and because StSendUIMdlFrame is only
    used with datagrams and broadcast datagrams, we know that the I/O being
    completed is a datagram.  Here we complete the in-progress datagram, and
    start-up the next one if there is one.

Arguments:

    Address - Pointer to a transport address on which the datagram
        is queued.

    NdisPacket - pointer to the NDIS packet describing this request.

Return Value:

    none.

--*/

{
    PTP_REQUEST Request;
    PLIST_ENTRY p;
    KIRQL oldirql;
    PNDIS_BUFFER HeaderBuffer;

    UNREFERENCED_PARAMETER(NdisPacket);

    StReferenceAddress ("Complete datagram", Address);

    //
    // Dequeue the current request and return it to the client.  Release
    // our hold on the send datagram queue.
    //
    // *** There may be no current request, if the one that was queued
    //     was aborted or timed out.
    //

    ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
    p = RemoveHeadList (&Address->SendDatagramQueue);

    if (p != &Address->SendDatagramQueue) {

        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

        Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);

        //
        // Strip off and unmap the buffers describing data and header.
        //

        NdisUnchainBufferAtFront (Address->Packet->NdisPacket, &HeaderBuffer);

        // drop the rest of the packet

        NdisReinitializePacket (Address->Packet->NdisPacket);

        NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
        NdisChainBufferAtFront (Address->Packet->NdisPacket, HeaderBuffer);

        //
        // Ignore NdisStatus; datagrams always "succeed".
        //

        StCompleteRequest (Request, STATUS_SUCCESS, Request->Buffer2Length);

        ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
        Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

        //
        // Send more datagrams on the Address if possible.
        //

        StSendDatagramsOnAddress (Address);       // do more datagrams.

    } else {

        Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

    }

    StDereferenceAddress ("Complete datagram", Address);

} /* StSendDatagramCompletion */