summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/uframes.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/uframes.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/tdi/st/uframes.c')
-rw-r--r--private/ntos/tdi/st/uframes.c980
1 files changed, 980 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/uframes.c b/private/ntos/tdi/st/uframes.c
new file mode 100644
index 000000000..c05f6eaa6
--- /dev/null
+++ b/private/ntos/tdi/st/uframes.c
@@ -0,0 +1,980 @@
+/*++
+
+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));
+
+
+ //
+ // 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 */
+