diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/uframes.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/tdi/st/uframes.c')
-rw-r--r-- | private/ntos/tdi/st/uframes.c | 980 |
1 files changed, 980 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/uframes.c b/private/ntos/tdi/st/uframes.c new file mode 100644 index 000000000..c05f6eaa6 --- /dev/null +++ b/private/ntos/tdi/st/uframes.c @@ -0,0 +1,980 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + uframes.c + +Abstract: + + This module contains a routine called StProcessConnectionless, + that gets control from routines in IND.C when a connectionless + frame is received. + +Environment: + + Kernel mode, DISPATCH_LEVEL. + +Revision History: + +--*/ + +#include "st.h" + + + +NTSTATUS +StIndicateDatagram( + IN PDEVICE_CONTEXT DeviceContext, + IN PTP_ADDRESS Address, + IN PUCHAR Header, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame. + BROADCAST and normal datagrams have the same receive logic, except + for broadcast datagrams Address will be the broadcast address. + + When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of + this routine will continue to call us for each address for the device + context. When we return STATUS_SUCCESS, the caller will switch to the + next address. When we return any other status code, including + STATUS_ABANDONED, the caller will stop distributing the frame. + +Arguments: + + DeviceContext - Pointer to our device context. + + Address - Pointer to the transport address object. + + StHeader - Pointer to a buffer that contains the receive datagram. + The first byte of information is the ST header. + + Length - The length of the MDL pointed to by StHeader. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + NTSTATUS status; + PLIST_ENTRY p, q; + PIRP irp; + PIO_STACK_LOCATION irpSp; + PTP_REQUEST Request; + ULONG IndicateBytesCopied, MdlBytesCopied; + KIRQL oldirql; + TA_NETBIOS_ADDRESS SourceName; + TA_NETBIOS_ADDRESS DestinationName; + PTDI_CONNECTION_INFORMATION remoteInformation; + ULONG returnLength; + PTP_ADDRESS_FILE addressFile, prevaddressFile; + PST_HEADER StHeader; + + // + // If this datagram wasn't big enough for a transport header, then don't + // let the caller look at any data. + // + + if (Length < sizeof(ST_HEADER)) { + return STATUS_ABANDONED; + } + + // + // Update our statistics. + // + + ++DeviceContext->DatagramsReceived; + ADD_TO_LARGE_INTEGER( + &DeviceContext->DatagramBytesReceived, + Length - sizeof(ST_HEADER)); + + + // + // Call the client's ReceiveDatagram indication handler. He may + // want to accept the datagram that way. + // + + StHeader = (PST_HEADER)Header; + + TdiBuildNetbiosAddress (StHeader->Source, FALSE, &SourceName); + TdiBuildNetbiosAddress (StHeader->Destination, FALSE, &DestinationName); + + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + // + // Find the first open address file in the list. + // + + p = Address->AddressFileDatabase.Flink; + while (p != &Address->AddressFileDatabase) { + addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage); + if (addressFile->State != ADDRESSFILE_STATE_OPEN) { + p = p->Flink; + continue; + } + StReferenceAddressFile(addressFile); + break; + } + + while (p != &Address->AddressFileDatabase) { + + // + // do we have a datagram receive request outstanding? If so, we will + // satisfy it first. + // + // NOTE: We should check if this receive dataframs is for + // a specific address. + // + + q = RemoveHeadList (&addressFile->ReceiveDatagramQueue); + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + if (q != &addressFile->ReceiveDatagramQueue) { + + Request = CONTAINING_RECORD (q, TP_REQUEST, Linkage); + + // + // Copy the actual user data. + // + + MdlBytesCopied = 0; + + status = TdiCopyBufferToMdl ( + StHeader, + sizeof(ST_HEADER), // offset + Length - sizeof(ST_HEADER), // length + Request->IoRequestPacket->MdlAddress, + 0, + &MdlBytesCopied); + + irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket); + remoteInformation = + ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))-> + ReturnDatagramInformation; + if (remoteInformation != NULL) { + try { + if (remoteInformation->RemoteAddressLength != 0) { + if (remoteInformation->RemoteAddressLength >= + sizeof (TA_NETBIOS_ADDRESS)) { + + RtlCopyMemory ( + (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, + &SourceName, + sizeof (TA_NETBIOS_ADDRESS)); + + returnLength = sizeof(TA_NETBIOS_ADDRESS); + remoteInformation->RemoteAddressLength = returnLength; + + } else { + + RtlCopyMemory ( + (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, + &SourceName, + remoteInformation->RemoteAddressLength); + + returnLength = remoteInformation->RemoteAddressLength; + remoteInformation->RemoteAddressLength = returnLength; + + } + + } else { + + returnLength = 0; + } + + status = STATUS_SUCCESS; + + } except (EXCEPTION_EXECUTE_HANDLER) { + + returnLength = 0; + status = GetExceptionCode (); + + } + + } + + StCompleteRequest (Request, STATUS_SUCCESS, MdlBytesCopied); + + } else { + + // + // no receive datagram requests; is there a kernel client? + // + + if (addressFile->RegisteredReceiveDatagramHandler) { + + IndicateBytesCopied = 0; + + // + // Note that we can always set the COPY_LOOKAHEAD + // flag because we are indicating from our own + // buffer, not directly from a lookahead indication. + // + + status = (*addressFile->ReceiveDatagramHandler)( + addressFile->ReceiveDatagramHandlerContext, + sizeof (TA_NETBIOS_ADDRESS), + &SourceName, + 0, + NULL, + TDI_RECEIVE_COPY_LOOKAHEAD, + Length - sizeof(ST_HEADER), // indicated + Length - sizeof(ST_HEADER), // available + &IndicateBytesCopied, + Header + sizeof(ST_HEADER), + &irp); + + if (status == STATUS_SUCCESS) { + + // + // The client accepted the datagram and so we're done. + // + + } else if (status == STATUS_DATA_NOT_ACCEPTED) { + + // + // The client did not accept the datagram and we need to satisfy + // a TdiReceiveDatagram, if possible. + // + + status = STATUS_MORE_PROCESSING_REQUIRED; + + } else if (status == STATUS_MORE_PROCESSING_REQUIRED) { + + // + // The client returned an IRP that we should queue up to the + // address to satisfy the request. + // + + irp->IoStatus.Status = STATUS_PENDING; // init status information. + irp->IoStatus.Information = 0; + irpSp = IoGetCurrentIrpStackLocation (irp); // get current stack loctn. + if ((irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) || + (irpSp->MinorFunction != TDI_RECEIVE_DATAGRAM)) { + irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; + return status; + } + + // + // Now copy the actual user data. + // + + MdlBytesCopied = 0; + + status = TdiCopyBufferToMdl ( + StHeader, + sizeof(ST_HEADER) + IndicateBytesCopied, + Length - sizeof(ST_HEADER) - IndicateBytesCopied, + irp->MdlAddress, + 0, + &MdlBytesCopied); + + irp->IoStatus.Information = MdlBytesCopied; + irp->IoStatus.Status = status; + IoCompleteRequest (irp, IO_NETWORK_INCREMENT); + } + } + } + + // + // Save this to dereference it later. + // + + prevaddressFile = addressFile; + + // + // Reference the next address file on the list, so it + // stays around. + // + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + p = p->Flink; + while (p != &Address->AddressFileDatabase) { + addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage); + if (addressFile->State != ADDRESSFILE_STATE_OPEN) { + p = p->Flink; + continue; + } + StReferenceAddressFile(addressFile); + break; + } + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + // + // Now dereference the previous address file with + // the lock released. + // + + StDereferenceAddressFile (prevaddressFile); + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + } // end of while loop + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + return status; // to dispatcher. +} /* StIndicateDatagram */ + + +NTSTATUS +StProcessConnect( + IN PDEVICE_CONTEXT DeviceContext, + IN PTP_ADDRESS Address, + IN PST_HEADER Header, + IN PHARDWARE_ADDRESS SourceAddress, + IN PUCHAR SourceRouting, + IN UINT SourceRoutingLength + ) + +/*++ + +Routine Description: + + This routine processes an incoming connect frame. It scans for + posted listens, otherwise it indicates to connect handlers + on this address if they are registered. + +Arguments: + + DeviceContext - Pointer to our device context. + + Address - Pointer to the transport address object. + + Header - Pointer to the ST header of the frame. + + SourceAddress - Pointer to the source hardware address in the received + frame. + + SourceRouting - Pointer to the source routing information in + the frame. + + SourceRoutingLength - Length of the source routing information. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + KIRQL oldirql, oldirql1, cancelirql; + NTSTATUS status; + PTP_CONNECTION Connection; + BOOLEAN ConnectIndicationBlocked = FALSE; + PLIST_ENTRY p; + BOOLEAN UsedListeningConnection = FALSE; + PTP_ADDRESS_FILE addressFile, prevaddressFile; + + PTP_REQUEST request; + PIO_STACK_LOCATION irpSp; + ULONG returnLength; + PTDI_CONNECTION_INFORMATION remoteInformation; + TA_NETBIOS_ADDRESS TempAddress; + PIRP acceptIrp; + + CONNECTION_CONTEXT connectionContext; + + // + // If we are just registering or deregistering this address, then don't + // allow state changes. Just throw the packet away, and let the frame + // distributor try the next address. + // + + if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING)) { + return STATUS_SUCCESS; + } + + // + // This is an incoming connection request. If we have a listening + // connection on this address, then continue with the connection setup. + // If there is no outstanding listen, then indicate any kernel mode + // clients that want to know about this frame. If a listen was posted, + // then a connection has already been set up for it. + // + + // + // First, check if we already have an active connection with + // this remote on this address. If so, we ignore this + // (NOTE: This is not the correct behaviour for a real + // transport). + // + + // + // If successful this adds a reference. + // + + if (Connection = StLookupRemoteName(Address, Header->Source)) { + + StDereferenceConnection ("Lookup done", Connection); + return STATUS_ABANDONED; + + } + + // If successful, this adds a reference which is removed before + // this function returns. + + Connection = StLookupListeningConnection (Address); + if (Connection == NULL) { + + // + // not having a listening connection is not reason to bail out here. + // we need to indicate to the user that a connect attempt occurred, + // and see if there is a desire to use this connection. We + // indicate in order to all address files that are + // using this address. + // + // If we already have an indication pending on this address, + // we ignore this frame (the NAME_QUERY may have come from + // a different address, but we can't know that). Also, if + // there is already an active connection on this remote + // name, then we ignore the frame. + // + + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + p = Address->AddressFileDatabase.Flink; + while (p != &Address->AddressFileDatabase) { + addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage); + if (addressFile->State != ADDRESSFILE_STATE_OPEN) { + p = p->Flink; + continue; + } + StReferenceAddressFile(addressFile); + break; + } + + while (p != &Address->AddressFileDatabase) { + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + if ((addressFile->RegisteredConnectionHandler == TRUE) && + (!addressFile->ConnectIndicationInProgress)) { + + + TdiBuildNetbiosAddress ( + Header->Source, + FALSE, + &TempAddress); + + addressFile->ConnectIndicationInProgress = TRUE; + + // + // we have a connection handler, now indicate that a connection + // attempt occurred. + // + + status = (addressFile->ConnectionHandler)( + addressFile->ConnectionHandlerContext, + sizeof (TDI_ADDRESS_NETBIOS), + &TempAddress, + 0, + NULL, + 0, + NULL, + &connectionContext, + &acceptIrp); + + if (status == STATUS_MORE_PROCESSING_REQUIRED) { + + // the user has connected a currently open connection, but + // we have to figure out which one it is. + // + + // + // If successful this adds a reference of type LISTENING + // (the same what StLookupListeningConnection adds). + // + + Connection = StLookupConnectionByContext ( + Address, + connectionContext); + + if (Connection == NULL) { + + // + // BUGBUG: We have to tell the client that + // his connection is bogus (or has this + // already happened??). + // + + StPrint0("MORE_PROCESSING_REQUIRED, connection not found\n"); + addressFile->ConnectIndicationInProgress = FALSE; + acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION; + IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT); + + goto whileend; // try next address file + + } else { + + if (Connection->AddressFile->Address != Address) { + addressFile->ConnectIndicationInProgress = FALSE; + + StPrint0("MORE_PROCESSING_REQUIRED, address wrong\n"); + StStopConnection (Connection, STATUS_INVALID_ADDRESS); + StDereferenceConnection("Bad Address", Connection); + Connection = NULL; + acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION; + IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT); + + goto whileend; // try next address file + } + + // + // OK, we have a valid connection. If the response to + // this connection was disconnect, we need to reject + // the connection request and return. If it was accept + // or not specified (to be done later), we simply + // fall through and continue processing on the U Frame. + // + + ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1); + if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) { + + Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT; + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1); + StPrint0("MORE_PROCESSING_REQUIRED, disconnect\n"); + addressFile->ConnectIndicationInProgress = FALSE; + StDereferenceConnection("Disconnecting", Connection); + Connection = NULL; + acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION; + IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT); + + goto whileend; // try next address file + } + + } + + // + // This connection is ready. + // + + Connection->Flags &= ~CONNECTION_FLAGS_STOPPING; + Connection->Status = STATUS_PENDING; + Connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED; + + Connection->Flags |= CONNECTION_FLAGS_READY; + INCREMENT_COUNTER (Connection->Provider, OpenConnections); + + Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED; + + StReferenceConnection("Indication completed", Connection); + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1); + + // + // Make a note that we have to set + // addressFile->ConnectIndicationInProgress to + // FALSE once the address is safely stored + // in the connection. + // + + ConnectIndicationBlocked = TRUE; + StDereferenceAddressFile (addressFile); + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + break; // exit the while + + } else if (status == STATUS_INSUFFICIENT_RESOURCES) { + + // + // we know the address, but can't create a connection to + // use on it. This gets passed to the network as a response + // saying I'm here, but can't help. + // + + addressFile->ConnectIndicationInProgress = FALSE; + + StDereferenceAddressFile (addressFile); + return STATUS_ABANDONED; + + } else { + + addressFile->ConnectIndicationInProgress = FALSE; + goto whileend; // try next address file + + } // end status ifs + + } else { + + goto whileend; // try next address file + + } // end no indication handler + +whileend: + // + // Jumping here is like a continue, except that the + // addressFile pointer is advanced correctly. + // + + // + // Save this to dereference it later. + // + + prevaddressFile = addressFile; + + // + // Reference the next address file on the list, so it + // stays around. + // + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + p = p->Flink; + while (p != &Address->AddressFileDatabase) { + addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage); + if (addressFile->State != ADDRESSFILE_STATE_OPEN) { + p = p->Flink; + continue; + } + StReferenceAddressFile(addressFile); + break; + } + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + // + // Now dereference the previous address file with + // the lock released. + // + + StDereferenceAddressFile (prevaddressFile); + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + + } // end of loop through the address files. + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + if (Connection == NULL) { + + // + // We used to return MORE_PROCESSING_REQUIRED, but + // since we matched with this address, no other + // address is going to match, so abandon it. + // + + return STATUS_ABANDONED; + + } + + } else { // end connection == null + + UsedListeningConnection = TRUE; + + IoAcquireCancelSpinLock (&cancelirql); + ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql); + + p = RemoveHeadList (&Connection->InProgressRequest); + if (p == &Connection->InProgressRequest) { + + Connection->IndicationInProgress = FALSE; + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + IoReleaseCancelSpinLock (cancelirql); + return STATUS_SUCCESS; + + } + + // + // If this listen indicated that we should wait for a + // TdiAccept, then do that, otherwise the connection is + // ready. + // + + if ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) == 0) { + + Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_ACCEPT; + + } else { + + Connection->Flags |= CONNECTION_FLAGS_READY; + INCREMENT_COUNTER (Connection->Provider, OpenConnections); + + Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED; + + StReferenceConnection("Listen completed", Connection); + + } + + // + // We have a completed connection with a queued listen. Complete + // the listen and let the user do an accept at some time down the + // road. + // + + RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql); + + request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); + request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL; + IoReleaseCancelSpinLock (cancelirql); + + irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket); + remoteInformation = + ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation; + if (remoteInformation != NULL) { + try { + if (remoteInformation->RemoteAddressLength != 0) { + + // + // Build a temporary TA_NETBIOS_ADDRESS, then + // copy over as many bytes as fit. + // + + TdiBuildNetbiosAddress( + Connection->CalledAddress.NetbiosName, + (BOOLEAN)(Connection->CalledAddress.NetbiosNameType == + TDI_ADDRESS_NETBIOS_TYPE_GROUP), + &TempAddress); + + if (remoteInformation->RemoteAddressLength >= + sizeof (TA_NETBIOS_ADDRESS)) { + + returnLength = sizeof(TA_NETBIOS_ADDRESS); + remoteInformation->RemoteAddressLength = returnLength; + + } else { + + returnLength = remoteInformation->RemoteAddressLength; + + } + + RtlCopyMemory( + (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress, + &TempAddress, + returnLength); + + } else { + + returnLength = 0; + } + + status = STATUS_SUCCESS; + + } except (EXCEPTION_EXECUTE_HANDLER) { + + returnLength = 0; + status = GetExceptionCode (); + + } + + } else { + + status = STATUS_SUCCESS; + returnLength = 0; + + } + + // + // Don't clear this until now, so that the connection is all + // set up before we allow more indications. + // + + Connection->IndicationInProgress = FALSE; + + StCompleteRequest (request, status, 0); + + } + + + // + // Before we continue, store the remote guy's transport address + // into the TdiListen's TRANSPORT_CONNECTION buffer. This allows + // the client to determine who called him. + // + + Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE; + NdisMoveFromMappedMemory( + Connection->CalledAddress.NetbiosName, + Header->Source, + 16); + + NdisMoveFromMappedMemory( + Connection->RemoteName, + Header->Source, + 16); + + Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID; + + if (ConnectIndicationBlocked) { + addressFile->ConnectIndicationInProgress = FALSE; + } + + StDereferenceConnection("ProcessNameQuery done", Connection); + + return STATUS_ABANDONED; + +} /* StProcessConnect */ + + +NTSTATUS +StProcessConnectionless( + IN PDEVICE_CONTEXT DeviceContext, + IN PHARDWARE_ADDRESS SourceAddress, + IN PST_HEADER StHeader, + IN ULONG StLength, + IN PUCHAR SourceRouting, + IN UINT SourceRoutingLength, + OUT PTP_ADDRESS * DatagramAddress + ) + +/*++ + +Routine Description: + + This routine receives control from the data link provider as an + indication that a connectionless frame has been received on the data link. + Here we dispatch to the correct handler. + +Arguments: + + DeviceContext - Pointer to our device context. + + SourceAddress - Pointer to the source hardware address in the received + frame. + + StHeader - Points to the ST header of the incoming packet. + + StLength - Actual length in bytes of the packet, starting at the + StHeader. + + SourceRouting - Source routing information in the MAC header. + + SourceRoutingLength - The length of SourceRouting. + + DatagramAddress - If this function returns STATUS_MORE_PROCESSING_ + REQUIRED, this will be the address the datagram should be + indicated to. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + PTP_ADDRESS Address; + KIRQL oldirql; + NTSTATUS status; + PLIST_ENTRY Flink; + BOOLEAN MatchedAddress; + PUCHAR MatchName; + + // + // Verify that this frame is long enough to examine. + // + + if (StLength < sizeof(ST_HEADER)) { + return STATUS_ABANDONED; // frame too small. + } + + // + // We have a valid connectionless protocol frame that's not a + // datagram, so deliver it to every address which matches the + // destination name in the frame. + // + + MatchedAddress = FALSE; + + // + // Search for the address; for broadcast datagrams we + // search for the special "broadcast" address. + // + + if ((StHeader->Command == ST_CMD_DATAGRAM) && + (StHeader->Flags & ST_FLAGS_BROADCAST)) { + + MatchName = NULL; + + } else { + + MatchName = StHeader->Destination; + + } + + ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); + + for (Flink = DeviceContext->AddressDatabase.Flink; + Flink != &DeviceContext->AddressDatabase; + Flink = Flink->Flink) { + + Address = CONTAINING_RECORD ( + Flink, + TP_ADDRESS, + Linkage); + + if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) { + continue; + } + + if (StMatchNetbiosAddress (Address, MatchName)) { + + StReferenceAddress ("UI Frame", Address); // prevent address from being destroyed. + MatchedAddress = TRUE; + break; + + } + } + + RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); + + if (MatchedAddress) { + + // + // Deliver the frame to the current address. + // + + switch (StHeader->Command) { + + case ST_CMD_CONNECT: + + status = StProcessConnect ( + DeviceContext, + Address, + StHeader, + SourceAddress, + SourceRouting, + SourceRoutingLength); + + break; + + case ST_CMD_DATAGRAM: + + // + // Reference the datagram so it sticks around until the + // ReceiveComplete, when it is processed. + // + + StReferenceAddress ("Datagram indicated", Address); + *DatagramAddress = Address; + status = STATUS_MORE_PROCESSING_REQUIRED; + break; + + default: + + ASSERT(FALSE); + + } /* switch on frame command code */ + + StDereferenceAddress ("Done", Address); // done with previous address. + + } else { + + status = STATUS_ABANDONED; + + } + + return status; + +} /* StProcessConnectionless */ + |