File:  [WindowsNT SDKs] / ntddk / src / network / tdi / uframes.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:

    uframes.c

Abstract:

    This module contains a routine called StProcessConnectionless,
    that gets control from routines in IND.C when a connectionless
    frame is received.

Environment:

    Kernel mode, DISPATCH_LEVEL.

Revision History:

--*/

#include "st.h"



NTSTATUS
StIndicateDatagram(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PTP_ADDRESS Address,
    IN PUCHAR Header,
    IN ULONG Length
    )

/*++

Routine Description:

    This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame.
    BROADCAST and normal datagrams have the same receive logic, except
    for broadcast datagrams Address will be the broadcast address.

    When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
    this routine will continue to call us for each address for the device
    context.  When we return STATUS_SUCCESS, the caller will switch to the
    next address.  When we return any other status code, including
    STATUS_ABANDONED, the caller will stop distributing the frame.

Arguments:

    DeviceContext - Pointer to our device context.

    Address - Pointer to the transport address object.

    StHeader - Pointer to a buffer that contains the receive datagram.
        The first byte of information is the ST header.

    Length - The length of the MDL pointed to by StHeader.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    NTSTATUS status;
    PLIST_ENTRY p, q;
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    PTP_REQUEST Request;
    ULONG IndicateBytesCopied, MdlBytesCopied;
    KIRQL oldirql;
    TA_NETBIOS_ADDRESS SourceName;
    TA_NETBIOS_ADDRESS DestinationName;
    PTDI_CONNECTION_INFORMATION remoteInformation;
    ULONG returnLength;
    PTP_ADDRESS_FILE addressFile, prevaddressFile;
    PST_HEADER StHeader;

    //
    // If this datagram wasn't big enough for a transport header, then don't
    // let the caller look at any data.
    //

    if (Length < sizeof(ST_HEADER)) {
        return STATUS_ABANDONED;
    }

    //
    // Update our statistics.
    //

    ++DeviceContext->DatagramsReceived;
    ADD_TO_LARGE_INTEGER(
        &DeviceContext->DatagramBytesReceived,
        Length - sizeof(ST_HEADER),
        &DeviceContext->StatisticsSpinLock);


    //
    // Call the client's ReceiveDatagram indication handler.  He may
    // want to accept the datagram that way.
    //

    StHeader = (PST_HEADER)Header;

    TdiBuildNetbiosAddress (StHeader->Source, FALSE, &SourceName);
    TdiBuildNetbiosAddress (StHeader->Destination, FALSE, &DestinationName);


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

    //
    // Find the first open address file in the list.
    //

    p = Address->AddressFileDatabase.Flink;
    while (p != &Address->AddressFileDatabase) {
        addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
        if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
            p = p->Flink;
            continue;
        }
        StReferenceAddressFile(addressFile);
        break;
    }

    while (p != &Address->AddressFileDatabase) {

        //
        // do we have a datagram receive request outstanding? If so, we will
        // satisfy it first.
        //
        // NOTE: We should check if this receive dataframs is for
        // a specific address.
        //

        q = RemoveHeadList (&addressFile->ReceiveDatagramQueue);
        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

        if (q != &addressFile->ReceiveDatagramQueue) {

            Request = CONTAINING_RECORD (q, TP_REQUEST, Linkage);

            //
            // Copy the actual user data.
            //

            MdlBytesCopied = 0;

            status = TdiCopyBufferToMdl (
                         StHeader,
                         sizeof(ST_HEADER),           // offset
                         Length - sizeof(ST_HEADER),  // length
                         Request->IoRequestPacket->MdlAddress,
                         0,
                         &MdlBytesCopied);

            irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
            remoteInformation =
                ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->
                                                        ReturnDatagramInformation;
            if (remoteInformation != NULL) {
                try {
                    if (remoteInformation->RemoteAddressLength != 0) {
                        if (remoteInformation->RemoteAddressLength >=
                                               sizeof (TA_NETBIOS_ADDRESS)) {

                            RtlCopyMemory (
                             (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
                             &SourceName,
                             sizeof (TA_NETBIOS_ADDRESS));

                            returnLength = sizeof(TA_NETBIOS_ADDRESS);
                            remoteInformation->RemoteAddressLength = returnLength;

                        } else {

                            RtlCopyMemory (
                             (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
                             &SourceName,
                             remoteInformation->RemoteAddressLength);

                            returnLength = remoteInformation->RemoteAddressLength;
                            remoteInformation->RemoteAddressLength = returnLength;

                        }

                    } else {

                        returnLength = 0;
                    }

                    status = STATUS_SUCCESS;

                } except (EXCEPTION_EXECUTE_HANDLER) {

                    returnLength = 0;
                    status = GetExceptionCode ();

                }

            }

            StCompleteRequest (Request, STATUS_SUCCESS, MdlBytesCopied);

        } else {

            //
            // no receive datagram requests; is there a kernel client?
            //

            if (addressFile->RegisteredReceiveDatagramHandler) {

                IndicateBytesCopied = 0;

                //
                // Note that we can always set the COPY_LOOKAHEAD
                // flag because we are indicating from our own
                // buffer, not directly from a lookahead indication.
                //

                status = (*addressFile->ReceiveDatagramHandler)(
                             addressFile->ReceiveDatagramHandlerContext,
                             sizeof (TA_NETBIOS_ADDRESS),
                             &SourceName,
                             0,
                             NULL,
                             TDI_RECEIVE_COPY_LOOKAHEAD,
                             Length - sizeof(ST_HEADER),  // indicated
                             Length - sizeof(ST_HEADER),  // available
                             &IndicateBytesCopied,
                             Header + sizeof(ST_HEADER),
                             &irp);

                if (status == STATUS_SUCCESS) {

                    //
                    // The client accepted the datagram and so we're done.
                    //

                } else if (status == STATUS_DATA_NOT_ACCEPTED) {

                    //
                    // The client did not accept the datagram and we need to satisfy
                    // a TdiReceiveDatagram, if possible.
                    //

                    status = STATUS_MORE_PROCESSING_REQUIRED;

                } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {

                    //
                    // The client returned an IRP that we should queue up to the
                    // address to satisfy the request.
                    //

                    irp->IoStatus.Status = STATUS_PENDING;  // init status information.
                    irp->IoStatus.Information = 0;
                    irpSp = IoGetCurrentIrpStackLocation (irp); // get current stack loctn.
                    if ((irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) ||
                        (irpSp->MinorFunction != TDI_RECEIVE_DATAGRAM)) {
                        irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
                        return status;
                    }

                    //
                    // Now copy the actual user data.
                    //

                    MdlBytesCopied = 0;

                    status = TdiCopyBufferToMdl (
                                 StHeader,
                                 sizeof(ST_HEADER) + IndicateBytesCopied,
                                 Length - sizeof(ST_HEADER) - IndicateBytesCopied,
                                 irp->MdlAddress,
                                 0,
                                 &MdlBytesCopied);

                    irp->IoStatus.Information = MdlBytesCopied;
                    irp->IoStatus.Status = status;
                    IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
                }
            }
        }

        //
        // Save this to dereference it later.
        //

        prevaddressFile = addressFile;

        //
        // Reference the next address file on the list, so it
        // stays around.
        //

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

        p = p->Flink;
        while (p != &Address->AddressFileDatabase) {
            addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
            if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
                p = p->Flink;
                continue;
            }
            StReferenceAddressFile(addressFile);
            break;
        }

        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

        //
        // Now dereference the previous address file with
        // the lock released.
        //

        StDereferenceAddressFile (prevaddressFile);

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

    }    // end of while loop

    RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

    return status;                      // to dispatcher.
} /* StIndicateDatagram */


NTSTATUS
StProcessConnect(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PTP_ADDRESS Address,
    IN PST_HEADER Header,
    IN PHARDWARE_ADDRESS SourceAddress,
    IN PUCHAR SourceRouting,
    IN UINT SourceRoutingLength
    )

/*++

Routine Description:

    This routine processes an incoming connect frame. It scans for
    posted listens, otherwise it indicates to connect handlers
    on this address if they are registered.

Arguments:

    DeviceContext - Pointer to our device context.

    Address - Pointer to the transport address object.

    Header - Pointer to the ST header of the frame.

    SourceAddress - Pointer to the source hardware address in the received
        frame.

    SourceRouting - Pointer to the source routing information in
        the frame.

    SourceRoutingLength - Length of the source routing information.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    KIRQL oldirql, oldirql1, cancelirql;
    NTSTATUS status;
    PTP_CONNECTION Connection;
    BOOLEAN ConnectIndicationBlocked = FALSE;
    PLIST_ENTRY p;
    BOOLEAN UsedListeningConnection = FALSE;
    PTP_ADDRESS_FILE addressFile, prevaddressFile;

    PTP_REQUEST request;
    PIO_STACK_LOCATION irpSp;
    ULONG returnLength;
    PTDI_CONNECTION_INFORMATION remoteInformation;
    TA_NETBIOS_ADDRESS TempAddress;
    PIRP acceptIrp;

    CONNECTION_CONTEXT connectionContext;

    //
    // If we are just registering or deregistering this address, then don't
    // allow state changes.  Just throw the packet away, and let the frame
    // distributor try the next address.
    //

    if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING)) {
        return STATUS_SUCCESS;
    }

    //
    // This is an incoming connection request.  If we have a listening
    // connection on this address, then continue with the connection setup.
    // If there is no outstanding listen, then indicate any kernel mode
    // clients that want to know about this frame. If a listen was posted,
    // then a connection has already been set up for it.
    //

    //
    // First, check if we already have an active connection with
    // this remote on this address. If so, we ignore this
    // (NOTE: This is not the correct behaviour for a real
    // transport).
    //

    //
    // If successful this adds a reference.
    //

    if (Connection = StLookupRemoteName(Address, Header->Source)) {

        StDereferenceConnection ("Lookup done", Connection);
        return STATUS_ABANDONED;

    }

    // If successful, this adds a reference which is removed before
    // this function returns.

    Connection = StLookupListeningConnection (Address);
    if (Connection == NULL) {

        //
        // not having a listening connection is not reason to bail out here.
        // we need to indicate to the user that a connect attempt occurred,
        // and see if there is a desire to use this connection. We
        // indicate in order to all address files that are
        // using this address.
        //
        // If we already have an indication pending on this address,
        // we ignore this frame (the NAME_QUERY may have come from
        // a different address, but we can't know that). Also, if
        // there is already an active connection on this remote
        // name, then we ignore the frame.
        //


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

        p = Address->AddressFileDatabase.Flink;
        while (p != &Address->AddressFileDatabase) {
            addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
            if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
                p = p->Flink;
                continue;
            }
            StReferenceAddressFile(addressFile);
            break;
        }

        while (p != &Address->AddressFileDatabase) {

            RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

            if ((addressFile->RegisteredConnectionHandler == TRUE) &&
                (!addressFile->ConnectIndicationInProgress)) {


                TdiBuildNetbiosAddress (
                    Header->Source,
                    FALSE,
                    &TempAddress);

                addressFile->ConnectIndicationInProgress = TRUE;

                //
                // we have a connection handler, now indicate that a connection
                // attempt occurred.
                //

                status = (addressFile->ConnectionHandler)(
                             addressFile->ConnectionHandlerContext,
                             sizeof (TDI_ADDRESS_NETBIOS),
                             &TempAddress,
                             0,
                             NULL,
                             0,
                             NULL,
                             &connectionContext,
                             &acceptIrp);

                if (status == STATUS_MORE_PROCESSING_REQUIRED) {

                    // the user has connected a currently open connection, but
                    // we have to figure out which one it is.
                    //

                    //
                    // If successful this adds a reference of type LISTENING
                    // (the same what StLookupListeningConnection adds).
                    //

                    Connection = StLookupConnectionByContext (
                                    Address,
                                    connectionContext);

                    if (Connection == NULL) {

                        //
                        // BUGBUG: We have to tell the client that
                        // his connection is bogus (or has this
                        // already happened??).
                        //

                        StPrint0("MORE_PROCESSING_REQUIRED, connection not found\n");
                        addressFile->ConnectIndicationInProgress = FALSE;
                        acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
                        IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);

                        goto whileend;    // try next address file

                    } else {

                        if (Connection->AddressFile->Address != Address) {
                            addressFile->ConnectIndicationInProgress = FALSE;

                            StPrint0("MORE_PROCESSING_REQUIRED, address wrong\n");
                            StStopConnection (Connection, STATUS_INVALID_ADDRESS);
                            StDereferenceConnection("Bad Address", Connection);
                            Connection = NULL;
                            acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
                            IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);

                            goto whileend;    // try next address file
                        }

                        //
                        // OK, we have a valid connection. If the response to
                        // this connection was disconnect, we need to reject
                        // the connection request and return. If it was accept
                        // or not specified (to be done later), we simply
                        // fall through and continue processing on the U Frame.
                        //

                        ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
                        if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {

                            Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT;
                            RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
                            StPrint0("MORE_PROCESSING_REQUIRED, disconnect\n");
                            addressFile->ConnectIndicationInProgress = FALSE;
                            StDereferenceConnection("Disconnecting", Connection);
                            Connection = NULL;
                            acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
                            IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);

                            goto whileend;    // try next address file
                        }

                    }

                    //
                    // This connection is ready.
                    //

                    Connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
                    Connection->Status = STATUS_PENDING;
                    Connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;

                    Connection->Flags |= CONNECTION_FLAGS_READY;
                    INCREMENT_COUNTER (Connection->Provider, OpenConnections);

                    Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;

                    StReferenceConnection("Indication completed", Connection);

                    RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);

                    //
                    // Make a note that we have to set
                    // addressFile->ConnectIndicationInProgress to
                    // FALSE once the address is safely stored
                    // in the connection.
                    //

                    ConnectIndicationBlocked = TRUE;
                    StDereferenceAddressFile (addressFile);
                    ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
                    break;    // exit the while

                } else if (status == STATUS_INSUFFICIENT_RESOURCES) {

                    //
                    // we know the address, but can't create a connection to
                    // use on it. This gets passed to the network as a response
                    // saying I'm here, but can't help.
                    //

                    addressFile->ConnectIndicationInProgress = FALSE;

                    StDereferenceAddressFile (addressFile);
                    return STATUS_ABANDONED;

                } else {

                    addressFile->ConnectIndicationInProgress = FALSE;
                    goto whileend;    // try next address file

                } // end status ifs

            } else {

                goto whileend;     // try next address file

            } // end no indication handler

whileend:
            //
            // Jumping here is like a continue, except that the
            // addressFile pointer is advanced correctly.
            //

            //
            // Save this to dereference it later.
            //

            prevaddressFile = addressFile;

            //
            // Reference the next address file on the list, so it
            // stays around.
            //

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

            p = p->Flink;
            while (p != &Address->AddressFileDatabase) {
                addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
                if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
                    p = p->Flink;
                    continue;
                }
                StReferenceAddressFile(addressFile);
                break;
            }

            RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

            //
            // Now dereference the previous address file with
            // the lock released.
            //

            StDereferenceAddressFile (prevaddressFile);

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

        } // end of loop through the address files.

        RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);

        if (Connection == NULL) {

            //
            // We used to return MORE_PROCESSING_REQUIRED, but
            // since we matched with this address, no other
            // address is going to match, so abandon it.
            //

            return STATUS_ABANDONED;

        }

    } else { // end connection == null

        UsedListeningConnection = TRUE;

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

        p = RemoveHeadList (&Connection->InProgressRequest);
        if (p == &Connection->InProgressRequest) {

            Connection->IndicationInProgress = FALSE;
            RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
            IoReleaseCancelSpinLock (cancelirql);
            return STATUS_SUCCESS;

        }

        //
        // If this listen indicated that we should wait for a
        // TdiAccept, then do that, otherwise the connection is
        // ready.
        //

        if ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) == 0) {

            Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_ACCEPT;

        } else {

            Connection->Flags |= CONNECTION_FLAGS_READY;
            INCREMENT_COUNTER (Connection->Provider, OpenConnections);

            Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;

            StReferenceConnection("Listen completed", Connection);

        }

        //
        // We have a completed connection with a queued listen. Complete
        // the listen and let the user do an accept at some time down the
        // road.
        //

        RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);

        request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
        request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
        IoReleaseCancelSpinLock (cancelirql);

        irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
        remoteInformation =
            ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
        if (remoteInformation != NULL) {
            try {
                if (remoteInformation->RemoteAddressLength != 0) {

                    //
                    // Build a temporary TA_NETBIOS_ADDRESS, then
                    // copy over as many bytes as fit.
                    //

                    TdiBuildNetbiosAddress(
                        Connection->CalledAddress.NetbiosName,
                        (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
                            TDI_ADDRESS_NETBIOS_TYPE_GROUP),
                        &TempAddress);

                    if (remoteInformation->RemoteAddressLength >=
                                           sizeof (TA_NETBIOS_ADDRESS)) {

                        returnLength = sizeof(TA_NETBIOS_ADDRESS);
                        remoteInformation->RemoteAddressLength = returnLength;

                    } else {

                        returnLength = remoteInformation->RemoteAddressLength;

                    }

                    RtlCopyMemory(
                        (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
                        &TempAddress,
                        returnLength);

                } else {

                    returnLength = 0;
                }

                status = STATUS_SUCCESS;

            } except (EXCEPTION_EXECUTE_HANDLER) {

                returnLength = 0;
                status = GetExceptionCode ();

            }

        } else {

            status = STATUS_SUCCESS;
            returnLength = 0;

        }

        //
        // Don't clear this until now, so that the connection is all
        // set up before we allow more indications.
        //

        Connection->IndicationInProgress = FALSE;

        StCompleteRequest (request, status, 0);

    }


    //
    // Before we continue, store the remote guy's transport address
    // into the TdiListen's TRANSPORT_CONNECTION buffer.  This allows
    // the client to determine who called him.
    //

    Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
    NdisMoveFromMappedMemory(
        Connection->CalledAddress.NetbiosName,
        Header->Source,
        16);

    NdisMoveFromMappedMemory(
        Connection->RemoteName,
        Header->Source,
        16);

    Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;

    if (ConnectIndicationBlocked) {
        addressFile->ConnectIndicationInProgress = FALSE;
    }

    StDereferenceConnection("ProcessNameQuery done", Connection);

    return STATUS_ABANDONED;

}   /* StProcessConnect */


NTSTATUS
StProcessConnectionless(
    IN PDEVICE_CONTEXT DeviceContext,
    IN PHARDWARE_ADDRESS SourceAddress,
    IN PST_HEADER StHeader,
    IN ULONG StLength,
    IN PUCHAR SourceRouting,
    IN UINT SourceRoutingLength,
    OUT PTP_ADDRESS * DatagramAddress
    )

/*++

Routine Description:

    This routine receives control from the data link provider as an
    indication that a connectionless frame has been received on the data link.
    Here we dispatch to the correct handler.

Arguments:

    DeviceContext - Pointer to our device context.

    SourceAddress - Pointer to the source hardware address in the received
        frame.

    StHeader - Points to the ST header of the incoming packet.

    StLength - Actual length in bytes of the packet, starting at the
        StHeader.

    SourceRouting - Source routing information in the MAC header.

    SourceRoutingLength - The length of SourceRouting.

    DatagramAddress - If this function returns STATUS_MORE_PROCESSING_
        REQUIRED, this will be the address the datagram should be
        indicated to.

Return Value:

    NTSTATUS - status of operation.

--*/

{
    PTP_ADDRESS Address;
    KIRQL oldirql;
    NTSTATUS status;
    PLIST_ENTRY Flink;
    BOOLEAN MatchedAddress;
    PUCHAR MatchName;

    //
    // Verify that this frame is long enough to examine.
    //

    if (StLength < sizeof(ST_HEADER)) {
        return STATUS_ABANDONED;        // frame too small.
    }

    //
    // We have a valid connectionless protocol frame that's not a
    // datagram, so deliver it to every address which matches the
    // destination name in the frame.
    //

    MatchedAddress = FALSE;

    //
    // Search for the address; for broadcast datagrams we
    // search for the special "broadcast" address.
    //

    if ((StHeader->Command == ST_CMD_DATAGRAM) &&
        (StHeader->Flags & ST_FLAGS_BROADCAST)) {

        MatchName = NULL;

    } else {

        MatchName = StHeader->Destination;

    }

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

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

        Address = CONTAINING_RECORD (
                    Flink,
                    TP_ADDRESS,
                    Linkage);

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

        if (StMatchNetbiosAddress (Address, MatchName)) {

            StReferenceAddress ("UI Frame", Address);   // prevent address from being destroyed.
            MatchedAddress = TRUE;
            break;

        }
    }

    RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);

    if (MatchedAddress) {

        //
        // Deliver the frame to the current address.
        //

        switch (StHeader->Command) {

        case ST_CMD_CONNECT:

            status = StProcessConnect (
                         DeviceContext,
                         Address,
                         StHeader,
                         SourceAddress,
                         SourceRouting,
                         SourceRoutingLength);

            break;

        case ST_CMD_DATAGRAM:

            //
            // Reference the datagram so it sticks around until the
            // ReceiveComplete, when it is processed.
            //

            StReferenceAddress ("Datagram indicated", Address);
            *DatagramAddress = Address;
            status = STATUS_MORE_PROCESSING_REQUIRED;
            break;

        default:

            ASSERT(FALSE);

        } /* switch on frame command code */

        StDereferenceAddress ("Done", Address);     // done with previous address.

    } else {

        status = STATUS_ABANDONED;

    }

    return status;

} /* StProcessConnectionless */


unix.superglobalmegacorp.com

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