mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
980 lines
29 KiB
980 lines
29 KiB
/*++
|
|
|
|
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 */
|
|
|