summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/uframes.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/nbf/uframes.c2974
1 files changed, 2974 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/uframes.c b/private/ntos/tdi/nbf/uframes.c
new file mode 100644
index 000000000..654f92ff6
--- /dev/null
+++ b/private/ntos/tdi/nbf/uframes.c
@@ -0,0 +1,2974 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ uframes.c
+
+Abstract:
+
+ This module contains a routine called NbfProcessUi, that gets control
+ from routines in DLC.C when a DLC UI frame is received. Here we
+ decode the encapsulated connectionless NetBIOS frame and dispatch
+ to the correct NetBIOS frame handler.
+
+ The following frame types are cracked by routines in this module:
+
+ o NBF_CMD_ADD_GROUP_NAME_QUERY
+ o NBF_CMD_ADD_NAME_QUERY
+ o NBF_CMD_NAME_IN_CONFLICT
+ o NBF_CMD_STATUS_QUERY
+ o NBF_CMD_TERMINATE_TRACE
+ o NBF_CMD_DATAGRAM
+ o NBF_CMD_DATAGRAM_BROADCAST
+ o NBF_CMD_NAME_QUERY
+ o NBF_CMD_ADD_NAME_RESPONSE
+ o NBF_CMD_NAME_RECOGNIZED
+ o NBF_CMD_STATUS_RESPONSE
+ o NBF_CMD_TERMINATE_TRACE2
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbfListenTimeout(
+ 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 the timeout
+ period for the session setup after listening a connection occurs. This
+ will occur if the remote has discovered our name and we do not get a
+ connection started within some reasonable period of time. In this
+ routine we simply tear down the connection (and, most likely, the link
+ associated with it).
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_CONNECTION block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ Connection = (PTP_CONNECTION)DeferredContext;
+
+ //
+ // If this connection is being run down, then we can't do anything.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) == 0)) {
+
+ //
+ // The connection is stopping, or the SESSION_INITIALIZE
+ // has already been processed.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx stopping.\n",
+ Connection);
+ }
+
+ NbfDereferenceConnection ("Listen timeout, ignored", Connection, CREF_TIMER);
+ LEAVE_NBF;
+ return;
+ }
+
+ //
+ // We connected to the link before sending the NAME_RECOGNIZED,
+ // so we disconnect from it now.
+ //
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName, localName;
+ remoteName.Length = NETBIOS_NAME_LENGTH - 1;
+ remoteName.Buffer = Connection->RemoteName;
+ localName.Length = NETBIOS_NAME_LENGTH - 1;
+ localName.Buffer = Connection->AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "NbfListenTimeout disconnecting connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+
+ //
+ // BUBGUG: This is really ugly and I doubt it is correct.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_ACCEPTED) != 0) {
+
+ //
+ // This connection is up, we stop it.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, accepted.\n",
+ Connection);
+ }
+
+ //
+ // Set this so that the client will get a disconnect
+ // indication.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
+
+ } else if (Connection->Link != (PTP_LINK)NULL) {
+
+ //
+ // This connection is from a listen...we want to
+ // silently reset the listen.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, listen restarted.\n",
+ Connection);
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SI;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfDereferenceConnection ("Timeout", Connection, CREF_LINK);
+ (VOID)NbfDisconnectFromLink (Connection, FALSE);
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("ListenTimeout: connection %lx, link down.\n",
+ Connection);
+ }
+
+ }
+
+
+ NbfDereferenceConnection("Listen Timeout", Connection, CREF_TIMER);
+
+ LEAVE_NBF;
+ return;
+
+} /* ListenTimeout */
+
+
+NTSTATUS
+ProcessAddGroupNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_GROUP_NAME_QUERY frame. Because
+ our caller has already verified that the destination name in the frame
+ matches the transport address passed to us, we must simply transmit an
+ ADD_NAME_RESPONSE frame and exit with STATUS_ABANDONED.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ PTP_UI_FRAME RawFrame; // ptr to allocated connectionless frame.
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ UNREFERENCED_PARAMETER (SourceAddress);
+ UNREFERENCED_PARAMETER (Address);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessAddGroupNameQuery %lx: [%.16s].\n", Address, Header->DestinationName);
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ if (NbfCreateConnectionlessFrame (DeviceContext, &RawFrame) != STATUS_SUCCESS) {
+ return STATUS_ABANDONED; // no resources to do this.
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_RESPONSE frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructAddNameResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // type of name is UNIQUE.
+ RESPONSE_CORR(Header), // correlator from rec'd frame.
+ (PUCHAR)Header->SourceName); // NetBIOS name being responded to.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback.
+
+ return STATUS_ABANDONED; // don't forward frame to other addr's.
+} /* ProcessAddGroupNameQuery */
+
+
+NTSTATUS
+ProcessAddNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_NAME_QUERY frame. Because
+ our caller has already verified that the destination name in the frame
+ matches the transport address passed to us, we must simply transmit an
+ ADD_NAME_RESPONSE frame and exit with STATUS_ABANDONED.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ PTP_UI_FRAME RawFrame; // ptr to allocated connectionless frame.
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ Address, SourceAddress; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessAddNameQuery %lx: [%.16s].\n", Address, Header->DestinationName);
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ if (NbfCreateConnectionlessFrame (DeviceContext, &RawFrame) != STATUS_SUCCESS) {
+ return STATUS_ABANDONED; // no resources to do this.
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_RESPONSE frames go out as
+ // non-broadcast source routing.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructAddNameResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // type of name is UNIQUE.
+ RESPONSE_CORR(Header), // correlator from received frame.
+ (PUCHAR)Header->SourceName); // NetBIOS name being responded to
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback.
+
+ return STATUS_ABANDONED; // don't forward frame to other addr's.
+} /* ProcessAddNameQuery */
+
+
+NTSTATUS
+ProcessNameInConflict(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_IN_CONFLICT frame.
+ Although we can't disrupt any traffic on this address, it is considered
+ invalid and cannot be used for any new address files or new connections.
+ Therefore, we just mark the address as invalid.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ DeviceContext, Header, SourceAddress; // prevent compiler warnings
+
+
+ //
+ // Ignore this if we are registering/deregistering (the name will
+ // go away anyway) or if we have already marked this name as
+ // in conflict and logged an error.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameInConflict %lx: address marked [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameInConflict %lx: [%.16s].\n", Address, Header->SourceName);
+ }
+
+#if 0
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ DbgPrint ("NBF: Name-in-conflict on <%.16s> from ", Header->DestinationName);
+ DbgPrint ("%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ SourceAddress->Address[0],
+ SourceAddress->Address[1],
+ SourceAddress->Address[2],
+ SourceAddress->Address[3],
+ SourceAddress->Address[4],
+ SourceAddress->Address[5]);
+#endif
+
+ NbfWriteGeneralErrorLog(
+ Address->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 2,
+ STATUS_DUPLICATE_NAME,
+ L"NAME_IN_CONFLICT",
+ 16/sizeof(ULONG),
+ (PULONG)(Header->DestinationName));
+
+ return STATUS_ABANDONED;
+
+} /* ProcessNameInConflict */
+
+
+NTSTATUS
+NbfIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Dsdu,
+ 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.
+
+ Dsdu - Pointer to a Mdl buffer that contains the received datagram.
+ The first byte of information in the buffer is the first byte in
+ the NetBIOS connectionless header, and it is already negotiated that
+ the data link layer will provide at least the entire NetBIOS header
+ as contiguous data.
+
+ Length - The length of the MDL pointed to by Dsdu.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PLIST_ENTRY p, q;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ ULONG IndicateBytesCopied, MdlBytesCopied, BytesToCopy;
+ TA_NETBIOS_ADDRESS SourceName;
+ TA_NETBIOS_ADDRESS DestinationName;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ ULONG returnLength;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PNBF_HDR_CONNECTIONLESS Header = (PNBF_HDR_CONNECTIONLESS)Dsdu;
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Entered.\n");
+ }
+
+ //
+ // If this datagram wasn't big enough for a transport header, then don't
+ // let the caller look at any data.
+ //
+
+ if (Length < sizeof(NBF_HDR_CONNECTIONLESS)) {
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Short datagram abandoned.\n");
+ }
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Update our statistics.
+ //
+
+ ++DeviceContext->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DatagramBytesReceived,
+ Length - sizeof(NBF_HDR_CONNECTIONLESS));
+
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress ((PUCHAR)Header->SourceName, FALSE, &SourceName);
+ TdiBuildNetbiosAddress ((PUCHAR)Header->DestinationName, FALSE, &DestinationName);
+
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // 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;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = addressFile->ReceiveDatagramQueue.Flink;
+ q != &addressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ irp = CONTAINING_RECORD (q, IRP, Tail.Overlay.ListEntry);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ &((IoGetCurrentIrpStackLocation(irp))->
+ Parameters))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbfParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ Header->SourceName,
+ DatagramAddress->NetbiosName,
+ NETBIOS_NAME_LENGTH))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &addressFile->ReceiveDatagramQueue) {
+ KIRQL cancelIrql;
+
+
+ RemoveEntryList (q);
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Receive datagram request found, copying.\n");
+ }
+
+ //
+ // Copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ BytesToCopy = Length - sizeof(NBF_HDR_CONNECTIONLESS);
+
+ if (BytesToCopy > 0) {
+ status = TdiCopyBufferToMdl (
+ Dsdu,
+ sizeof(NBF_HDR_CONNECTIONLESS), // offset
+ BytesToCopy, // length
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+ 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 ();
+
+ }
+
+ }
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Receive DG done", Address, AREF_REQUEST);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // no receive datagram requests; is there a kernel client?
+ //
+
+ if (addressFile->RegisteredReceiveDatagramHandler) {
+
+ IndicateBytesCopied = 0;
+
+ status = (*addressFile->ReceiveDatagramHandler)(
+ addressFile->ReceiveDatagramHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ Length - sizeof(NBF_HDR_CONNECTIONLESS), // indicated
+ Length - sizeof(NBF_HDR_CONNECTIONLESS), // available
+ &IndicateBytesCopied,
+ Dsdu + sizeof(NBF_HDR_CONNECTIONLESS),
+ &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.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint0 ("NbfIndicateDatagram: Picking off a rcv datagram request from this address.\n");
+ }
+ 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;
+
+ BytesToCopy = Length - sizeof(NBF_HDR_CONNECTIONLESS) - IndicateBytesCopied;
+
+ if (BytesToCopy > 0) {
+ status = TdiCopyBufferToMdl (
+ Dsdu,
+ sizeof(NBF_HDR_CONNECTIONLESS) + IndicateBytesCopied,
+ BytesToCopy,
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = status;
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+ }
+ }
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ 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;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ NbfDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ } // end of while loop
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ return status; // to dispatcher.
+} /* NbfIndicateDatagram */
+
+
+NTSTATUS
+ProcessNameQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_QUERY frame. There are two
+ types of NAME_QUERY frames, with basically the same layout. If the
+ session number in the frame is 0, then the frame is really a request
+ for information about the name, and not a request to establish a
+ session. If the session number is non-zero, then the frame is a
+ connection request that we use to satisfy a listen.
+
+ With the new version of TDI, we now indicate the user that a request
+ for connection has been received, iff there is no outstanding listen.
+ If this does occur, the user can return a connection that is to be used
+ to accept the connection on.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_UI_FRAME RawFrame;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+ UCHAR NameType;
+ BOOLEAN ConnectIndicationBlocked = FALSE;
+ PLIST_ENTRY p;
+ UINT HeaderLength;
+ PUCHAR GeneralSR;
+ UINT GeneralSRLength;
+ BOOLEAN UsedListeningConnection = FALSE;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PIRP acceptIrp;
+
+ CONNECTION_CONTEXT connectionContext;
+ TA_NETBIOS_ADDRESS RemoteAddress;
+
+ //
+ // 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.
+ //
+ // Also drop it if the address is in conflict.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: address not stable [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Process this differently depending on whether it is a find name
+ // request or an incoming connection.
+ //
+
+ if (Header->Data2Low == 0) {
+
+ //
+ // This is a find-name request. Respond with a NAME_RECOGNIZED frame.
+ //
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: find name [%.16s].\n", Address, Header->SourceName);
+ }
+
+ NbfSendNameRecognized(
+ Address,
+ 0, // LSN 0 == FIND_NAME response
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ return STATUS_ABANDONED; // don't allow multiple responses.
+
+ } else { // (if Data2Low is non-zero)
+
+ //
+ // 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. The LSN field of
+ // the connection is set to 0, so we look for the first 0 LSN in the
+ // database.
+ //
+
+ //
+ // First, check if we already have an active connection with
+ // this remote on this address. If so, we resend the NAME_RECOGNIZED
+ // if we have not yet received the SESSION_INITIALIZE; otherwise
+ // we ignore the frame.
+ //
+
+ //
+ // If successful this adds a reference of type CREF_LISTENING.
+ //
+
+ if (Connection = NbfLookupRemoteName(Address, (PUCHAR)Header->SourceName, Header->Data2Low)) {
+
+ //
+ // We have an active connection on this guy, see if he
+ // still appears to be waiting to a NAME_RECOGNIZED.
+ //
+
+ if (((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) &&
+ (Connection->Link != (PTP_LINK)NULL) &&
+ (Connection->Link->State == LINK_STATE_ADM)) {
+
+ //
+ // Yes, he must have dropped a previous NAME_RECOGNIZED
+ // so we send another one.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2("Dup NAME_QUERY found: %lx [%.16s]\n", Connection, Header->SourceName);
+ }
+
+ NbfSendNameRecognized(
+ Address,
+ Connection->Lsn,
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2("Dup NAME_QUERY ignored: %lx [%.16s]\n", Connection, Header->SourceName);
+ }
+
+ }
+
+ NbfDereferenceConnection ("Lookup done", Connection, CREF_LISTENING);
+
+ return STATUS_ABANDONED;
+
+ }
+
+ // If successful, this adds a reference which is removed before
+ // this function returns.
+
+ Connection = NbfLookupListeningConnection (Address, (PUCHAR)Header->SourceName);
+ 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_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ 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;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if ((addressFile->RegisteredConnectionHandler == TRUE) &&
+ (!addressFile->ConnectIndicationInProgress)) {
+
+
+ TdiBuildNetbiosAddress (
+ (PUCHAR)Header->SourceName,
+ FALSE,
+ &RemoteAddress);
+
+ addressFile->ConnectIndicationInProgress = TRUE;
+
+ //
+ // we have a connection handler, now indicate that a connection
+ // attempt occurred.
+ //
+
+ status = (addressFile->ConnectionHandler)(
+ addressFile->ConnectionHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &RemoteAddress,
+ 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 NbfLookupListeningConnection adds).
+ //
+
+ Connection = NbfLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ NbfPrint0("STATUS_MORE_PROCESSING, 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;
+
+ NbfPrint0("STATUS_MORE_PROCESSING, address wrong\n");
+ NbfStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ NbfDereferenceConnection("Bad Address", Connection, CREF_LISTENING);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_ADDRESS;
+ 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_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+// Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfPrint0("STATUS_MORE_PROCESSING, disconnect\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ NbfDereferenceConnection("Disconnecting", Connection, CREF_LISTENING);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ }
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectIndicationInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint4 ("ProcessNameQuery %lx: indicate DONE, context %lx conn %lx [%.16s].\n", Address, connectionContext, Connection, Header->SourceName);
+ }
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint6 ("Link is %x-%x-%x-%x-%x-%x\n",
+ SourceAddress->Address[0],
+ SourceAddress->Address[1],
+ SourceAddress->Address[2],
+ SourceAddress->Address[3],
+ SourceAddress->Address[4],
+ SourceAddress->Address[5]);
+ }
+
+ //
+ // Set up our flags...we turn on REQ_COMPLETED
+ // so that disconnect will be indicated if the
+ // connection goes down before a session init
+ // is received.
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
+ Connection->Status = STATUS_PENDING;
+ Connection->Flags2 |= (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_REQ_COMPLETED);
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ ConnectIndicationBlocked = TRUE;
+ NbfDereferenceAddressFile (addressFile);
+ acceptIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+ break; // exit the while
+
+#if 0
+ } else if (status == STATUS_EVENT_PENDING) {
+
+ //
+ // user has returned a connectionContext, use that for further
+ // processing of the connection. First validate it so
+ // we can know we won't just start a connection and never
+ // finish.
+ //
+ //
+ // If successful this adds a reference of type LISTENING
+ // (the same what NbfLookupListeningConnection adds).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameQuery %lx: indicate PENDING, context %lx [%.16s].\n", Address, connectionContext, Header->SourceName);
+ }
+
+
+ Connection = NbfLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ NbfPrint0("STATUS_MORE_PROCESSING, but connection not found\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ goto whileend; // try next address file.
+
+ } else {
+
+ if (Connection->AddressFile->Address != Address) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ NbfStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ NbfDereferenceConnection("Bad Address", Connection, CREF_LISTENING);
+ Connection = NULL;
+
+ goto whileend; // try next address file.
+ }
+
+ }
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectionIndicatInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ ConnectIndicationBlocked = TRUE;
+ NbfDereferenceAddressFile (addressFile);
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+ break; // exit the while
+#endif
+
+ } 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.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: indicate RESOURCES [%.16s].\n", Address, Header->SourceName);
+ }
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ //
+ // We should send a NR with LSN 0xff, indicating
+ // no resources, but LM 2.0 does not interpret
+ // that correctly. So, we send LSN 0 (no listens)
+ // instead.
+ //
+
+ NbfSendNameRecognized(
+ Address,
+ 0,
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ NbfDereferenceAddressFile (addressFile);
+ return STATUS_ABANDONED;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: indicate invalid [%.16s].\n", Address, Header->SourceName);
+ }
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ goto whileend; // try next address file
+
+ } // end status ifs
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: no handler [%.16s].\n", Address, Header->SourceName);
+ }
+
+ 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_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ 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;
+ }
+ NbfReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ NbfDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ } // end of loop through the address files.
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (Connection == NULL) {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameQuery %lx: no connection [%.16s].\n", Address, Header->SourceName);
+ }
+
+ //
+ // We still did not find a connection after looping
+ // through the address files.
+ //
+
+ NbfSendNameRecognized(
+ Address,
+ 0, // LSN 0 == No listens
+ Header,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ //
+ // 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;
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameQuery %lx: found listen %lx: [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ }
+
+
+ //
+ // At this point the connection has a reference of type
+ // CREF_LISTENING. Allocate a UI frame from the pool.
+ //
+
+ status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (status)) { // no resources to respond.
+ PANIC ("ProcessNameQuery: Can't get UI Frame, dropping query\n");
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+ if (UsedListeningConnection) {
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ;
+ } else {
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ }
+ NbfDereferenceConnection("Can't get UI Frame", Connection, CREF_LISTENING);
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Build the MAC header. NAME_RECOGNIZED frames go out as
+ // general-route source routing.
+ //
+
+ MacReturnGeneralRouteSR(
+ &DeviceContext->MacInfo,
+ &GeneralSR,
+ &GeneralSRLength);
+
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ GeneralSR,
+ GeneralSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // 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;
+
+ TdiCopyLookaheadData(
+ Connection->CalledAddress.NetbiosName,
+ Header->SourceName,
+ 16,
+ DeviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 );
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+
+ //
+ // Now formulate a reply.
+ //
+
+ NameType = (UCHAR)((Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ //
+ // We have a listening connection on the address now. Create a link
+ // for it to be associated with and make that link ready. Respond to
+ // the sender with a name_recognized frame. then we will receive our
+ // first connection-oriented frame, SESSION_INITIALIZE, handled
+ // in IFRAMES.C. Then we respond with SESSION_CONFIRM, and then
+ // the TdiListen completes.
+ //
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink. It does NOT add a link reference.
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ LISTENER_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (NT_SUCCESS (status)) { // link established.
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference
+ // which is removed in NbfDisconnectFromLink
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) &&
+ ((status = NbfConnectToLink (Link, Connection)) == STATUS_SUCCESS)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SI; // wait for SI.
+ Connection->Retries = 1;
+ Connection->Rsn = Header->Data2Low; // save remote LSN.
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfWaitLink (Link); // start link going.
+
+ ConstructNameRecognized ( // build a good response.
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of local name.
+ Connection->Lsn, // return our LSN.
+ RESPONSE_CORR(Header), // new xmit corr.
+ 0, // our response correlator (unused).
+ Header->DestinationName,// our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ //
+ // Now, to avoid problems with hanging listens, we'll start the
+ // connection timer and give a limited period for the connection
+ // to succeed. This avoids waiting forever for those first few
+ // frames to be exchanged. When the timeout occurs, the
+ // the dereference will cause the circuit to be torn down.
+ //
+ // The maximum delay we can accomodate on a link is
+ // NameQueryRetries * NameQueryTimeout (assuming the
+ // remote has the same timeous). There are three
+ // exchanges of packets until the SESSION_INITIALIZE
+ // shows up, to be safe we multiply by four.
+ //
+
+ NbfStartConnectionTimer(
+ Connection,
+ NbfListenTimeout,
+ 4 * DeviceContext->NameQueryRetries * DeviceContext->NameQueryTimeout);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ TRUE); // loopback if needed.
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint2("Connection %lx on link %lx\n", Connection, Link);
+ }
+
+ NbfDereferenceConnection("ProcessNameQuery", Connection, CREF_LISTENING);
+ return STATUS_ABANDONED; // successful!
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // We don't have a free LSN to allocate, so fall through to
+ // report "no resources".
+ //
+
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("No more LSNS", Link, LREF_CONNECTION);
+
+ ASSERT (Connection->Lsn == 0);
+
+ }
+
+ //
+ // If we fall through here, then we couldn't get resources to set
+ // up this connection, so just send him a "no resources" reply.
+ //
+
+ if (UsedListeningConnection) {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NQ; // put this back.
+
+ } else {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+
+ }
+
+ //
+ // We should send a NR with LSN 0xff, indicating
+ // no resources, but LM 2.0 does not interpret
+ // that correctly. So, we send LSN 0 (no listens)
+ // instead.
+ //
+
+ ConstructNameRecognized (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType,
+ 0, // LSN=0 means no listens
+ RESPONSE_CORR(Header),
+ 0,
+ Header->DestinationName, // our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ TRUE); // loopback if needed.
+
+ NbfDereferenceConnection("ProcessNameQuery done", Connection, CREF_LISTENING);
+ }
+
+ return STATUS_ABANDONED;
+
+} /* ProcessNameQuery */
+
+
+NTSTATUS
+ProcessAddNameResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming ADD_NAME_RESPONSE frame.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ BOOLEAN SendNameInConflict = FALSE;
+ UNREFERENCED_PARAMETER(DeviceContext);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // If we aren't trying to register this address, then the sender of
+ // this frame is bogus. We cannot allow our state to change based
+ // on the reception of a random frame.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_REGISTERING)) {
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint2("ProcessAddNameResponse %lx: not registering [%.16s]\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED; // just destroy the packet.
+ }
+
+ //
+ // Unfortunately, we are registering this address and another host
+ // on the network is also attempting to register the same NetBIOS
+ // name on the same network. Because he got to us first, we cannot
+ // register our name. Thus, the address must die. We set this flag
+ // and on the next timeout we will shut down.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+
+ if (Header->Data2Low == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ //
+ // If we have already gotten a response from someone saying
+ // this address is uniquely owned, then make sure any future
+ // responses come from the same MAC address.
+ //
+
+ if ((*((LONG UNALIGNED *)Address->UniqueResponseAddress) == 0) &&
+ (*((SHORT UNALIGNED *)(&Address->UniqueResponseAddress[4])) == 0)) {
+
+ RtlMoveMemory(Address->UniqueResponseAddress, SourceAddress->Address, 6);
+
+ } else if (!RtlEqualMemory(
+ Address->UniqueResponseAddress,
+ SourceAddress->Address,
+ 6)) {
+
+ if (!Address->NameInConflictSent) {
+ SendNameInConflict = TRUE;
+ }
+
+ }
+
+ } else {
+
+ //
+ // For group names, make sure nobody else decided that it was
+ // a unique address.
+ //
+
+ if ((*((LONG UNALIGNED *)Address->UniqueResponseAddress) != 0) ||
+ (*((SHORT UNALIGNED *)(&Address->UniqueResponseAddress[4])) != 0)) {
+
+ if (!Address->NameInConflictSent) {
+ SendNameInConflict = TRUE;
+ }
+
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (SendNameInConflict) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->DestinationName);
+
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint2("ProcessAddNameResponse %lx: stopping [%.16s]\n", Address, Header->SourceName);
+ }
+
+ return STATUS_ABANDONED; // done with this frame.
+} /* ProcessAddNameResponse */
+
+
+NTSTATUS
+ProcessNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming NAME_RECOGNIZED frame. This frame
+ is received because we issued a NAME_QUERY frame to actively initiate
+ a connection with a remote host.
+
+ 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.
+
+ Header - Pointer to the connectionless NetBIOS 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.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+ BOOLEAN TimerCancelled;
+
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING | ADDRESS_FLAGS_CONFLICT)) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameRecognized %lx: address not stable [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED; // invalid address state, drop packet.
+ }
+
+ //
+ // Find names and connections both require a TP_CONNECTION to work.
+ // In either case, the ConnectionId field of the TP_CONNECTION object
+ // was sent as the response correlator in the NAME_QUERY frame, so
+ // we should get the same correlator back in this frame in the
+ // transmit correlator. Because this number is unique across
+ // all the connections on an address, we can determine if the frame
+ // was for this address or not.
+ //
+
+ // this causes a reference which is removed before this function returns.
+
+ Connection = NbfLookupConnectionById (
+ Address,
+ TRANSMIT_CORR(Header));
+
+ //
+ // has he been deleted while we were waiting?
+ //
+
+ if (Connection == NULL) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint2 ("ProcessNameRecognized %lx: no connection [%.16s].\n", Address, Header->SourceName);
+ }
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // This frame is a response to a NAME_QUERY frame that we previously
+ // sent to him. Either he's returning "insufficient resources",
+ // indicating that a session cannot be established, or he's initiated
+ // his side of the connection.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+
+ //
+ // Connection is stopping, don't process this.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx stopping [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection("Name Recognized, stopping", Connection, CREF_BY_ID);
+
+ return STATUS_ABANDONED;
+ }
+
+ if (Header->Data2Low == 0x00 ||
+ (Header->Data2Low > 0x00 && (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN))) { // no listens, or FIND.NAME response.
+
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_CONNECTOR)) {
+
+ //
+ // This is just a find name request, we are not trying to
+ // establish a connection. Currently, there is no reason
+ // for this to occur, so just save some room to add this
+ // extra feature later to support NETBIOS find name.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx not connector [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection("Unexpected FN Response", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED; // we processed the frame.
+ }
+
+ //
+ // We're setting up a session. If we are waiting for the first NAME
+ // RECOGNIZED, then setup the link and send the second NAME_QUERY.
+ // If we're waiting for the second NAME_RECOGNIZED, then he didn't
+ // have an LSN to finish the connection, so tear it down.
+ //
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN) {
+
+ //
+ // Now that we know the data link address of the remote host
+ // we're connecting to, we need to create a TP_LINK object to
+ // represent the data link between these two machines. If there
+ // is already a data link there, then the object will be reused.
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NR_FN;
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // The Netbios address we are connecting to is a
+ // unique name
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx send 2nd NQ [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ CONNECTOR_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (!NT_SUCCESS (status)) { // no resources.
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("No Resources for link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference which is
+ // removed in NbfDisconnectFromLink. It does NOT add a link ref.
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((status = NbfConnectToLink (Link, Connection)) != STATUS_SUCCESS)) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // Connection stopping or no LSN's available on this link.
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("Can't connect to link", Link, LREF_CONNECTION); // most likely destroys this.
+
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("Cant connect to link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ (VOID)InterlockedIncrement(&Link->NumberOfConnectors);
+
+ } else {
+
+ //
+ // We are connecting to a group name; we have to
+ // assign an LSN now, but we don't connect to
+ // the link until we get a committed name response.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx send 2nd NQ GROUP [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ if (NbfAssignGroupLsn(Connection) != STATUS_SUCCESS) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection("Can't get group LSN", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+
+ }
+
+ }
+
+
+ //
+ // Send the second NAME_QUERY frame, committing our LSN to
+ // the remote guy.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_NR;
+ Connection->Retries = (USHORT)DeviceContext->NameQueryRetries;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ DeviceContext->NameQueryTimeout);
+
+ KeQueryTickCount (&Connection->ConnectStartTime);
+
+ NbfSendNameQuery(
+ Connection,
+ TRUE);
+
+ NbfDereferenceConnection ("Done with lookup", Connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ if (Connection->Link) {
+
+ if (RtlEqualMemory(
+ Connection->Link->HardwareAddress.Address,
+ SourceAddress->Address,
+ 6)) {
+
+ //
+ // Unfortunately, he's telling us that he doesn't have resources
+ // to allocate an LSN. We set a flag to record this and
+ // ignore the frame.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_NO_LISTEN;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx no listens [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ } else {
+
+ //
+ // This response comes from a different remote from the
+ // last one. For unique names this indicates a duplicate
+ // name on the network.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ if (!Address->NameInConflictSent) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->SourceName);
+
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx name in conflict [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ }
+
+ } else {
+
+ //
+ // The response came back so fast the connection is
+ // not stable, ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ NbfDereferenceConnection ("No remote resources", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else {
+
+ //
+ // Strange state. This should never happen, because we should be
+ // either waiting for a first or second name recognized frame. It
+ // is possible that the remote station received two frames because
+ // of our retransmits, and so he responded to both. Toss the frame.
+ //
+
+ if (Connection->Link) {
+
+ if (!RtlEqualMemory(
+ Connection->Link->HardwareAddress.Address,
+ SourceAddress->Address,
+ 6)) {
+
+ //
+ // This response comes from a different remote from the
+ // last one. For unique names this indicates a duplicate
+ // name on the network.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (Header->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ if (!Address->NameInConflictSent) {
+
+ Address->NameInConflictSent = TRUE;
+ NbfSendNameInConflict(
+ Address,
+ (PUCHAR)Header->SourceName);
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // This is the same remote, just ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ } else {
+
+ //
+ // The response came back so fast the connection is
+ // not stable, ignore it.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+ } else if (Header->Data2Low == 0xff) { // no resources to complete connection.
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ //
+ // The recipient of our previously-sent NAME_QUERY frame that we sent
+ // to actively establish a connection has unfortunately run out of
+ // resources and cannot setup his side of the connection. We have to
+ // report "no resources" on the TdiConnect.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx no resources [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ProcessNameRecognized: No resources.\n");
+ }
+
+ NbfStopConnection (Connection, STATUS_REMOTE_RESOURCES);
+ NbfDereferenceConnection ("No Resources", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ } else {
+
+ //
+ // We don't have a committed NAME_QUERY out there, so
+ // we ignore this frame.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected no resources [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+ } else { // Data2Low is in the range 0x01-0xfe
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) {
+
+ //
+ // This is a successful response to a second NAME_QUERY we sent when
+ // we started processing a TdiConnect request. Clear the "waiting
+ // for Name Recognized" bit in the connection flags so that the
+ // connection timer doesn't blow us away when it times out.
+ //
+ // BUGBUG: What prevents the timeout routine from running while
+ // we're in here and destroying the connection/link by
+ // calling NbfStopConnection?
+ //
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NR;
+
+ //
+ // Before we continue, store the remote guy's transport address
+ // into the TdiConnect's TRANSPORT_CONNECTION buffer. This allows
+ // the client to determine who responded to his TdiConnect.
+ //
+ // BUGBUG: this used to be done prior to sending the second
+ // Name Query, but since I fixed the Buffer2 problem, meaning
+ // that I really do overwrite the input buffer with the
+ // output buffer, that was screwing up the second query.
+ // Note that doing the copy after sending is probably unsafe
+ // in the case where the second Name Recognized arrives
+ // right away.
+ //
+
+ Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ TdiCopyLookaheadData(
+ Connection->CalledAddress.NetbiosName,
+ Header->SourceName,
+ 16,
+ DeviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ RtlCopyMemory( Connection->RemoteName, Header->SourceName, 16 );
+
+ Connection->Rsn = Header->Data2Low; // save his remote LSN.
+
+ //
+ // Save the correlator from the NR for eventual use in the
+ // SESSION_INITIALIZE frame.
+ //
+
+ Connection->NetbiosHeader.TransmitCorrelator = RESPONSE_CORR(Header);
+
+ //
+ // Cancel the timer; it would have no effect since WAIT_NR
+ // is not set, but there is no need for it to run. We cancel
+ // it with the lock held so it won't interfere with the
+ // timer's use when a connection is closing.
+ //
+
+ TimerCancelled = KeCancelTimer (&Connection->Timer);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) != 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // The Netbios address we are connecting to is a
+ // group name; we need to connect to the link
+ // now that we have the committed session.
+ //
+
+ // If successful, this adds a link reference which is removed
+ // in NbfDisconnectFromLink
+
+ status = NbfCreateLink (
+ DeviceContext,
+ SourceAddress, // remote hardware address.
+ SourceRouting,
+ SourceRoutingLength,
+ CONNECTOR_LINK, // for loopback link
+ &Link); // resulting link.
+
+ if (!NT_SUCCESS (status)) { // no resources.
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("No Resources for link", Connection, CREF_BY_ID);
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ return STATUS_ABANDONED;
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ // If successful, this adds a connection reference which is
+ // removed in NbfDisconnectFromLink. It does NOT add a link ref.
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) ||
+ ((status = NbfConnectToLink (Link, Connection)) != STATUS_SUCCESS)) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ // Connection stopping or no LSN's available on this link.
+ // We did a link reference since NbfCreateLink succeeded,
+ // but since NbfConnectToLink failed we will never remove
+ // that reference in NbfDisconnectFromLink, so do it here.
+
+ NbfDereferenceLink ("Can't connect to link", Link, LREF_CONNECTION); // most likely destroys this.
+
+ NbfStopConnection (Connection, STATUS_INSUFFICIENT_RESOURCES);
+ NbfDereferenceConnection ("Cant connect to link", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ (VOID)InterlockedIncrement(&Link->NumberOfConnectors);
+
+ } else {
+
+ //
+ // It's to a unique address, we set up the link
+ // before we sent out the committed NAME_QUERY.
+ //
+
+ Link = Connection->Link;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx session up! [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ //
+ // When we sent the committed NAME_QUERY, we stored that
+ // time in Connection->ConnectStartTime; we can now use
+ // that for a rough estimate of the link delay, if this
+ // is the first connection on the link. For async lines
+ // we do not do this because the delay introduced by the
+ // gateway messes up the timing.
+ //
+
+ if (!DeviceContext->MacInfo.MediumAsync) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if (Link->State == LINK_STATE_ADM) {
+
+ //
+ // HACK: Set the necessary variables in the link
+ // so that FakeUpdateBaseT1Timeout works. These
+ // variables are the same ones that FakeStartT1 sets.
+ //
+
+ Link->CurrentPollSize = Link->HeaderLength + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ Link->CurrentTimerStart = Connection->ConnectStartTime;
+ FakeUpdateBaseT1Timeout (Link);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ if (TimerCancelled) {
+ NbfDereferenceConnection("NR received, cancel timer", Connection, CREF_TIMER);
+ }
+
+ NbfActivateLink (Connection->Link); // start link going.
+
+ //
+ // We'll get control again in LINK.C when the data link has either
+ // been established, denied, or destroyed. This happens at I/O
+ // completion time from NbfCreateLink's PdiConnect request.
+ //
+
+ } else {
+
+ //
+ // We don't have a committed NAME_QUERY out there, so
+ // we ignore this frame.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint3 ("ProcessNameRecognized %lx: connection %lx unexpected session up! [%.16s].\n", Address, Connection, Header->SourceName);
+ }
+
+ NbfDereferenceConnection ("Tossing second response Done with lookup", Connection, CREF_BY_ID); // release our lookup hold.
+ return STATUS_ABANDONED; // we processed the frame.
+
+ }
+
+
+ }
+
+ NbfDereferenceConnection("ProcessNameRecognized lookup", Connection, CREF_BY_ID);
+ return STATUS_ABANDONED; // don't distribute packet.
+} /* ProcessNameRecognized */
+
+
+NTSTATUS
+NbfProcessUi(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR Header,
+ IN PUCHAR DlcHeader,
+ IN ULONG DlcLength,
+ 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 DLC UI-frame has been received on the data link.
+ Here we dispatch to the correct UI-frame handler.
+
+ Part of this routine's job is to optionally distribute the frame to
+ every address that needs to look at it.
+ We accomplish this by lock-stepping through the address database,
+ and for each address that matches the address this frame is aimed at,
+ calling the frame handler.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ Header - Points to the MAC header of the incoming packet.
+
+ DlcHeader - Points to the DLC header of the incoming packet.
+
+ DlcLength - Actual length in bytes of the packet, starting at the
+ DlcHeader.
+
+ 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;
+ PNBF_HDR_CONNECTIONLESS UiFrame;
+ NTSTATUS status;
+ PLIST_ENTRY Flink;
+ UCHAR MatchType;
+ BOOLEAN MatchedAddress;
+ PUCHAR MatchName;
+ ULONG NetbiosLength = DlcLength - 3;
+
+ UiFrame = (PNBF_HDR_CONNECTIONLESS)(DlcHeader + 3);
+
+ //
+ // Verify that this frame is long enough to examine and that it
+ // has the proper signature. We can't test the signature as a
+ // 16-bit word as specified in the NetBIOS Formats and Protocols
+ // manual because this is processor-dependent.
+ //
+
+ if ((NetbiosLength < sizeof (NBF_HDR_CONNECTIONLESS)) ||
+ (HEADER_LENGTH(UiFrame) != sizeof (NBF_HDR_CONNECTIONLESS)) ||
+ (HEADER_SIGNATURE(UiFrame) != NETBIOS_SIGNATURE)) {
+
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUi: Bad size or NetBIOS signature.\n");
+ }
+ return STATUS_ABANDONED; // frame too small or too large.
+ }
+
+ //
+ // If this frame has a correlator with the high bit on, it was due
+ // to a FIND.NAME request; we don't handle those here since they
+ // are not per-address.
+ //
+
+ if ((UiFrame->Command == NBF_CMD_NAME_RECOGNIZED) &&
+ (TRANSMIT_CORR(UiFrame) & 0x8000)) {
+
+ //
+ // Make sure the frame is sent to our reserved address;
+ // if not, drop it.
+ //
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return NbfProcessQueryNameRecognized(
+ DeviceContext,
+ Header,
+ UiFrame);
+ } else {
+
+ return STATUS_ABANDONED;
+
+ }
+ }
+
+ //
+ // If this is a STATUS_RESPONSE, process that separately.
+ //
+
+ if (UiFrame->Command == NBF_CMD_STATUS_RESPONSE) {
+
+ //
+ // Make sure the frame is sent to our reserved address;
+ // if not, drop it.
+ //
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else {
+
+ return STATUS_ABANDONED;
+
+ }
+ }
+
+ //
+ // If this is a STATUS_QUERY, check if it is to our reserved
+ // address. If so, we process it. If not, we fall through to
+ // the normal checking. This ensures that queries to our
+ // reserved address are always processed, even if nobody
+ // has opened that address yet.
+ //
+
+ if (UiFrame->Command == NBF_CMD_STATUS_QUERY) {
+
+ if (RtlEqualMemory(
+ UiFrame->DestinationName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ return NbfProcessStatusQuery(
+ DeviceContext,
+ NULL,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ }
+
+ }
+
+ //
+ // We have a valid connectionless NetBIOS protocol frame that's not a
+ // datagram, so deliver it to every address which matches the destination
+ // name in the frame. Some frames
+ // (NAME_QUERY) cannot be delivered to multiple recipients. Therefore,
+ // if a frame handler returns STATUS_MORE_PROCESSING_REQUIRED, we continue
+ // through the remaining addresses. Otherwise simply get out and assume
+ // that the frame was eaten. Thus, STATUS_SUCCESS means that the handler
+ // ate the frame and that no other addresses can have it.
+ //
+
+ //
+ // Determine what kind of lookup we want to do.
+ //
+
+ switch (UiFrame->Command) {
+
+ case NBF_CMD_NAME_QUERY:
+ case NBF_CMD_DATAGRAM:
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ case NBF_CMD_ADD_NAME_QUERY:
+ case NBF_CMD_STATUS_QUERY:
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ case NBF_CMD_NAME_RECOGNIZED:
+
+ MatchType = NETBIOS_NAME_TYPE_EITHER;
+ break;
+
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ case NBF_CMD_NAME_IN_CONFLICT:
+
+ MatchType = NETBIOS_NAME_TYPE_UNIQUE;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("NbfProcessUi: Frame delivered; Unrecognized command %x.\n",
+ UiFrame->Command);
+ }
+ return STATUS_SUCCESS;
+ break;
+
+ }
+
+ if ((UiFrame->Command == NBF_CMD_ADD_GROUP_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_ADD_NAME_QUERY)) {
+
+ MatchName = (PUCHAR)UiFrame->SourceName;
+
+ } else if (UiFrame->Command == NBF_CMD_DATAGRAM_BROADCAST) {
+
+ MatchName = NULL;
+
+ } else {
+
+ MatchName = (PUCHAR)UiFrame->DestinationName;
+
+ }
+
+ if (MatchName && DeviceContext->AddressCounts[MatchName[0]] == 0) {
+ status = STATUS_ABANDONED;
+ goto RasIndication;
+ }
+
+
+ MatchedAddress = FALSE;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ 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 (NbfMatchNetbiosAddress (Address,
+ MatchType,
+ MatchName)) {
+
+ NbfReferenceAddress ("UI Frame", Address, AREF_PROCESS_UI); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (MatchedAddress) {
+
+ //
+ // If the datagram's destination name does not match the address's
+ // network name and TSAP components, then skip this address. Some
+ // frames have the source and destination names backwards for this
+ // algorithm, so we account for that here. Also, broadcast datagrams
+ // have no destination name in the frame, but get delivered to every
+ // address anyway.
+ //
+
+#if 0
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ USHORT i;
+ NbfPrint0 ("NbfProcessUi: SourceName: ");
+ for (i=0;i<16;i++) {
+ NbfPrint1 ("%c",UiFrame->SourceName[i]);
+ }
+ NbfPrint0 (" Destination Name:");
+ for (i=0;i<16;i++) {
+ NbfPrint1 ("%c",UiFrame->DestinationName[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+#endif
+
+ //
+ // Deliver the frame to the current address.
+ //
+
+ switch (UiFrame->Command) {
+
+ case NBF_CMD_NAME_QUERY:
+
+ status = ProcessNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_DATAGRAM:
+ case NBF_CMD_DATAGRAM_BROADCAST:
+
+ //
+ // Reference the datagram so it sticks around until the
+ // ReceiveComplete, when it is processed.
+ //
+
+ if ((Address->Flags & ADDRESS_FLAGS_CONFLICT) == 0) {
+ NbfReferenceAddress ("Datagram indicated", Address, AREF_PROCESS_DATAGRAM);
+ *DatagramAddress = Address;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ } else {
+ status = STATUS_ABANDONED;
+ }
+ break;
+
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+
+ //
+ // did this frame originate with us? If so, we don't want to
+ // do any processing of it.
+ //
+
+ if (RtlEqualMemory (
+ SourceAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ if ((Address->Flags & ADDRESS_FLAGS_REGISTERING) != 0) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUI: loopback AddGroupNameQuery dropped\n");
+ }
+ status = STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ status = ProcessAddGroupNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+
+ //
+ // did this frame originate with us? If so, we don't want to
+ // do any processing of it.
+ //
+
+ if (RtlEqualMemory (
+ SourceAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ if ((Address->Flags & ADDRESS_FLAGS_REGISTERING) != 0) {
+ IF_NBFDBG (NBF_DEBUG_UFRAMES) {
+ NbfPrint0 ("NbfProcessUI: loopback AddNameQuery dropped\n");
+ }
+ status = STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ status = ProcessAddNameQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+
+ status = ProcessNameInConflict (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_STATUS_QUERY:
+
+ status = NbfProcessStatusQuery (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+
+ status = ProcessAddNameResponse (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+
+ status = ProcessNameRecognized (
+ DeviceContext,
+ Address,
+ UiFrame,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+
+ } /* switch on NetBIOS frame command code */
+
+ NbfDereferenceAddress ("Done", Address, AREF_PROCESS_UI); // done with previous address.
+
+ } else {
+
+ status = STATUS_ABANDONED;
+
+ }
+
+
+RasIndication:;
+
+ //
+ // Let the RAS clients have a crack at this if they want
+ //
+
+ if (DeviceContext->IndicationQueuesInUse) {
+
+ //
+ // If RAS has datagram indications posted, and this is a
+ // datagram that nobody wanted, then receive it anyway.
+ //
+
+ if ((UiFrame->Command == NBF_CMD_DATAGRAM) &&
+ (status == STATUS_ABANDONED)) {
+
+ *DatagramAddress = NULL;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else if ((UiFrame->Command == NBF_CMD_ADD_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_ADD_GROUP_NAME_QUERY) ||
+ (UiFrame->Command == NBF_CMD_NAME_QUERY)) {
+
+ NbfActionQueryIndication(
+ DeviceContext,
+ UiFrame);
+
+ }
+ }
+
+
+ return status;
+
+} /* NbfProcessUi */
+