diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/nbf/uframes.c | 2974 |
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 */ + |