summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/nbf')
-rw-r--r--private/ntos/tdi/nbf/action.c642
-rw-r--r--private/ntos/tdi/nbf/address.c3046
-rw-r--r--private/ntos/tdi/nbf/autodial.c502
-rw-r--r--private/ntos/tdi/nbf/connect.c1700
-rw-r--r--private/ntos/tdi/nbf/connobj.c2413
-rw-r--r--private/ntos/tdi/nbf/devctx.c408
-rw-r--r--private/ntos/tdi/nbf/dlc.c3270
-rw-r--r--private/ntos/tdi/nbf/event.c190
-rw-r--r--private/ntos/tdi/nbf/framecon.c1087
-rw-r--r--private/ntos/tdi/nbf/framesnd.c2504
-rw-r--r--private/ntos/tdi/nbf/iframes.c3339
-rw-r--r--private/ntos/tdi/nbf/info.c3487
-rw-r--r--private/ntos/tdi/nbf/link.c2315
-rw-r--r--private/ntos/tdi/nbf/linktree.c537
-rw-r--r--private/ntos/tdi/nbf/makefile6
-rw-r--r--private/ntos/tdi/nbf/nbf.h166
-rw-r--r--private/ntos/tdi/nbf/nbf.rc12
-rw-r--r--private/ntos/tdi/nbf/nbfcnfg.c1155
-rw-r--r--private/ntos/tdi/nbf/nbfcnfg.h102
-rw-r--r--private/ntos/tdi/nbf/nbfconst.h436
-rw-r--r--private/ntos/tdi/nbf/nbfdebug.c646
-rw-r--r--private/ntos/tdi/nbf/nbfdrvr.c2493
-rw-r--r--private/ntos/tdi/nbf/nbfhdrs.h257
-rw-r--r--private/ntos/tdi/nbf/nbfmac.c417
-rw-r--r--private/ntos/tdi/nbf/nbfmac.h766
-rw-r--r--private/ntos/tdi/nbf/nbfndis.c1956
-rw-r--r--private/ntos/tdi/nbf/nbfpnp.c210
-rw-r--r--private/ntos/tdi/nbf/nbfprocs.h2322
-rw-r--r--private/ntos/tdi/nbf/nbftypes.h2202
-rw-r--r--private/ntos/tdi/nbf/packet.c1808
-rw-r--r--private/ntos/tdi/nbf/precomp.h219
-rw-r--r--private/ntos/tdi/nbf/rcv.c309
-rw-r--r--private/ntos/tdi/nbf/rcveng.c823
-rw-r--r--private/ntos/tdi/nbf/request.c1376
-rw-r--r--private/ntos/tdi/nbf/send.c503
-rw-r--r--private/ntos/tdi/nbf/sendeng.c3657
-rw-r--r--private/ntos/tdi/nbf/sources79
-rw-r--r--private/ntos/tdi/nbf/spnlckdb.c156
-rw-r--r--private/ntos/tdi/nbf/testnbf.c1466
-rw-r--r--private/ntos/tdi/nbf/testtdi.c291
-rw-r--r--private/ntos/tdi/nbf/timer.c2762
-rw-r--r--private/ntos/tdi/nbf/uframes.c2974
42 files changed, 55009 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/action.c b/private/ntos/tdi/nbf/action.c
new file mode 100644
index 000000000..84a51695a
--- /dev/null
+++ b/private/ntos/tdi/nbf/action.c
@@ -0,0 +1,642 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains support for the TdiAction handler.
+
+Author:
+
+ David Beaver (dbeaver) 2-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _QUERY_INDICATION {
+ UCHAR Command;
+ USHORT Data2;
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+} QUERY_INDICATION, *PQUERY_INDICATION;
+
+typedef struct _ACTION_QUERY_INDICATION {
+ TDI_ACTION_HEADER Header;
+ QUERY_INDICATION QueryIndication;
+} ACTION_QUERY_INDICATION, *PACTION_QUERY_INDICATION;
+
+
+typedef struct _DATAGRAM_INDICATION {
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+ USHORT DatagramBufferLength;
+ UCHAR DatagramBuffer[1];
+} DATAGRAM_INDICATION, *PDATAGRAM_INDICATION;
+
+typedef struct _ACTION_DATAGRAM_INDICATION {
+ TDI_ACTION_HEADER Header;
+ DATAGRAM_INDICATION DatagramIndication;
+} ACTION_DATAGRAM_INDICATION, *PACTION_DATAGRAM_INDICATION;
+
+
+#define QUERY_INDICATION_CODE 1
+#define DATAGRAM_INDICATION_CODE 2
+
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+
+NTSTATUS
+NbfTdiAction(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - The device context for the operation
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_ACTION_HEADER ActionHeader;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_REQUEST tpRequest;
+ KIRQL oldirql, cancelirql;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+
+ //
+ // Handle the requests based on the action code.
+ //
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // These two requests are sent by RAS to "MABF"
+ //
+
+ if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // They should be sent on the control channel
+ //
+
+ if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Create a request to describe this.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress,
+ MmGetMdlByteCount(Irp->MdlAddress),
+ timeout,
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+ tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ //
+ // Disallow these requests on a stopping device.
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+
+ InsertTailList (
+ &DeviceContext->QueryIndicationQueue,
+ &tpRequest->Linkage);
+
+ } else {
+
+ InsertTailList (
+ &DeviceContext->DatagramIndicationQueue,
+ &tpRequest->Linkage);
+
+ }
+
+ DeviceContext->IndicationQueuesInUse = TRUE;
+
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ Irp->CancelIrql = cancelirql;
+ NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelAction);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ status = STATUS_PENDING;
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ }
+
+
+ return status;
+
+}
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ PTDI_ACTION_HEADER ActionHeader;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_ACTION));
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // Scan through the appropriate queue, looking for this IRP.
+ // If we find it, we just remove it from the queue; there
+ // is nothing else involved in cancelling.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+ Found = FALSE;
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ } else {
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel action %lx on %lx, not found\n",
+ Irp, DeviceContext);
+#endif
+ }
+
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+
+}
+
+
+VOID
+NbfStopControlChannel(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN USHORT ChannelIdentifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an MJ_CLEANUP IRP is received
+ on a control channel. It walks the device context's list of
+ pending action requests and cancels those associated with
+ this channel (as identified by ChannelIdentifier.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ ChannelIdentifier - The identifier for this open of the control
+ channel, which is stored in Request->FrameContext for requests
+ made on this channel.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ BOOLEAN FoundRequest;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+
+ //
+ // Scan both queues, looking for requests. Since the list
+ // may change, we scan until we find one, then remove it
+ // and complete it. We then start scanning at the beginning
+ // again. We continue until we find none on the queue that
+ // belong to this control channel.
+ //
+ // The outer loop only runs twice; the first time it
+ // processes QueryIndicationQueue, the second time
+ // DatagramIndicationQueue.
+ //
+
+ for (i = 0; i < 2; i++) {
+
+ do {
+
+ //
+ // Loop until we do not find a request on this
+ // pass through the queue.
+ //
+
+ FoundRequest = FALSE;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (i == 0) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+
+ //
+ // Scan the appropriate queue for a request on this
+ // channel.
+ //
+
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->FrameContext == ChannelIdentifier) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ RemoveEntryList (p);
+
+ FoundRequest = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we found a request, then complete it and loop
+ // back to the top of the while loop to rescan the
+ // list. If not, then we will exit the while loop
+ // now.
+ //
+
+ if (FoundRequest) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ }
+
+ } while (FoundRequest);
+
+ }
+
+}
+
+
+VOID
+NbfActionQueryIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a UI frame of type NAME_QUERY,
+ ADD_NAME_QUERY, or ADD_GROUP_NAME_QUERY has been processed.
+ It checks if there is a QUERY.INDICATION IRP waiting to
+ be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PMDL Mdl;
+ PACTION_QUERY_INDICATION ActionHeader;
+ PQUERY_INDICATION QueryIndication;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->QueryIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->QueryIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket,NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_QUERY_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ QueryIndication = &ActionHeader->QueryIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ QueryIndication->Command = UiFrame->Command;
+ RtlCopyMemory ((PUCHAR)(&QueryIndication->Data2), (PUCHAR)(&UiFrame->Data2Low), 2);
+ RtlCopyMemory ((PUCHAR)(QueryIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, sizeof(ACTION_QUERY_INDICATION));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+
+
+VOID
+NbfActionDatagramIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a datagram frame has been
+ received. It checks if there is a DATAGRAM.INDICATION IRP
+ waiting to be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+ Length - The length of the frame starting at UiFrame.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PACTION_DATAGRAM_INDICATION ActionHeader;
+ PDATAGRAM_INDICATION DatagramIndication;
+ ULONG CopyLength;
+ PMDL Mdl;
+ NTSTATUS Status;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->DatagramIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->DatagramIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_DATAGRAM_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ DatagramIndication = &ActionHeader->DatagramIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ RtlCopyMemory ((PUCHAR)(DatagramIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ if ((Length-sizeof(NBF_HDR_CONNECTIONLESS)) <=
+ (ULONG)DatagramIndication->DatagramBufferLength) {
+
+ CopyLength = Length - sizeof(NBF_HDR_CONNECTIONLESS);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ CopyLength = DatagramIndication->DatagramBufferLength;
+ Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+
+ RtlCopyMemory(
+ (PUCHAR)DatagramIndication->DatagramBuffer,
+ ((PUCHAR)UiFrame) + sizeof(NBF_HDR_CONNECTIONLESS),
+ CopyLength);
+ DatagramIndication->DatagramBufferLength = (USHORT)CopyLength;
+
+ NbfCompleteRequest (Request, Status, CopyLength +
+ FIELD_OFFSET (ACTION_DATAGRAM_INDICATION, DatagramIndication.DatagramBuffer[0]));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+
diff --git a/private/ntos/tdi/nbf/address.c b/private/ntos/tdi/nbf/address.c
new file mode 100644
index 000000000..f5bda0cc7
--- /dev/null
+++ b/private/ntos/tdi/nbf/address.c
@@ -0,0 +1,3046 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the TP_ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+#define NbfDbgShowAddr(TNA)\
+ { \
+ if ((TNA) == NULL) { \
+ NbfPrint0("<NetBios broadcast>\n"); \
+ } else { \
+ NbfPrint6("%c %c %c %c %d (%c)\n", \
+ (TNA)->NetbiosName[0], \
+ (TNA)->NetbiosName[1], \
+ (TNA)->NetbiosName[4], \
+ (TNA)->NetbiosName[6], \
+ (TNA)->NetbiosName[15], \
+ (TNA)->NetbiosNameType + 'A'); \
+ } \
+ }
+#else
+#define NbfDbgShowAddr(TNA)
+#endif
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+VOID
+AddressTimeoutHandler(
+ 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 ADD_NAME_QUERY/ADD_NAME_RECOGNIZED protocol expires.
+ The retry count in the Address object is decremented, and if it reaches 0,
+ the address is registered. If the retry count has not reached zero,
+ then the ADD NAME QUERY is retried.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_ADDRESS block representing the
+ address that is being registered.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+ LARGE_INTEGER timeout;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+
+ address = (PTP_ADDRESS)DeferredContext;
+ DeviceContext = address->Provider;
+
+ //
+ // We are waiting for an ADD_NAME_RECOGNIZED indicating that there is a
+ // conflict. Decrement the retry count, and if it dropped to zero,
+ // then we've waited a sufficiently long time. If there was no conflict,
+ // complete all waiting file opens for the address.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((address->Flags & ADDRESS_FLAGS_QUICK_REREGISTER) != 0) {
+
+ BOOLEAN DuplicateName;
+ PTP_CONNECTION Connection;
+
+ DuplicateName = ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0);
+
+ for (p=address->ConnectionDatabase.Flink;
+ p != &address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+ continue;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_W_ADDRESS) != 0) {
+
+ if (DuplicateName) {
+
+ NbfStopConnection (Connection, STATUS_DUPLICATE_NAME);
+
+ } else {
+
+ //
+ // Continue with the connection attempt.
+ //
+ ULONG NameQueryTimeout;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_W_ADDRESS;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ KeQueryTickCount (&Connection->ConnectStartTime);
+
+ NameQueryTimeout = Connection->Provider->NameQueryTimeout;
+ if (Connection->Provider->MacInfo.MediumAsync &&
+ !Connection->Provider->MediumSpeedAccurate) {
+ NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
+ }
+
+ NbfSendNameQuery (
+ Connection,
+ TRUE);
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ NameQueryTimeout);
+ }
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_QUICK_REREGISTER;
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else if ((address->Flags & (ADDRESS_FLAGS_DUPLICATE_NAME|ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ PIRP irp;
+
+ //
+ // the address registration has failed. We signal the user in
+ // the normal way (by failing the open of the address). Now clean up
+ // the transport's data structures.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: duplicate\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+// address->Flags |= ADDRESS_FLAGS_STOPPING;
+
+ //
+ // BUGBUG: This is probably all overkill, the
+ // uframes handler will already have called
+ // NbfStopAddress, which will tear off all
+ // the address files etc., and set the
+ // STOPPING flag which prevents further opens.
+ //
+
+ p = address->AddressFileDatabase.Flink;
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ NbfStopAddressFile (addressFile, address);
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // There will be no more timer events happening, so we dereference the
+ // address to account for the timer.
+ //
+
+ NbfStopAddress (address);
+ NbfDereferenceAddress ("Timer, dup address", address, AREF_TIMER);
+
+ } else {
+
+ //
+ // has the address registration succeeded?
+ //
+
+ if (--(address->Retries) <= 0) { // if retry count exhausted.
+ PIRP irp;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("AddressTimeoutHandler %lx: successful.\n", address);
+ }
+
+ address->Flags &= ~ADDRESS_FLAGS_REGISTERING;
+
+ p = address->AddressFileDatabase.Flink;
+
+ while (p != &address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ p = p->Flink;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("AddressTimeoutHandler %lx: Completing IRP %lx for file %lx\n",
+ address,
+ addressFile->Irp,
+ addressFile);
+ }
+
+ if (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_DPC_SPIN_LOCK (&address->SpinLock);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ NbfDereferenceAddress ("Timer, registered", address, AREF_TIMER);
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("AddressTimeoutHandler %lx: step %x.\n",
+ address,
+ DeviceContext->AddNameQueryRetries - address->Retries);
+ }
+
+ //
+ // restart the timer if we haven't yet completed registration
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&address->SpinLock);
+
+ timeout.LowPart = (ULONG)(-(LONG)DeviceContext->AddNameQueryTimeout);
+ timeout.HighPart = -1;
+ KeSetTimer (&address->Timer,*(PTIME)&timeout, &address->Dpc);
+ (VOID)NbfSendAddNameQuery (address); // send another ADD_NAME_QUERY.
+ }
+
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* AddressTimeoutHandler */
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbfParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+)
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength ==
+ sizeof(TDI_ADDRESS_NETBIOS)) {
+ return((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbfParseTdiAddress */
+
+
+BOOLEAN
+NbfValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+)
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbfPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbfPrint0 ("NbfValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbfValidateTdiAddress */
+
+
+NTSTATUS
+NbfOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ DeviceObject - pointer to the device object describing the NBF transport.
+
+ Irp - a pointer to the Irp used for the creation of the address.
+
+ IrpSp - a pointer to the Irp stack location.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PNBF_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN QuickAdd = FALSE;
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // The network name is in the EA, passed in AssociatedIrp.SystemBuffer
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ if (ea == NULL) {
+ NbfPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (TRANSPORT_ADDRESS UNALIGNED *)&ea->EaName[ea->EaNameLength+1];
+
+ if (!NbfValidateTdiAddress(name, ea->EaValueLength)) {
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // The name can have with multiple entries; we'll use the Netbios one.
+ // This call returns NULL if not Netbios address is found, (PVOID)-1
+ // if it is the broadcast address, and a pointer to a Netbios
+ // address otherwise.
+ //
+
+ netbiosName = NbfParseTdiAddress(name, TRUE);
+
+ if (netbiosName != NULL) {
+ if (netbiosName != (PVOID)-1) {
+ networkName = (PNBF_NETBIOS_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (NBF_NETBIOS_ADDRESS),
+ 'nFBN');
+ if (networkName == NULL) {
+ PANIC ("NbfOpenAddress: PANIC! could not allocate networkName!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 1,
+ sizeof(TA_NETBIOS_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // get the name to local storage
+ //
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
+ } else {
+ networkName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ }
+ RtlCopyMemory (networkName->NetbiosName, netbiosName->NetbiosName, 16);
+
+ if ((netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_UNIQUE) ||
+ (netbiosName->NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_QUICK_GROUP)) {
+ QuickAdd = TRUE;
+ }
+ } else {
+ networkName = NULL;
+ }
+
+ } else {
+ NbfPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("OpenAddress %s: ",
+ ((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ "shared" : "exclusive");
+ NbfDbgShowAddr (networkName);
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = NbfCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+ return status;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context AddressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&DeviceContext->AddressResource, TRUE);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ address = NbfLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = NbfCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (NT_SUCCESS (status)) {
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped. BUGBUG: Need to synchronize Assign and Access).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ PagedPool);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3 ("Assign security A %lx AF %lx, status %lx\n",
+ address,
+ addressFile,
+ status);
+ }
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ NbfDereferenceAddress ("Device context stopping", address, AREF_TEMP_CREATE);
+ NbfDereferenceAddressFile (addressFile);
+ return status;
+
+ }
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: DeviceContext %lx not open\n",
+ address,
+ addressFile,
+ DeviceContext);
+ }
+ NbfDereferenceAddressFile (addressFile);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+
+ NbfReferenceAddress("Opened new", address, AREF_OPEN);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: created.\n",
+ address,
+ addressFile);
+ }
+
+ ExInterlockedInsertTailList(
+ &address->AddressFileDatabase,
+ &addressFile->Linkage,
+ &address->SpinLock);
+
+
+ //
+ // Begin address registration unless this is the broadcast
+ // address (which is a "fake" address with no corresponding
+ // Netbios address) or the reserved address, which we know
+ // is unique since it is based on the adapter address.
+ //
+ // Also, for "quick" add names, do not register.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) &&
+ (!QuickAdd)) {
+
+ NbfRegisterAddress (address); // begin address registration.
+ status = STATUS_PENDING;
+
+ } else {
+
+ address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ }
+
+ NbfDereferenceAddress("temp create", address, AREF_TEMP_CREATE);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint4 ("Access check A %lx AF %lx, %s (%lx)\n",
+ address,
+ addressFile,
+ AccessAllowed ? "allowed" : "not allowed",
+ status);
+ }
+
+ if (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // BUGBUG: Compare DesiredAccess to GrantedAccess?
+ //
+
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+ // BUGBUG: This code is structured funny, the only reason
+ // this is inside this if is to avoid indenting too much.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("Address types differ: old %c, new %c\n",
+ address->NetworkName->NetbiosNameType + 'A',
+ networkName->NetbiosNameType + 'A');
+ }
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ACL bad.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &address->u.ShareAccess,
+ TRUE);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: ShareAccess problem.\n",
+ address,
+ addressFile);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ } else {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // now, if the address registered, we simply return success after
+ // pointing the file object at the address file (which points to
+ // the address). If the address registration is pending, we mark
+ // the registration pending and let the registration completion
+ // routine complete the open. If the address is bad, we simply
+ // fail the open.
+ //
+
+ if ((address->Flags &
+ (ADDRESS_FLAGS_CONFLICT |
+ ADDRESS_FLAGS_REGISTERING |
+ ADDRESS_FLAGS_DEREGISTERING |
+ ADDRESS_FLAGS_DUPLICATE_NAME |
+ ADDRESS_FLAGS_NEEDS_REG |
+ ADDRESS_FLAGS_STOPPING |
+ ADDRESS_FLAGS_BAD_ADDRESS |
+ ADDRESS_FLAGS_CLOSED)) == 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = NULL;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ NbfReferenceAddress("open ready", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address ready.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // if the address is still registering, make the open pending.
+ //
+
+ if ((address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_NEEDS_REG)) != 0) {
+
+ InsertTailList (
+ &address->AddressFileDatabase,
+ &addressFile->Linkage);
+
+ addressFile->Irp = Irp;
+ addressFile->Address = address;
+ addressFile->FileObject = IrpSp->FileObject;
+
+ NbfReferenceAddress("open registering", address, AREF_OPEN);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2("OpenAddress A %lx AF %lx: address registering.\n",
+ address,
+ addressFile);
+ }
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ if ((address->Flags & ADDRESS_FLAGS_CONFLICT) != 0) {
+ status = STATUS_DUPLICATE_NAME;
+ } else {
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint3("OpenAddress A %lx AF %lx: address flags %lx.\n",
+ address,
+ addressFile,
+ address->Flags);
+ }
+
+ NbfDereferenceAddressFile (addressFile);
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // This isn't needed since it was not used in the
+ // creation of the address.
+ //
+
+ if (networkName != NULL) {
+ ExFreePool (networkName);
+ }
+
+ //
+ // Remove the reference from NbfLookupAddress.
+ //
+
+ NbfDereferenceAddress ("Done opening", address, AREF_LOOKUP);
+ }
+
+ return status;
+} /* NbfOpenAddress */
+
+
+VOID
+NbfAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport address. Some minimal
+ initialization is done on the address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure. Returns NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ PSEND_PACKET_TAG SendTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 101,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS),
+ 'aFBN');
+ if (Address == NULL) {
+ PANIC("NBF: Could not allocate address: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 201,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &Address->UIFramePoolHandle,
+ 1,
+ sizeof(SEND_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC("NBF: Could not allocate address UI frame pool: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 311,
+ sizeof(SEND_PACKET_TAG),
+ ADDRESS_RESOURCE_ID);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+
+ //
+ // This code is similar to NbfAllocateUIFrame.
+ //
+
+ Address->UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->UIFrameLength,
+ 'uFBN');
+ if (Address->UIFrame == NULL) {
+ PANIC("NBF: Could not allocate address UI frame: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 411,
+ DeviceContext->UIFrameLength,
+ ADDRESS_RESOURCE_ID);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address->UIFrame, DeviceContext->UIFrameLength);
+
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ Address->UIFramePoolHandle);
+
+ ASSERT (NdisStatus == NDIS_STATUS_SUCCESS);
+
+ Address->UIFrame->NdisPacket = NdisPacket;
+ Address->UIFrame->DataBuffer = NULL;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_ADDRESS_FRAME;
+ SendTag->Owner = (PVOID)Address;
+ SendTag->Frame = Address->UIFrame;
+
+ //
+ // Make the packet header known to the packet descriptor
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ Address->UIFrame->Header,
+ DeviceContext->UIFrameHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ PANIC("NBF: Could not allocate address UI frame buffer: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 511,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+ ExFreePool (Address->UIFrame);
+ NdisFreePacketPool (Address->UIFramePoolHandle);
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ DeviceContext->MemoryUsage +=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+ ++DeviceContext->AddressAllocated;
+
+ Address->Type = NBF_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+// KeInitializeSpinLock (&Address->Interlock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ KeInitializeDpc (&Address->Dpc, AddressTimeoutHandler, (PVOID)Address);
+ KeInitializeTimer (&Address->Timer);
+
+ //
+ // For each address, allocate a receive packet and a receive buffer.
+ //
+
+ NbfAddReceivePacket (DeviceContext);
+ NbfAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* NbfAllocateAddress */
+
+
+VOID
+NbfDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport address.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Address - Pointer to a transport address structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (TransportAddress->UIFrame->NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+ ExFreePool (TransportAddress->UIFrame);
+ NdisFreePacketPool (TransportAddress->UIFramePoolHandle);
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+
+ DeviceContext->MemoryUsage -=
+ sizeof(TP_ADDRESS) +
+ sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG) +
+ DeviceContext->UIFrameLength;
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ NbfRemoveReceivePacket (DeviceContext);
+ NbfRemoveReceiveBuffer (DeviceContext);
+
+} /* NbfDeallocateAddress */
+
+
+NTSTATUS
+NbfCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+ NOTE: This has only the basic NetbiosNameType values, not the
+ QUICK_ ones.
+
+ Address - Pointer to a place where this routine will return a pointer
+ to a transport address structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS pAddress;
+ PLIST_ENTRY p;
+
+
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ if (p == &DeviceContext->AddressPool) {
+
+ if ((DeviceContext->AddressMaxAllocated == 0) ||
+ (DeviceContext->AddressAllocated < DeviceContext->AddressMaxAllocated)) {
+
+ NbfAllocateAddress (DeviceContext, &pAddress);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address at %lx\n", pAddress);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 401,
+ sizeof(TP_ADDRESS),
+ ADDRESS_RESOURCE_ID);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("NbfCreateAddress: Could not allocate address object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ pAddress = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ }
+
+ ++DeviceContext->AddressInUse;
+ if (DeviceContext->AddressInUse > DeviceContext->AddressMaxInUse) {
+ ++DeviceContext->AddressMaxInUse;
+ }
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS | NBF_DEBUG_UFRAMES) {
+ NbfPrint1 ("NbfCreateAddress %lx: ", pAddress);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_AREFS; Counter++) {
+ pAddress->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by the caller.
+
+ pAddress->RefTypes[AREF_TEMP_CREATE] = 1;
+ }
+#endif
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_GROUP;
+
+ }
+
+ if (NetworkName != (PNBF_NETBIOS_ADDRESS)NULL) {
+ ++DeviceContext->AddressCounts[NetworkName->NetbiosName[0]];
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&DeviceContext->AddressDatabase, &pAddress->Linkage);
+ pAddress->Provider = DeviceContext;
+ NbfReferenceDeviceContext ("Create Address", DeviceContext, DCREF_ADDRESS); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* NbfCreateAddress */
+
+
+VOID
+NbfRegisterAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process of the transport address
+ specified, if it has not already been started.
+
+Arguments:
+
+ Address - Pointer to a transport address object to begin registering
+ on the network.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ LARGE_INTEGER Timeout;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: NEEDS_REG 0.\n", Address);
+ }
+
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfRegisterAddress %lx: registering.\n", Address);
+ }
+
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ RtlZeroMemory (Address->UniqueResponseAddress, 6);
+
+ //
+ // Keep a reference on this address until the registration process
+ // completes or is aborted. It will be aborted in UFRAMES.C, in
+ // either the NAME_IN_CONFLICT or ADD_NAME_RESPONSE frame handlers.
+ //
+
+ NbfReferenceAddress ("start registration", Address, AREF_TIMER);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now start registration process by starting up a retransmission timer
+ // and begin sending ADD_NAME_QUERY NetBIOS frames.
+ //
+ // On an async line that is disconnected, we only send one packet
+ // with a short timeout.
+ //
+
+ if (Address->Provider->MacInfo.MediumAsync && !Address->Provider->MediumSpeedAccurate) {
+ Address->Retries = 1;
+ Timeout.LowPart = (ULONG)(-(ADD_NAME_QUERY_TIMEOUT / 10));
+ } else {
+ Address->Retries = Address->Provider->AddNameQueryRetries;
+ Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
+ }
+ Timeout.HighPart = -1;
+ KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
+
+ (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
+} /* NbfRegisterAddress */
+
+
+NTSTATUS
+NbfVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a TP_ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+ PTP_ADDRESS address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile != (PTP_ADDRESS_FILE)NULL) &&
+ (AddressFile->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == NBF_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address != (PTP_ADDRESS)NULL) &&
+ (address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == NBF_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ NbfReferenceAddress ("verify", address, AREF_VERIFY);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbfPrint1("NbfVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+NbfDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool or our lookaside list. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ The routine is called from a worker thread so that the security
+ descriptor can be accessed.
+
+ This worked thread is only queued by NbfDerefAddress. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address = (PTP_ADDRESS)Parameter;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfDestroyAddress %lx:.\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (Address->NetworkName) {
+ --DeviceContext->AddressCounts[Address->NetworkName->NetbiosName[0]];
+ }
+
+ RemoveEntryList (&Address->Linkage);
+
+ if (Address->NetworkName != NULL) {
+ ExFreePool (Address->NetworkName);
+ Address->NetworkName = NULL;
+ }
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ NbfDeallocateAddress (DeviceContext, Address);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address at %lx\n", Address);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ NbfDereferenceDeviceContext ("Destroy Address", DeviceContext, DCREF_ADDRESS); // just housekeeping.
+
+} /* NbfDestroyAddress */
+
+
+#if DBG
+VOID
+NbfRefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Address->ReferenceCount);
+
+} /* NbfRefAddress */
+#endif
+
+
+VOID
+NbfDerefAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Address->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbfDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* NbfDerefAddress */
+
+
+
+VOID
+NbfAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for an address file. Some
+ minimal initialization is done on the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a place where this routine will return
+ a pointer to a transport address file structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_ADDRESS_FILE AddressFile;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS_FILE)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate address file: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 102,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_ADDRESS_FILE),
+ 'fFBN');
+ if (AddressFile == NULL) {
+ PANIC("NBF: Could not allocate address file: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 202,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = NBF_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* NbfAllocateAddressFile */
+
+
+VOID
+NbfDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for an address file.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportAddressFile - Pointer to a transport address file structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportAddressFile);
+ --DeviceContext->AddressFileAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS_FILE);
+
+} /* NbfDeallocateAddressFile */
+
+
+NTSTATUS
+NbfCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AddressFile - Pointer to a place where this routine will return a pointer
+ to a transport address file structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ if (p == &DeviceContext->AddressFilePool) {
+
+ if ((DeviceContext->AddressFileMaxAllocated == 0) ||
+ (DeviceContext->AddressFileAllocated < DeviceContext->AddressFileMaxAllocated)) {
+
+ NbfAllocateAddressFile (DeviceContext, &addressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated address file at %lx\n", addressFile);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 402,
+ sizeof(TP_ADDRESS_FILE),
+ ADDRESS_FILE_RESOURCE_ID);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateAddressFile: Could not allocate address file object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ }
+
+ ++DeviceContext->AddressFileInUse;
+ if (DeviceContext->AddressFileInUse > DeviceContext->AddressFileMaxInUse) {
+ ++DeviceContext->AddressFileMaxInUse;
+ }
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ InitializeListHead (&addressFile->ConnectionDatabase);
+ addressFile->Address = NULL;
+ addressFile->FileObject = NULL;
+ addressFile->Provider = DeviceContext;
+ addressFile->State = ADDRESSFILE_STATE_OPENING;
+ addressFile->ConnectIndicationInProgress = FALSE;
+ addressFile->ReferenceCount = 1;
+ addressFile->CloseIrp = (PIRP)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ addressFile->RegisteredConnectionHandler = FALSE;
+ addressFile->ConnectionHandler = TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ addressFile->DisconnectHandler = TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ addressFile->ReceiveHandler = TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ addressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ addressFile->ExpeditedDataHandler = TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ addressFile->ErrorHandler = TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+
+
+ *AddressFile = addressFile;
+ return STATUS_SUCCESS;
+
+} /* NbfCreateAddress */
+
+
+NTSTATUS
+NbfDestroyAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by NbfDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS address;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+
+ address = AddressFile->Address;
+ DeviceContext = AddressFile->Provider;
+
+ if (address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (address->AddressFileDatabase.Flink == &address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbfDereferenceAddress ("Close", address, AREF_OPEN); // remove the creation hold
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseIrp = AddressFile->CloseIrp;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->AddressFileTotal += DeviceContext->AddressFileInUse;
+ ++DeviceContext->AddressFileSamples;
+ --DeviceContext->AddressFileInUse;
+
+ if ((DeviceContext->AddressFileAllocated - DeviceContext->AddressFileInUse) >
+ DeviceContext->AddressFileInitAllocated) {
+ NbfDeallocateAddressFile (DeviceContext, AddressFile);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated address file at %lx\n", AddressFile);
+ }
+ } else {
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ if (CloseIrp != (PIRP)NULL) {
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyAddressFile */
+
+
+VOID
+NbfReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ASSERT (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&AddressFile->ReferenceCount);
+
+} /* NbfReferenceAddressFile */
+
+
+VOID
+NbfDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&AddressFile->ReferenceCount);
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyAddressFile (AddressFile);
+ }
+} /* NbfDerefAddressFile */
+
+
+PTP_ADDRESS
+NbfLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ TP_ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the DeviceContext
+ spinlock held.
+
+Arguments:
+
+ DeviceContext - Pointer to the device object and its extension.
+ NetworkName - Pointer to an NBF_NETBIOS_ADDRESS structure containing the
+ network name.
+
+Return Value:
+
+ Pointer to the TP_ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PLIST_ENTRY p;
+ ULONG i;
+
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // If the network name is specified and the network names don't match,
+ // then the addresses don't match.
+ //
+
+ i = NETBIOS_NAME_LENGTH; // length of a Netbios name
+
+ if (address->NetworkName != NULL) {
+ if (NetworkName != NULL) {
+ if (!RtlEqualMemory (
+ address->NetworkName->NetbiosName,
+ NetworkName->NetbiosName,
+ i)) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+
+ } else {
+ if (NetworkName != NULL) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint2 ("NbfLookupAddress DC %lx: found %lx ", DeviceContext, address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ NbfReferenceAddress ("lookup", address, AREF_LOOKUP);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfLookupAddress DC %lx: did not find ", address);
+ NbfDbgShowAddr (NetworkName);
+ }
+
+ return NULL;
+
+} /* NbfLookupAddress */
+
+
+PTP_CONNECTION
+NbfLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN UCHAR RemoteSessionNumber
+ )
+
+/*++
+
+Routine Description:
+
+
+ This routine scans the connections associated with the
+ given address, and determines if there is an connection
+ associated with the specific remote address and session
+ number which is becoming active. This is used
+ in determining whether name queries should be processed,
+ or ignored as duplicates.
+
+Arguments:
+
+ Address - Pointer to the address object.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+ RemoteSessionNumber - The session number assigned to this
+ connection by the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+ BOOLEAN Found = FALSE;
+
+
+ //
+ // Hold the spinlock so the connection database doesn't
+ // change.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) == 0)) {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, and the connection's RSN is
+ // the same (or zero, which is a temporary condition where
+ // we should err on the side of caution), then return the
+ // connection, which will cause the NAME_QUERY to be ignored.
+ //
+
+ if ((RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) &&
+ ((connection->Rsn == RemoteSessionNumber) || (connection->Rsn == 0))) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ NbfReferenceConnection ("Lookup found", connection, CREF_LISTENING);
+ Found = TRUE;
+
+ }
+
+ } else {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupRemoteName\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ return (PTP_CONNECTION)NULL;
+ }
+
+ if (Found) {
+ return connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+NbfMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN UCHAR NameType,
+ IN PUCHAR NetBIOSName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to compare the addressing information in a
+ TP_ADDRESS object with the 16-byte NetBIOS name in a frame header.
+ If they match, then this routine returns TRUE, else it returns FALSE.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+ NameType - One of NETBIOS_NAME_TYPE_GROUP, NETBIOS_NAME_TYPE_UNIQUE,
+ or NETBIOS_NAME_TYPE_EITHER. Controls what type we are matching
+ on, if it matters.
+
+ NetBIOSName - Pointer to a 16-byte character string (non-terminated),
+ or NULL if this is a received broadcast address.
+
+Return Value:
+
+ BOOLEAN, TRUE if match, FALSE if not.
+
+--*/
+
+{
+
+ PULONG AddressNamePointer;
+ ULONG UNALIGNED * NetbiosNamePointer;
+
+ //
+ // If this is address is the Netbios broadcast address, the comparison
+ // succeeds only if the passed in address is also NULL.
+ //
+
+ if (Address->NetworkName == NULL) {
+
+ if (NetBIOSName == NULL) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else if (NetBIOSName == NULL) {
+
+ return FALSE;
+
+ }
+
+ //
+ // Do a quick check of the first character in the names.
+ //
+
+ if (Address->NetworkName->NetbiosName[0] != NetBIOSName[0]) {
+ return FALSE;
+ }
+
+ //
+ // If name type is important and it doesn't match
+ // this address' type, fail.
+ //
+
+ if (NameType != NETBIOS_NAME_TYPE_EITHER) {
+
+ if (Address->NetworkName->NetbiosNameType != (USHORT)NameType) {
+
+ return FALSE;
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DATAGRAMS) {
+ NbfPrint2 ("MatchNetbiosAddress %lx: compare %.16s to ", Address, NetBIOSName);
+ NbfDbgShowAddr (Address->NetworkName);
+ }
+
+ //
+ // Now compare the 16-character Netbios names as ULONGs
+ // for speed. We know the one stored in the address
+ // structure is aligned.
+ //
+
+ AddressNamePointer = (PULONG)(Address->NetworkName->NetbiosName);
+ NetbiosNamePointer = (ULONG UNALIGNED *)NetBIOSName;
+
+ if ((AddressNamePointer[0] == NetbiosNamePointer[0]) &&
+ (AddressNamePointer[1] == NetbiosNamePointer[1]) &&
+ (AddressNamePointer[2] == NetbiosNamePointer[2]) &&
+ (AddressNamePointer[3] == NetbiosNamePointer[3])) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+} /* NbfMatchNetbiosAddress */
+
+
+VOID
+NbfStopAddress(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an address and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding addressfiles are removed from the addressfile database, and
+ all their activities are shut down.
+
+Arguments:
+
+ Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_ADDRESS_FILE addressFile;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // If we're already stopping this address, then don't try to do it again.
+ //
+
+ if (!(Address->Flags & ADDRESS_FLAGS_STOPPING)) {
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: stopping\n", Address);
+ }
+
+ NbfReferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ Address->Flags |= ADDRESS_FLAGS_STOPPING;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+
+ //
+ // Run down all addressfiles on this address. This
+ // will leave the address with no references
+ // potentially, but we don't need a temp one
+ // because every place that calls NbfStopAddress
+ // already has a temp reference.
+ //
+
+ while (!IsListEmpty (&Address->AddressFileDatabase)) {
+ p = RemoveHeadList (&Address->AddressFileDatabase);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ addressFile->Address = NULL;
+ addressFile->FileObject->FsContext = NULL;
+ addressFile->FileObject->FsContext2 = NULL;
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Run-down this addressFile without the lock on.
+ // We don't care about removing ourselves from
+ // the address' ShareAccess because we are
+ // tearing it down.
+ //
+
+ NbfStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbfDereferenceAddressFile (addressFile);
+
+ NbfDereferenceAddress ("stop address", Address, AREF_OPEN);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Stopping", Address, AREF_TEMP_STOP);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddress %lx: already stopping\n", Address);
+ }
+
+ }
+
+} /* NbfStopAddress */
+
+
+NTSTATUS
+NbfStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ LIST_ENTRY localIrpList;
+ PLIST_ENTRY p, pFlink;
+ PIRP irp;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: already closing.\n", AddressFile);
+ }
+ return STATUS_SUCCESS;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfStopAddressFile %lx: closing.\n", AddressFile);
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localIrpList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of NbfDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 |= CONNECTION_FLAGS2_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ NbfReferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfStopAddressFile\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+#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 = AddressFile->Address->NetworkName->NetbiosName;
+ NbfPrint2( "TpStopEndpoint stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ KeLowerIrql (oldirql1);
+ NbfDereferenceConnection ("Close AddressFile", connection, CREF_STOP_ADDRESS);
+
+ NbfDereferenceAddress ("Destroy association", Address, AREF_CONNECTION);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ //
+ // If the address has a datagram send in progress, skip the
+ // first one, it will complete when the NdisSend completes.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ if (Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS) {
+ ASSERT (p != &Address->SendDatagramQueue);
+ p = p->Flink;
+ }
+
+ for ( ;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (IoGetCurrentIrpStackLocation(irp)->FileObject->FsContext == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localIrpList, p);
+ }
+
+ //
+ // and finally, signal failure if the address file was waiting for a
+ // registration to complete (Irp is set to NULL when this succeeds).
+ //
+
+ if (AddressFile->Irp != NULL) {
+ PIRP irp=AddressFile->Irp;
+#if DBG
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ DbgPrint ("NBF: AddressFile %lx closed while opening!!\n", AddressFile);
+ DbgBreakPoint();
+ }
+#endif
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ LEAVE_NBF;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localIrpList)) {
+ KIRQL cancelIrql;
+
+ p = RemoveHeadList (&localIrpList);
+ irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_NETWORK_NAME_DELETED;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Datagram aborted", Address, AREF_REQUEST);
+ }
+
+} /* NbfStopAddressFile */
+
+
+NTSTATUS
+NbfCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Irp - the Irp Address - Pointer to a TP_ADDRESS object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the Irp does not
+ point to a real address.
+
+--*/
+
+{
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+
+ addressFile = IrpSp->FileObject->FsContext;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfCloseAddress AF %lx:\n", addressFile);
+ }
+
+ addressFile->CloseIrp = Irp;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ address = addressFile->Address;
+ ASSERT (address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&addressFile->Provider->AddressResource, TRUE);
+ IoRemoveShareAccess (addressFile->FileObject, &address->u.ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ NbfStopAddressFile (addressFile, address);
+ NbfDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ NbfDereferenceAddress ("IRP_MJ_CLOSE", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* NbfCloseAddress */
+
+
+NTSTATUS
+NbfSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to acquire a hold on the SendDatagramQueue of
+ the specified address, prepare the next datagram for shipment, and
+ call NbfSendUIMdlFrame to actually do the work. When NbfSendUIMdlFrame
+ is finished, it will cause an I/O completion routine in UFRAMES.C to
+ be called, at which time this routine is called again to handle the
+ next datagram in the pipeline.
+
+ NOTE: This routine must be called at a point where the address
+ has another reference that will keep it around.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ PUCHAR LocalName;
+
+ IF_NBFDBG (NBF_DEBUG_ADDRESS) {
+ NbfPrint1 ("NbfSendDatagramsOnAddress %lx:\n", Address);
+ }
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (!(Address->Flags & ADDRESS_FLAGS_SEND_IN_PROGRESS)) {
+
+ //
+ // If the queue is empty, don't do anything.
+ //
+
+ if (IsListEmpty (&Address->SendDatagramQueue)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and NBF header will not be used for two requests at the
+ // same time.
+ //
+
+ Address->Flags |= ADDRESS_FLAGS_SEND_IN_PROGRESS;
+
+ //
+ // We own the hold, and we've released the spinlock. So pick off the
+ // next datagram to be sent, and ship it.
+ //
+
+ p = Address->SendDatagramQueue.Flink;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // If there is no remote Address specified (the Address specified has
+ // length 0), this is a broadcast datagram. If anything is specified, it
+ // will be used as a netbios address.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ remoteAddress = NbfParseTdiAddress (
+ ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress,
+ TRUE);
+ ASSERT (remoteAddress != NULL);
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->UIFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS) +
+ Irp->IoStatus.Information,
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&(Address->UIFrame->Header[HeaderLength]));
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the correct Netbios header.
+ //
+
+ if (Address->NetworkName != NULL) {
+ LocalName = Address->NetworkName->NetbiosName;
+ } else {
+ LocalName = DeviceContext->ReservedNetBIOSAddress;
+ }
+
+ if (remoteAddress == (PVOID)-1) {
+
+ ConstructDatagramBroadcast (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ LocalName);
+
+ } else {
+
+ ConstructDatagram (
+ (PNBF_HDR_CONNECTIONLESS)&(Address->UIFrame->Header[HeaderLength]),
+ (PNAME)remoteAddress->NetbiosName,
+ LocalName);
+
+ }
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DatagramBytesSent,
+ Irp->IoStatus.Information);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ NbfSetNdisPacketLength(Address->UIFrame->NdisPacket, HeaderLength);
+
+ if (Irp->MdlAddress) {
+ NdisChainBufferAtBack (Address->UIFrame->NdisPacket, (PNDIS_BUFFER)Irp->MdlAddress);
+ }
+
+ NbfSendUIMdlFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler in
+ // UFRAMES.C. At that time, if there is another outstanding datagram
+ // to send, it will reset the hold and call this routine again.
+ //
+
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ return STATUS_SUCCESS;
+} /* NbfSendDatagramsOnAddress */
diff --git a/private/ntos/tdi/nbf/autodial.c b/private/ntos/tdi/nbf/autodial.c
new file mode 100644
index 000000000..85bea057e
--- /dev/null
+++ b/private/ntos/tdi/nbf/autodial.c
@@ -0,0 +1,502 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ This module contains code that interacts with the
+ automatic connection driver (rasacd.sys):
+
+ o NbfNoteNewConnection
+ o NbfAcdBind
+ o NbfAcdUnbind
+
+Author:
+
+ Anthony Discolo (adiscolo) 6 September 1995
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables.
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbf ';
+
+
+
+BOOLEAN
+NbfCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+ if (nArgs != 1)
+ return FALSE;
+
+ return (pArgs[0] == pArg);
+} // NbfCancelAutoDialRequest
+
+
+
+VOID
+NbfRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION pConnection = pArgs[0];
+ KIRQL irql;
+ BOOL fStopping;
+
+ //
+ // Check for a destroyed connection.
+ //
+ if (pConnection == NULL)
+ return;
+ status = NbfVerifyConnectionObject(pConnection);
+ if (status != STATUS_SUCCESS) {
+ DbgPrint(
+ "NbfRetryTdiConnect: NbfVerifyConnectionObject failed (status=0x%x)\n",
+ status);
+ return;
+ }
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbfRetryTdiConnect: fSuccess=%d, pConnection=0x%x, STOPPING=%d\n",
+ fSuccess,
+ pConnection,
+ pConnection->Flags2 & CONNECTION_FLAGS2_STOPPING);
+#endif
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+ //
+ // Check to see if the connection
+ // is closing.
+ //
+ ACQUIRE_DPC_SPIN_LOCK(&pConnection->SpinLock);
+ fStopping = (pConnection->Flags2 & CONNECTION_FLAGS2_STOPPING);
+ //
+ // Clear the automatic connection
+ // in-progress flag, and set the
+ // autoconnected flag.
+ //
+ pConnection->Flags2 &= ~CONNECTION_FLAGS2_AUTOCONNECTING;
+ pConnection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECTED;
+ RELEASE_DPC_SPIN_LOCK(&pConnection->SpinLock);
+ if (!fStopping) {
+ if (fSuccess) {
+ //
+ // Restart the name query.
+ //
+ pConnection->Retries =
+ (USHORT)pConnection->Provider->NameQueryRetries;
+ NbfSendNameQuery (
+ pConnection,
+ TRUE);
+ NbfStartConnectionTimer (
+ pConnection,
+ ConnectionEstablishmentTimeout,
+ pConnection->Provider->NameQueryTimeout);
+ }
+ else {
+ //
+ // Terminate the connection with an error.
+ //
+ NbfStopConnection(pConnection, STATUS_BAD_NETWORK_PATH);
+ }
+ }
+ KeLowerIrql(irql);
+ NbfDereferenceConnection ("NbfRetryTdiConnect", pConnection, CREF_BY_ID);
+} /* NbfRetryTdiConnect */
+
+
+
+BOOLEAN
+NbfCancelTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDeviceObject: a pointer to the device object for this driver
+
+ pIrp: a pointer to the irp to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ PIO_STACK_LOCATION pIrpSp;
+ PTP_CONNECTION pConnection;
+ ACD_ADDR addr;
+
+ UNREFERENCED_PARAMETER(pDeviceObject);
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+ pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
+ pConnection = pIrpSp->FileObject->FsContext;
+ if (pConnection == NULL)
+ return FALSE;
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbfCancelTdiConnect: pIrp=0x%x, pConnection=0x%x\n",
+ pIrp,
+ pConnection);
+#endif
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbfCancelAutoDialRequest,
+ pConnection);
+} // NbfCancelTdiConnect
+
+
+
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pConnection - a pointer to the TP_CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pArg - the single parameter to the callback procedure
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[1];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic
+ // connection on this connection, then
+ // don't try again.
+ //
+ if (pConnection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+#ifdef notdef // DBG
+ DbgPrint("NbfAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbfRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pArg;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 1,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the CONNECTION_FLAGS2_AUTOCONNECTING flag on
+ // the connection. This will prevent it from being
+ // aborted during the automatic connection process.
+ //
+ pConnection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECTING;
+ }
+
+ return bSuccess;
+} // NbfAttemptAutoDial
+
+
+
+VOID
+NbfNoteNewConnection(
+ PTP_CONNECTION pConnection,
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+ Inform the automatic connection driver of a successful
+ new connection.
+
+Arguments:
+ Connection - a pointer to a connection object
+
+ DeviceContext - a pointer to the device context
+
+Return Value:
+ None.
+
+--*/
+
+{
+ KIRQL irql;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG ulcChars;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->CalledAddress.NetbiosName, 15);
+#ifdef notdef // DBG
+ DbgPrint("NbfNoteNewConnection: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Eliminate the "/Device/Nbf_" prefix when
+ // copying the adapter name.
+ //
+ adapter.fType = ACD_ADAPTER_NAME;
+ ulcChars = DeviceContext->DeviceNameLength - 12;
+ if (ulcChars >= ACD_ADAPTER_NAME_LEN)
+ ulcChars = ACD_ADAPTER_NAME_LEN - 1;
+ RtlCopyMemory(
+ adapter.szName,
+ &DeviceContext->DeviceName[12],
+ ulcChars * sizeof (WCHAR));
+ adapter.szName[ulcChars] = L'\0';
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbfNoteNewConnection
+
+
+
+VOID
+NbfAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbfAcdBind
+
+
+
+VOID
+NbfAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbfAcdUnbind
+
+#endif // RASAUTODIAL
+
diff --git a/private/ntos/tdi/nbf/connect.c b/private/ntos/tdi/nbf/connect.c
new file mode 100644
index 000000000..af2aec64b
--- /dev/null
+++ b/private/ntos/tdi/nbf/connect.c
@@ -0,0 +1,1700 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAccept
+ o TdiListen
+ o TdiConnect
+ o TdiDisconnect
+ o TdiAssociateAddress
+ o TdiDisassociateAddress
+ o OpenConnection
+ o CloseConnection
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef notdef // RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+#ifdef notdef // RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported functions.
+//
+VOID
+NbfRetryPreTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION Connection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ );
+
+VOID
+NbfCancelPreTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+#endif // RASAUTODIAL
+
+NTSTATUS
+NbfTdiConnectCommon(
+ IN PIRP Irp
+ );
+
+
+
+NTSTATUS
+NbfTdiAccept(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAccept request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiAccept: Entered.\n");
+ }
+
+ //
+ // Get the connection this is associated with; if there is none, get out.
+ // This adds a connection reference of type BY_ID if successful.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // This adds a connection reference of type BY_ID if successful.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // just set the connection flags to allow reads and writes to proceed.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ //
+ // Turn off the stopping flag for this connection.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+
+ if (connection->AddressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_WAITING_SC) != 0) {
+
+ //
+ // We previously completed a listen, now the user is
+ // coming back with an accept, Set this flag to allow
+ // the connection to proceed.
+ //
+ // BUGBUG: If the connection has gone down in the
+ // meantime, we have just reenabled it.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ connection->Flags |= CONNECTION_FLAGS_READY;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (connection->Provider, OpenConnections);
+
+ //
+ // Set this flag to enable disconnect indications; once
+ // the client has accepted he expects those.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfSendSessionConfirm (connection);
+
+ } else {
+
+ //
+ // This accept is being called at some point before
+ // the link is up; directly from the connection handler
+ // or at some point slightly later. We don't set
+ // FLAGS2_REQ_COMPLETED now because the reference
+ // count is not high enough; we set it when we get
+ // the session initialize.
+ //
+ // BUGBUG: If the connection goes down in the meantime,
+ // we won't indicate the disconnect.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ }
+
+ NbfDereferenceConnection ("Temp TdiAccept", connection, CREF_BY_ID);
+
+ KeLowerIrql (oldirql);
+
+ return STATUS_SUCCESS;
+
+} /* NbfTdiAccept */
+
+
+NTSTATUS
+NbfTdiAssociateAddress(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and the address for
+ the user.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PFILE_OBJECT fileObject;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS oldAddress;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_ASSOCIATE parameters;
+ PDEVICE_CONTEXT deviceContext;
+
+ KIRQL oldirql, oldirql2;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiAssociateAddress: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ connection = irpSp->FileObject->FsContext;
+ status = NbfVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ //
+ // Make sure this connection is ready to be associated.
+ //
+
+ oldAddress = (PTP_ADDRESS)NULL;
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+
+ //
+ // The connection is already associated with
+ // an active connection...bad!
+ //
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+
+ return STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // See if there is an old association hanging around...
+ // this happens if the connection has been disassociated,
+ // but not closed.
+ //
+
+ if (connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiAssociateAddress: removing association.\n");
+ }
+
+ //
+ // Save this; since it is non-null this address
+ // will be dereferenced after the connection
+ // spinlock is released.
+ //
+
+ oldAddress = connection->AddressFile->Address;
+
+ //
+ // Remove the old association.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RemoveEntryList (&connection->AddressList);
+ RemoveEntryList (&connection->AddressFileList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ }
+
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 1 in NbfTdiAssociateAddress\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+ return GetExceptionCode();
+ }
+
+
+ //
+ // If we removed an old association, dereference the
+ // address.
+ //
+
+ if (oldAddress != (PTP_ADDRESS)NULL) {
+
+ NbfDereferenceAddress("Removed old association", oldAddress, AREF_CONNECTION);
+
+ }
+
+
+ deviceContext = connection->Provider;
+
+ parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&irpSp->Parameters;
+
+ //
+ // get a pointer to the address File Object, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ status = ObReferenceObjectByHandle (
+ parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *) &fileObject,
+ NULL);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // we might have one of our address objects; verify that.
+ //
+
+ addressFile = fileObject->FsContext;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint3 ("NbfTdiAssociateAddress: Connection %lx Irp %lx AddressFile %lx \n",
+ connection, Irp, addressFile);
+ }
+
+ if (NT_SUCCESS (NbfVerifyAddressObject (addressFile))) {
+
+ //
+ // have an address and connection object. Add the connection to the
+ // address object database. Also add the connection to the address
+ // file object db (used primarily for cleaning up). Reference the
+ // address to account for one more reason for it staying open.
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+ if ((addressFile->Address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint2 ("NbfTdiAssociateAddress: Valid Address %lx %lx\n",
+ addressFile->Address, addressFile);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ NbfReferenceAddress (
+ "Connection associated",
+ addressFile->Address,
+ AREF_CONNECTION);
+
+#if DBG
+ if (!(IsListEmpty(&connection->AddressList))) {
+ DbgPrint ("NBF: C %lx, new A %lx, in use\n",
+ connection, addressFile->Address);
+ DbgBreakPoint();
+ }
+#endif
+ InsertTailList (
+ &addressFile->Address->ConnectionDatabase,
+ &connection->AddressList);
+
+#if DBG
+ if (!(IsListEmpty(&connection->AddressFileList))) {
+ DbgPrint ("NBF: C %lx, new AF %lx, in use\n",
+ connection, addressFile);
+ DbgBreakPoint();
+ }
+#endif
+ InsertTailList (
+ &addressFile->ConnectionDatabase,
+ &connection->AddressFileList);
+
+ connection->AddressFile = addressFile;
+ connection->Flags2 |= CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags2 &= ~CONNECTION_FLAGS2_DISASSOCIATED;
+
+ if (addressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // The connection is closing, stop the
+ // association.
+ //
+
+ status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 2 in NbfTdiAssociateAddress\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ status = GetExceptionCode();
+ }
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE; //BUGBUG: should this be more informative?
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Temp associate", addressFile->Address, AREF_VERIFY);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ //
+ // Note that we don't keep a reference to this file object around.
+ // That's because the IO subsystem manages the object for us; we simply
+ // want to keep the association. We only use this association when the
+ // IO subsystem has asked us to close one of the file object, and then
+ // we simply remove the association.
+ //
+
+ ObDereferenceObject (fileObject);
+
+ } else {
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ NbfDereferenceConnection ("Temp Ref Associate", connection, CREF_BY_ID);
+
+ return status;
+
+} /* TdiAssociateAddress */
+
+
+NTSTATUS
+NbfTdiDisassociateAddress(
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection and the address
+ for the user. If the connection has not been stopped, it will be stopped
+ here.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTP_CONNECTION connection;
+ NTSTATUS status;
+// PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiDisassociateAddress: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // and now we disassociate the address. This only removes
+ // the appropriate reference for the connection, the
+ // actually disassociation will be done later.
+ //
+ // The DISASSOCIATED flag is used to make sure that
+ // only one person removes this reference.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Temp use in Associate", connection, CREF_BY_ID);
+
+ return STATUS_SUCCESS;
+
+} /* TdiDisassociateAddress */
+
+
+
+NTSTATUS
+NbfTdiConnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiConnect: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // Check that the remote is a Netbios address.
+ //
+
+ if (!NbfValidateTdiAddress(
+ parameters->RequestConnectionInformation->RemoteAddress,
+ parameters->RequestConnectionInformation->RemoteAddressLength)) {
+
+ NbfDereferenceConnection ("Invalid Address", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress((PTRANSPORT_ADDRESS)(parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteAddress == NULL) {
+
+ NbfDereferenceConnection ("Not Netbios", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // copy the called address someplace we can use it.
+ //
+
+ connection->CalledAddress.NetbiosNameType =
+ RemoteAddress->NetbiosNameType;
+
+ RtlCopyMemory(
+ connection->CalledAddress.NetbiosName,
+ RemoteAddress->NetbiosName,
+ 16);
+
+#ifdef notdef // RASAUTODIAL
+ if (fAcdLoadedG) {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbfAttemptAutoDial(
+ connection,
+ ACD_NOTIFICATION_PRECONNECT,
+ NbfRetryPreTdiConnect,
+ Irp))
+ {
+ ACQUIRE_SPIN_LOCK(&connection->SpinLock, &oldirql);
+ connection->Flags2 |= CONNECTION_FLAGS2_AUTOCONNECT;
+ connection->Status = STATUS_PENDING;
+ RELEASE_SPIN_LOCK(&connection->SpinLock, oldirql);
+ NbfDereferenceConnection ("Automatic connection", connection, CREF_BY_ID);
+ //
+ // Set a special cancel routine on the irp
+ // in case we get cancelled during the
+ // automatic connection.
+ //
+ IoSetCancelRoutine(Irp, NbfCancelPreTdiConnect);
+ return STATUS_PENDING;
+ }
+ }
+#endif // RASAUTODIAL
+
+ return NbfTdiConnectCommon(Irp);
+} // NbfTdiConnect
+
+
+
+NTSTATUS
+NbfTdiConnectCommon(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiConnect request for the transport provider.
+ Note: the caller needs to call NbfVerifyConnectionObject(pConnection)
+ before calling this routine.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG NameQueryTimeout;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfTdiConnectCommon: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no connect request should take more
+ // than 15 seconds if there is someone out there. We'll assume that's
+ // what the user wanted if they specify -1 as the timer length.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("TdiConnect: Modifying user timeout to %lx seconds.\n",
+ TDI_TIMEOUT_CONNECT);
+ }
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_CONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ NbfDereferenceConnection ("Throw away", connection, CREF_BY_ID);
+ return status; // return with failure.
+ } else {
+
+ // Reference the connection since NbfDestroyRequest derefs it.
+
+ NbfReferenceConnection("For connect request", connection, CREF_REQUEST);
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ tpRequest->Owner = ConnectionType;
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+
+ //
+ // Initialize this now, we cut these down on an async medium
+ // that is disconnected.
+ //
+
+ connection->Retries = (USHORT)connection->Provider->NameQueryRetries;
+ NameQueryTimeout = connection->Provider->NameQueryTimeout;
+
+ if (connection->Provider->MacInfo.MediumAsync) {
+
+ //
+ // If we are on an async medium, then we need to send out
+ // a committed NAME_QUERY frame right from the start, since
+ // the FIND_NAME frames are not forwarded by the gateway.
+ //
+
+ connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
+ CONNECTION_FLAGS2_WAIT_NR); // wait for NAME_RECOGNIZED.
+
+ //
+ // Because we may call NbfTdiConnect twice
+ // via an automatic connection, check to see
+ // if an LSN has already been assigned.
+ //
+ if (!(connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_GROUP_LSN;
+
+ if (NbfAssignGroupLsn(connection) != STATUS_SUCCESS) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+ RemoveEntryList(&tpRequest->Linkage);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection("Temporary Use 1", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+
+ }
+ }
+
+ if (!connection->Provider->MediumSpeedAccurate) {
+
+ //
+ // The link is not up, so we cut our timeouts down.
+ // We still send one frame so that loopback works.
+ //
+
+ connection->Retries = 1;
+ NameQueryTimeout = NAME_QUERY_TIMEOUT / 10;
+
+ }
+
+ } else {
+
+ //
+ // Normal connection, we send out a FIND_NAME first.
+ //
+
+ connection->Flags2 |= (CONNECTION_FLAGS2_CONNECTOR | // we're the initiator.
+ CONNECTION_FLAGS2_WAIT_NR_FN); // wait for NAME_RECOGNIZED.
+
+ }
+
+ connection->Flags2 &= ~(CONNECTION_FLAGS2_STOPPING |
+ CONNECTION_FLAGS2_INDICATING);
+ connection->Status = STATUS_PENDING;
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelConnection);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+ }
+
+
+ //
+ // On "easily disconnected" networks, quick reregister
+ // (one ADD_NAME_QUERY) the address if NEED_REREGISTER
+ // is set (happens when we get a five-second period
+ // with no multicast activity). If we are currently
+ // quick reregistering, wait for it to complete.
+ //
+
+ if (connection->Provider->EasilyDisconnected) {
+
+ PTP_ADDRESS Address;
+ LARGE_INTEGER Timeout;
+
+ //
+ // If the address needs (or is) reregistering, then do wait,
+ // setting a flag so the connect will be resumed when the
+ // reregistration times out.
+ //
+
+ Address = connection->AddressFile->Address;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if ((Address->Flags &
+ (ADDRESS_FLAGS_NEED_REREGISTER | ADDRESS_FLAGS_QUICK_REREGISTER)) != 0) {
+
+ connection->Flags2 |= CONNECTION_FLAGS2_W_ADDRESS;
+
+ if (Address->Flags & ADDRESS_FLAGS_NEED_REREGISTER) {
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEED_REREGISTER;
+ Address->Flags |= ADDRESS_FLAGS_QUICK_REREGISTER;
+
+ NbfReferenceAddress ("start registration", Address, AREF_TIMER);
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ //
+ // Now start reregistration process by starting up a retransmission timer
+ // and begin sending ADD_NAME_QUERY NetBIOS frames.
+ //
+
+ Address->Retries = 1;
+ Timeout.LowPart = (ULONG)(-(LONG)Address->Provider->AddNameQueryTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Address->Timer, *(PTIME)&Timeout, &Address->Dpc);
+
+ (VOID)NbfSendAddNameQuery (Address); // send first ADD_NAME_QUERY.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ }
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection("Temporary Use 4", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ }
+
+ }
+
+ //
+ // Send the NAME_QUERY frame as a FIND.NAME to get a NAME_RECOGNIZED
+ // frame back. The first time we send this frame, we are just looking
+ // for the data link information to decide whether we already have
+ // a link with the remote NetBIOS name. If we do, we can reuse it.
+ // If we don't, then we make one first, and then use it. A consequence
+ // of this is that we really engage in an extra non-committal NQ/NR
+ // exchange up front to locate the remote guy, and then commit to an actual
+ // LSN with a second NQ/NR sequence to establish the transport connection
+ //
+
+ NbfSendNameQuery (
+ connection,
+ TRUE);
+
+ //
+ // Start the connection timer (do this at the end, so that
+ // if we get delayed in this routine the connection won't
+ // get into an unexpected state).
+ //
+
+ NbfStartConnectionTimer (
+ connection,
+ ConnectionEstablishmentTimeout,
+ NameQueryTimeout);
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection("Temporary Use 3", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+
+} /* TdiConnect */
+
+
+
+NTSTATUS
+NbfTdiDisconnect(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiDisconnect request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ KIRQL oldirql;
+ NTSTATUS status;
+
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiDisconnect: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ STRING remoteName;
+ STRING 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( "TdiDisconnect entered for connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+
+ //
+ // if the connection is currently stopping, there's no reason to blow
+ // it away...
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+#if 0
+ NbfPrint2 ("TdiDisconnect: ignoring disconnect %lx, connection stopping (%lx)\n",
+ connection, connection->Status);
+#endif
+
+ //
+ // In case a connect indication is in progress.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+
+ //
+ // If possible, queue the disconnect. This flag is cleared
+ // when the indication is about to be done.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_LDISC) == 0) {
+#if DBG
+ DbgPrint ("NBF: Queueing disconnect irp %lx\n", Irp);
+#endif
+ connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
+ status = STATUS_SUCCESS;
+ } else {
+ status = connection->Status;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ KeLowerIrql (oldirql);
+ NbfDereferenceConnection ("Ignoring disconnect", connection, CREF_BY_ID); // release our lookup reference.
+ return status;
+
+ }
+
+ connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_PRE_ACCEPT |
+ CONNECTION_FLAGS2_WAITING_SC);
+
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+ connection->Flags2 |= CONNECTION_FLAGS2_LDISC;
+
+ //
+ // Set this flag so the disconnect IRP is completed.
+ //
+ // BUGBUG: If the connection goes down before we can
+ // call NbfStopConnection with STATUS_LOCAL_DISCONNECT,
+ // the disconnect IRP won't get completed.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+// connection->DisconnectIrp = Irp;
+
+ //
+ // fix up the timeout if required; no disconnect request should take very
+ // long. However, the user can cause the timeout to not happen if they
+ // desire that.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL)(&irpSp->Parameters);
+
+ //
+ // fix up the timeout if required; no disconnect request should take more
+ // than 15 seconds. We'll assume that's what the user wanted if they
+ // specify -1 as the timer.
+ //
+
+ if (parameters->RequestSpecific != NULL) {
+ if ((((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart == -1) &&
+ (((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart == -1)) {
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("TdiDisconnect: Modifying user timeout to %lx seconds.\n",
+ TDI_TIMEOUT_CONNECT);
+ }
+
+ timeout.LowPart = (ULONG)(-TDI_TIMEOUT_DISCONNECT * 10000000L); // n * 10 ** 7 => 100ns units
+ if (timeout.LowPart != 0) {
+ timeout.HighPart = -1L;
+ } else {
+ timeout.HighPart = 0;
+ }
+
+ } else {
+ timeout.LowPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->LowPart;
+ timeout.HighPart = ((PLARGE_INTEGER)(parameters->RequestSpecific))->HighPart;
+ }
+ }
+
+ //
+ // Now the reason for the disconnect
+ //
+
+ if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_RELEASE) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DESTROY;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
+ connection->Flags2 |= CONNECTION_FLAGS2_ABORT;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
+ connection->Flags2 |= CONNECTION_FLAGS2_ORDREL;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("TdiDisconnect calling NbfStopConnection %lx\n", connection);
+ }
+
+ //
+ // This will get passed to IoCompleteRequest during TdiDestroyConnection
+ //
+
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Disconnecting", connection, CREF_BY_ID); // release our lookup reference.
+
+ //
+ // This request will be completed by TdiDestroyConnection once
+ // the connection reference count drops to 0.
+ //
+
+ return STATUS_SUCCESS;
+} /* TdiDisconnect */
+
+
+NTSTATUS
+NbfTdiListen(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiListen request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_LISTEN parameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ PVOID RequestBuffer2;
+ ULONG RequestBuffer2Length;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiListen: Entered.\n");
+ }
+
+ //
+ // validate this connection
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference of type BY_ID.
+ //
+
+ status = NbfVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
+
+ //
+ // Record the remote address if there is one.
+ //
+
+ ListenInformation = parameters->RequestConnectionInformation;
+
+ if ((ListenInformation != NULL) &&
+ (ListenInformation->RemoteAddress != NULL)) {
+
+ if ((NbfValidateTdiAddress(
+ ListenInformation->RemoteAddress,
+ ListenInformation->RemoteAddressLength)) &&
+ ((ListenAddress = NbfParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) != NULL)) {
+
+ RequestBuffer2 = (PVOID)ListenAddress->NetbiosName,
+ RequestBuffer2Length = NETBIOS_NAME_LENGTH;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("TdiListen: Create Request Failed, bad address.\n");
+ }
+
+ NbfDereferenceConnection ("Bad address", connection, CREF_BY_ID);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ RequestBuffer2 = NULL;
+ RequestBuffer2Length = 0;
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ RequestBuffer2,
+ RequestBuffer2Length,
+ timeout, // timeout value (can be 0).
+ &tpRequest);
+
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint1 ("TdiListen: Create Request Failed, reason: %lx.\n", status);
+ }
+
+ NbfDereferenceConnection ("For create", connection, CREF_BY_ID);
+ return status; // return with failure.
+ }
+
+ // Reference the connection since NbfDestroyRequest derefs it.
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_C_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ tpRequest->Owner = ConnectionType;
+
+ NbfReferenceConnection("For listen request", connection, CREF_REQUEST);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0) {
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ NbfCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
+ return STATUS_PENDING;
+
+ } else {
+
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+ connection->Flags2 |= (CONNECTION_FLAGS2_LISTENER | // we're the passive one.
+ CONNECTION_FLAGS2_WAIT_NQ); // wait for NAME_QUERY.
+ connection->Flags2 &= ~(CONNECTION_FLAGS2_INDICATING |
+ CONNECTION_FLAGS2_STOPPING);
+ connection->Status = STATUS_PENDING;
+
+ //
+ // If TDI_QUERY_ACCEPT is not set, then we set PRE_ACCEPT to
+ // indicate that when the listen completes we do not have to
+ // wait for a TDI_ACCEPT to continue.
+ //
+
+ if ((parameters->RequestFlags & TDI_QUERY_ACCEPT) == 0) {
+ connection->Flags2 |= CONNECTION_FLAGS2_PRE_ACCEPT;
+ }
+
+ RELEASE_C_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ NbfCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelConnection);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ //
+ // Wait for an incoming NAME_QUERY frame. The remainder of the
+ // connectionless protocol to set up a connection is processed
+ // in the NAME_QUERY frame handler.
+ //
+
+ NbfDereferenceConnection("Temp create", connection, CREF_BY_ID);
+
+ return STATUS_PENDING; // things are started.
+} /* TdiListen */
+
+
+NTSTATUS
+NbfOpenConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PFILE_FULL_EA_INFORMATION ea;
+
+ UNREFERENCED_PARAMETER (Irp);
+
+ //
+ // BUGBUG: check ea to make sure it's correct
+ //
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfOpenConnection: Entered.\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ status = NbfCreateConnection (DeviceContext, &connection);
+ if (!NT_SUCCESS (status)) {
+ return status; // sorry, we couldn't make one.
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ IrpSp->FileObject->FsContext = (PVOID)connection;
+ IrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
+ connection->FileObject = IrpSp->FileObject;
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint1 ("NBFOpenConnection: Opened Connection %lx.\n",
+ connection);
+ }
+
+ return status;
+
+} /* NbfOpenConnection */
+
+#if DBG
+VOID
+ConnectionCloseTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+{
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ Connection = (PTP_CONNECTION)DeferredContext;
+
+ DbgPrint ("NBF: Close of connection %lxpending for 2 minutes\n", Connection);
+ DbgBreakPoint();
+
+}
+#endif
+
+
+NTSTATUS
+NbfCloseConnection (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection. There may be actions in
+ progress on this connection, so we note the closing IRP, mark the
+ connection as closing, and complete it somewhere down the road (when all
+ references have been removed).
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_CONNECTION connection;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+ UNREFERENCED_PARAMETER (Irp);
+
+ IF_NBFDBG (NBF_DEBUG_CONNECT) {
+ NbfPrint0 ("NbfCloseConnection: Entered.\n");
+ }
+
+ //
+ // is the file object a connection?
+ //
+
+ connection = IrpSp->FileObject->FsContext;
+
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // We duplicate the code from VerifyConnectionObject,
+ // although we don't actually call that since it does
+ // a reference, which we don't want (to avoid bouncing
+ // the reference count up from 0 if this is a dead
+ // link).
+ //
+
+ try {
+
+ if ((connection->Size == sizeof (TP_CONNECTION)) &&
+ (connection->Type == NBF_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ KeLowerIrql (oldirql);
+ return GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS (status)) {
+ KeLowerIrql (oldirql);
+ return status;
+ }
+
+ //
+ // We recognize it; is it closing already?
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ KeLowerIrql (oldirql);
+#if DBG
+ NbfPrint1("Closing already-closing connection %lx\n", connection);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
+
+ //
+ // if there is activity on the connection, tear it down.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ NbfStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // If the connection is still associated, disassociate it.
+ //
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ } else {
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+ }
+
+ //
+ // Save this to complete the IRP later.
+ //
+
+ connection->CloseIrp = Irp;
+
+#if 0
+ //
+ // make it impossible to use this connection from the file object
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+ connection->FileObject = NULL;
+#endif
+
+#if DBG
+ {
+ LARGE_INTEGER Timeout;
+ BOOLEAN AlreadyInserted;
+
+ Timeout.LowPart = (ULONG)(-(120*SECONDS));
+ Timeout.HighPart = -1;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ AlreadyInserted = KeCancelTimer (&connection->Timer);
+
+ KeInitializeDpc (
+ &connection->Dpc,
+ ConnectionCloseTimeout,
+ (PVOID)connection);
+
+ KeSetTimer (
+ &connection->Timer,
+ Timeout,
+ &connection->Dpc);
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if (AlreadyInserted) {
+ DbgPrint ("NBF: Cancelling connection timer for debug %lx\n", connection);
+ NbfDereferenceConnection ("debug", connection, CREF_TIMER);
+ }
+
+ }
+#endif
+
+ KeLowerIrql (oldirql);
+
+ //
+ // dereference for the creation. Note that this dereference
+ // here won't have any effect until the regular reference count
+ // hits zero.
+ //
+
+ NbfDereferenceConnectionSpecial (" Closing Connection", connection, CREF_SPECIAL_CREATION);
+
+ return STATUS_PENDING;
+
+} /* NbfCloseConnection */
+
+
diff --git a/private/ntos/tdi/nbf/connobj.c b/private/ntos/tdi/nbf/connobj.c
new file mode 100644
index 000000000..1e7e9221b
--- /dev/null
+++ b/private/ntos/tdi/nbf/connobj.c
@@ -0,0 +1,2413 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ connobj.c
+
+Abstract:
+
+ This module contains code which implements the TP_CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+ A word about connection reference counts:
+
+ With TDI version 2, connections live on even after they have been stopped.
+ This necessitated changing the way NBF handles connection reference counts,
+ making the stopping of a connection only another way station in the life
+ of a connection, rather than its demise. Reference counts now work like
+ this:
+
+ Connection State Reference Count Flags
+ ------------------ ----------------- --------
+ Opened, no activity 1 0
+ Open, Associated 2 FLAGS2_ASSOCIATED
+ Open, Assoc., Connected 3 FLAGS_READY
+ Above + activity >3 varies
+ Open, Assoc., Stopping >3 FLAGS_STOPPING
+ Open, Assoc., Stopped 3 FLAGS_STOPPING
+ Open, Disassoc. Complete 2 FLAGS_STOPPING
+ FLAGS2_ASSOCIATED == 0
+ Closing 1 FLAGS2_CLOSING
+ Closed 0 FLAGS2_CLOSING
+
+ Note that keeping the stopping flag set when the connection has fully
+ stopped avoids using the connection until it is connected again; the
+ CLOSING flag serves the same purpose. This allows a connection to run
+ down in its own time.
+
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported routines
+//
+BOOLEAN
+NbfAttemptAutoDial(
+ IN PTP_CONNECTION Connection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PVOID pArg
+ );
+
+VOID
+NbfRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+
+BOOLEAN
+NbfCancelTdiConnect(
+ IN PDEVICE_OBJECT pDeviceObject,
+ IN PIRP pIrp
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+ConnectionEstablishmentTimeout(
+ 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 NAME_QUERY/NAME_RECOGNIZED protocol expires. The retry
+ count in the Connection object is decremented, and if it reaches 0,
+ the connection is aborted. If the retry count has not reached zero,
+ then the NAME QUERY is retried. The following cases are covered by
+ this routine:
+
+ 1. Initial NAME_QUERY timeout for find_name portion of connection setup.
+
+ NQ(find_name) ------------------->
+ [TIMEOUT]
+ NQ(find_name) ------------------->
+ <------------------- NR(find_name)
+
+ 2. Secondary NAME_QUERY timeout for connection setup.
+
+ NQ(connection) ------------------->
+ [TIMEOUT]
+ NQ(connection) ------------------->
+ <------------------- NR(connection)
+
+ There is another case where the data link connection does not get
+ established within a reasonable amount of time. This is handled by
+ the link layer routines.
+
+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_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("ConnectionEstablishmentTimeout: Entered for connection %lx.\n",
+ Connection);
+ }
+
+ //
+ // 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) {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfDereferenceConnection ("Connect timed out", Connection, CREF_TIMER);
+ LEAVE_NBF;
+ return;
+ }
+
+
+ if (Connection->Flags2 & (CONNECTION_FLAGS2_WAIT_NR_FN | CONNECTION_FLAGS2_WAIT_NR)) {
+
+ //
+ // We are waiting for a commital or non-commital NAME_RECOGNIZED frame.
+ // Decrement the retry count, and possibly resend the NAME_QUERY.
+ //
+
+ if (--(Connection->Retries) == 0) { // if retry count exhausted.
+
+ NTSTATUS StopStatus;
+
+ //
+ // See if we got a no listens response, or just
+ // nothing.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_NO_LISTEN) != 0) {
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_NO_LISTEN;
+ StopStatus = STATUS_REMOTE_NOT_LISTENING; // no listens
+
+ } else {
+
+ StopStatus = STATUS_BAD_NETWORK_PATH; // name not found.
+
+ }
+
+#ifdef RASAUTODIAL
+ //
+ // If this is a connect operation that has
+ // returned with STATUS_BAD_NETWORK_PATH, then
+ // attempt to create an automatic connection.
+ //
+ if (fAcdLoadedG &&
+ StopStatus == STATUS_BAD_NETWORK_PATH)
+ {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbfAttemptAutoDial(
+ Connection,
+ 0,
+ NbfRetryTdiConnect,
+ Connection))
+ {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ goto done;
+ }
+ }
+#endif // RASAUTODIAL
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStopConnection (Connection, StopStatus);
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // We make source routing optional on every second
+ // name query (whenever Retries is even).
+ //
+
+ NbfSendNameQuery (
+ Connection,
+ (BOOLEAN)((Connection->Retries & 1) ? FALSE : TRUE));
+
+ NbfStartConnectionTimer (
+ Connection,
+ ConnectionEstablishmentTimeout,
+ Connection->Provider->NameQueryTimeout);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+
+ //
+ // Dereference the connection, to account for the fact that the
+ // timer went off. Note that if we restarted the timer using
+ // NbfStartConnectionTimer, the reference count has already been
+ // incremented to account for the new timer.
+ //
+
+done:
+ NbfDereferenceConnection ("Timer timed out",Connection, CREF_TIMER);
+
+ LEAVE_NBF;
+ return;
+
+} /* ConnectionEstablishmentTimeout */
+
+
+VOID
+NbfAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a transport connection. Some
+ minimal initialization is done.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure. Returns
+ NULL if the storage cannot be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_CONNECTION Connection;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate connection: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 103,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ *TransportConnection = NULL;
+ return;
+ }
+
+ Connection = (PTP_CONNECTION)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_CONNECTION),
+ 'cFBN');
+ if (Connection == NULL) {
+ PANIC("NBF: Could not allocate connection: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 203,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ *TransportConnection = NULL;
+ return;
+ }
+ RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
+
+ DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
+ ++DeviceContext->ConnectionAllocated;
+
+ Connection->Type = NBF_CONNECTION_SIGNATURE;
+ Connection->Size = sizeof (TP_CONNECTION);
+
+ Connection->Provider = DeviceContext;
+ Connection->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Connection->SpinLock);
+ KeInitializeDpc (
+ &Connection->Dpc,
+ ConnectionEstablishmentTimeout,
+ (PVOID)Connection);
+ KeInitializeTimer (&Connection->Timer);
+
+
+ InitializeListHead (&Connection->LinkList);
+ InitializeListHead (&Connection->AddressFileList);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->PacketWaitLinkage);
+ InitializeListHead (&Connection->PacketizeLinkage);
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+ InitializeListHead (&Connection->DeferredQueue);
+
+ NbfAddSendPacket (DeviceContext);
+ NbfAddSendPacket (DeviceContext);
+ NbfAddUIFrame (DeviceContext);
+
+ *TransportConnection = Connection;
+
+} /* NbfAllocateConnection */
+
+
+VOID
+NbfDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a transport connection.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - the device context for this connection to be
+ associated with.
+
+ TransportConnection - Pointer to a transport connection structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportConnection);
+ --DeviceContext->ConnectionAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION);
+
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveUIFrame (DeviceContext);
+
+} /* NbfDeallocateConnection */
+
+
+NTSTATUS
+NbfCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection. The reference count in the
+ connection is automatically set to 1, and the reference count in the
+ DeviceContext is incremented.
+
+Arguments:
+
+ Address - the address for this connection to be associated with.
+
+ TransportConnection - Pointer to a place where this routine will
+ return a pointer to a transport connection structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfCreateConnection: Entered.\n");
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ if (p == &DeviceContext->ConnectionPool) {
+
+ if ((DeviceContext->ConnectionMaxAllocated == 0) ||
+ (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
+
+ NbfAllocateConnection (DeviceContext, &Connection);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated connection at %lx\n", Connection);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 403,
+ sizeof(TP_CONNECTION),
+ CONNECTION_RESOURCE_ID);
+ Connection = NULL;
+
+ }
+
+ if (Connection == NULL) {
+ ++DeviceContext->ConnectionExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateConnection: Could not allocate connection object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+#if DBG
+ InitializeListHead (p);
+#endif
+
+ }
+
+ ++DeviceContext->ConnectionInUse;
+ if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
+ ++DeviceContext->ConnectionMaxInUse;
+ }
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfCreateConnection: Connection at %lx.\n", Connection);
+ }
+
+ //
+ // We have two references; one is for creation, and the
+ // other is a temporary one so that the connection won't
+ // go away before the creator has a chance to access it.
+ //
+
+ Connection->SpecialRefCount = 1;
+ Connection->ReferenceCount = -1; // this is -1 based
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_CREFS; Counter++) {
+ Connection->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfCloseConnection
+
+ Connection->RefTypes[CREF_SPECIAL_CREATION] = 1;
+ }
+#endif
+
+ //
+ // Initialize the request queues & components of this connection.
+ //
+
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->AddressFileList);
+ Connection->SpecialReceiveIrp = (PIRP)NULL;
+ Connection->Flags = 0;
+ Connection->Flags2 = 0;
+ Connection->DeferredFlags = 0;
+ Connection->Lsn = 0;
+ Connection->Rsn = 0;
+ Connection->Retries = 0; // no retries yet.
+ Connection->MessageBytesReceived = 0; // no data yet
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->ReceiveBytesUnaccepted = 0;
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ Connection->CurrentReceiveSynchronous = FALSE;
+ Connection->ConsecutiveSends = 0;
+ Connection->ConsecutiveReceives = 0;
+ Connection->Link = NULL; // no datalink connection yet.
+ Connection->LinkSpinLock = NULL;
+ Connection->Context = NULL; // no context yet.
+ Connection->Status = STATUS_PENDING; // default NbfStopConnection status.
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->CurrentReceiveIrp = (PIRP)NULL;
+ Connection->DisconnectIrp = (PIRP)NULL;
+ Connection->CloseIrp = (PIRP)NULL;
+ Connection->AddressFile = NULL;
+ Connection->IndicationInProgress = FALSE;
+ Connection->OnDataAckQueue = FALSE;
+ Connection->OnPacketWaitQueue = FALSE;
+ Connection->TransferBytesPending = 0;
+ Connection->TotalTransferBytesPending = 0;
+
+ RtlZeroMemory (&Connection->NetbiosHeader, sizeof(NBF_HDR_CONNECTION));
+
+#if DBG
+ Connection->Destroyed = FALSE;
+ Connection->TotalReferences = 0;
+ Connection->TotalDereferences = 0;
+ Connection->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalConnectionList, &Connection->GlobalLinkage, &NbfGlobalInterlock);
+ StoreConnectionHistory (Connection, TRUE);
+#endif
+
+ //
+ // Now assign this connection an ID. This is used later to identify the
+ // connection across multiple processes.
+ //
+ // The high bit of the ID is not user, it is off for connection
+ // initiating NAME.QUERY frames and on for ones that are the result
+ // of a FIND.NAME request.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ Connection->ConnectionId = DeviceContext->UniqueIdentifier;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ NbfReferenceDeviceContext ("Create Connection", DeviceContext, DCREF_CONNECTION);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ *TransportConnection = Connection; // return the connection.
+
+ return STATUS_SUCCESS;
+} /* NbfCreateConnection */
+
+
+NTSTATUS
+NbfVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object.
+
+Arguments:
+
+ Connection - potential pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // try to verify the connection signature. If the signature is valid,
+ // get the connection spinlock, check its state, and increment the
+ // reference count if it's ok to use it. Note that being in the stopping
+ // state is an OK place to be and reference the connection; we can
+ // disassociate the address while running down.
+ //
+
+ try {
+
+ if ((Connection != (PTP_CONNECTION)NULL) &&
+ (Connection->Size == sizeof (TP_CONNECTION)) &&
+ (Connection->Type == NBF_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ NbfReferenceConnection ("Verify Temp Use", Connection, CREF_BY_ID);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+
+NTSTATUS
+NbfDestroyAssociation(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the association between a transport connection and
+ the address it was formerly associated with. The only action taken is
+ to disassociate the address and remove the connection from all address
+ queues.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql2;
+ PTP_ADDRESS_FILE addressFile;
+ BOOLEAN NotAssociated = FALSE;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfDestroyAssociation: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+#if DBG
+ if (!(IsListEmpty(&TransportConnection->AddressList)) ||
+ !(IsListEmpty(&TransportConnection->AddressFileList))) {
+ DbgPrint ("NBF: C %lx, AF %lx, freed while still queued\n",
+ TransportConnection, TransportConnection->AddressFile);
+ DbgBreakPoint();
+ }
+#endif
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ NotAssociated = TRUE;
+ } else {
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 1 in NbfDestroyAssociation\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ if (NotAssociated) {
+ return STATUS_SUCCESS;
+ }
+
+ addressFile = TransportConnection->AddressFile;
+
+ //
+ // Delink this connection from its associated address connection
+ // database. To do this we must spin lock on the address object as
+ // well as on the connection,
+ //
+
+ ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ RemoveEntryList (&TransportConnection->AddressFileList);
+ RemoveEntryList (&TransportConnection->AddressList);
+
+ InitializeListHead (&TransportConnection->AddressList);
+ InitializeListHead (&TransportConnection->AddressFileList);
+
+ //
+ // remove the association between the address and the connection.
+ //
+
+ TransportConnection->AddressFile = NULL;
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception 2 in NbfDestroyAssociation\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ //
+ // and remove a reference to the address
+ //
+
+ NbfDereferenceAddress ("Destroy association", addressFile->Address, AREF_CONNECTION);
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyAssociation */
+
+
+NTSTATUS
+NbfIndicateDisconnect(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a remote disconnection on this connection if it
+ is necessary to do so. No other action is taken here.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS_FILE addressFile;
+ PDEVICE_CONTEXT DeviceContext;
+ ULONG DisconnectReason;
+ PIRP DisconnectIrp;
+ KIRQL oldirql;
+ ULONG Lflags2;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfIndicateDisconnect: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+
+ if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ //
+ // Turn off all but the still-relevant bits in the flags.
+ //
+
+ Lflags2 = TransportConnection->Flags2;
+ TransportConnection->Flags2 &=
+ (CONNECTION_FLAGS2_ASSOCIATED |
+ CONNECTION_FLAGS2_DISASSOCIATED |
+ CONNECTION_FLAGS2_CLOSING);
+ TransportConnection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
+
+ //
+ // Clean up other stuff -- basically everything gets
+ // done here except for the flags and the status, since
+ // they are used to block other requests. When the connection
+ // is given back to us (in Accept, Connect, or Listen)
+ // they are cleared.
+ //
+
+ TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
+ TransportConnection->Retries = 0; // no retries yet.
+ TransportConnection->MessageBytesReceived = 0; // no data yet
+ TransportConnection->MessageBytesAcked = 0;
+ TransportConnection->MessageInitAccepted = 0;
+ TransportConnection->ReceiveBytesUnaccepted = 0;
+ TransportConnection->ConsecutiveSends = 0;
+ TransportConnection->ConsecutiveReceives = 0;
+ TransportConnection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ TransportConnection->TransmittedTsdus = 0;
+ TransportConnection->ReceivedTsdus = 0;
+
+ TransportConnection->CurrentReceiveIrp = (PIRP)NULL;
+
+ DisconnectIrp = TransportConnection->DisconnectIrp;
+ TransportConnection->DisconnectIrp = (PIRP)NULL;
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) != 0) {
+ addressFile = TransportConnection->AddressFile;
+ } else {
+ addressFile = NULL;
+ }
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+
+ DeviceContext = TransportConnection->Provider;
+
+
+ //
+ // If this connection was stopped by a call to TdiDisconnect,
+ // we have to complete that. We save the Irp so we can return
+ // the connection to the pool before we complete the request.
+ //
+
+
+ if (DisconnectIrp != (PIRP)NULL ||
+ (Lflags2 & CONNECTION_FLAGS2_LDISC) != 0) {
+
+ if (DisconnectIrp != (PIRP)NULL) {
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("IndicateDisconnect %lx, complete IRP\n", TransportConnection);
+ }
+
+ //
+ // Now complete the IRP if needed. This will be non-null
+ // only if TdiDisconnect was called, and we have not
+ // yet completed it.
+ //
+
+ DisconnectIrp->IoStatus.Information = 0;
+ DisconnectIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT);
+ }
+
+ } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) &&
+ (addressFile != NULL) &&
+ (addressFile->RegisteredDisconnectHandler == TRUE)) {
+
+ //
+ // This was a remotely spawned disconnect, so indicate that
+ // to our client. Note that in the comparison above we
+ // check the status first, since if it is LOCAL_DISCONNECT
+ // addressFile may be NULL (BUGBUG: This is sort of a hack
+ // for PDK2, we should really indicate the disconnect inside
+ // NbfStopConnection, where we know addressFile is valid).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("IndicateDisconnect %lx, indicate\n", TransportConnection);
+ }
+
+ //
+ // if the disconnection was remotely spawned, then indicate
+ // disconnect. In the case that a disconnect was issued at
+ // the same time as the connection went down remotely, we
+ // won't do this because DisconnectIrp will be non-NULL.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfIndicateDisconnect calling DisconnectHandler, refcnt=%ld\n",
+ TransportConnection->ReferenceCount);
+ }
+
+ //
+ // Invoke the user's disconnection event handler, if any. We do this here
+ // so that any outstanding sends will complete before we tear down the
+ // connection.
+ //
+
+ DisconnectReason = 0;
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ (*addressFile->DisconnectHandler)(
+ addressFile->DisconnectHandlerContext,
+ TransportConnection->Context,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ TDI_DISCONNECT_ABORT);
+
+#if MAGIC
+ if (NbfEnableMagic) {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+#endif
+ }
+
+ } else {
+
+ //
+ // The client does not yet think that this connection
+ // is up...generally this happens due to request count
+ // fluctuation during connection setup.
+ //
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfIndicateDisconnect\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfIndicateDisconnect */
+
+
+NTSTATUS
+NbfDestroyConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to our lookaside list. It is assumed that the caller
+ has removed all IRPs from the connections's queues first.
+
+ This routine is only called by NbfDereferenceConnection. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same connection object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection structure to
+ be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PIRP CloseIrp;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfDestroyConnection: Entered for connection %lx.\n",
+ TransportConnection);
+ }
+
+#if DBG
+ if (TransportConnection->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed connection 0x%lx\n", TransportConnection);
+ DbgBreakPoint ();
+ }
+ if (!(TransportConnection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
+ NbfPrint1 ("attempt to destroy unstopped connection 0x%lx\n", TransportConnection);
+ DbgBreakPoint ();
+ }
+ TransportConnection->Destroyed = TRUE;
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&TransportConnection->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#endif
+
+ DeviceContext = TransportConnection->Provider;
+
+ //
+ // Destroy any association that this connection has.
+ //
+
+ NbfDestroyAssociation (TransportConnection);
+
+ //
+ // Clear out any associated nasties hanging around the connection. Note
+ // that the current flags are set to STOPPING; this way anyone that may
+ // maliciously try to use the connection after it's dead and gone will
+ // just get ignored.
+ //
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ TransportConnection->Flags = 0;
+ TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
+ TransportConnection->NetbiosHeader.TransmitCorrelator = 0;
+ TransportConnection->Retries = 0; // no retries yet.
+ TransportConnection->MessageBytesReceived = 0; // no data yet
+ TransportConnection->MessageBytesAcked = 0;
+ TransportConnection->MessageInitAccepted = 0;
+ TransportConnection->ReceiveBytesUnaccepted = 0;
+
+
+ //
+ // Now complete the close IRP. This will be set to non-null
+ // when CloseConnection was called.
+ //
+
+ CloseIrp = TransportConnection->CloseIrp;
+
+ if (CloseIrp != (PIRP)NULL) {
+
+ TransportConnection->CloseIrp = (PIRP)NULL;
+ CloseIrp->IoStatus.Information = 0;
+ CloseIrp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+#if DBG
+ NbfPrint1("Connection %x destroyed, no CloseIrp!!\n", TransportConnection);
+#endif
+
+ }
+
+ //
+ // Return the connection to the provider's pool.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+ --DeviceContext->ConnectionInUse;
+
+ if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) >
+ DeviceContext->ConnectionInitAllocated) {
+ NbfDeallocateConnection (DeviceContext, TransportConnection);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated connection at %lx\n", TransportConnection);
+ }
+ } else {
+ InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Destroy Connection", DeviceContext, DCREF_CONNECTION);
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyConnection */
+
+
+#if DBG
+VOID
+NbfRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfReferenceConnection: entered for connection %lx, "
+ "current level=%ld.\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, TRUE );
+#endif
+
+ result = InterlockedIncrement (&TransportConnection->ReferenceCount);
+
+ if (result == 0) {
+
+ //
+ // The first increment causes us to increment the
+ // "ref count is not zero" special ref.
+ //
+
+ ExInterlockedAddUlong(
+ (PULONG)(&TransportConnection->SpecialRefCount),
+ 1,
+ TransportConnection->ProviderInterlock);
+
+#if DBG
+ ++TransportConnection->RefTypes[CREF_SPECIAL_TEMP];
+#endif
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* NbfRefConnection */
+#endif
+
+
+VOID
+NbfDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyConnection to remove it from the system.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfDereferenceConnection: entered for connection %lx, "
+ "current level=%ld.\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, FALSE );
+#endif
+
+ result = InterlockedDecrement (&TransportConnection->ReferenceCount);
+
+ //
+ // If all the normal references to this connection are gone, then
+ // we can remove the special reference that stood for
+ // "the regular ref count is non-zero".
+ //
+
+ if (result < 0) {
+
+ //
+ // If the refcount is -1, then we need to disconnect from
+ // the link and indicate disconnect. However, we need to
+ // do this before we actually do the special deref, since
+ // otherwise the connection might go away while we
+ // are doing that.
+ //
+ // Note that both these routines are protected in that if they
+ // are called twice, the second call will have no effect.
+ //
+
+
+ //
+ // If both the connection and its link are active, then they have
+ // mutual references to each other. We remove the link's
+ // reference to the connection in NbfStopConnection, now
+ // the reference count has fallen enough that we know it
+ // is okay to remove the connection's reference to the
+ // link.
+ //
+
+ if (NbfDisconnectFromLink (TransportConnection, TRUE)) {
+
+ //
+ // if the reference count goes to one, we can safely indicate the
+ // user about disconnect states. That reference should
+ // be for the connection's creation.
+ //
+
+ NbfIndicateDisconnect (TransportConnection);
+
+ }
+
+ //
+ // Now it is OK to let the connection go away.
+ //
+
+ NbfDereferenceConnectionSpecial ("Regular ref gone", TransportConnection, CREF_SPECIAL_TEMP);
+
+ }
+
+} /* NbfDerefConnection */
+
+
+VOID
+NbfDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routines completes the dereferencing of a connection.
+ It may be called any time, but it does not do its work until
+ the regular reference count is also 0.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint3 ("NbfDereferenceConnectionSpecial: entered for connection %lx, "
+ "current level=%ld (%ld).\n",
+ TransportConnection,
+ TransportConnection->ReferenceCount,
+ TransportConnection->SpecialRefCount);
+ }
+
+#if DBG
+ StoreConnectionHistory( TransportConnection, FALSE );
+#endif
+
+
+ ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql);
+
+ --TransportConnection->SpecialRefCount;
+
+ if ((TransportConnection->SpecialRefCount == 0) &&
+ (TransportConnection->ReferenceCount == -1)) {
+
+ //
+ // If we have deleted all references to this connection, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the connection any longer.
+ //
+
+#if DBG
+ {
+ BOOLEAN TimerCancelled;
+ TimerCancelled = KeCancelTimer (&TransportConnection->Timer);
+ ASSERT (TimerCancelled);
+ }
+#endif
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ NbfDestroyConnection (TransportConnection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ }
+
+} /* NbfDerefConnectionSpecial */
+
+
+VOID
+NbfClearConnectionLsn(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine clears the LSN field in a connection. To do this is
+ acquires the device context lock, and modifies the table value
+ for that LSN depending on the type of the connection.
+
+ NOTE: This routine is called with the connection spinlock held,
+ or in a state where nobody else will be accessing the
+ connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ KIRQL oldirql;
+
+ DeviceContext = TransportConnection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (TransportConnection->Lsn != 0) {
+
+ if (TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) {
+
+ //
+ // It was to a group address; the count should be
+ // LSN_TABLE_MAX.
+ //
+
+ ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] == LSN_TABLE_MAX);
+
+ DeviceContext->LsnTable[TransportConnection->Lsn] = 0;
+
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_GROUP_LSN;
+
+ } else {
+
+ ASSERT(DeviceContext->LsnTable[TransportConnection->Lsn] > 0);
+
+ --(DeviceContext->LsnTable[TransportConnection->Lsn]);
+
+ }
+
+ TransportConnection->Lsn = 0;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+}
+
+
+PTP_CONNECTION
+NbfLookupConnectionById(
+ IN PTP_ADDRESS Address,
+ IN USHORT ConnectionId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection identifier and an address and
+ returns a pointer to the connection object, TP_CONNECTION. If the
+ connection identifier is not found on the address, then NULL is returned.
+ This routine automatically increments the reference count of the
+ TP_CONNECTION structure if it is found. It is assumed that the
+ TP_ADDRESS structure is already held with a reference count.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConnectionId - Identifier of the connection for this address.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+ BOOLEAN Found = FALSE;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfLookupConnectionById: entered, Address: %lx ID: %lx\n",
+ Address, ConnectionId);
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) &&
+ (Connection->ConnectionId == ConnectionId)) {
+
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Lookup up for request", Connection, CREF_BY_ID);
+ Found = TRUE;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ }
+
+ if (Found) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return Connection;
+ }
+
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* NbfLookupConnectionById */
+
+
+PTP_CONNECTION
+NbfLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection identifier and an address and
+ returns a pointer to the connection object, TP_CONNECTION. If the
+ connection identifier is not found on the address, then NULL is returned.
+ This routine automatically increments the reference count of the
+ TP_CONNECTION structure if it is found. It is assumed that the
+ TP_ADDRESS structure is already held with a reference count.
+
+ BUGBUG: Should the ConnectionDatabase go in the address file?
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConnectionContext - Connection Context for this address.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ BOOLEAN Found = FALSE;
+ PTP_CONNECTION Connection;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfLookupConnectionByContext: entered, Address: %lx Context: %lx\n",
+ Address, ConnectionContext);
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+
+ try {
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (Connection->Context == ConnectionContext) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Lookup up for request", Connection, CREF_LISTENING);
+ Found = TRUE;
+ }
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgPrint ("NBF: Got exception in NbfLookupConnectionById\n");
+ DbgBreakPoint();
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ }
+
+ if (Found) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return Connection;
+ }
+
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* NbfLookupConnectionByContext */
+
+
+PTP_CONNECTION
+NbfLookupListeningConnection(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connection database on an address to find
+ a TP_CONNECTION object which has LSN=0 and CONNECTION_FLAGS_WAIT_NQ
+ flag set. It returns a pointer to the found connection object (and
+ simultaneously resets the flag) or NULL if it could not be found.
+ The reference count is also incremented atomically on the connection.
+
+ The list is scanned for listens posted to this specific remote
+ name, or to those with no remote name specified.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ RemoteName - The name of the remote.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p, q;
+ PTP_REQUEST ListenRequest;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfLookupListeningConnection: Entered.\n");
+ }
+
+ //
+ // Currently, this implementation is inefficient, but brute force so
+ // that a system can get up and running. Later, a cache of the mappings
+ // of popular connection id's and pointers to their TP_CONNECTION structures
+ // will be searched first.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p=Address->ConnectionDatabase.Flink;
+ p != &Address->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
+ if ((Connection->Lsn == 0) &&
+ (Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NQ)) {
+
+ q = Connection->InProgressRequest.Flink;
+ if (q != &Connection->InProgressRequest) {
+ ListenRequest = CONTAINING_RECORD (q, TP_REQUEST, Linkage);
+ if ((ListenRequest->Buffer2 != NULL) &&
+ (!RtlEqualMemory(
+ ListenRequest->Buffer2,
+ RemoteName,
+ NETBIOS_NAME_LENGTH))) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found Listening", Connection, CREF_LISTENING);
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_NQ;
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfLookupListeningConnection: Found Connection %lx\n",Connection);
+ }
+ return Connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("NbfLookupListeningConnection: Found No Connection!\n");
+ }
+
+ return NULL;
+
+} /* NbfLookupListeningConnection */
+
+
+VOID
+NbfStopConnection(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on a connection and
+ destroy the object. This is done in a graceful manner; i.e., all
+ outstanding requests are terminated by cancelling them, etc. It is
+ assumed that the caller has a reference to this connection object,
+ but this routine will do the dereference for the one issued at creation
+ time.
+
+ Orderly release is a function of this routine, but it is not a provided
+ service of this transport provider, so there is no code to do it here.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Status - The status that caused us to stop the connection. This
+ will determine what status pending requests are aborted with,
+ and also how we proceed during the stop (whether to send a
+ session end, and whether to indicate disconnect).
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ PTP_REQUEST Request;
+ BOOLEAN TimerWasCleared;
+ ULONG DisconnectReason;
+ PULONG StopCounter;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint3 ("NbfStopConnection: Entered for connection %lx LSN %x RSN %x.\n",
+ Connection, Connection->Lsn, Connection->Rsn);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING)) {
+
+ //
+ // We are stopping the connection, record statistics
+ // about it.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_READY) {
+ DECREMENT_COUNTER (DeviceContext, OpenConnections);
+ }
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_STOPPING;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->Status = Status;
+
+ if (Connection->Link != NULL) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->Flags &= ~(CONNECTION_FLAGS_READY|
+ CONNECTION_FLAGS_WAIT_SI|
+ CONNECTION_FLAGS_WAIT_SC); // no longer open for business
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // If this flag was on, turn it off.
+ //
+ Connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Stop the timer if it was running.
+ //
+
+ TimerWasCleared = KeCancelTimer (&Connection->Timer);
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2 ("NbfStopConnection: Timer for connection %lx "
+ "%s canceled.\n", Connection,
+ TimerWasCleared ? "was" : "was NOT" );
+ }
+
+
+ switch (Status) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ StopCounter = &DeviceContext->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ StopCounter = &DeviceContext->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ StopCounter = &DeviceContext->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ StopCounter = &DeviceContext->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ StopCounter = &DeviceContext->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ StopCounter = &DeviceContext->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ StopCounter = &DeviceContext->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ StopCounter = &DeviceContext->Statistics.NotFoundFailures;
+ break;
+ case STATUS_REMOTE_NOT_LISTENING:
+ StopCounter = &DeviceContext->Statistics.NoListenFailures;
+ break;
+
+ default:
+ StopCounter = NULL;
+ break;
+
+ }
+
+ if (StopCounter != NULL) {
+ (*StopCounter)++;
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+ break;
+ }
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ LARGE_INTEGER MilliSeconds, Time;
+ ULONG junk;
+ KeQuerySystemTime (&Time);
+ MilliSeconds.LowPart = Time.LowPart;
+ MilliSeconds.HighPart = Time.HighPart;
+ MilliSeconds.QuadPart = MilliSeconds.QuadPart -
+ (Request->Time).QuadPart;
+ MilliSeconds = RtlExtendedLargeIntegerDivide (MilliSeconds, 10000L, &junk);
+ NbfPrint3 ("NbfStopConnection: Canceling pending CONNECT, Irp: %lx Time Pending: %ld%ld msec\n",
+ Request->IoRequestPacket, MilliSeconds.HighPart, MilliSeconds.LowPart);
+ }
+#endif
+
+ NbfCompleteRequest (Request, Connection->Status, 0);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ }
+
+
+ if (Connection->Link == NULL) {
+
+ //
+ // We are stopping early on.
+ //
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+
+ if (TimerWasCleared) {
+ NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
+ }
+
+
+ ASSERT (Connection->SendState == CONNECTION_SENDSTATE_IDLE);
+ ASSERT (!Connection->OnPacketWaitQueue);
+ ASSERT (!Connection->OnDataAckQueue);
+ ASSERT (!(Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK));
+ ASSERT (IsListEmpty(&Connection->SendQueue));
+ ASSERT (IsListEmpty(&Connection->ReceiveQueue));
+
+ return;
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If this connection is waiting to packetize,
+ // remove it from the device context queue it is on.
+ //
+ // NOTE: If the connection is currently in the
+ // packetize queue, it will eventually go to get
+ // packetized and at that point it will get
+ // removed.
+ //
+
+ if (Connection->OnPacketWaitQueue) {
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1("Stop waiting connection, flags %lx\n",
+ Connection->Flags);
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ Connection->OnPacketWaitQueue = FALSE;
+ ASSERT ((Connection->Flags & CONNECTION_FLAGS_SEND_SE) == 0);
+ Connection->Flags &= ~(CONNECTION_FLAGS_STARVED|CONNECTION_FLAGS_W_PACKETIZE);
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+
+ //
+ // If we are on the data ack queue, then take ourselves off.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if (Connection->OnDataAckQueue) {
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = FALSE;
+ DeviceContext->DataAckQueueChanged = TRUE;
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If this connection is waiting to send a piggyback ack,
+ // remove it from the device context queue for that, and
+ // send a data ack (which will get there before the
+ // SessionEnd).
+ //
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+
+#if DBG
+ {
+ extern ULONG NbfDebugPiggybackAcks;
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint1("Stop waiting connection, deferred flags %lx\n",
+ Connection->DeferredFlags);
+ }
+ }
+#endif
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfSendDataAck (Connection);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (TimerWasCleared) {
+ NbfDereferenceConnection ("Stopping timer", Connection, CREF_TIMER); // account for timer reference.
+ }
+
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ //
+ // Run down all TdiSend requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->SendQueue);
+ if (p == &Connection->SendQueue) {
+ break;
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1("NbfStopConnection: Canceling pending SEND, Irp: %lx\n",
+ Irp);
+ }
+#endif
+ NbfCompleteSendIrp (Irp, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ++Connection->TransmissionErrors;
+ }
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ //
+ // Run down all TdiReceive requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ if (p == &Connection->ReceiveQueue) {
+ break;
+ }
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NULL);
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfStopConnection: Canceling pending RECEIVE, Irp: %lx\n",
+ Irp);
+ }
+#endif
+
+ //
+ // It is OK to call this with the locks held.
+ //
+ NbfCompleteReceiveIrp (Irp, Connection->Status, 0);
+
+ ++Connection->ReceiveErrors;
+ }
+
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we aren't DESTROYing the link, then send a SESSION_END frame
+ // to the remote side. When the SESSION_END frame is acknowleged,
+ // we will decrement the connection's reference count by one, removing
+ // its creation reference. This will cause the connection object to
+ // be disposed of, and will begin running down the link.
+ // DGB: add logic to avoid blowing away link if one doesn't exist yet.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ DisconnectReason = 0;
+ if (Connection->Flags2 & CONNECTION_FLAGS2_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (Connection->Flags2 & CONNECTION_FLAGS2_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ if (Connection->Link != NULL) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if ((Status == STATUS_LOCAL_DISCONNECT) ||
+ (Status == STATUS_CANCELLED)) {
+
+ //
+ // (note that a connection should only get stopped
+ // with STATUS_INSUFFICIENT_RESOURCES if it is not
+ // yet connected to the remote).
+ //
+
+ //
+ // If this is done, when this packet is destroyed
+ // it will dereference the connection for CREF_LINK.
+ //
+
+ NbfSendSessionEnd (
+ Connection,
+ (BOOLEAN)((DisconnectReason & TDI_DISCONNECT_ABORT) != 0));
+
+ } else {
+
+ //
+ // Not attached to the link anymore; this dereference
+ // will allow our reference to fall below 3, which
+ // will cause NbfDisconnectFromLink to be called.
+ //
+
+ NbfDereferenceConnection("Stopped", Connection, CREF_LINK);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ }
+
+
+ //
+ // Note that we've blocked all new requests being queued during the
+ // time we have been in this teardown code; NbfDestroyConnection also
+ // sets the connection flags to STOPPING when returning the
+ // connection to the queue. This avoids lingerers using non-existent
+ // connections.
+ //
+
+ } else {
+
+ //
+ // The connection was already stopping; it may have a
+ // SESSION_END pending in which case we should kill
+ // it.
+ //
+
+ if ((Status != STATUS_LOCAL_DISCONNECT) &&
+ (Status != STATUS_CANCELLED)) {
+
+ if (Connection->Flags & CONNECTION_FLAGS_SEND_SE) {
+
+ ASSERT (Connection->Link != NULL);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags &= ~CONNECTION_FLAGS_SEND_SE;
+
+ if (Connection->OnPacketWaitQueue) {
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+#if DBG
+ DbgPrint ("NBF: Removing connection %lx from PacketWait for SESSION_END\n", Connection);
+#endif
+ Connection->OnPacketWaitQueue = FALSE;
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ NbfDereferenceConnection("Stopped again", Connection, CREF_LINK);
+ return;
+
+ }
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ }
+} /* NbfStopConnection */
+
+
+VOID
+NbfCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ or a listen. It is simple since there can only be one of these
+ active on a connection; we just stop the connection, the IRP
+ will get completed as part of normal session teardown.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ NbfReferenceConnection ("Cancelling Send", Connection, CREF_TEMP);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ ASSERT (p != &Connection->InProgressRequest);
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ ASSERT (Request->IoRequestPacket == Irp);
+#ifdef RASAUTODIAL
+ //
+ // If there's an automatic connection in
+ // progress, cancel it.
+ //
+ if (Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING)
+ fCanceled = NbfCancelTdiConnect(NULL, Irp);
+#endif // RASAUTODIAL
+
+ if (fCanceled)
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ if (fCanceled) {
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint2("NBF: Cancelled in-progress connect/listen %lx on %lx\n",
+ Request->IoRequestPacket, Connection);
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT); // prevent indication to clients
+ KeLowerIrql (oldirql);
+ }
+
+ NbfDereferenceConnection ("Cancel done", Connection, CREF_TEMP);
+
+}
+
+#if 0
+VOID
+NbfWaitConnectionOnLink(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to suspend a connection's activities because
+ the specified session-oriented frame could not be sent due to link
+ problems. Routines in FRAMESND.C call this.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Flags - Field containing bitflag set to indicate starved frame to be sent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint0 ("NbfWaitConnectionOnLink: Entered.\n");
+ }
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0) ||
+ (Flags == CONNECTION_FLAGS_SEND_SE)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= Flags;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+} /* NbfWaitConnectionOnLink */
+#endif
+
+
+VOID
+NbfStartConnectionTimer(
+ IN PTP_CONNECTION Connection,
+ IN PKDEFERRED_ROUTINE TimeoutFunction,
+ IN ULONG WaitTime
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to start a timeout on NAME_QUERY/NAME_RECOGNIZED
+ activities on a connection.
+
+Arguments:
+
+ TransportConnection - Pointer to a TP_CONNECTION object.
+
+ TimeoutFunction - The function to call when the timer fires.
+
+ WaitTime - a longword containing the low order time to wait.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER Timeout;
+ BOOLEAN AlreadyInserted;
+
+ IF_NBFDBG (NBF_DEBUG_CONNOBJ) {
+ NbfPrint1 ("NbfStartConnectionTimer: Entered for connection %lx.\n",
+ Connection );
+ }
+
+ //
+ // Start the timer. Unlike the link timers, this is simply a kernel-
+ // managed object.
+ //
+
+ Timeout.LowPart = (ULONG)(-(LONG)WaitTime);
+ Timeout.HighPart = -1;
+
+ //
+ // Take the lock so we synchronize the cancelling with
+ // restarting the timer. This is so two threads won't
+ // both fail to cancel and then start the timer at the
+ // same time (it messes up the reference count).
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ AlreadyInserted = KeCancelTimer (&Connection->Timer);
+
+ KeInitializeDpc (
+ &Connection->Dpc,
+ TimeoutFunction,
+ (PVOID)Connection);
+
+ KeSetTimer (
+ &Connection->Timer,
+ Timeout,
+ &Connection->Dpc);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // If the timer wasn't already running, reference the connection to
+ // account for the new timer. If the timer was already started,
+ // then KeCancelTimer will have returned TRUE. In this
+ // case, the prior call to NbfStartConnectionTimer referenced the
+ // connection, so we don't do it again here.
+ //
+
+ if ( !AlreadyInserted ) {
+
+ // This reference is removed in ConnectionEstablishmentTimeout,
+ // or when the timer is cancelled.
+
+ NbfReferenceConnection ("starting timer", Connection, CREF_TIMER);
+ }
+
+} /* NbfStartConnectionTimer */
+
diff --git a/private/ntos/tdi/nbf/devctx.c b/private/ntos/tdi/nbf/devctx.c
new file mode 100644
index 000000000..0d6179e60
--- /dev/null
+++ b/private/ntos/tdi/nbf/devctx.c
@@ -0,0 +1,408 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ devctx.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects. Currently, there is no need to create them or destroy
+ them, as this is handled at configuration time. If it is later required
+ to dynamically load/unload the transport provider's device object and
+ associated context, then we can add the create and destroy functions.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Author:
+
+ David Beaver (dbeaver) 1 -July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfCreateDeviceContext)
+#else
+#pragma alloc_text(PAGE,NbfCreateDeviceContext)
+#endif
+
+#endif
+
+
+VOID
+NbfRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint0 ("NbfRefDeviceContext: Entered.\n");
+ }
+
+ ASSERT (DeviceContext->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&DeviceContext->ReferenceCount);
+
+} /* NbfRefDeviceContext */
+
+
+VOID
+NbfDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ DeviceContext - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint0 ("NbfDerefDeviceContext: Entered.\n");
+ }
+
+ result = InterlockedDecrement (&DeviceContext->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyDeviceContext (DeviceContext);
+ }
+
+} /* NbfDerefDeviceContext */
+
+
+
+NTSTATUS
+NbfCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_CONTEXT deviceContext;
+ USHORT i;
+
+
+ //
+ // Create the device object for NETBEUI.
+ //
+
+ status = IoCreateDevice(
+ DriverObject,
+ sizeof (DEVICE_CONTEXT) - sizeof (DEVICE_OBJECT) +
+ (DeviceName->Length + sizeof(UNICODE_NULL)),
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ deviceContext = (PDEVICE_CONTEXT)deviceObject;
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)deviceContext) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE_CONTEXT) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ deviceContext->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ deviceContext->DeviceName = (PWCHAR)(deviceContext+1);
+ RtlCopyMemory(
+ deviceContext->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ deviceContext->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize device context fields.
+ //
+
+ deviceContext->NetmanVariables = NULL; // no variables yet.
+
+ //
+ // Initialize the reference count.
+ //
+
+ deviceContext->ReferenceCount = 1;
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_DCREFS; Counter++) {
+ deviceContext->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by the caller.
+
+ deviceContext->RefTypes[DCREF_CREATION] = 1;
+ }
+#endif
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ KeInitializeSpinLock (&deviceContext->Interlock);
+ KeInitializeSpinLock (&deviceContext->SpinLock);
+ KeInitializeSpinLock (&deviceContext->LinkSpinLock);
+ KeInitializeSpinLock (&deviceContext->TimerSpinLock);
+ KeInitializeSpinLock (&deviceContext->LoopbackSpinLock);
+ KeInitializeSpinLock (&deviceContext->SendPoolListLock);
+ KeInitializeSpinLock (&deviceContext->RcvPoolListLock);
+
+ deviceContext->LinkTreeRoot = NULL;
+ deviceContext->LastLink = NULL;
+ deviceContext->LinkTreeElements = 0;
+
+ deviceContext->LoopbackLinks[0] = NULL;
+ deviceContext->LoopbackLinks[1] = NULL;
+ deviceContext->LoopbackInProgress = FALSE;
+ KeInitializeDpc(
+ &deviceContext->LoopbackDpc,
+ NbfProcessLoopbackQueue,
+ (PVOID)deviceContext
+ );
+
+ deviceContext->WanThreadQueued = FALSE;
+ ExInitializeWorkItem(
+ &deviceContext->WanDelayedQueueItem,
+ NbfProcessWanDelayedQueue,
+ (PVOID)deviceContext);
+
+
+ deviceContext->UniqueIdentifier = 1;
+ deviceContext->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&deviceContext->ConnectionPool);
+ InitializeListHead (&deviceContext->AddressPool);
+ InitializeListHead (&deviceContext->AddressFilePool);
+ InitializeListHead (&deviceContext->AddressDatabase);
+ InitializeListHead (&deviceContext->LinkPool);
+ InitializeListHead (&deviceContext->LinkDeferred);
+ InitializeListHead (&deviceContext->PacketWaitQueue);
+ InitializeListHead (&deviceContext->PacketizeQueue);
+ InitializeListHead (&deviceContext->DataAckQueue);
+ InitializeListHead (&deviceContext->DeferredRrQueue);
+ InitializeListHead (&deviceContext->RequestPool);
+ InitializeListHead (&deviceContext->UIFramePool);
+ deviceContext->PacketPool.Next = NULL;
+ deviceContext->ReceivePacketPool.Next = NULL;
+ deviceContext->ReceiveBufferPool.Next = NULL;
+ InitializeListHead (&deviceContext->ReceiveInProgress);
+ InitializeListHead (&deviceContext->ShortList);
+ InitializeListHead (&deviceContext->LongList);
+ InitializeListHead (&deviceContext->PurgeList);
+ InitializeListHead (&deviceContext->LoopbackQueue);
+ InitializeListHead (&deviceContext->FindNameQueue);
+ InitializeListHead (&deviceContext->StatusQueryQueue);
+ InitializeListHead (&deviceContext->IrpCompletionQueue);
+
+ InitializeListHead (&deviceContext->QueryIndicationQueue);
+ InitializeListHead (&deviceContext->DatagramIndicationQueue);
+ deviceContext->IndicationQueuesInUse = FALSE;
+
+ //
+ // Equivalent to setting ShortListActive, DataAckQueueActive,
+ // and LinkDeferredActive to FALSE.
+ //
+
+ deviceContext->a.AnyActive = 0;
+
+ deviceContext->ProcessingShortTimer = FALSE;
+ deviceContext->DataAckQueueChanged = FALSE;
+ deviceContext->StalledConnectionCount = (USHORT)0;
+
+ deviceContext->EasilyDisconnected = FALSE;
+
+ //
+ // Initialize provider statistics.
+ //
+
+ deviceContext->Statistics.Version = 0x0100;
+
+#if 0
+ deviceContext->Information.Version = 2; // BUGBUG: define TDI_VERSION in TDI.H.
+ deviceContext->Information.MaxTsduSize = NBF_MAX_TSDU_SIZE;
+ deviceContext->Information.MaxDatagramSize = NBF_MAX_DATAGRAM_SIZE;
+ deviceContext->Information.MaxConnectionUserData = NBF_MAX_CONNECTION_USER_DATA;
+ deviceContext->Information.ServiceFlags = NBF_SERVICE_FLAGS;
+ deviceContext->Information.TransmittedTsdus = 0;
+ deviceContext->Information.ReceivedTsdus = 0;
+ deviceContext->Information.TransmissionErrors = 0;
+ deviceContext->Information.ReceiveErrors = 0;
+ deviceContext->Information.MinimumLookaheadData = NBF_MIN_LOOKAHEAD_DATA;
+ deviceContext->Information.MaximumLookaheadData = NBF_MAX_LOOKAHEAD_DATA;
+ deviceContext->Information.DiscardedFrames = 0;
+ deviceContext->Information.OversizeTsdusReceived = 0;
+ deviceContext->Information.UndersizeTsdusReceived = 0;
+ deviceContext->Information.MulticastTsdusReceived = 0;
+ deviceContext->Information.BroadcastTsdusReceived = 0;
+ deviceContext->Information.MulticastTsdusTransmitted = 0;
+ deviceContext->Information.BroadcastTsdusTransmitted = 0;
+ deviceContext->Information.SendTimeouts = 0;
+ deviceContext->Information.ReceiveTimeouts = 0;
+ deviceContext->Information.ConnectionIndicationsReceived = 0;
+ deviceContext->Information.ConnectionIndicationsAccepted = 0;
+ deviceContext->Information.ConnectionsInitiated = 0;
+ deviceContext->Information.ConnectionsAccepted = 0;
+#endif
+
+ deviceContext->State = DEVICECONTEXT_STATE_OPENING;
+
+ //
+ // Loopback buffer is not allocated.
+ //
+
+ deviceContext->LookaheadContiguous = NULL;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&deviceContext->AddressResource);
+
+ //
+ // No LSNs are in use.
+ //
+
+ for (i=0; i<(NETBIOS_SESSION_LIMIT+1); i++) {
+ deviceContext->LsnTable[i] = 0;
+ }
+ deviceContext->NextLsnStart = 1;
+
+ //
+ // No addresses are in use.
+ //
+
+ for (i=0; i<256; i++) {
+ deviceContext->AddressCounts[i] = 0;
+ }
+
+ //
+ // set the netbios multicast address for this network type
+ //
+
+ for (i=0; i<HARDWARE_ADDRESS_LENGTH; i++) {
+ deviceContext->LocalAddress.Address [i] = 0; // set later
+ deviceContext->NetBIOSAddress.Address [i] = 0;
+ }
+
+ deviceContext->Type = NBF_DEVICE_CONTEXT_SIGNATURE;
+ deviceContext->Size = sizeof (DEVICE_CONTEXT);
+
+ *DeviceContext = deviceContext;
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NbfDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ DeviceContext - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ExDeleteResource (&DeviceContext->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)DeviceContext);
+ return;
+}
diff --git a/private/ntos/tdi/nbf/dlc.c b/private/ntos/tdi/nbf/dlc.c
new file mode 100644
index 000000000..893bffd49
--- /dev/null
+++ b/private/ntos/tdi/nbf/dlc.c
@@ -0,0 +1,3270 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ dlc.c
+
+Abstract:
+
+ This module contains code which implements the data link layer for the
+ transport provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Macros
+
+
+//
+// These two functions are used by the loopback indicator.
+//
+
+STATIC
+VOID
+NbfCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ );
+
+
+VOID
+NbfProcessSabme(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header,
+ IN PVOID MacHeader,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received SABME frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+ MacHeader - Pointer to the MAC header of the packet.
+
+ DeviceContext - The device context of this adapter.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessSabme: Entered.\n");
+ }
+
+ //
+ // Format must be: SABME-c/x, on a real link object.
+ //
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ //
+ // Build response routing information. We do this on the SABME, even
+ // though we already did in on the Name Query, because the client may
+ // choose a different route (if there were multiple routes) than we
+ // did.
+ //
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ MacHeader,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Link->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ 0, // PacketLength, filled in later
+ ResponseSR,
+ SourceRoutingLength,
+ (PUINT)&(Link->HeaderLength));
+
+ //
+ // We optimize for fourteen-byte headers by putting
+ // the correct Dsap/Ssap at the end, so we can fill
+ // in new packets as one 16-byte move.
+ //
+
+ if (Link->HeaderLength <= 14) {
+ Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
+ Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
+ }
+
+ //
+ // Process the SABME.
+ //
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Remote station is initiating this link. Send UA and wait for
+ // his checkpoint before setting READY state.
+ //
+
+ // Moving out of ADM, add special reference
+ NbfReferenceLinkSpecial("Waiting for Poll", Link, LREF_NOT_ADM);
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+
+ // Don't start T1, but prepare for timing the response
+ FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ NbfResetLink (Link);
+ NbfSendUa (Link, PollFinal); // releases lock
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint4("ADM SABME on %lx %x-%x-%x\n",
+ Link,
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5]);
+ }
+ StartTi (Link);
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent a
+ // SABME at the same time, so we tried to do it at the same time.
+ // The only balanced thing we can do at this time is to respond
+ // with UA and duplicate the effort. To not send anything would
+ // be bad because the link would never complete.
+ //
+
+ //
+ // BUGBUG: What about timers here?
+ //
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+ NbfSendUa (Link, PollFinal); // releases lock
+ StartTi (Link);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a SABME, so this is really a link reset.
+ //
+ // Unfortunately, if we happen to get two SABMEs
+ // and respond to the second one with another UA
+ // (when he has sent the RR-c/p and is expecting
+ // an RR-r/f), he will send a FRMR. So, we ignore
+ // this frame.
+ //
+
+ // Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ StartTi(Link);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is already balanced. He's resetting the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent this SABME. We have to assume he wants to reset the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this SABME. He wants to initiate the link
+ // again because a transport connection has been initiated while
+ // we were taking the link down.
+ //
+
+ Link->State = LINK_STATE_W_POLL; // wait for RR-c/p.
+
+ // Don't start T1, but prepare for timing the response
+ FakeStartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ NbfResetLink (Link); // reset this connection.
+ NbfSendUa (Link, PollFinal); // releases lock.
+ StartTi(Link);
+#if DBG
+ s = "READY/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessSabme: Processed, State was %s.\n", s);
+ }
+#endif
+
+} /* NbfProcessSabme */
+
+
+VOID
+NbfProcessUa(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received UA frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ PollFinal, Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessUa: Entered.\n");
+ }
+
+ //
+ // Format must be: UA-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received an unnumbered acknowlegement while in ADM. Somehow
+ // the remote station is confused, so tell him we're disconnected.
+ //
+
+ NbfSendDm (Link, FALSE); // indicate we're disconnected, release lock
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received the UA.
+ //
+
+ UpdateBaseT1Timeout (Link); // got response to poll.
+
+ Link->State = LINK_STATE_W_FINAL; // wait for RR-r/f.
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is already balanced. He's confused; throw it away.
+ //
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a UA, so he is confused. Throw it away.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent this UA. He is confused. Throw it away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "READY/W_POLL/W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received the correct response.
+ // Disconnect this link.
+ //
+
+ Link->State = LINK_STATE_ADM; // completed disconnection.
+
+ //
+ // This is the normal "clean" disconnect path, so we stop
+ // all the timers here since we won't call NbfStopLink.
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ // Moving to ADM, dereference link
+ NbfDereferenceLinkSpecial ("Got UA for DISC", Link, LREF_NOT_ADM); // decrement link's last ref.
+
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessUa */
+
+
+VOID
+NbfProcessDisc(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received DISC frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessDisc: Entered.\n");
+ }
+
+ //
+ // Format must be: DISC-c/x, on a real link object.
+ //
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a DISC while in ADM. Simply report disconnected mode.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, PollFinal); // indicate we're disconnected, release lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. Kill the link.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessDisc calling NbfStopLink\n" );
+ }
+#endif
+ NbfStopLink (Link); // say goodnight, gracie
+
+ // Moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Stopping link", Link, LREF_NOT_ADM);
+
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a DISC. That means
+ // we have crossed a disconnection and reconnection. Throw away
+ // the disconnect.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a DISC, so he wants to drop the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent DISC, so he wants to drop the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a DISC from him as well.
+ // Disconnect this link.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendUa (Link, PollFinal); // Send UA-r/x, release lock.
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial ("Got DISC on W_DIS_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
+
+#if DBG
+ s = "W_POLL/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessDisc */
+
+
+VOID
+NbfProcessDm(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received DM frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessDm: Entered.\n");
+ }
+
+ //
+ // Format must be: DM-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ Link->LinkBusy = FALSE; // he's cleared his busy condition.
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a DM while in ADM. Do nothing.
+ //
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a DM. That means
+ // we have crossed a disconnection and reconnection. Throw away
+ // the disconnect mode indicator, we will reconnect in time.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "ADM/CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced and he is in ADM, so we have to shut down.
+ //
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessDm calling NbfStopLink\n" );
+ }
+#endif
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a DM, so he has dropped the link.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent DM, so he has already dropped the link.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a DM from him, indicating
+ // that he is now in ADM. While technically not what we expected,
+ // this protocol is commonly used in place of UA-r/f, so just treat
+ // as though we got a UA-r/f. Disconnect the link normally.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial ("Got DM in W_DISC_RSP", Link, LREF_NOT_ADM); // remove its "alive" ref.
+
+#if DBG
+ s = "READY/W_FINAL/W_POLL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessDm */
+
+
+VOID
+NbfProcessFrmr(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received FRMR response frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ ULONG DumpData[6];
+
+ PollFinal, Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessFrmr: Entered.\n");
+ }
+
+ //
+ // Log an error, this shouldn't happen.
+ //
+
+ DumpData[0] = Link->State;
+ DumpData[1] = Link->Flags;
+ DumpData[2] = (Header->Information.FrmrInfo.Command << 8) +
+ (Header->Information.FrmrInfo.Ctrl);
+ DumpData[3] = (Header->Information.FrmrInfo.Vs << 16) +
+ (Header->Information.FrmrInfo.Vr << 8) +
+ (Header->Information.FrmrInfo.Reason);
+ DumpData[4] = (Link->SendState << 24) +
+ (Link->NextSend << 16) +
+ (Link->LastAckReceived << 8) +
+ (Link->SendWindowSize);
+ DumpData[5] = (Link->ReceiveState << 24) +
+ (Link->NextReceive << 16) +
+ (Link->LastAckSent << 8) +
+ (Link->ReceiveWindowSize);
+
+ NbfWriteGeneralErrorLog(
+ Link->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 1,
+ STATUS_LINK_FAILED,
+ L"FRMR",
+ 6,
+ DumpData);
+
+
+ ++Link->Provider->FrmrReceived;
+
+ //
+ // Format must be: FRMR-r/x, on a real link object.
+ //
+
+ if (Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // Received a FRMR while in ADM. Report disconnected mode.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced and he reported a protocol error.
+ //
+#if 0
+ // We want to reset the link, but not quite as fully
+ // as NbfResetLink. This code is the same as what
+ // is in there, except for:
+ //
+ // - resetting the send/receive numbers
+ // - removing packets from the WackQ
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ Link->Flags &= LINK_FLAGS_DEFERRED_MASK; // keep deferred operations
+
+ Link->SendWindowSize = 1;
+ Link->LinkBusy = FALSE;
+
+ Link->ReceiveWindowSize = 1;
+ Link->WindowErrors = 0;
+ Link->BestWindowSize = 1;
+ Link->WorstWindowSize = Link->MaxWindowSize;
+ Link->Flags |= LINK_FLAGS_JUMP_START;
+
+ Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
+ Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentPollOutstanding = FALSE;
+ Link->T2Timeout = Link->Provider->DefaultT2Timeout;
+ Link->TiTimeout = Link->Provider->DefaultTiTimeout;
+ Link->LlcRetries = Link->Provider->LlcRetries;
+ Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
+
+ //
+ // The rest is similar to NbfActivateLink
+ //
+
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+#else
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
+#endif
+
+#if DBG
+ NbfPrint1("Received FRMR on link %lx\n", Link);
+#endif
+
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and have just received a FRMR.
+ //
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. Instead, we
+ // got a FRMR.
+ //
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy but instead
+ // he sent FRMR.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We've sent a DISC-c/p and have received a FRMR.
+ //
+
+ Link->State = LINK_STATE_ADM; // we're reset now.
+ NbfSendDm (Link, FALSE); // indicate disconnected, release lock
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Got DM in W_POLL", Link, LREF_NOT_ADM);
+
+#if DBG
+ s = "CONN/W_POLL/W_FINAL/W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+} /* NbfProcessFrmr */
+
+
+VOID
+NbfProcessTest(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received TEST frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Header, PollFinal; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessTest: Entered.\n");
+ }
+
+ //
+ // Process only: TEST-c/x.
+ //
+
+ // BUGBUG: respond to TEST on a link that is NULL.
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+
+#if DBG
+ PANIC ("NbfSendTest: Received Test Packet, not processing....\n");
+#endif
+ //NbfSendTest (Link, FALSE, PollFinal, Psdu);
+
+} /* NbfProcessTest */
+
+
+VOID
+NbfProcessXid(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_U_FRAME Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received XID frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC U-type frame.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Header; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessXid: Entered.\n");
+ }
+
+ //
+ // Process only: XID-c/x.
+ //
+
+ // BUGBUG: respond to XID with a link that is NULL.
+
+ if (!Command || (Link == NULL)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ NbfSendXid (Link, FALSE, PollFinal); // releases lock
+
+} /* NbfProcessXid */
+
+
+VOID
+NbfProcessSFrame(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PDLC_S_FRAME Header,
+ IN UCHAR CommandByte
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received RR, RNR, or REJ frame.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC S-type frame.
+
+ CommandByte - The command byte of the frame (RR, RNR, or REJ).
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ BOOLEAN Resend;
+ BOOLEAN AckedPackets;
+ UCHAR AckSequenceNumber;
+ UCHAR OldLinkSendRetries;
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 (" NbfProcessSFrame %s: Entered, Link: %lx\n", Link,
+ Command == DLC_CMD_RR ? "RR" : (Command == DLC_CMD_RNR ? "RNR" : "REJ"));
+ }
+
+ //
+ // Process any of: RR-x/x, RNR-x/x, REJ-x/x
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ if (CommandByte == DLC_CMD_RNR) {
+ Link->LinkBusy = TRUE; // he's set a busy condition.
+ } else {
+ Link->LinkBusy = FALSE; // busy condition cleared.
+ }
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ //
+ // We're disconnected. Tell him.
+ //
+
+#if DBG
+ s = "ADM";
+#endif
+ NbfSendDm (Link, PollFinal); // releases lock
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. Note that the sections below surrounded by
+ // if (Command && PollFinal) variants are all disjoint sets.
+ // That's the only reason the Spinlock stuff works right. DO NOT
+ // attempt to fiddle this unless you figure out the locking first!
+ //
+
+ //
+ // If the AckSequenceNumber is not valid, ignore it. The
+ // number should be between the first packet on the WackQ
+ // and one more than the last packet. These correspond to
+ // Link->LastAckReceived and Link->NextSend.
+ //
+
+ AckSequenceNumber = (UCHAR)(Header->RcvSeq >> 1);
+
+ if (Link->NextSend >= Link->LastAckReceived) {
+
+ //
+ // There is no 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) ||
+ (AckSequenceNumber > Link->NextSend)) {
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
+ Link->HardwareAddress.Address[0],
+ Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2],
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5],
+ AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
+#endif
+ break;
+
+ }
+
+ } else {
+
+ //
+ // There is a 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) &&
+ (AckSequenceNumber > Link->NextSend)) {
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ DbgPrint("NbfResendLlcPackets: %.2x-%.2x-%.2x-%.2x-%.2x-%.2x Unexpected N(R) %d, LastAck %d NextSend %d\n",
+ Link->HardwareAddress.Address[0],
+ Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2],
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5],
+ AckSequenceNumber, Link->LastAckReceived, Link->NextSend);
+#endif
+ break;
+
+ }
+
+ }
+
+
+ //
+ // We always resend on a REJ, and never on an RNR;
+ // for an RR we may change Resend to TRUE below.
+ // If we get a REJ on a WAN line (T1 is more than
+ // five seconds) then we pretend this was a final
+ // so we will resend even if a poll was outstanding.
+ //
+
+ if (CommandByte == DLC_CMD_REJ) {
+ Resend = TRUE;
+ if (Link->CurrentT1Timeout >= ((5 * SECONDS) / SHORT_TIMER_DELTA)) {
+ PollFinal = TRUE;
+ }
+ OldLinkSendRetries = (UCHAR)Link->SendRetries;
+ } else {
+ Resend = FALSE;
+ }
+
+
+#if 0
+ //
+ // If we've got a request with no poll, must have fired T2 on
+ // the other side (or, if the other side is OS/2, he lost a
+ // packet and knows it or is telling me to lower the window size).
+ // In the T2 case, we've Acked current stuff, mark the window as
+ // needing adjustment at some future time. In the OS/2 cases, this
+ // is also the right thing to do.
+ //
+
+ if ((!Command) && (!PollFinal)) {
+ ;
+ }
+#endif
+
+ if (PollFinal) {
+
+ if (Command) {
+
+ //
+ // If he is checkpointing, then we must respond with RR-r/f to
+ // update him on the status of our reception of his I-frames.
+ //
+
+ StopT2 (Link); // we acked some I-frames.
+ NbfSendRr (Link, FALSE, PollFinal); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ //
+ // If we were checkpointing, and he has sent an RR-r/f, we
+ // can clear the checkpoint condition. Any packets which
+ // are still waiting for acknowlegement at this point must
+ // now be resent.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessRr: he's responded to our checkpoint.\n");
+ }
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessRr: BUGBUG: not ckpting, but final received.\n");
+ }
+ } else if (CommandByte == DLC_CMD_RR) {
+ OldLinkSendRetries = (UCHAR)Link->SendRetries;
+ Resend = TRUE;
+ UpdateBaseT1Timeout (Link); // gor response to poll
+ }
+ StopT1 (Link); // checkpointing finished.
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+ }
+ }
+
+ //
+ // NOTE: The link spinlock is held here.
+ //
+
+ //
+ // The N(R) in this frame acknowleges some (or all) of our packets.
+ // We'll ack packets on our send queue if this is a final when we
+ // call Resend. This call must come after the checkpoint
+ // acknowlegement check so that an RR-r/f is always sent BEFORE
+ // any new I-frames. This allows us to always send I-frames as
+ // commands.
+ //
+
+ if (Link->WackQ.Flink != &Link->WackQ) {
+
+ //
+ // NOTE: ResendLlcPackets may release and reacquire
+ // the link spinlock.
+ //
+
+ AckedPackets = ResendLlcPackets(
+ Link,
+ AckSequenceNumber,
+ Resend);
+
+ if (Resend && (!AckedPackets) && (Link->State == LINK_STATE_READY)) {
+
+ //
+ // To prevent stalling, pretend this RR wasn't
+ // received.
+ //
+
+ if (OldLinkSendRetries == 1) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+#if DBG
+ DbgPrint ("NBF: No ack teardown of %lx\n", Link);
+#endif
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfStopLink (Link);
+
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+ } else {
+
+ StopTi (Link);
+ Link->SendRetries = OldLinkSendRetries-1;
+
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ NbfSendRr (Link, TRUE, TRUE);// send RR-c/p, StartT1, release lock
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ }
+#if DBG
+ s = "READY";
+#endif
+ break; // No need to RestartLinkTraffic
+
+ } else if (AckedPackets) {
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ }
+
+ }
+
+
+ //
+ // If the link send state is READY, get the link going
+ // again.
+ //
+ // NOTE: RestartLinkTraffic releases the link spinlock.
+ //
+
+ if (Link->SendState == SEND_STATE_READY) {
+ RestartLinkTraffic (Link);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+#if DBG
+ s = "READY";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent a
+ // RR too early, so just let the SABME timeout.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. If he just
+ // sends something without a poll, we'll let that get by.
+ //
+
+ if (!Command) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_POLL";
+#endif
+ break; // don't allow this protocol.
+ }
+ Link->State = LINK_STATE_READY; // we're up!
+
+ FakeUpdateBaseT1Timeout (Link);
+ NbfSendRr (Link, FALSE, PollFinal); // send RR-r/x, release lock
+ NbfCompleteLink (Link); // fire up the connections.
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint4("W_POLL RR on %lx %x-%x-%x\n",
+ Link,
+ Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4],
+ Link->HardwareAddress.Address[5]);
+ }
+ StartTi (Link);
+
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy.
+ //
+
+ if (Command || !PollFinal) { // wait for final.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break; // we sent RR-c/p.
+ }
+ Link->State = LINK_STATE_READY; // we're up.
+ StopT1 (Link); // poll was acknowleged.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this RR. Throw the packet away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ if (CommandByte == DLC_CMD_REJ) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessRej: (%s) REJ received.\n", s);
+ }
+ }
+#endif
+
+} /* NbfProcessSFrame */
+
+
+VOID
+NbfInsertInLoopbackQueue (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UCHAR LinkIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine places a packet on the loopback queue, and
+ queues a DPC to do the indication if needed.
+
+Arguments:
+
+ DeviceContext - The device context in question.
+
+ NdisPacket - The packet to place on the loopback queue.
+
+ LinkIndex - The index of the loopback link to indicate to.
+
+Return Value:
+
+ None:
+
+--*/
+
+{
+ PSEND_PACKET_TAG SendPacketTag;
+ KIRQL oldirql;
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendPacketTag->OnLoopbackQueue = TRUE;
+
+ SendPacketTag->LoopbackLinkIndex = LinkIndex;
+
+ ACQUIRE_SPIN_LOCK(&DeviceContext->LoopbackSpinLock, &oldirql);
+
+ InsertTailList(&DeviceContext->LoopbackQueue, &SendPacketTag->Linkage);
+
+ if (!DeviceContext->LoopbackInProgress) {
+
+ KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
+ DeviceContext->LoopbackInProgress = TRUE;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LoopbackSpinLock, oldirql);
+
+}
+
+
+VOID
+NbfProcessLoopbackQueue (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This is the DPC routine which processes items on the
+ loopback queue. It processes a single request off the
+ queue (if there is one), then if there is another request
+ it requeues itself.
+
+Arguments:
+
+ Dpc - The system DPC object.
+
+ DeferredContext - A pointer to the device context.
+
+ SystemArgument1, SystemArgument2 - Not used.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER FirstBuffer;
+ PVOID LookaheadBuffer;
+ UINT LookaheadBufferSize;
+ UINT BytesCopied;
+ UINT PacketSize;
+ ULONG HeaderLength;
+ PTP_LINK Link;
+ PSEND_PACKET_TAG SendPacketTag;
+ PLIST_ENTRY p;
+
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+
+ DeviceContext = (PDEVICE_CONTEXT)DeferredContext;
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
+
+ if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
+
+ p = RemoveHeadList(&DeviceContext->LoopbackQueue);
+
+ //
+ // BUGBUG: This depends on the fact that the Linkage field is
+ // the first one in ProtocolReserved.
+ //
+
+ NdisPacket = CONTAINING_RECORD(p, NDIS_PACKET, ProtocolReserved[0]);
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendPacketTag->OnLoopbackQueue = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+
+
+ //
+ // Determine the data needed to indicate. We don't guarantee
+ // that we will have the correct lookahead length, but since
+ // we know that any header we prepend is a single piece,
+ // and that's all we'll have to look at in an indicated packet,
+ // that's not a concern.
+ //
+ // Unfortunately that last paragraph is bogus since for
+ // indications to our client we need more data...
+ //
+
+ NdisQueryPacket(NdisPacket, NULL, NULL, &FirstBuffer, &PacketSize);
+
+ NdisQueryBuffer(FirstBuffer, &LookaheadBuffer, &LookaheadBufferSize);
+
+ if ((LookaheadBufferSize != PacketSize) &&
+ (LookaheadBufferSize < NBF_MAX_LOOPBACK_LOOKAHEAD)) {
+
+ //
+ // There is not enough contiguous data in the
+ // packet's first buffer, so we merge it into
+ // DeviceContext->LookaheadContiguous.
+ //
+
+ if (PacketSize > NBF_MAX_LOOPBACK_LOOKAHEAD) {
+ LookaheadBufferSize = NBF_MAX_LOOPBACK_LOOKAHEAD;
+ } else {
+ LookaheadBufferSize = PacketSize;
+ }
+
+ NbfCopyFromPacketToBuffer(
+ NdisPacket,
+ 0,
+ LookaheadBufferSize,
+ DeviceContext->LookaheadContiguous,
+ &BytesCopied);
+
+ ASSERT (BytesCopied == LookaheadBufferSize);
+
+ LookaheadBuffer = DeviceContext->LookaheadContiguous;
+
+ }
+
+
+ //
+ // Now determine which link to loop it back to;
+ // UI frames are not indicated on any link.
+ //
+
+ SendPacketTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+
+ //
+ // Hold DeviceContext->LinkSpinLock until we get a
+ // reference.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ switch (SendPacketTag->LoopbackLinkIndex) {
+
+ case LOOPBACK_TO_CONNECTOR:
+
+ Link = DeviceContext->LoopbackLinks[CONNECTOR_LINK];
+ break;
+
+ case LOOPBACK_TO_LISTENER:
+
+ Link = DeviceContext->LoopbackLinks[LISTENER_LINK];
+ break;
+
+ case LOOPBACK_UI_FRAME:
+ default:
+
+ Link = (PTP_LINK)NULL;
+ break;
+
+ }
+
+ //
+ // For non-null links, we have to reference them.
+ // We use LREF_TREE since that is what
+ // NbfGeneralReceiveHandler expects.
+ //
+
+ if (Link != (PTP_LINK)NULL) {
+ NbfReferenceLink("loopback indication", Link, LREF_TREE);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ MacReturnHeaderLength(
+ &DeviceContext->MacInfo,
+ LookaheadBuffer,
+ &HeaderLength);
+
+ DeviceContext->LoopbackHeaderLength = HeaderLength;
+
+ //
+ // Process the receive like any other. We don't have to
+ // worry about frame padding since we construct the
+ // frame ourselves.
+ //
+
+ NbfGeneralReceiveHandler(
+ DeviceContext,
+ (NDIS_HANDLE)NdisPacket,
+ &DeviceContext->LocalAddress, // since it is loopback
+ Link,
+ LookaheadBuffer, // header
+ PacketSize - HeaderLength, // total packet size
+ (PDLC_FRAME)((PUCHAR)LookaheadBuffer + HeaderLength), // l/a data
+ LookaheadBufferSize - HeaderLength, // lookahead data length
+ TRUE
+ );
+
+
+ //
+ // Now complete the send.
+ //
+
+ NbfSendCompletionHandler(
+ DeviceContext->NdisBindingHandle,
+ NdisPacket,
+ NDIS_STATUS_SUCCESS
+ );
+
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->LoopbackSpinLock);
+
+ if (!IsListEmpty(&DeviceContext->LoopbackQueue)) {
+
+ KeInsertQueueDpc(&DeviceContext->LoopbackDpc, NULL, NULL);
+
+ //
+ // Remove these two lines if it is decided thet
+ // NbfReceiveComplete should be called after every
+ // loopback indication.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+ return;
+
+ } else {
+
+ DeviceContext->LoopbackInProgress = FALSE;
+
+ }
+
+ } else {
+
+ //
+ // This shouldn't happen!
+ //
+
+ DeviceContext->LoopbackInProgress = FALSE;
+
+#if DBG
+ NbfPrint1("Loopback queue empty for device context %x\n", DeviceContext);
+#endif
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LoopbackSpinLock);
+
+ NbfReceiveComplete(
+ (NDIS_HANDLE)DeviceContext
+ );
+
+} /* NbfProcessLoopbackQueue */
+
+
+NDIS_STATUS
+NbfReceiveIndication (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ PDEVICE_CONTEXT DeviceContext;
+ KIRQL oldirql;
+ PTP_LINK Link;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ UINT RealPacketSize;
+ PDLC_FRAME DlcHeader;
+ BOOLEAN Multicast;
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ PUCHAR p;
+ SHORT i;
+ NbfPrint2 ("NbfReceiveIndication: Packet, Size: 0x0%lx LookaheadSize: 0x0%lx\n 00:",
+ PacketSize, LookaheadBufferSize);
+ p = (PUCHAR)LookaheadBuffer;
+ for (i=0;i<25;i++) {
+ NbfPrint1 (" %2x",p[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+ RealPacketSize = 0;
+
+ //
+ // Obtain the packet length; this may optionally adjust
+ // the lookahead buffer forward if the header we wish
+ // to remove spills over into what the MAC considers
+ // data. If it determines that the header is not
+ // valid, it keeps RealPacketSize at 0.
+ //
+
+ MacReturnPacketLength(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ HeaderBufferSize,
+ PacketSize,
+ &RealPacketSize,
+ &LookaheadBuffer,
+ &LookaheadBufferSize
+ );
+
+ if (RealPacketSize < 2) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NbfReceiveIndication: Discarding packet, bad length %lx\n",
+ HeaderBuffer);
+ }
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ //
+ // We've negotiated at least a contiguous DLC header passed back in the
+ // lookahead buffer. Check it to see if we want this packet.
+ //
+
+ DlcHeader = (PDLC_FRAME)LookaheadBuffer;
+
+ if (((*(USHORT UNALIGNED *)(&DlcHeader->Dsap)) &
+ (USHORT)((DLC_SSAP_MASK << 8) | DLC_DSAP_MASK)) !=
+ (USHORT)((DSAP_NETBIOS_OVER_LLC << 8) | DSAP_NETBIOS_OVER_LLC)) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NbfReceiveIndication: Discarding lookahead data, not NetBIOS: %lx\n",
+ LookaheadBuffer);
+ }
+ LEAVE_NBF;
+ return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
+ }
+
+
+ //
+ // Check that the packet is not too long.
+ //
+
+ if (PacketSize > DeviceContext->MaxReceivePacketSize) {
+#if DBG
+ NbfPrint2("NbfReceiveIndication: Ignoring packet length %d, max %d\n",
+ PacketSize, DeviceContext->MaxReceivePacketSize);
+#endif
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceAddressBuffer,
+ &SourceAddress,
+ &Multicast
+ );
+
+ //
+ // Record how many multicast packets we get, to monitor
+ // general network activity.
+ //
+
+ if (Multicast) {
+ ++DeviceContext->MulticastPacketCount;
+ }
+
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ //
+ // Unless this is a UI frame find the Link this packet belongs to.
+ // If there is not a recognized link, pass the frame on to be handled
+ // by the receive complete code.
+ //
+
+ if ((((PDLC_U_FRAME)LookaheadBuffer)->Command) != DLC_CMD_UI) {
+
+ // This adds a link reference if it is found
+
+ Link = NbfFindLink (DeviceContext, SourceAddress->Address);
+
+ if (Link != NULL) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndication: Found link, Link: %lx\n", Link);
+ }
+
+ }
+
+ } else {
+
+ Link = NULL;
+
+ }
+
+
+ NbfGeneralReceiveHandler(
+ DeviceContext,
+ ReceiveContext,
+ SourceAddress,
+ Link,
+ HeaderBuffer, // header
+ RealPacketSize, // total data length in packet
+ (PDLC_FRAME)LookaheadBuffer, // lookahead data
+ LookaheadBufferSize, // lookahead data length
+ FALSE // not loopback
+ );
+
+ KeLowerIrql (oldirql);
+
+ return STATUS_SUCCESS;
+
+} /* NbfReceiveIndication */
+
+
+VOID
+NbfGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PTP_LINK Link,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PDLC_FRAME DlcHeader,
+ IN UINT DlcSize,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from either NbfReceiveIndication
+ or NbfProcessLoopbackQueue. It continues the processing of
+ indicated data once the link has been determined.
+
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ DeviceContext - The device context of this adapter.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ SourceAddress - The source address of the packet.
+
+ Link - The link that this packet was received on, may be NULL
+ if the link was not found. If not NULL, Link will have
+ a reference of type LREF_TREE.
+
+ HeaderBuffer - pointer to the packet header.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ DlcHeader - Points to the DLC header of the packet.
+
+ DlcSize - The length of the packet indicated, starting from DlcHeader.
+
+ Loopback - TRUE if this was called by NbfProcessLoopbackQueue;
+ used to determine whether to call NdisTransferData or
+ NbfTransferLoopbackData.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PNDIS_PACKET NdisPacket;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ PSINGLE_LIST_ENTRY linkage;
+ UINT BytesTransferred;
+ BOOLEAN Command;
+ BOOLEAN PollFinal;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PDLC_I_FRAME IHeader;
+ PDLC_U_FRAME UHeader;
+ PDLC_S_FRAME SHeader;
+ PTP_ADDRESS DatagramAddress;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+
+ ENTER_NBF;
+
+
+ INCREMENT_COUNTER (DeviceContext, PacketsReceived);
+
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+
+ if (Link == (PTP_LINK)NULL) {
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+ if (((UHeader->Command & ~DLC_U_PF) == DLC_CMD_UI) && Command) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfGeneralReceiveHandler: Processing packet as UI frame.\n");
+ }
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength > MAX_SOURCE_ROUTING) {
+ Status = STATUS_ABANDONED;
+ }
+ else {
+ Status = NbfProcessUi (
+ DeviceContext,
+ SourceAddress,
+ HeaderBuffer,
+ (PUCHAR)UHeader,
+ DlcSize,
+ SourceRouting,
+ SourceRoutingLength,
+ &DatagramAddress);
+ }
+ } else {
+
+ //
+ // or drop on the floor. (BUGBUG: Note that state tables say that
+ // we'll always handle a DM with a DM response. This should change.)
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveIndication: it's not a UI frame!\n");
+ }
+ Status = STATUS_SUCCESS;
+ }
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ LEAVE_NBF;
+ return;
+
+ } else if (((PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3))->Command ==
+ NBF_CMD_STATUS_RESPONSE) {
+
+ (VOID)NbfProcessStatusResponse(
+ DeviceContext,
+ ReceiveContext,
+ (PNBF_HDR_CONNECTIONLESS)((PUCHAR)UHeader + 3),
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+ return;
+
+ } else {
+ goto HandleAtComplete; // only datagrams will get through this
+ }
+ }
+
+
+ //
+ // At this point we have a link reference count of type LREF_TREE
+ //
+
+ ++Link->PacketsReceived;
+
+ //
+ // deal with I-frames first; they are what we expect the most of...
+ //
+
+ if (!(DlcHeader->Byte1 & DLC_I_INDICATOR)) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: I-frame encountered.\n");
+ }
+ if (DlcSize >= 4 + sizeof (NBF_HDR_CONNECTION)) {
+ IHeader = (PDLC_I_FRAME)DlcHeader;
+ NbfProcessIIndicate (
+ Command,
+ (BOOLEAN)(IHeader->RcvSeq & DLC_I_PF),
+ Link,
+ (PUCHAR)DlcHeader,
+ DlcSize,
+ PacketSize,
+ ReceiveContext,
+ Loopback);
+ } else {
+#if DBG
+// IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: Runt I-frame, discarded!\n");
+// }
+#endif
+ ;
+ }
+
+ } else if (((DlcHeader->Byte1 & DLC_U_INDICATOR) == DLC_U_INDICATOR)) {
+
+ //
+ // different case switches for S and U frames, because structures
+ // are different.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NbfReceiveIndication: U-frame encountered.\n");
+ }
+
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+ PollFinal = (BOOLEAN)(UHeader->Command & DLC_U_PF);
+ switch (UHeader->Command & ~DLC_U_PF) {
+
+ case DLC_CMD_SABME:
+ NbfProcessSabme (Command, PollFinal, Link, UHeader,
+ HeaderBuffer, SourceAddress, DeviceContext);
+ break;
+
+ case DLC_CMD_DISC:
+ NbfProcessDisc (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_UA:
+ NbfProcessUa (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_DM:
+ NbfProcessDm (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_FRMR:
+ NbfProcessFrmr (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_UI:
+
+ ASSERT (FALSE);
+ break;
+
+ case DLC_CMD_XID:
+ PANIC ("ReceiveIndication: XID!\n");
+ NbfProcessXid (Command, PollFinal, Link, UHeader);
+ break;
+
+ case DLC_CMD_TEST:
+ PANIC ("NbfReceiveIndication: TEST!\n");
+ NbfProcessTest (Command, PollFinal, Link, UHeader);
+ break;
+
+ default:
+ PANIC ("NbfReceiveIndication: bad U-frame, packet dropped.\n");
+
+ } /* switch */
+
+ } else {
+
+ //
+ // We have an S-frame.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfReceiveIndication: S-frame encountered.\n");
+ }
+ SHeader = (PDLC_S_FRAME)DlcHeader;
+ PollFinal = (BOOLEAN)(SHeader->RcvSeq & DLC_S_PF);
+ switch (SHeader->Command) {
+
+ case DLC_CMD_RR:
+ case DLC_CMD_RNR:
+ case DLC_CMD_REJ:
+ NbfProcessSFrame (Command, PollFinal, Link, SHeader, SHeader->Command);
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveIndication: bad S-frame.\n");
+ }
+
+ } /* switch */
+
+ } // if U-frame or S-frame
+
+ //
+ // If we reach here, the packet has been processed. If it needs
+ // to be copied, we will jump to HandleAtComplete.
+ //
+
+ NbfDereferenceLinkMacro ("Done with Indicate frame", Link, LREF_TREE);
+ LEAVE_NBF;
+ return;
+
+HandleAtComplete:;
+
+ //
+ // At this point we DO NOT have any link references added in
+ // this function.
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive packets.\n");
+ DeviceContext->ReceivePacketExhausted++;
+ LEAVE_NBF;
+ return;
+ }
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
+ } else {
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ // PANIC ("NbfReceiveIndicate: Discarding Packet, no receive buffers.\n");
+ DeviceContext->ReceiveBufferExhausted++;
+ LEAVE_NBF;
+ return;
+ }
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
+ NdisChainBufferAtFront (NdisPacket, BufferTag->NdisBuffer);
+
+ //
+ // DatagramAddress has a reference of type AREF_PROCESS_DATAGRAM,
+ // unless this is a datagram intended for RAS only, in which case
+ // it is NULL.
+ //
+
+ BufferTag->Address = DatagramAddress;
+
+ //
+ // set up async return status so we can tell when it has happened;
+ // can never get return of NDIS_STATUS_PENDING in synch completion routine
+ // for NdisTransferData, so we know it has completed when this status
+ // changes
+ //
+
+ BufferTag->NdisStatus = NDIS_STATUS_PENDING;
+ ReceiveTag->PacketType = TYPE_AT_COMPLETE;
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->ReceiveInProgress,
+ &BufferTag->Linkage,
+ &DeviceContext->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndicate: Packet on Queue: %lx\n",NdisPacket);
+ }
+
+ //
+ // receive packet is mapped at initalize
+ //
+
+ //
+ // Determine how to handle the data transfer.
+ //
+
+ if (Loopback) {
+
+ NbfTransferLoopbackData(
+ &NdisStatus,
+ DeviceContext,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred
+ );
+
+ } else {
+
+ NdisTransferData (
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred);
+
+ }
+
+ //
+ // handle the various error codes
+ //
+
+ switch (NdisStatus) {
+ case NDIS_STATUS_SUCCESS: // received packet
+ BufferTag->NdisStatus = NDIS_STATUS_SUCCESS;
+
+ if (BytesTransferred == PacketSize) { // Did we get the entire packet?
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ LEAVE_NBF;
+ return;
+ }
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 ("NbfReceiveIndicate: Discarding Packet, Partial transfer: 0x0%lx of 0x0%lx transferred\n",
+ BytesTransferred, PacketSize);
+ }
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+ LEAVE_NBF;
+ return;
+ break;
+
+ default: // something broke; certainly we'll never get NdisTransferData
+ // asynch completion with this error status...
+ break;
+ }
+
+ //
+ // receive failed, for some reason; cleanup and fail return
+ // BUGBUG: Statistics go here
+ //
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfReceiveIndicate: Discarding Packet, transfer failed: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ RemoveEntryList (&BufferTag->Linkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD (
+ BufferPointer,
+ BUFFER_TAG,
+ Buffer[0]
+ );
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ if (DatagramAddress) {
+ NbfDereferenceAddress ("DG TransferData failed", DatagramAddress, AREF_PROCESS_DATAGRAM);
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* NbfGeneralReceiveHandler */
+
+
+
+VOID
+NbfTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to start stripping buffers from the receive queue.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PTP_CONNECTION Connection;
+ KIRQL oldirql1;
+ PTP_REQUEST Request;
+ PNDIS_BUFFER NdisBuffer;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PBUFFER_TAG BufferTag;
+
+ //
+ // Put the NDIS status into a place we can use in packet processing.
+ // Note that this complete indication may be occuring during the call
+ // to NdisTransferData in the receive indication.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint2 (" NbfTransferDataComplete: Entered, Packet: %lx bytes transferred: 0x0%x\n",
+ NdisPacket, BytesTransferred);
+ }
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+
+ //
+ // note that the processing below depends on having only one packet
+ // transfer outstanding at a time. NDIS is supposed to guarentee this.
+ //
+
+ switch (ReceiveTag->PacketType) {
+
+ case TYPE_AT_COMPLETE: // datagrams
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
+ BufferTag->NdisStatus = NdisStatus;
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ case TYPE_AT_INDICATE: // I-frames
+
+ //
+ // The transfer for this packet is complete. Was it successful??
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ Connection = ReceiveTag->Connection;
+
+ //
+ // rip all of the NDIS_BUFFERs we've used off the chain and return them.
+ //
+
+ if (ReceiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (NdisPacket);
+ }
+
+
+ if ((NdisStatus != NDIS_STATUS_SUCCESS) ||
+ (!DeviceContext->MacInfo.SingleReceive)) {
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ULONG DumpData[2];
+ DumpData[0] = BytesTransferred;
+ DumpData[1] = ReceiveTag->BytesToTransfer;
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 603,
+ NdisStatus,
+ NULL,
+ 2,
+ DumpData);
+
+ // Drop the packet.
+#if DBG
+ NbfPrint1 ("NbfTransferDataComplete: status %s\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_TRANSFER_FAIL;
+
+ } else {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ Connection->TransferBytesPending -= ReceiveTag->BytesToTransfer;
+
+ if ((Connection->TransferBytesPending == 0) &&
+ (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
+
+ Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
+ Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
+ Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
+ Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ ReceiveTag->CompleteReceive = FALSE;
+
+ } else {
+
+ //
+ // BUGBUG: If we have more data outstanding, this can't
+ // be the last piece; i.e. we can't handle having
+ // the last piece complete asynchronously before
+ // an earlier piece.
+ //
+#if DBG
+ if (Connection->TransferBytesPending > 0) {
+ ASSERT (!ReceiveTag->CompleteReceive);
+ }
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+
+ //
+ // dereference the connection to say we've done the I frame processing.
+ // This reference was done before calling NdisTransferData.
+ //
+
+ if (ReceiveTag->TransferDataPended) {
+ NbfDereferenceConnection("TransferData done", Connection, CREF_TRANSFER_DATA);
+ }
+
+
+ } else {
+
+ ASSERT (NdisStatus == STATUS_SUCCESS);
+ ASSERT (!ReceiveTag->TransferDataPended);
+ ASSERT (Connection->CurrentReceiveSynchronous);
+
+ if (!Connection->SpecialReceiveIrp) {
+ Connection->CurrentReceiveIrp->IoStatus.Information += BytesTransferred;
+ }
+
+ }
+
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (ReceiveTag->CompleteReceive) {
+ CompleteReceive (Connection, ReceiveTag->EndOfMessage, (ULONG)BytesTransferred);
+ }
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ KeLowerIrql (oldirql1);
+
+ break;
+
+ case TYPE_STATUS_RESPONSE: // response to remote adapter status
+
+ //
+ // BUGBUG: Handle failure.
+ //
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DbgPrint ("NBF: STATUS_RESPONSE TransferData failed\n");
+ }
+#endif
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ASSERT (NdisBuffer);
+ NdisFreeBuffer (NdisBuffer);
+
+ Request = (PTP_REQUEST)ReceiveTag->Connection;
+
+ if (ReceiveTag->CompleteReceive) {
+ NbfCompleteRequest(
+ Request,
+ ReceiveTag->EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ Request->BytesWritten);
+ }
+
+ NbfDereferenceRequest("Status xfer done", Request, RREF_STATUS);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ default:
+#if DBG
+ NbfPrint1 ("NbfTransferDataComplete: Bang! Packet Transfer failed, unknown packet type: %ld\n",
+ ReceiveTag->PacketType);
+ DbgBreakPoint ();
+#endif
+ break;
+ }
+
+ //
+ // BUGBUG: Statistics need to be kept here.
+ //
+
+ return;
+
+} // NbfTransferDataComplete
+
+
+
+VOID
+NbfReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+ Nbf uses the DeviceContext for this parameter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ UINT i;
+ NTSTATUS Status;
+ KIRQL oldirql2;
+ BOOLEAN Command;
+ PDLC_U_FRAME UHeader;
+ PDLC_FRAME DlcHeader;
+ PLIST_ENTRY linkage;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PBUFFER_TAG BufferTag;
+ PTP_ADDRESS Address;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PTP_LINK Link;
+
+ ENTER_NBF;
+
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Entered.\n");
+ }
+
+ DeviceContext = (PDEVICE_CONTEXT) BindingContext;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql2);
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
+
+ linkage = ExInterlockedRemoveHeadList(
+ &DeviceContext->IrpCompletionQueue,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+
+ Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ Connection = IRP_RECEIVE_CONNECTION(IrpSp);
+
+ if (Connection == NULL) {
+#if DBG
+ DbgPrint ("Connection of Irp %lx is NULL\n", Irp);
+ DbgBreakPoint();
+#endif
+ }
+
+ IRP_RECEIVE_REFCOUNT(IrpSp) = 0;
+ IRP_RECEIVE_IRP (IrpSp) = NULL;
+
+ LEAVE_NBF;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (Connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_RC_PENDING;
+
+ if (Connection->Flags & CONNECTION_FLAGS_PEND_INDICATE) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PEND_INDICATE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // We got an indicate (and sent a NO_RECEIVE) while
+ // this was in progress, so send the receive outstanding
+ // now.
+ //
+
+ NbfSendReceiveOutstanding (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ NbfDereferenceConnectionMacro ("receive completed", Connection, CREF_RECEIVE_IRP);
+
+ } else {
+
+ //
+ // ExInterlockedRemoveHeadList returned NULL, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // Packetize all waiting connections
+ //
+
+ if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ PacketizeConnections (DeviceContext);
+
+ }
+
+ if (!IsListEmpty (&DeviceContext->DeferredRrQueue)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ while (!IsListEmpty(&DeviceContext->DeferredRrQueue)) {
+
+ linkage = RemoveHeadList (&DeviceContext->DeferredRrQueue);
+
+ Link = CONTAINING_RECORD (linkage, TP_LINK, DeferredRrLinkage);
+
+ Link->OnDeferredRrQueue = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, FALSE); // releases lock
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->Interlock);
+
+ }
+
+
+ //
+ // Get every waiting packet, in order...
+ //
+
+
+ if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
+ BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfReceiveComplete: Processing Buffer %lx\n", BufferTag);
+ }
+
+ //
+ // NdisTransferData may have failed at async completion; check and
+ // see. If it did, then we discard this packet. If we're still waiting
+ // for transfer to complete, go back to sleep and hope (no guarantee!)
+ // we get waken up later.
+ //
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfReceiveComplete: NdisStatus: %s.\n",
+ NbfGetNdisStatus(BufferTag->NdisStatus));
+ }
+#endif
+ if (BufferTag->NdisStatus == NDIS_STATUS_PENDING) {
+ InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Status pending, returning packet to queue.\n");
+ }
+ KeLowerIrql (oldirql2);
+ LEAVE_NBF;
+ return;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (BufferTag->NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 (" NbfReceiveComplete: Failed return from Transfer data, reason: %s\n",
+ NbfGetNdisStatus (BufferTag->NdisStatus));
+#endif
+ // BUGBUG: some statistics go here for lost packet
+
+ goto FreeBuffer; // skip the buffer, continue with while loop
+ }
+
+ //
+ // Have a buffer. Since I allocated the storage for it, I know it's
+ // virtually contiguous and can treat it that way, which I will
+ // henceforth.
+ //
+
+ NdisQueryBuffer (BufferTag->NdisBuffer, &BufferPointer, &NdisBufferLength);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ PUCHAR pc;
+ NbfPrint0 (" NbfRC Packet: \n ");
+ pc = (PUCHAR)BufferPointer;
+ for (i=0;i<25;i++) {
+ NbfPrint1 (" %2x",pc[i]);
+ }
+ NbfPrint0 ("\n");
+ }
+
+ //
+ // Determine what address this is for, which is stored
+ // in the buffer tag header.
+ //
+
+ Address = BufferTag->Address;
+
+ //
+ // Process the frame as a UI frame; only datagrams should
+ // be processed here. If Address is NULL then this datagram
+ // is not needed for any bound address and should be given
+ // to RAS only.
+ //
+
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfReceiveComplete: Delivering this frame manually.\n");
+ }
+ DlcHeader = (PDLC_FRAME)BufferPointer;
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+ UHeader = (PDLC_U_FRAME)DlcHeader;
+
+ BufferPointer = (PUCHAR)BufferPointer + 3;
+ NdisBufferLength -= 3; // 3 less bytes.
+
+ if (Address != NULL) {
+
+ //
+ // Indicate it or complete posted datagrams.
+ //
+
+ Status = NbfIndicateDatagram (
+ DeviceContext,
+ Address,
+ BufferPointer, // the Dsdu, with some tweaking
+ NdisBufferLength);
+
+ //
+ // Dereference the address.
+ //
+
+ NbfDereferenceAddress ("Datagram done", Address, AREF_PROCESS_DATAGRAM);
+
+ }
+
+ //
+ // Let the RAS clients have a crack at this if they want
+ // (they only want directed datagrams, not broadcast).
+ //
+
+ if ((((PNBF_HDR_CONNECTIONLESS)BufferPointer)->Command == NBF_CMD_DATAGRAM) &&
+ (DeviceContext->IndicationQueuesInUse)) {
+
+ NbfActionDatagramIndication(
+ DeviceContext,
+ (PNBF_HDR_CONNECTIONLESS)BufferPointer,
+ NdisBufferLength);
+
+ }
+
+ BufferPointer = (PUCHAR)BufferPointer - 3;
+ NdisBufferLength += 3; // 3 more bytes.
+
+ //
+ // Finished with buffer; return to pool.
+ //
+
+FreeBuffer:;
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, BufferTag->Length);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ (PSINGLE_LIST_ENTRY)&BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ } // if queue not empty
+
+ KeLowerIrql (oldirql2);
+ LEAVE_NBF;
+ return;
+
+} /* NbfReceiveComplete */
+
+
+VOID
+NbfTransferLoopbackData (
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called instead of NdisTransferData for
+ loopback indications. It copies the data from the
+ source packet to the receive packet.
+
+Arguments:
+
+ NdisStatus - Returns the status of the operation.
+
+ DeviceContext - The device context.
+
+ ReceiveContext - A pointer to the source packet.
+
+ ByteOffset - The offset from the start of the source packet
+ that the transfer should begin at.
+
+ BytesToTransfer - The number of bytes to transfer.
+
+ Packet - A pointer to the receive packet.
+
+ BytesTransferred - Returns the number of bytes copied.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET SourcePacket = (PNDIS_PACKET)ReceiveContext;
+
+ NdisCopyFromPacketToPacket(
+ Packet,
+ 0,
+ BytesToTransfer,
+ SourcePacket,
+ DeviceContext->LoopbackHeaderLength + ByteOffset,
+ BytesTransferred
+ );
+
+ *NdisStatus = NDIS_STATUS_SUCCESS; // BUGBUG: what if BytesTransferred is too small
+
+}
+
+
+VOID
+NbfCopyFromPacketToBuffer(
+ IN PNDIS_PACKET Packet,
+ IN UINT Offset,
+ IN UINT BytesToCopy,
+ OUT PCHAR Buffer,
+ OUT PUINT BytesCopied
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from an ndis packet into a buffer.
+
+Arguments:
+
+ Packet - The packet to copy from.
+
+ Offset - The offset from which to start the copy.
+
+ BytesToCopy - The number of bytes to copy from the packet.
+
+ Buffer - The destination of the copy.
+
+ BytesCopied - The number of bytes actually copied. Can be less then
+ BytesToCopy if the packet is shorter than BytesToCopy.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Holds the number of ndis buffers comprising the packet.
+ //
+ UINT NdisBufferCount;
+
+ //
+ // Points to the buffer from which we are extracting data.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Holds the virtual address of the current buffer.
+ //
+ PVOID VirtualAddress;
+
+ //
+ // Holds the length of the current buffer of the packet.
+ //
+ UINT CurrentLength;
+
+ //
+ // Keep a local variable of BytesCopied so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesCopied = 0;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ *BytesCopied = 0;
+ if (!BytesToCopy) return;
+
+ //
+ // Get the first buffer.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &NdisBufferCount,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (!NdisBufferCount) return;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+
+ while (LocalBytesCopied < BytesToCopy) {
+
+ if (!CurrentLength) {
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.
+ //
+
+ if (!CurrentBuffer) break;
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ &VirtualAddress,
+ &CurrentLength
+ );
+ continue;
+
+ }
+
+ //
+ // Try to get us up to the point to start the copy.
+ //
+
+ if (Offset) {
+
+ if (Offset > CurrentLength) {
+
+ //
+ // What we want isn't in this buffer.
+ //
+
+ Offset -= CurrentLength;
+ CurrentLength = 0;
+ continue;
+
+ } else {
+
+ VirtualAddress = (PCHAR)VirtualAddress + Offset;
+ CurrentLength -= Offset;
+ Offset = 0;
+
+ }
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ AmountToMove =
+ ((CurrentLength <= (BytesToCopy - LocalBytesCopied))?
+ (CurrentLength):(BytesToCopy - LocalBytesCopied));
+
+ RtlCopyMemory(
+ Buffer,
+ VirtualAddress,
+ AmountToMove
+ );
+
+ Buffer = (PCHAR)Buffer + AmountToMove;
+ VirtualAddress = (PCHAR)VirtualAddress + AmountToMove;
+
+ LocalBytesCopied += AmountToMove;
+ CurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesCopied = LocalBytesCopied;
+
+}
+
diff --git a/private/ntos/tdi/nbf/event.c b/private/ntos/tdi/nbf/event.c
new file mode 100644
index 000000000..6cb072d8a
--- /dev/null
+++ b/private/ntos/tdi/nbf/event.c
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiSetEventHandler(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Irp - Pointer to the IRP for this request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS rc=STATUS_SUCCESS;
+ KIRQL oldirql;
+ PTDI_REQUEST_KERNEL_SET_EVENT parameters;
+ PIO_STACK_LOCATION irpSp;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ NTSTATUS status;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ addressFile = irpSp->FileObject->FsContext;
+ status = NbfVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&irpSp->Parameters;
+
+ switch (parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;
+ addressFile->ReceiveHandlerContext = NULL;
+ addressFile->RegisteredReceiveHandler = FALSE;
+ } else {
+ addressFile->ReceiveHandler =
+ (PTDI_IND_RECEIVE)parameters->EventHandler;
+ addressFile->ReceiveHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;
+ addressFile->ExpeditedDataHandlerContext = NULL;
+ addressFile->RegisteredExpeditedDataHandler = FALSE;
+ } else {
+ addressFile->ExpeditedDataHandler =
+ (PTDI_IND_RECEIVE_EXPEDITED)parameters->EventHandler;
+ addressFile->ExpeditedDataHandlerContext = parameters->EventContext;
+ addressFile->RegisteredExpeditedDataHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ addressFile->ReceiveDatagramHandlerContext = NULL;
+ addressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ addressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)parameters->EventHandler;
+ addressFile->ReceiveDatagramHandlerContext = parameters->EventContext;
+ addressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ addressFile->ErrorHandlerContext = NULL;
+ addressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ addressFile->ErrorHandler =
+ (PTDI_IND_ERROR)parameters->EventHandler;
+ addressFile->ErrorHandlerContext = parameters->EventContext;
+ addressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;
+ addressFile->DisconnectHandlerContext = NULL;
+ addressFile->RegisteredDisconnectHandler = FALSE;
+ } else {
+ addressFile->DisconnectHandler =
+ (PTDI_IND_DISCONNECT)parameters->EventHandler;
+ addressFile->DisconnectHandlerContext = parameters->EventContext;
+ addressFile->RegisteredDisconnectHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ if (parameters->EventHandler == NULL) {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)TdiDefaultConnectHandler;
+ addressFile->ConnectionHandlerContext = NULL;
+ addressFile->RegisteredConnectionHandler = FALSE;
+ } else {
+ addressFile->ConnectionHandler =
+ (PTDI_IND_CONNECT)parameters->EventHandler;
+ addressFile->ConnectionHandlerContext = parameters->EventContext;
+ addressFile->RegisteredConnectionHandler = TRUE;
+ }
+ break;
+
+ default:
+
+ rc = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ NbfDereferenceAddress ("Set event handler", address, AREF_VERIFY);
+
+ return rc;
+} /* TdiSetEventHandler */
diff --git a/private/ntos/tdi/nbf/framecon.c b/private/ntos/tdi/nbf/framecon.c
new file mode 100644
index 000000000..6905d9668
--- /dev/null
+++ b/private/ntos/tdi/nbf/framecon.c
@@ -0,0 +1,1087 @@
+
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ framecon.c
+
+Abstract:
+
+ This module contains routines which build NetBIOS Frames Protocol frames,
+ both connection-oriented and connectionless. The following frames are
+ constructed 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
+ o NBF_CMD_DATA_ACK
+ o NBF_CMD_DATA_FIRST_MIDDLE
+ o NBF_CMD_DATA_ONLY_LAST
+ o NBF_CMD_SESSION_CONFIRM
+ o NBF_CMD_SESSION_END
+ o NBF_CMD_SESSION_INITIALIZE
+ o NBF_CMD_NO_RECEIVE
+ o NBF_CMD_RECEIVE_OUTSTANDING
+ o NBF_CMD_RECEIVE_CONTINUE
+ o NBF_CMD_SESSION_ALIVE
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+VOID
+ConstructAddGroupNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME GroupName // NetBIOS group name to be added.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_GROUP_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Correlator - Correlator for ADD_NAME_RESPONSE frame.
+
+ GroupName - Pointer to NetBIOS group name to be added.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddGroupNameQuery: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_GROUP_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = GroupName [i];
+ }
+} /* ConstructAddGroupNameQuery */
+
+
+VOID
+ConstructAddNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME Name // NetBIOS name to be added.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Correlator - Correlator for ADD_NAME_RESPONSE frame.
+
+ Name - Pointer to NetBIOS name to be added.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddNameQuery: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = Name [i];
+ }
+} /* ConstructAddNameQuery */
+
+
+VOID
+ConstructNameInConflict(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ConflictingName, // NetBIOS name that is conflicting.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_IN_CONFLICT connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ Conflictingname - Pointer to NetBIOS name that is conflicting.
+
+ SendingPermanentName - Pointer to NetBIOS permanent node name of sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNameInConflict: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_IN_CONFLICT;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ConflictingName[i];
+ RawFrame->SourceName [i] = SendingPermanentName[i];
+ }
+
+} /* ConstructNameInConflict */
+
+
+VOID
+ConstructStatusQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request.
+ IN USHORT BufferLength, // length of user's status buffer.
+ IN USHORT Correlator, // correlator for STATUS_RESPONSE.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_STATUS_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ RequestType - Type of request. One of:
+ 0 - request is 1.x or 2.0.
+ 1 - first request, 2.1 or above.
+ >1 - subsequent request, 2.1 or above.
+
+ BufferLength - Length of user's status buffer.
+
+ Correlator - Correlator for STATUS_RESPONSE frame.
+
+ ReceiverName - Pointer to NetBIOS name of receiver.
+
+ SendingPermanentName - Pointer to NetBIOS permanent node name of sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint1 ("ConstructStatusQuery: Entered, frame: %lx\n", RawFrame);
+ }
+
+ RawFrame->Command = NBF_CMD_STATUS_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = RequestType;
+ RawFrame->Data2Low = (UCHAR)(BufferLength & 0xff);
+ RawFrame->Data2High = (UCHAR)(BufferLength >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SendingPermanentName [i];
+ }
+
+} /* ConstructStatusQuery */
+
+
+VOID
+ConstructDatagram(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATAGRAM connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDatagram: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATAGRAM;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructDatagram */
+
+
+VOID
+ConstructDatagramBroadcast(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATAGRAM_BROADCAST connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDatagramBroadcast: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATAGRAM_BROADCAST;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = 0;
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructDatagramBroadcast */
+
+
+VOID
+ConstructNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session (0=FIND_NAME).
+ IN USHORT Correlator, // correlator in NAME_RECOGNIZED.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_QUERY connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, one of the following:
+ NAME_QUERY_LSN_FIND_NAME
+
+ LocalSessionNumber - LSN assigned to session (0=FIND.NAME).
+
+ Correlator - Correlator in NAME_RECOGNIZED.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint1 ("ConstructNameQuery: Entered, frame: %lx\n", RawFrame);
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_QUERY;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = LocalSessionNumber;
+ RawFrame->Data2High = NameType;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructNameQuery */
+
+
+VOID
+ConstructAddNameResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN USHORT Correlator, // correlator from ADD_[GROUP_]NAME_QUERY.
+ IN PNAME Name // NetBIOS name being responded to.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_ADD_NAME_RESPONSE connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, either group or unique.
+
+ Correlator - Correlator from ADD_[GROUP]NAME_QUERY.
+
+ Name - Pointer to NetBIOS name being responded to.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructAddNameResponse: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_ADD_NAME_RESPONSE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = NameType;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = Name [i];
+ RawFrame->SourceName [i] = Name [i];
+ }
+} /* ConstructAddNameResponse */
+
+
+VOID
+ConstructNameRecognized(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN USHORT NameQueryCorrelator, // correlator from NAME_QUERY.
+ IN USHORT Correlator, // correlator expected from next response.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NAME_RECOGNIZED connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ NameType - Type of name, either group or unique.
+
+ LocalSessionNumber - LSN assigned to session. Special values are:
+ NAME_RECOGNIZED_LSN_NO_LISTENS // no listens available.
+ NAME_RECOGNIZED_LSN_FIND_NAME // this is a find name response.
+ NAME_RECOGNIZED_LSN_NO_RESOURCE // listen available, but no resources.
+
+ NameQueryCorrelator - Correlator from NAME_QUERY.
+
+ Correlator - Correlator expected from next response.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+ ReceiverName - Pointer to a NetBIOS name of the receiver.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ USHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNameRecognized: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NAME_RECOGNIZED;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0; // reserved field, MBZ.
+ RawFrame->Data2Low = LocalSessionNumber;
+ RawFrame->Data2High = NameType;
+ TRANSMIT_CORR(RawFrame) = NameQueryCorrelator;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceiverName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+} /* ConstructNameRecognized */
+
+
+VOID
+ConstructStatusResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN BOOLEAN Truncated, // data is truncated.
+ IN BOOLEAN DataOverflow, // too much data for user's buffer.
+ IN USHORT DataLength, // length of data sent.
+ IN USHORT Correlator, // correlator from STATUS_QUERY.
+ IN PNAME ReceivingPermanentName, // NetBIOS permanent node name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_STATUS_RESPONSE connectionless
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 44-byte connectionless frame buffer.
+
+ RequestType - type of request, one of the below:
+ 0 - request is 1.x or 2.0.
+ >0 - number of names, 2.1 or above.
+
+ Truncated - TRUE if there are more names.
+
+ DataOverflow - TRUE if the total data is larger than the user's buffer.
+
+ DataLength - The length of the data in Buffer.
+
+ Correlator - Correlator from STATUS_QUERY.
+
+ ReceivingPermanentName - Pointer to the NetBIOS permanent node name of the receiver,
+ as passed in the STATUS_QUERY frame.
+
+ SenderName - Pointer to a NetBIOS name of the sender.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ SHORT i;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructStatusResponse: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_STATUS_RESPONSE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTIONLESS);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = RequestType;
+ RawFrame->Data2Low = (UCHAR)(DataLength & 0xff);
+ RawFrame->Data2High = (UCHAR)((DataLength >> 8) +
+ (Truncated << 7) +
+ (DataOverflow << 6));
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = 0;
+ for (i=0; i<NETBIOS_NAME_LENGTH; i++) {
+ RawFrame->DestinationName [i] = ReceivingPermanentName [i];
+ RawFrame->SourceName [i] = SenderName [i];
+ }
+
+} /* ConstructStatusResponse */
+
+
+VOID
+ConstructDataAck(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_ONLY_LAST.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATA_ACK connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Correlator - Correlator from DATA_ONLY_LAST being acked.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDataAck: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATA_ACK;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructDataAck */
+
+
+VOID
+ConstructDataOnlyLast(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN BOOLEAN Resynched, // TRUE if we are resynching.
+ IN USHORT Correlator, // correlator for RECEIVE_CONTINUE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_DATA_ONLY_LAST connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Resynched - TRUE if we are resynching and should set the
+ correct bit in the frame.
+
+ Correlator - Correlator for RECEIVE_CONTINUE, if any.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructDataOnlyLast: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_DATA_ONLY_LAST;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ ASSERT (TRUE == (UCHAR)1);
+ RawFrame->Data2Low = Resynched;
+ RawFrame->Data2High = (UCHAR)0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructDataOnlyLast */
+
+
+VOID
+ConstructSessionConfirm(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT Correlator, // correlator from SESSION_INITIALIZE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_CONFIRM connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ SESSION_CONFIRM_OPTIONS_20 // set if NETBIOS 2.0 or above.
+ SESSION_CONFIRM_NO_ACK // set if NO.ACK protocol supported.
+
+ MaximumUserBufferSize - Maximum size of user data per frame on this
+ session, in bytes. This is limited by the following constant:
+ SESSION_CONFIRM_MAXIMUM_FRAME_SIZE // defined limit of this field.
+
+ Correlator - Correlator from SESSION_INITIALIZE.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionConfirm: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_CONFIRM;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = Options;
+ RawFrame->Data2Low = (UCHAR)(MaximumUserBufferSize & 0xff);
+ RawFrame->Data2High = (UCHAR)(MaximumUserBufferSize >> 8);
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionConfirm */
+
+
+VOID
+ConstructSessionEnd(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Reason, // reason for termination, defined below.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_END connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Reason - Reason code for termination, any of the following:
+ SESSION_END_REASON_HANGUP // normal termination via HANGUP.
+ SESSION_END_REASON_ABEND // abnormal session termination.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionEnd: Entered (BUGBUG).\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_END;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = (UCHAR)(Reason & 0xff);
+ RawFrame->Data2High = (UCHAR)(Reason >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionEnd */
+
+
+VOID
+ConstructSessionInitialize(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT NameRecognizedCorrelator, // correlator from NAME_RECOGNIZED.
+ IN USHORT Correlator, // correlator for SESSION_CONFIRM.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_INITIALIZE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ SESSION_INITIALIZE_OPTIONS_20 // set if NETBIOS 2.0 or above.
+ SESSION_INITIALIZE_NO_ACK // set if NO.ACK protocol supported.
+
+ MaximumUserBufferSize - Maximum size of user data per frame on this
+ session, in bytes. This is limited by the following constant:
+ SESSION_INITIALIZE_MAXIMUM_FRAME_SIZE // defined limit of this field.
+
+ NameRecognizedCorrelator - Correlator from NAME_RECOGNIZED.
+
+ Correlator - Correlator for SESSION_CONFIRM.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionInitialize: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_INITIALIZE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = Options;
+ RawFrame->Data2Low = (UCHAR)(MaximumUserBufferSize & 0xff);
+ RawFrame->Data2High = (UCHAR)(MaximumUserBufferSize >> 8);
+ TRANSMIT_CORR(RawFrame) = NameRecognizedCorrelator;
+ RESPONSE_CORR(RawFrame) = Correlator;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructSessionInitialize */
+
+
+VOID
+ConstructNoReceive(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Options, // option bitflags, defined below.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_NO_RECEIVE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Options - Bitflag options, any of the following:
+ NO_RECEIVE_OPTIONS_PARTIAL_NO_ACK // NO.ACK data partially received.
+
+ BytesAccepted - Number of bytes accepted, current outstanding message.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+// Options; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructNoReceive: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_NO_RECEIVE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ if (Options == NO_RECEIVE_PARTIAL_NO_ACK) {
+ RawFrame->Data1 = NO_RECEIVE_PARTIAL_NO_ACK;
+ } else {
+ RawFrame->Data1 = 0;
+ }
+ RawFrame->Data2Low = (UCHAR)(BytesAccepted & 0xff);
+ RawFrame->Data2High = (UCHAR)(BytesAccepted >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructNoReceive */
+
+
+VOID
+ConstructReceiveOutstanding(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_RECEIVE_OUTSTANDING connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ BytesAccepted - Number of bytes accepted, current outstanding message.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructReceiveOutstanding: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_RECEIVE_OUTSTANDING;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = (UCHAR)(BytesAccepted & 0xff);
+ RawFrame->Data2High = (UCHAR)(BytesAccepted >> 8);
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructReceiveOutstanding */
+
+
+VOID
+ConstructReceiveContinue(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_FIRST_MIDDLE
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_RECEIVE_CONTINUE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+ Correlator - The correlator from the DATA_FIRST_MIDDLE frame.
+
+ LocalSessionNumber - Session number of SENDER.
+
+ RemoteSessionNumber - Session number of RECEIVER.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructReceiveContinue: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_RECEIVE_CONTINUE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = Correlator;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = LocalSessionNumber;
+ RawFrame->DestinationSessionNumber = RemoteSessionNumber;
+} /* ConstructReceiveContinue */
+
+#if 0
+
+VOID
+ConstructSessionAlive(
+ IN PNBF_HDR_CONNECTION RawFrame // frame buffer to format.
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an NBF_CMD_SESSION_ALIVE connection-oriented
+ NetBIOS Frame.
+
+Arguments:
+
+ RawFrame - Pointer to an unformatted 14-byte connection-oriented buffer.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_FRAMECON) {
+ NbfPrint0 ("ConstructSessionAlive: Entered.\n");
+ }
+
+ RawFrame->Command = NBF_CMD_SESSION_ALIVE;
+ HEADER_LENGTH(RawFrame) = sizeof(NBF_HDR_CONNECTION);
+ HEADER_SIGNATURE(RawFrame) = NETBIOS_SIGNATURE;
+ RawFrame->Data1 = 0;
+ RawFrame->Data2Low = 0;
+ RawFrame->Data2High = 0;
+ TRANSMIT_CORR(RawFrame) = (USHORT)0;
+ RESPONSE_CORR(RawFrame) = (USHORT)0;
+ RawFrame->SourceSessionNumber = 0;
+ RawFrame->DestinationSessionNumber = 0;
+} /* ConstructSessionAlive */
+
+#endif
diff --git a/private/ntos/tdi/nbf/framesnd.c b/private/ntos/tdi/nbf/framesnd.c
new file mode 100644
index 000000000..e4c356d99
--- /dev/null
+++ b/private/ntos/tdi/nbf/framesnd.c
@@ -0,0 +1,2504 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ framesnd.c
+
+Abstract:
+
+ This module contains routines which build and send NetBIOS Frames Protocol
+ frames and data link frames for other modules. These routines call on the
+ ones in FRAMECON.C to do the construction work.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+ULONG NbfSendsIssued = 0;
+ULONG NbfSendsCompletedInline = 0;
+ULONG NbfSendsCompletedOk = 0;
+ULONG NbfSendsCompletedFail = 0;
+ULONG NbfSendsPended = 0;
+ULONG NbfSendsCompletedAfterPendOk = 0;
+ULONG NbfSendsCompletedAfterPendFail = 0;
+
+ULONG NbfPacketPanic = 0;
+#endif
+
+
+NTSTATUS
+NbfSendAddNameQuery(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a ADD_NAME_QUERY frame to register the specified
+ address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint3 ("NbfSendAddNameQuery: Sending Frame: %lx, NdisPacket: %lx MacHeader: %lx\n",
+ RawFrame, RawFrame->NdisPacket, RawFrame->Header);
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the appropriate Netbios header based on the type
+ // of the address.
+ //
+
+ if ((Address->Flags & ADDRESS_FLAGS_GROUP) != 0) {
+
+ ConstructAddGroupNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ 0, // correlator we don't use.
+ Address->NetworkName->NetbiosName);
+
+ } else {
+
+ ConstructAddNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ 0, // correlator we don't use.
+ Address->NetworkName->NetbiosName);
+
+ }
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame).
+
+ return STATUS_SUCCESS;
+} /* NbfSendAddNameQuery */
+
+
+VOID
+NbfSendNameQuery(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN SourceRoutingOptional
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_QUERY frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+ SourceRoutingOptional - TRUE if source routing should be removed if
+ we are configured that way.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_ADDRESS Address;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR NameQuerySR;
+ UINT NameQuerySRLength;
+ PUCHAR NameQueryAddress;
+ UINT HeaderLength;
+ UCHAR Lsn;
+ UCHAR NameType;
+
+ Address = Connection->AddressFile->Address;
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame(DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameQuery: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header.
+ //
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) != 0) &&
+ ((Connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0)) {
+
+ //
+ // This is the second find name to a unique name; this
+ // means that we already have a link and we can send this
+ // frame directed to it.
+ //
+
+ ASSERT (Connection->Link != NULL);
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ Connection->Link->Header,
+ &NameQuerySR,
+ &NameQuerySRLength);
+
+ NameQueryAddress = Connection->Link->HardwareAddress.Address;
+
+ } else {
+
+ //
+ // Standard NAME_QUERY frames go out as
+ // single-route source routing, except if
+ // it is optional and we are configured
+ // that way.
+ //
+
+ if (SourceRoutingOptional &&
+ Connection->Provider->MacInfo.QueryWithoutSourceRouting) {
+
+ NameQuerySR = NULL;
+ NameQuerySRLength = 0;
+
+ } else {
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &NameQuerySR,
+ &NameQuerySRLength);
+
+ }
+
+ NameQueryAddress = DeviceContext->NetBIOSAddress.Address;
+
+ }
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ NameQueryAddress,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ NameQuerySR,
+ NameQuerySRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ Lsn = (UCHAR)((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN) ?
+ NAME_QUERY_LSN_FIND_NAME : Connection->Lsn);
+
+ NameType = (UCHAR)((Connection->AddressFile->Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ ConstructNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of our name.
+ Lsn, // calculated, above.
+ (USHORT)Connection->ConnectionId, // corr. in 1st NAME_RECOGNIZED.
+ Address->NetworkName->NetbiosName, // NetBIOS name of sender.
+ Connection->CalledAddress.NetbiosName); // NetBIOS name of receiver.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameQuery */
+
+
+VOID
+NbfSendNameRecognized(
+ IN PTP_ADDRESS Address,
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_RECOGNIZED frame of the appropriate type
+ in response to the NAME_QUERY pointed to by Header.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ LocalSessionNumber - The LSN to use in the frame.
+
+ Header - Pointer to the connectionless NetBIOS header of the
+ NAME_QUERY frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRoutingInformation - Pointer to source routing information, if any.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ UINT HeaderLength;
+ PUCHAR ReplySR;
+ UINT ReplySRLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ UCHAR NameType;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. NAME_RECOGNIZED frames go out as
+ // directed source routing unless configured for general-route.
+ //
+
+ if (DeviceContext->MacInfo.AllRoutesNameRecognized) {
+
+ MacReturnGeneralRouteSR(
+ &DeviceContext->MacInfo,
+ &ReplySR,
+ &ReplySRLength);
+
+ } else {
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ReplySR);
+
+ ReplySRLength = SourceRoutingLength;
+
+ } else {
+
+ ReplySR = NULL;
+ }
+ }
+
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ SourceAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ ReplySR,
+ ReplySRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ NameType = (UCHAR)((Address->Flags & ADDRESS_FLAGS_GROUP) ?
+ NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE);
+
+ ConstructNameRecognized ( // build a good response.
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NameType, // type of local name.
+ LocalSessionNumber, // return our LSN.
+ RESPONSE_CORR(Header), // new xmit corr.
+ 0, // our response correlator (unused).
+ Header->DestinationName, // our NetBIOS name.
+ Header->SourceName); // his NetBIOS name.
+
+ //
+ // BUGBUG: Use Address->NetworkName->Address[0].Address[0].NetbiosName
+ // instead of Header->DestinationName?
+ //
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameRecognized */
+
+
+VOID
+NbfSendNameInConflict(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR ConflictingName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NAME_IN_CONFLICT frame.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+ ConflictingName - The NetBIOS name which is in conflict.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_UI_FRAME RawFrame;
+ UINT HeaderLength;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ DeviceContext = Address->Provider;
+
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. ADD_NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructNameInConflict (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ ConflictingName, // his NetBIOS name.
+ DeviceContext->ReservedNetBIOSAddress); // our reserved NetBIOS name.
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length and send the it.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendNameInConflict */
+
+
+VOID
+NbfSendSessionInitialize(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_INITIALIZE frame on the specified connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session Initialize", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionInitialize: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SI);
+ NbfDereferenceConnection("Couldn't get SI packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionInitialize (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ SESSION_INIT_OPTIONS_20 | SESSION_INIT_NO_ACK |
+ SESSION_INIT_OPTIONS_LF, // supported options BUGBUG: Set LF correctly.
+ (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)),
+ // maximum frame size/this session.
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED.
+ 0, // correlator for expected SESSION_CONFIRM.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionInitialize */
+
+
+VOID
+NbfSendSessionConfirm(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_CONFIRM frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session Confirm", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionConfirm: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SC);
+ NbfDereferenceConnection("Couldn't get SC packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionConfirm (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ SESSION_CONFIRM_OPTIONS_20 | SESSION_CONFIRM_NO_ACK, // supported options.
+ (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)),
+ // maximum frame size/this session.
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionConfirm */
+
+
+VOID
+NbfSendSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Abort
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SESSION_END frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+ Abort - Boolean set to TRUE if the connection is abnormally terminating.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Session End", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSessionEnd: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SE);
+ NbfDereferenceConnection("Couldn't get SE packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+ //
+ // The following statements instruct the packet destructor to run
+ // down this connection when the packet is acknowleged.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_END;
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructSessionEnd (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ (USHORT)(Abort ? // reason for termination.
+ SESSION_END_REASON_ABEND :
+ SESSION_END_REASON_HANGUP),
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+ // Note that we force an ack for this packet, as we want to make sure we
+ // run down the connection and link correctly.
+ //
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, TRUE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendSessionEnd */
+
+
+VOID
+NbfSendNoReceive(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a NO_RECEIVE frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send No Receive", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendNoReceive: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfDereferenceConnection("Couldn't get NR packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructNoReceive (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ (USHORT)0, // options
+ MessageBytesToAck, // number of bytes accepted.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendNoReceive */
+
+
+VOID
+NbfSendReceiveContinue(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RECEIVE_CONTINUE frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send Receive Continue", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendReceiveContinue: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RC);
+ NbfDereferenceConnection("Couldn't get RC packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+ //
+ // Save this variable now since it is what we are implicitly ack'ing.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructReceiveContinue (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from DFM
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendReceiveContinue */
+
+
+VOID
+NbfSendReceiveOutstanding(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RECEIVE_OUTSTANDING frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ USHORT MessageBytesToAck;
+
+ NbfReferenceConnection("send Receive Outstanding", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendReceiveOutstanding: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RO);
+ NbfDereferenceConnection("Couldn't get RO packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ MessageBytesToAck = (USHORT)
+ (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked);
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructReceiveOutstanding (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ MessageBytesToAck, // number of bytes accepted.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status != STATUS_LINK_FAILED) {
+ ExInterlockedAddUlong(
+ &Connection->MessageBytesAcked,
+ MessageBytesToAck,
+ Connection->LinkSpinLock);
+ } else {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendReceiveOutstanding */
+
+
+VOID
+NbfSendDataAck(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DATA_ACK frame on the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET Packet;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+
+ NbfReferenceConnection("send Data Ack", Connection, CREF_FRAME_SEND);
+
+ DeviceContext = Connection->Provider;
+ Link = Connection->Link;
+ Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet);
+
+ if (!NT_SUCCESS (Status)) { // if we couldn't make frame.
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDataAck: NbfCreatePacket failed.\n");
+ }
+#endif
+ NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_DA);
+ NbfDereferenceConnection("Couldn't get DA packet", Connection, CREF_FRAME_SEND);
+ return;
+ }
+
+
+ //
+ // Initialize the Netbios header.
+ //
+
+ ConstructDataAck (
+ (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]),
+ Connection->NetbiosHeader.TransmitCorrelator, // correlator from DATA_ONLY_LAST.
+ Connection->Lsn, // our local session number.
+ Connection->Rsn); // his session number (our RSN).
+
+ //
+ // Now send the packet on the connection via the link. If there are
+ // conditions on the link which make it impossible to send the packet,
+ // then the packet will be queued to the WackQ, and then timeouts will
+ // restart the link. This is acceptable when the traffic level is so
+ // high that we encounter this condition. Note that Data Ack will be
+ // seeing this condition frequently when send windows close after large
+ // sends.
+ //
+
+ //
+ // Set this so NbfDestroyPacket will dereference the connection.
+ //
+
+ Packet->Owner = Connection;
+ Packet->Action = PACKET_ACTION_CONNECTION;
+
+ Packet->NdisIFrameLength =
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Packet->NdisIFrameLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget.
+
+ if (Status == STATUS_LINK_FAILED) {
+ NbfDereferencePacket (Packet); // destroy the packet.
+ }
+
+ return;
+} /* NbfSendDataAck */
+
+
+VOID
+NbfSendDm(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DM-r/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC
+ LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC DM-r/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_DM | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDm: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendDm */
+
+
+VOID
+NbfSendUa(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a UA-r/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC
+ LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+ OldIrql - The IRQL at which Link->SpinLock was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // U-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ // Format LLC UA-r/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_UA | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendUa: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendUa */
+
+
+VOID
+NbfSendSabme(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a SABME-c/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ PTP_PACKET RawFrame, packet;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC SABME-c/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_SABME | (PollFinal ? DLC_U_PF : 0));
+
+ //
+ // Set up so that T1 will be started when the send
+ // completes.
+ //
+
+ if (PollFinal) {
+ if (Link->Provider->MacInfo.MediumAsync) {
+ RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME);
+ RawFrame->Link = Link;
+ NbfReferenceLink ("Sabme/p", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ }
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ //
+ // Reset the link state based on having sent this packet..
+ // Note that a SABME can be sent under some conditions on an existing
+ // link. If it is, it means we want to reset this link to a known state.
+ // We'll do that; note that that involves ditching any packets outstanding
+ // on the link.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->NextSend = 0;
+ Link->LastAckReceived = 0;
+ Link->NextReceive = 0; // expect next packet to be sequence 0
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ } else {
+ if (PollFinal) {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendSabme: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendSabme */
+
+
+VOID
+NbfSendDisc(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DISC-c/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_U_FRAME DlcHeader; // S-format frame alias.
+ KIRQL oldirql;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME));
+
+ //
+ // Format LLC DISC-c/x header.
+ //
+
+ DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Command = (UCHAR)(DLC_CMD_DISC | (PollFinal ? DLC_U_PF : 0));
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // This releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendDisc: packet not sent.\n");
+ }
+#endif
+ }
+
+ KeLowerIrql (oldirql);
+
+} /* NbfSendDisc */
+
+
+VOID
+NbfSendRr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RR-x/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released. THIS ROUTINE MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+
+ Status = NbfCreateRrPacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+
+ //
+ // RawFrame->Action will be set to PACKET_ACTION_RR if
+ // NbfCreateRrPacket got a packet from the RrPacketPool
+ // and PACKET_ACTION_NULL if it got one from the regular
+ // pool.
+ //
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC RR-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_RR;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ //
+ // If this is a command frame (which will always be a
+ // poll with the current code) set up so that T1 will
+ // be started when the send completes.
+ //
+
+ if (Command) {
+ if (Link->Provider->MacInfo.MediumAsync) {
+ RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME);
+ RawFrame->Link = Link;
+ NbfReferenceLink ("Rr/p", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ }
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spinlock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ if (Command) {
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME));
+ }
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRr: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendRr */
+
+#if 0
+
+//
+// These functions are not currently called, so they are commented
+// out.
+//
+
+
+VOID
+NbfSendRnr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a RNR-x/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+ KIRQL oldirql;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC RR-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_RNR;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRnr: packet not sent.\n");
+ }
+#endif
+ }
+ KeLowerIrql (oldirql);
+} /* NbfSendRnr */
+
+
+VOID
+NbfSendTest(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PMDL Psdu
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a TEST-x/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+ Psdu - Pointer to an MDL chain describing received TEST-c frame's storage.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, Command, PollFinal, Psdu; // prevent compiler warnings
+
+ PANIC ("NbfSendTest: Entered (BUGBUG).\n");
+} /* NbfSendTest */
+
+
+VOID
+NbfSendFrmr(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a FRMR-r/x DLC frame on the specified link.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, PollFinal; // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendFrmr: Entered (BUGBUG).\n");
+ }
+} /* NbfSendFrmr */
+
+#endif
+
+
+VOID
+NbfSendXid(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an XID-x/x DLC frame on the specified link.
+
+ NOTE: This routine is called with the link spinlock held,
+ and returns with it released.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ Link, Command, PollFinal; // prevent compiler warnings
+
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+ PANIC ("NbfSendXid: Entered (BUGBUG).\n");
+} /* NbfSendXid */
+
+
+VOID
+NbfSendRej(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a REJ-x/x DLC frame on the specified link.
+
+ NOTE: This function is called with Link->SpinLock held and
+ returns with it released. THIS MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ Command - TRUE if command bit should be set.
+
+ PollFinal - TRUE if poll/final bit should be set.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_PACKET RawFrame;
+ PDLC_S_FRAME DlcHeader; // S-format frame alias.
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendRej: Entered.\n");
+ }
+
+ Status = NbfCreatePacket (Link->Provider, Link, &RawFrame);
+ if (NT_SUCCESS (Status)) {
+
+ RawFrame->Owner = NULL;
+ RawFrame->Action = PACKET_ACTION_NULL;
+
+ //
+ // set the packet length correctly (Note that the NDIS_BUFFER
+ // gets returned to the proper length in NbfDestroyPacket)
+ //
+
+ MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME));
+ NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME));
+
+ //
+ // Format LLC REJ-x/x header.
+ //
+
+ DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]);
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE));
+ DlcHeader->Command = DLC_CMD_REJ;
+ DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0);
+
+ //
+ // This puts Link->NextReceive into DlcHeader->RcvSeq
+ // and releases the spin lock.
+ //
+
+ SendControlPacket (Link, RawFrame);
+
+ } else {
+ RELEASE_DPC_SPIN_LOCK(&Link->SpinLock);
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfSendRej: packet not sent.\n");
+ }
+#endif
+ }
+} /* NbfSendRej */
+
+
+NTSTATUS
+NbfCreateConnectionlessFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME *RawFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a connectionless frame (either from the local
+ device context pool or out of non-paged pool).
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the frame to.
+
+ RawFrame - Pointer to a place where we will return a pointer to the
+ allocated frame.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_UI_FRAME UIFrame;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfCreateConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Make sure that structure padding hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTIONLESS) == 44);
+
+ p = ExInterlockedRemoveHeadList (
+ &DeviceContext->UIFramePool,
+ &DeviceContext->Interlock);
+
+ if (p == NULL) {
+#if DBG
+ if (NbfPacketPanic) {
+ PANIC ("NbfCreateConnectionlessFrame: PANIC! no more UI frames in pool!\n");
+ }
+#endif
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->UIFrameExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ UIFrame = (PTP_UI_FRAME) CONTAINING_RECORD (p, TP_UI_FRAME, Linkage);
+
+ *RawFrame = UIFrame;
+
+ return STATUS_SUCCESS;
+} /* NbfCreateConnectionlessFrame */
+
+
+VOID
+NbfDestroyConnectionlessFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME RawFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a connectionless frame by either returning it
+ to the device context's pool or to the system's non-paged pool.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to return the frame to.
+
+ RawFrame - Pointer to a frame to be returned.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &HeaderBuffer);
+
+ // data buffers get thrown away
+
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer);
+ }
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+
+ //
+ // If this UI frame has some transport-created data,
+ // free the buffer now.
+ //
+
+ if (RawFrame->DataBuffer) {
+ ExFreePool (RawFrame->DataBuffer);
+ RawFrame->DataBuffer = NULL;
+ }
+
+ NdisChainBufferAtFront (RawFrame->NdisPacket, HeaderBuffer);
+
+ ExInterlockedInsertTailList (
+ &DeviceContext->UIFramePool,
+ &RawFrame->Linkage,
+ &DeviceContext->Interlock);
+
+} /* NbfDestroyConnectionlessFrame */
+
+
+VOID
+NbfSendUIFrame(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_UI_FRAME RawFrame,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connectionless frame by calling the physical
+ provider's Send service. When the request completes, or if the service
+ does not return successfully, then the frame is deallocated.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ RawFrame - Pointer to a connectionless frame to be sent.
+
+ Loopback - A boolean flag set to TRUE if the source hardware address
+ of the packet should be set to zeros.
+
+ SourceRoutingInformation - Pointer to optional source routing information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PUCHAR DestinationAddress;
+
+ UNREFERENCED_PARAMETER(Loopback);
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint2 ("NbfSendUIFrame: Entered, RawFrame: %lx NdisPacket %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ DbgPrint ("NbfSendUIFrame: MacHeader: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x \n",
+ RawFrame->Header[0],
+ RawFrame->Header[1],
+ RawFrame->Header[2],
+ RawFrame->Header[3],
+ RawFrame->Header[4],
+ RawFrame->Header[5],
+ RawFrame->Header[6],
+ RawFrame->Header[7],
+ RawFrame->Header[8],
+ RawFrame->Header[9],
+ RawFrame->Header[10],
+ RawFrame->Header[11],
+ RawFrame->Header[12],
+ RawFrame->Header[13]);
+ }
+#endif
+
+ //
+ // Send the packet.
+ //
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ //
+ // Loopback will be FALSE for multicast frames or other
+ // frames that we know are not directly addressed to
+ // our hardware address.
+ //
+
+ if (Loopback) {
+
+ //
+ // See if this frame should be looped back.
+ //
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ &DestinationAddress);
+
+ if (RtlEqualMemory(
+ DestinationAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ NbfInsertInLoopbackQueue(
+ DeviceContext,
+ RawFrame->NdisPacket,
+ LOOPBACK_UI_FRAME
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ goto NoNdisSend;
+
+ }
+
+ }
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ NdisSend (
+ &NdisStatus,
+ (NDIS_HANDLE)DeviceContext->NdisBindingHandle,
+ RawFrame->NdisPacket);
+
+NoNdisSend:
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+#if DBG
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ NbfSendsCompletedOk++;
+ } else {
+ NbfSendsCompletedFail++;
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint1 ("NbfSendUIFrame: NdisSend failed, status other Pending or Complete: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+ }
+#endif
+
+ NbfDestroyConnectionlessFrame (DeviceContext, RawFrame);
+
+ } else {
+
+#if DBG
+ NbfSendsPended++;
+#endif
+ }
+
+} /* NbfSendUIFrame */
+
+
+VOID
+NbfSendUIMdlFrame(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connectionless frame by calling the NbfSendUIFrame.
+ It is intended that this routine be used for sending datagrams and
+ braodcast datagrams.
+
+ The datagram to be sent is described in the NDIS packet contained
+ in the Address. When the send completes, the send completion handler
+ returns the NDIS buffer describing the datagram to the buffer pool and
+ marks the address ndis packet as usable again. Thus, all datagram and
+ UI frames are sequenced through the address they are sent on.
+
+Arguments:
+
+ Address - pointer to the address from which to send this datagram.
+
+ SourceRoutingInformation - Pointer to optional source routing information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+// NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR DestinationAddress;
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendUIMdlFrame: Entered.\n");
+ }
+
+
+ //
+ // Send the packet.
+ //
+
+ DeviceContext = Address->Provider;
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ Address->UIFrame->Header,
+ &DestinationAddress);
+
+ if (RtlEqualMemory(
+ DestinationAddress,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ DeviceContext,
+ Address->UIFrame->NdisPacket,
+ LOOPBACK_UI_FRAME
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ (NDIS_HANDLE)Address->Provider->NdisBindingHandle,
+ Address->UIFrame->NdisPacket);
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbfSendDatagramCompletion (Address, Address->UIFrame->NdisPacket, NdisStatus);
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) { // This is an error, trickle it up
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint1 ("NbfSendUIMdlFrame: NdisSend failed, status other Pending or Complete: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+ }
+#endif
+ }
+
+} /* NbfSendUIMdlFrame */
+
+
+VOID
+NbfSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called as an I/O completion handler at the time a
+ NbfSendUIMdlFrame send request is completed. Because this handler is only
+ associated with NbfSendUIMdlFrame, and because NbfSendUIMdlFrame is only
+ used with datagrams and broadcast datagrams, we know that the I/O being
+ completed is a datagram. Here we complete the in-progress datagram, and
+ start-up the next one if there is one.
+
+Arguments:
+
+ Address - Pointer to a transport address on which the datagram
+ is queued.
+
+ NdisPacket - pointer to the NDIS packet describing this request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ PNDIS_BUFFER HeaderBuffer;
+
+ NdisPacket; // prevent compiler warnings.
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfSendDatagramCompletion: Entered.\n");
+ }
+
+
+ //
+ // Dequeue the current request and return it to the client. Release
+ // our hold on the send datagram queue.
+ //
+ // *** There may be no current request, if the one that was queued
+ // was aborted or timed out. If this is the case, we added a
+ // special reference to the address, so we still want to deref
+ // when we are done (I don't think this is true - adb 3/22/93).
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ p = RemoveHeadList (&Address->SendDatagramQueue);
+
+ if (p != &Address->SendDatagramQueue) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IF_NBFDBG (NBF_DEBUG_FRAMESND) {
+ NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n");
+ }
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Address->UIFrame->NdisPacket, &HeaderBuffer);
+
+ // drop the rest of the packet
+
+ NdisReinitializePacket (Address->UIFrame->NdisPacket);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Address->UIFrame->NdisPacket, HeaderBuffer);
+
+ //
+ // Ignore NdisStatus; datagrams always "succeed". The Information
+ // field was filled in when we queued the datagram.
+ //
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Send more datagrams on the Address if possible.
+ //
+
+ NbfSendDatagramsOnAddress (Address); // do more datagrams.
+
+ } else {
+
+ ASSERT (FALSE);
+
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ }
+
+ NbfDereferenceAddress ("Complete datagram", Address, AREF_REQUEST);
+
+} /* NbfSendDatagramCompletion */
diff --git a/private/ntos/tdi/nbf/iframes.c b/private/ntos/tdi/nbf/iframes.c
new file mode 100644
index 000000000..d14eeb505
--- /dev/null
+++ b/private/ntos/tdi/nbf/iframes.c
@@ -0,0 +1,3339 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ iframes.c
+
+Abstract:
+
+ This module contains routines called to handle i-frames received
+ from the data link provider. Most of these routines are called at receive
+ indication time.
+
+ Also included here are routines that process data at receive completion
+ time. These are limited to handling DFM/DOL frames.
+
+ The following frame types are cracked by routines in this module:
+
+ o NBF_CMD_DATA_ACK
+ o NBF_CMD_DATA_FIRST_MIDDLE
+ o NBF_CMD_DATA_ONLY_LAST
+ o NBF_CMD_SESSION_CONFIRM
+ o NBF_CMD_SESSION_END
+ o NBF_CMD_SESSION_INITIALIZE
+ o NBF_CMD_NO_RECEIVE
+ o NBF_CMD_RECEIVE_OUTSTANDING
+ o NBF_CMD_RECEIVE_CONTINUE
+ o NBF_CMD_SESSION_ALIVE
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+extern ULONG StartTimerDelayedAck;
+
+#define NbfUsePiggybackAcks 1
+#if DBG
+extern ULONG NbfDebugPiggybackAcks;
+#endif
+
+
+VOID
+NbfAcknowledgeDataOnlyLast(
+ IN PTP_CONNECTION Connection,
+ IN ULONG MessageLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes care of acknowledging a DOL which has
+ been received. It either sends a DATA_ACK right away, or
+ queues a request for a piggyback ack.
+
+ NOTE: This routine is called with the connection spinlock
+ held, and it returns with it released. IT MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ MessageLength - the total length (including all DFMs and this
+ DOL) of the message.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+
+ //
+ // Determine if we need to ack at all.
+ //
+
+ if (Connection->CurrentReceiveNoAck) {
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return;
+ }
+
+
+ //
+ // Determine if a piggyback ack is feasible.
+ //
+ if (NbfUsePiggybackAcks &&
+ Connection->CurrentReceiveAckQueueable) {
+
+ //
+ // The sender allows it, see if we want to.
+ //
+
+#if 0
+ //
+ // First reset this variable, to be safe.
+ //
+
+ Connection->CurrentReceiveAckQueueable = FALSE;
+#endif
+
+ //
+ // For long sends, don't bother since these
+ // often happen without back traffic.
+ //
+
+ if (MessageLength >= 8192L) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("M");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // If there have been two receives in a row with
+ // no sends in between, don't wait for back traffic.
+ //
+
+ if (Connection->ConsecutiveReceives >= 2) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("R");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // Do not put a stopping connection on the DataAckQueue
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("S");
+ }
+#endif
+ goto NormalDataAck;
+ }
+
+ //
+ // Queue the piggyback ack request. If the timer expires
+ // before a DFM or DOL is sent, a normal DATA ACK will
+ // be sent.
+ //
+ // Connection->Header.TransmitCorrelator has already been filled in.
+ //
+
+ //
+ // BAD! We shouldn't already have an ack queued.
+ //
+
+ ASSERT ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) == 0);
+
+ KeQueryTickCount (&Connection->ConnectStartTime);
+ Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_ACK;
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("Q");
+ }
+#endif
+
+ DeviceContext = Connection->Link->Provider;
+
+ if (!Connection->OnDataAckQueue) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&DeviceContext->DataAckQueue, &Connection->DataAckLinkage);
+
+ if (!(DeviceContext->a.i.DataAckQueueActive)) {
+
+ StartTimerDelayedAck++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.DataAckQueueActive = TRUE;
+
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (DeviceContext, PiggybackAckQueued);
+
+ return;
+
+ }
+
+NormalDataAck:;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendDataAck (Connection);
+
+} /* NbfAcknowledgeDataOnlyLast */
+
+
+NTSTATUS
+ProcessSessionConfirm(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_CONFIRM NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ USHORT HisMaxDataSize;
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ ULONG returnLength;
+ TA_NETBIOS_ADDRESS TempAddress;
+// BOOLEAN TimerWasSet;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint1 ("ProcessSessionConfirm: Entered, Flags: %lx\n", Connection->Flags);
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SC) != 0) {
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SC;
+
+ //
+ // Get his capability bits and maximum frame size.
+ //
+
+ if (IFrame->Data1 & SESSION_CONFIRM_OPTIONS_20) {
+ Connection->Flags |= CONNECTION_FLAGS_VERSION2;
+ }
+
+ if (Connection->Link->Loopback) {
+ Connection->MaximumDataSize = 0x8000;
+ } else {
+ Connection->MaximumDataSize = (USHORT)
+ (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
+
+ HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ if (HisMaxDataSize < Connection->MaximumDataSize) {
+ Connection->MaximumDataSize = HisMaxDataSize;
+ }
+ }
+
+ //
+ // Build a standard Netbios header for speed when sending
+ // data frames.
+ //
+
+ ConstructDataOnlyLast(
+ &Connection->NetbiosHeader,
+ FALSE,
+ (USHORT)0,
+ Connection->Lsn,
+ Connection->Rsn);
+
+ //
+ // Turn off the connection request timer if there is one, and set
+ // this connection's state to READY.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ //
+ // Record that the connect request has been successfully
+ // completed by TpCompleteRequest.
+ //
+
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ Connection->IndicationInProgress = FALSE;
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Complete the TdiConnect request.
+ //
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ //
+ // Now complete the request and get out.
+ //
+
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // We have a completed connection with a queued connect. Complete
+ // the connect.
+ //
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(request->IoRequestPacket, 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;
+
+ }
+
+ if (status == STATUS_SUCCESS) {
+
+ if ((ULONG)Connection->Retries == Connection->Provider->NameQueryRetries) {
+
+ INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterNoRetry);
+
+ } else {
+
+ INCREMENT_COUNTER (Connection->Provider, ConnectionsAfterRetry);
+
+ }
+
+ }
+
+ //
+ // Don't clear this until now, so that the connection is all
+ // set up before we allow more indications.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ NbfCompleteRequest (request, status, returnLength);
+
+ } else {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionConfirm */
+
+
+NTSTATUS
+ProcessSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_END NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT data2;
+ NTSTATUS StopStatus;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessSessionEnd: Entered.\n");
+ }
+
+ //
+ // Handle the error code in the Data2 field. Current protocol says
+ // if the field is 0, then this is a normal HANGUP.NCB operation.
+ // If the field is 1, then this is an abnormal session end, caused
+ // by something like a SEND.NCB timing out. Of course, new protocol
+ // may be added in the future, so we handle only these specific cases.
+ //
+
+ data2 = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ switch (data2) {
+ case 0:
+ case 1:
+ StopStatus = STATUS_REMOTE_DISCONNECT;
+ break;
+
+ default:
+ PANIC ("ProcessSessionEnd: frame not expected.\n");
+ StopStatus = STATUS_INVALID_NETWORK_RESPONSE;
+ }
+#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;
+ NbfPrint3( "SessionEnd received for connection to %S from %S; reason %s\n",
+ &remoteName, &localName,
+ data2 == 0 ? "NORMAL" : data2 == 1 ? "ABORT" : "UNKNOWN" );
+ }
+#endif
+
+ //
+ // Run-down this connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ProcessSessionEnd calling NbfStopConnection\n");
+ }
+ NbfStopConnection (Connection, StopStatus); // disconnected by the other end
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionEnd */
+
+
+NTSTATUS
+ProcessSessionInitialize(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_INITIALIZE NetBIOS frame.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL cancelirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PIO_STACK_LOCATION irpSp;
+ USHORT HisMaxDataSize;
+ ULONG returnLength;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ NTSTATUS status;
+ TA_NETBIOS_ADDRESS TempAddress;
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint1 ("ProcessSessionInitialize: Entered, Flags: %lx\n", Connection->Flags);
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_SI;
+
+ //
+ // Get his capability bits and maximum frame size.
+ //
+
+ if (IFrame->Data1 & SESSION_INIT_OPTIONS_20) {
+ Connection->Flags |= CONNECTION_FLAGS_VERSION2;
+ }
+
+ if (Connection->Link->Loopback) {
+ Connection->MaximumDataSize = 0x8000;
+ } else {
+ Connection->MaximumDataSize = (USHORT)
+ (Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME));
+
+ HisMaxDataSize = (USHORT)(IFrame->Data2Low + IFrame->Data2High*256);
+ if (HisMaxDataSize < Connection->MaximumDataSize) {
+ Connection->MaximumDataSize = HisMaxDataSize;
+ }
+ }
+
+ //
+ // Build a standard Netbios header for speed when sending
+ // data frames.
+ //
+
+ ConstructDataOnlyLast(
+ &Connection->NetbiosHeader,
+ FALSE,
+ (USHORT)0,
+ Connection->Lsn,
+ Connection->Rsn);
+
+ //
+ // Save his session initialize correlator so we can send it
+ // in the session confirm frame.
+ //
+
+ Connection->NetbiosHeader.TransmitCorrelator = RESPONSE_CORR(IFrame);
+
+ //
+ // Turn off the connection request timer if there is one (we're done).
+ // Do this with the lock held in case the connection is about to
+ // be closed, to not interfere with the timer started when the
+ // connection started then.
+ //
+
+ if (KeCancelTimer (&Connection->Timer)) {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("Timer canceled", Connection, CREF_TIMER); // remove timer reference.
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // Now, complete the listen request on the connection (if there was
+ // one) and continue with as much of the protocol request as possible.
+ // if the user has "pre-accepted" the connection, we'll just continue
+ // onward here and complete the entire connection setup. If the user
+ // was indicated and has not yet accepted, we'll just put the
+ // connection into the proper state and fall out the bottom without
+ // completing anything.
+ //
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (((Connection->Flags2 & CONNECTION_FLAGS2_ACCEPTED) != 0) ||
+ ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) != 0)) {
+
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("SessionInitialize: Accepted connection %lx\n", Connection);
+ }
+ //
+ // we've already accepted the connection; allow it to proceed.
+ // this is the normal path for kernel mode indication clients,
+ // or for those who don't specify TDI_QUERY_ACCEPT on the listen.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ //
+ // Record that the listen request has been successfully
+ // completed by NbfCompleteRequest.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ status = STATUS_SUCCESS;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfSendSessionConfirm (Connection);
+
+ } else {
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+ //
+ // we disconnected, destroy the connection
+ //
+ IF_NBFDBG (NBF_DEBUG_SETUP) {
+ NbfPrint1("SessionInitialize: Disconnected connection %lx\n", Connection);
+ }
+
+ status = STATUS_LOCAL_DISCONNECT;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+
+ } else {
+
+ //
+ // we've done nothing, wait for the user to accept on this
+ // connection. This is the "normal" path for non-indication
+ // clients.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAITING_SC;
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // Now, if there was no queued listen, we have done everything we can
+ // for this connection, so we simply exit and leave everything up to
+ // the user. If we've gotten an indication response that allows the
+ // connection to proceed, we will come out of here with a connection
+ // that's up and running.
+ //
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // 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_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(request->IoRequestPacket, 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;
+
+ NbfCompleteRequest (request, status, 0);
+
+ } else {
+
+ Connection->IndicationInProgress = FALSE;
+#if DBG
+ NbfPrint3 ("ProcessSessionInitialize: C %lx, Flags %lx, Flags2 %lx\n",
+ Connection, Connection->Flags, Connection->Flags2);
+#endif
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ }
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionInitialize */
+
+
+NTSTATUS
+ProcessNoReceive(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming NO_RECEIVE NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessNoReceive: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+// Connection->SendState = CONNECTION_SENDSTATE_W_RCVCONT;
+//
+// this used to be here, and is right for the other side of the connection. It's
+// wrong here.
+// Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ break;
+
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessNoReceive: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessNoReceive: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return STATUS_SUCCESS;
+} /* ProcessNoReceive */
+
+
+NTSTATUS
+ProcessReceiveOutstanding(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming RECEIVE_OUTSTANDING NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessReceiveOutstanding: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, IFrame->Data2Low + IFrame->Data2High*256);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) != 0) {
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ }
+ break;
+
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessReceiveOutstanding: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessReceiveOutstanding: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Now start packetizing the connection again since we've reframed
+ // the current send. If we were idle or in a bad state, then the
+ // packetizing routine will detect that.
+ //
+ // *** StartPacketizingConnection releases the Connection spin lock.
+ //
+
+ StartPacketizingConnection (Connection, FALSE);
+ return STATUS_SUCCESS;
+} /* ProcessReceiveOutstanding */
+
+
+NTSTATUS
+ProcessReceiveContinue(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming RECEIVE_CONTINUE NetBIOS frame.
+
+ NOTE: This routine is called with the connection spinlock
+ held and returns with it released.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessReceiveContinue: Entered.\n");
+ }
+
+ switch (Connection->SendState) {
+ case CONNECTION_SENDSTATE_W_PACKET: // waiting for free packet.
+ case CONNECTION_SENDSTATE_PACKETIZE: // send being packetized.
+ case CONNECTION_SENDSTATE_W_LINK: // waiting for good link conditions.
+ case CONNECTION_SENDSTATE_W_EOR: // waiting for TdiSend(EOR).
+ case CONNECTION_SENDSTATE_W_ACK: // waiting for DATA_ACK.
+ case CONNECTION_SENDSTATE_W_RCVCONT: // waiting for RECEIVE_CONTINUE.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ReframeSend (Connection, Connection->sp.MessageBytesSent);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ break;
+
+ case CONNECTION_SENDSTATE_IDLE: // no sends being processed.
+ PANIC ("ProcessReceiveContinue: Frame not expected.\n");
+ break;
+
+ default:
+ PANIC ("ProcessReceiveContinue: Invalid SendState.\n");
+ }
+
+ //
+ // Don't clear this until ReframeSend has been called
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Now start packetizing the connection again since we've reframed
+ // the current send. If we were idle or in a bad state, then the
+ // packetizing routine will detect that.
+ //
+ // *** StartPacketizingConnection releases the Connection spin lock.
+ //
+
+ StartPacketizingConnection (Connection, FALSE);
+ return STATUS_SUCCESS;
+} /* ProcessReceiveContinue */
+
+
+NTSTATUS
+ProcessSessionAlive(
+ IN PTP_CONNECTION Connection,
+ IN PNBF_HDR_CONNECTION IFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles an incoming SESSION_ALIVE NetBIOS frame. This
+ routine is by far the simplest in the transport because it does nothing.
+ The SESSION_ALIVE frame is simply a dummy frame that is sent on the
+ reliable data link layer to determine if the data link is still active;
+ no NetBIOS level protocol processing is performed.
+
+Arguments:
+
+ Connection - Pointer to a transport connection (TP_CONNECTION).
+
+ IFrame - Pointer to NetBIOS connection-oriented header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Connection); // prevent compiler warnings
+ UNREFERENCED_PARAMETER (IFrame); // prevent compiler warnings
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("ProcessSessionAlive: Entered.\n");
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+} /* ProcessSessionAlive */
+
+
+VOID
+NbfProcessIIndicate(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN UINT DlcTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a received I frame at indication time. It will do
+ all necessary verification processing of the frame and pass those frames
+ that are valid on to the proper handling routines.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Command - Boolean set to TRUE if command, else FALSE if response.
+
+ PollFinal - Boolean set to TRUE if Poll or Final.
+
+ Link - Pointer to a transport link object.
+
+ Header - Pointer to a DLC I-type frame.
+
+ DlcHeader - A pointer to the start of the DLC header in the packet.
+
+ DlcIndicatedLength - The length of the packet indicated, starting at
+ DlcHeader.
+
+ DlcTotalLength - The total length of the packet, starting at DlcHeader.
+
+ ReceiveContext - A magic value for NDIS that indicates which packet we're
+ talking about.
+
+ Loopback - Is this a loopback indication; used to determine whether
+ to call NdisTransferData or NbfTransferLoopbackData.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#if DBG
+ UCHAR *s;
+#endif
+ PNBF_HDR_CONNECTION nbfHeader;
+ PDLC_I_FRAME header;
+ NTSTATUS Status;
+ UCHAR lsn, rsn;
+ PTP_CONNECTION connection;
+ PUCHAR DataHeader;
+ ULONG DataTotalLength;
+ PLIST_ENTRY p;
+ BOOLEAN ConnectionFound;
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessIIndicate: Entered.\n");
+ }
+
+ //
+ // Process any of: I-x/x.
+ //
+
+ header = (PDLC_I_FRAME)DlcHeader;
+ nbfHeader = (PNBF_HDR_CONNECTION)((PUCHAR)header + 4); // skip DLC hdr.
+
+ //
+ // Verify signatures. We test the signature as a 16-bit
+ // word as specified in the NetBIOS Formats and Protocols manual,
+ // with the assert guarding us against big-endian systems.
+ //
+
+ ASSERT ((((PUCHAR)(&nbfHeader->Length))[0] + ((PUCHAR)(&nbfHeader->Length))[1]*256) ==
+ HEADER_LENGTH(nbfHeader));
+
+ if (HEADER_LENGTH(nbfHeader) != sizeof(NBF_HDR_CONNECTION)) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Too short or long.\n");
+ }
+ return; // frame too small or too large.
+ }
+
+ if (HEADER_SIGNATURE(nbfHeader) != NETBIOS_SIGNATURE) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 ("NbfProcessIIndicate: Dropped I frame, Signature bad.\n");
+ }
+ return; // invalid signature in frame.
+ }
+
+ DataHeader = (PUCHAR)DlcHeader + (4 + sizeof(NBF_HDR_CONNECTION));
+ DataTotalLength = DlcTotalLength - (4 + sizeof(NBF_HDR_CONNECTION));
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); // keep state stable
+
+ switch (Link->State) {
+
+ case LINK_STATE_READY:
+
+ //
+ // Link is balanced. This code is extremely critical since
+ // it is the most-covered path in the system for small and
+ // large I/O. Be very careful in adding code here as it will
+ // seriously affect the overall performance of the LAN. It is
+ // first in the list of possible states for that reason.
+ //
+
+#if DBG
+ s = "READY";
+#endif
+ Link->LinkBusy = FALSE;
+
+ //
+ // The I-frame's N(S) should match our V(R). If it
+ // doesn't, issue a reject. Otherwise, increment our V(R).
+ //
+
+ if ((UCHAR)((header->SendSeq >> 1) & 0x7F) != Link->NextReceive) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessIIndicate: N(S) != V(R).\n");
+ }
+
+ if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
+
+
+ //
+ // We already sent a reject, only respond if
+ // he is polling.
+ //
+
+ if (Command & PollFinal) {
+ NbfSendRr(Link, FALSE, TRUE); // releases lock
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ } else {
+
+ Link->ReceiveState = RECEIVE_STATE_REJECTING;
+
+ //
+ // NbfSendRej releases the spinlock.
+ //
+
+ if (Command) {
+ NbfSendRej (Link, FALSE, PollFinal);
+ } else {
+ NbfSendRej (Link, FALSE, FALSE);
+ }
+ }
+
+ //
+ // Update our "bytes rejected" counters.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Link->Provider->Statistics.DataFrameBytesRejected,
+ DataTotalLength);
+ ++Link->Provider->Statistics.DataFramesRejected;
+
+ //
+ // Discard this packet.
+ //
+
+ break;
+
+ }
+
+
+ //
+ // Find the transport connection object associated with this frame.
+ // Because there may be several NetBIOS (transport) connections
+ // over the same data link connection, and the ConnectionContext
+ // value represents a data link connection to a specific address,
+ // we simply use the RSN field in the frame to index into the
+ // connection database for this link object.
+ //
+ // We do this before processing the rest of the LLC header,
+ // in case the connection is busy and we have to ignore
+ // the frame.
+ //
+
+ ConnectionFound = FALSE;
+
+ lsn = nbfHeader->DestinationSessionNumber;
+ rsn = nbfHeader->SourceSessionNumber;
+
+ if ((lsn == 0) || (lsn > NETBIOS_SESSION_LIMIT)) {
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Invalid LSN.\n");
+ }
+
+ } else {
+
+ p = Link->ConnectionDatabase.Flink;
+ while (p != &Link->ConnectionDatabase) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (connection->Lsn >= lsn) { // assumes ordered list
+ break;
+ }
+ p = p->Flink;
+ }
+
+ // Don't use compound if 'cause Connection may be garbage
+
+ if (p == &Link->ConnectionDatabase) {
+#if DBG
+ NbfPrint2 ("NbfProcessIIndicate: Connection not found in database: \n Lsn %x Link %lx",
+ lsn, Link);
+ NbfPrint6 ("Remote: %x-%x-%x-%x-%x-%x\n",
+ Link->HardwareAddress.Address[0], Link->HardwareAddress.Address[1],
+ Link->HardwareAddress.Address[2], Link->HardwareAddress.Address[3],
+ Link->HardwareAddress.Address[4], Link->HardwareAddress.Address[5]);
+#endif
+ } else if (connection->Lsn != lsn) {
+#if DBG
+ NbfPrint0 ("NbfProcessIIndicate: Connection in database doesn't match.\n");
+#endif
+ } else if (connection->Rsn != rsn) {
+#if DBG
+ NbfPrint3 ("NbfProcessIIndicate: Connection lsn %d had rsn %d, got frame for %d\n",
+ connection->Lsn, connection->Rsn, rsn);
+#endif
+ } else {
+
+ //
+ // The connection is good, proceed.
+ //
+
+ ConnectionFound = TRUE;
+
+ if (connection->IndicationInProgress) {
+ NbfPrint1("ProcessIIndicate: Indication in progress on %lx\n", connection);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+ }
+
+ //
+ // Set this, it prevents other I-frames from being received
+ // on this connection. The various ProcessXXX routines
+ // that are called from the switch below will clear
+ // this flag when they determine it is OK to be reentered.
+ //
+
+ connection->IndicationInProgress = TRUE;
+
+
+ // This reference is removed before this function returns or
+ // we are done with the LINK_STATE_READY part of the outer switch.
+
+ NbfReferenceConnection ("Processing IFrame", connection, CREF_PROCESS_DATA);
+
+
+ }
+
+ }
+
+
+ //
+ // As long as we don't have to drop this frame, adjust the link
+ // state correctly. If ConnectionFound is FALSE, then we exit
+ // right after doing this.
+ //
+
+
+ //
+ // The I-frame we expected arrived, clear rejecting state.
+ //
+
+ if (Link->ReceiveState == RECEIVE_STATE_REJECTING) {
+ Link->ReceiveState = RECEIVE_STATE_READY;
+ }
+
+ Link->NextReceive = (UCHAR)((Link->NextReceive+1) & 0x7f);
+
+ //
+ // If he is checkpointing, we need to respond with RR-c/f. If
+ // we respond, then stop the delayed ack timer. Otherwise, we
+ // need to start it because this is an I-frame that will not be
+ // acked immediately.
+ //
+
+ if (Command && PollFinal) {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessI: he's checkpointing.\n");
+ }
+ Link->RemoteNoPoll = FALSE;
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, TRUE); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ if (Link->RemoteNoPoll) {
+
+ if ((++Link->ConsecutiveIFrames) == Link->Provider->MaxConsecutiveIFrames) {
+
+ //
+ // This appears to be one of those remotes which
+ // never polls, so we send an RR if there are two
+ // frames outstanding (StopT2 sets ConsecutiveIFrames
+ // to 0).
+ //
+
+ StopT2 (Link); // we're acking, so no delay req'd.
+ NbfSendRr (Link, FALSE, FALSE); // releases lock
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ } else {
+
+ StartT2 (Link);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
+ if (!Link->OnDeferredRrQueue) {
+ InsertTailList(
+ &Link->Provider->DeferredRrQueue,
+ &Link->DeferredRrLinkage);
+ Link->OnDeferredRrQueue = TRUE;
+ }
+ RELEASE_DPC_SPIN_LOCK (&Link->Provider->Interlock);
+
+ }
+
+ } else {
+
+ StartT2 (Link); // start delayed ack sequence.
+ }
+
+ //
+ // If he is responding to a checkpoint, we need to clear our
+ // send state. Any packets which are still waiting for acknowlegement
+ // at this point must now be resent.
+ //
+
+ if ((!Command) && PollFinal) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint0 (" NbfProcessI: he's responding to our checkpoint.\n");
+ }
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessI: BUGBUG: Ckpt but SendState=%ld.\n",
+ Link->SendState);
+ }
+ }
+ StopT1 (Link); // checkpoint completed.
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+ }
+
+ }
+
+ //
+ // Now, if we could not find the connection or the sequence
+ // numbers did not match, return. We don't call ResendLlcPackets
+ // in this case, but that is OK (eventually we will poll).
+ //
+
+ if (!ConnectionFound) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+ }
+
+ ASSERT (connection->LinkSpinLock == &Link->SpinLock);
+
+ //
+ // The N(R) in this frame may acknowlege some WackQ packets.
+ // We delay checking this until after processing the I-frame,
+ // so that we can get IndicationInProgress set to FALSE
+ // before we start resending the WackQ.
+ //
+
+ switch (nbfHeader->Command) {
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ case NBF_CMD_DATA_ONLY_LAST:
+
+ //
+ // First see if this packet has a piggyback ack -- we process
+ // this even if we throw the packet away below.
+ //
+ // This is a bit ugly since theoretically the piggyback
+ // ack bits in a DFM and a DOL could be different, but
+ // they aren't.
+ //
+ if (NbfUsePiggybackAcks) {
+ ASSERT (DFM_OPTIONS_ACK_INCLUDED == DOL_OPTIONS_ACK_INCLUDED);
+
+ if ((nbfHeader->Data1 & DFM_OPTIONS_ACK_INCLUDED) != 0) {
+
+ //
+ // This returns with the connection spinlock held
+ // but may release it and reacquire it.
+ //
+
+ CompleteSend(
+ connection,
+ TRANSMIT_CORR(nbfHeader));
+
+ }
+ }
+
+ //
+ // NOTE: The connection spinlock is held here.
+ //
+
+ //
+ // If the connection is not ready, drop the frame.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+ //
+ // A quick check for the three flags that are
+ // rarely set.
+ //
+
+ if ((connection->Flags & (CONNECTION_FLAGS_W_RESYNCH |
+ CONNECTION_FLAGS_RC_PENDING |
+ CONNECTION_FLAGS_RECEIVE_WAKEUP)) == 0) {
+ goto NoFlagsSet;
+ }
+
+ //
+ // If we are waiting for a resynch bit to be set in an
+ // incoming frame, toss the frame if it isn't set.
+ // Otherwise, clear the wait condition.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_W_RESYNCH) {
+ if ((nbfHeader->Data2Low == 1) && (nbfHeader->Data2High == 0)) {
+ connection->Flags &= ~CONNECTION_FLAGS_W_RESYNCH;
+ } else {
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, waiting for resynch.\n");
+ }
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+ }
+
+ //
+ // If we have a previous receive that is pending
+ // completion, then we need to ignore this frame.
+ // This may be common on MP, so rather than drop
+ // it and wait for a poll, we send a NO_RECEIVE,
+ // then a RCV_OUTSTANDING when we have some
+ // resources.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_RC_PENDING) {
+
+ //
+ // Hack the connection object so the NO_RECEIVE
+ // looks right.
+ //
+
+ connection->MessageBytesReceived = 0;
+ connection->MessageBytesAcked = 0;
+ connection->MessageInitAccepted = 0;
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ NbfSendNoReceive (connection);
+
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ //
+ // We now turn on the PEND_INDICATE flag to show
+ // that we need to send RCV_OUTSTANDING when the
+ // receive completes. If RC_PENDING is now off,
+ // it means the receive was just completed, so
+ // we ourselves need to send the RCV_OUTSTANDING.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_RC_PENDING) == 0) {
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ NbfSendReceiveOutstanding (connection);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ } else {
+
+ connection->Flags |= CONNECTION_FLAGS_PEND_INDICATE;
+
+ }
+
+ connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ NbfPrint0 ("NbfProcessIIndicate: Discarded DFM/DOL, receive complete pending.\n");
+ }
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+ //
+ // If we are discarding data received on this connection
+ // because we've sent a no receive, ditch it.
+ //
+
+ if (connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
+ connection->IndicationInProgress = FALSE;
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 ("NbfProcessIIndicate: In wakeup state, discarding frame.\n");
+ }
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ goto SkipProcessIndicateData;
+ }
+
+NoFlagsSet:;
+
+ //
+ // The connection spinlock is held here.
+ //
+
+ if (nbfHeader->Command == NBF_CMD_DATA_FIRST_MIDDLE) {
+
+ //
+ // NOTE: This release connection->LinkSpinLock.
+ //
+
+ Status = ProcessIndicateData (
+ connection,
+ DlcHeader,
+ DlcIndicatedLength,
+ DataHeader,
+ DataTotalLength,
+ ReceiveContext,
+ FALSE,
+ Loopback);
+
+ //
+ // If the receive-continue bit is set in this frame, then we must
+ // reply with a RECEIVE_CONTINUE frame saying that he can continue
+ // sending. This old protocol option allowed a sender to send a
+ // single frame over to see if there was a receive posted before
+ // sending the entire message and potentially dropping the entire
+ // message. Because the TDI is indication-based, we cannot know
+ // if there is NO receive available until we actually try perform
+ // the indication, so we simply say that there is one posted.
+ // (This will only happen on DFMs.)
+ //
+
+ if (nbfHeader->Data1 & 0x01) {
+
+ //
+ // Save this to use in RECEIVE_CONTINUE.
+ //
+
+ connection->NetbiosHeader.TransmitCorrelator =
+ RESPONSE_CORR(nbfHeader);
+
+ NbfSendReceiveContinue (connection);
+ }
+ } else {
+
+ //
+ // Keep track of how many consecutive receives we have had.
+ //
+
+ connection->ConsecutiveReceives++;
+ connection->ConsecutiveSends = 0;
+
+ //
+ // Save this information now, it will be needed
+ // when the ACK for this DOL is sent.
+ //
+
+ connection->CurrentReceiveAckQueueable =
+ (nbfHeader->Data1 & DOL_OPTIONS_ACK_W_DATA_ALLOWED);
+
+ connection->CurrentReceiveNoAck =
+ (nbfHeader->Data1 & DOL_OPTIONS_NO_ACK);
+
+ connection->NetbiosHeader.TransmitCorrelator =
+ RESPONSE_CORR(nbfHeader);
+
+ //
+ // NOTE: This release connection->LinkSpinLock.
+ //
+
+ Status = ProcessIndicateData (
+ connection,
+ DlcHeader,
+ DlcIndicatedLength,
+ DataHeader,
+ DataTotalLength,
+ ReceiveContext,
+ TRUE,
+ Loopback);
+ }
+
+ //
+ // Update our "bytes received" counters.
+ //
+
+ Link->Provider->TempIFrameBytesReceived += DataTotalLength;
+ ++Link->Provider->TempIFramesReceived;
+
+SkipProcessIndicateData:
+
+ break;
+
+ case NBF_CMD_DATA_ACK:
+
+ connection->IndicationInProgress = FALSE;
+
+ //
+ // This returns with the lock held.
+ //
+
+ CompleteSend(
+ connection,
+ TRANSMIT_CORR(nbfHeader));
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionConfirm (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_END:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionEnd (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionInitialize (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_NO_RECEIVE:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessNoReceive (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessReceiveOutstanding (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+
+ //
+ // This releases the connection spinlock.
+ //
+
+ Status = ProcessReceiveContinue (
+ connection,
+ nbfHeader);
+ break;
+
+ case NBF_CMD_SESSION_ALIVE:
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ Status = ProcessSessionAlive (
+ connection,
+ nbfHeader);
+ break;
+
+ //
+ // An unrecognized command was found in a NetBIOS frame. Because
+ // this is a connection-oriented frame, we should probably shoot
+ // the sender, but for now we will simply discard the packet.
+ //
+ // BUGBUG: trash the session here-- protocol violation.
+ //
+
+ default:
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ PANIC ("NbfProcessIIndicate: Unknown NBF command byte.\n");
+ connection->IndicationInProgress = FALSE;
+ Status = STATUS_SUCCESS;
+ } /* switch */
+
+ //
+ // A status of STATUS_MORE_PROCESSING_REQUIRED means
+ // that the connection reference count was inherited
+ // by the routine we called, so we don't do the dereference
+ // here.
+ //
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ NbfDereferenceConnectionMacro("ProcessIIndicate done", connection, CREF_PROCESS_DATA);
+ }
+
+
+ //
+ // The N(R) in this frame acknowleges some (or all) of our packets.
+ // This call must come after the checkpoint acknowlegement check
+ // so that an RR-r/f is always sent BEFORE any new I-frames. This
+ // allows us to always send I-frames as commands.
+ // If he responded to a checkpoint, then resend all left-over
+ // packets.
+ //
+
+ // Link->NextSend = (UCHAR)(header->RcvSeq >> 1) < Link->NextSend ?
+ // Link->NextSend : (UCHAR)(header->RcvSeq >> 1);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->WackQ.Flink != &Link->WackQ) {
+
+ UCHAR AckSequenceNumber = (UCHAR)(header->RcvSeq >> 1);
+
+ //
+ // Verify that the sequence number is reasonable.
+ //
+
+ if (Link->NextSend >= Link->LastAckReceived) {
+
+ //
+ // There is no 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) ||
+ (AckSequenceNumber > Link->NextSend)) {
+ goto NoResend;
+ }
+
+ } else {
+
+ //
+ // There is a 127 -> 0 wrap between the two...
+ //
+
+ if ((AckSequenceNumber < Link->LastAckReceived) &&
+ (AckSequenceNumber > Link->NextSend)) {
+ goto NoResend;
+ }
+
+ }
+
+ //
+ // NOTE: ResendLlcPackets may release and
+ // reacquire the link spinlock.
+ //
+
+ (VOID)ResendLlcPackets(
+ Link,
+ AckSequenceNumber,
+ (BOOLEAN)((!Command) && PollFinal));
+
+NoResend:;
+
+ }
+
+
+ //
+ // Get link going again.
+ //
+ // NOTE: RestartLinkTraffic releases the link spinlock
+ //
+
+ RestartLinkTraffic (Link);
+ break;
+
+ case LINK_STATE_ADM:
+
+ //
+ // used to be, we'd just blow off the other guy with a DM and go home.
+ // it seems that OS/2 likes to believe (under some conditions) that
+ // it has a link up and it is still potentially active (probably
+ // because we return the same connection number to him that he used
+ // to be using). This would all be ok, except for the fact that we
+ // may have a connection hanging on this link waiting for a listen
+ // to finish. If we're in that state, go ahead and accept the
+ // connect.
+ // Set our values for link packet serial numbers to what he wants.
+ //
+
+ if (!IsListEmpty (&Link->ConnectionDatabase)) {
+ if (nbfHeader->Command == NBF_CMD_SESSION_INITIALIZE) {
+
+ //
+ // OK, we're at the only legal case. We've gotten an SI
+ // and we have a connection on this link. If the connection
+ // is waiting SI, we will go ahead and make believe we did
+ // all the correct stuff before we got it.
+ //
+
+ for (
+ p = Link->ConnectionDatabase.Flink, connection = NULL;
+ p != &Link->ConnectionDatabase ;
+ p = p->Flink, connection = NULL
+ ) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_SI) != 0) {
+ // This reference is removed below
+ NbfReferenceConnection ("Found Listener at session init", connection, CREF_ADM_SESS);
+ break;
+ }
+ }
+
+ //
+ // Well, we've looked through the connections, if we have one,
+ // make it the connection of the day. Note that it will
+ // complete when we call ProcessSessionInitialize.
+ //
+
+ if (connection != NULL) {
+
+ Link->NextReceive = (UCHAR)(header->SendSeq >> 1) & (UCHAR)0x7f;
+ Link->NextSend = (UCHAR)(header->RcvSeq >> 1) & (UCHAR)0x7F;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfCompleteLink (Link); // completes the listening connection
+
+ Status = ProcessSessionInitialize (
+ connection,
+ nbfHeader);
+ NbfDereferenceConnection ("Processed SessInit", connection, CREF_ADM_SESS);
+
+#if DBG
+ s = "ADM";
+#endif
+
+ // Link is ready for use.
+
+ break;
+ }
+ }
+
+ //
+ // we've got a connection on a link that's in state admin.
+ // really bad, kill it and the link.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "NbfProcessIIndicate calling NbfStopLink\n" );
+ }
+#endif
+ NbfStopLink (Link);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ //
+ // We're disconnected. Tell him.
+ //
+
+ NbfSendDm (Link, PollFinal); // releases lock
+#if DBG
+ s = "ADM";
+#endif
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We've sent a SABME and are waiting for a UA. He's sent an
+ // I-frame too early, so just let the SABME time out.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "CONNECTING";
+#endif
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ //
+ // We're waiting for his initial poll on a RR-c/p. If he starts
+ // with an I-frame, then we'll let him squeak by.
+ //
+
+ if (!Command) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+ }
+
+ Link->State = LINK_STATE_READY; // we're up!
+ StopT1 (Link); // no longer waiting.
+ FakeUpdateBaseT1Timeout (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+ NbfProcessIIndicate ( // recursive, but safe
+ Command,
+ PollFinal,
+ Link,
+ DlcHeader,
+ DlcIndicatedLength,
+ DlcTotalLength,
+ ReceiveContext,
+ Loopback);
+#if DBG
+ s = "W_POLL";
+#endif
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We're waiting for a RR-r/f from the remote guy. I-r/f will do.
+ //
+
+ if (Command || !PollFinal) { // don't allow this protocol.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break; // we sent RR-c/p.
+ }
+
+ Link->State = LINK_STATE_READY; // we're up.
+ StopT1 (Link); // no longer waiting.
+ StartT2 (Link); // we have an unacked I-frame.
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfCompleteLink (Link); // fire up the connections.
+ StartTi (Link);
+ NbfProcessIIndicate ( // recursive, but safe
+ Command,
+ PollFinal,
+ Link,
+ DlcHeader,
+ DlcIndicatedLength,
+ DlcTotalLength,
+ ReceiveContext,
+ Loopback);
+#if DBG
+ s = "W_FINAL";
+#endif
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We're waiting for a response from our DISC-c/p but instead of
+ // a UA-r/f, we got this I-frame. Throw the packet away.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ s = "W_DISC_RSP";
+#endif
+ break;
+
+
+ default:
+
+ ASSERT (FALSE);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ s = "Unknown link state";
+#endif
+
+ } /* switch */
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" NbfProcessIIndicate: (%s) I-Frame processed.\n", s);
+ }
+#endif
+
+ return;
+} /* NbfProcessIIndicate */
+
+
+NTSTATUS
+ProcessIndicateData(
+ IN PTP_CONNECTION Connection,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN PUCHAR DataHeader,
+ IN UINT DataTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last,
+ IN BOOLEAN Loopback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to process data received in a DATA_FIRST_MIDDLE
+ or DATA_ONLY_LAST frame. We attempt to satisfy as many TdiReceive
+ requests as possible with this data.
+
+ If a receive is already active on this Connection, then we copy as much
+ data into the active receive's buffer as possible. If all the data is
+ copied and the receive request's buffer has not been filled, then the
+ Last flag is checked, and if it is TRUE, we go ahead and complete the
+ current receive with the TDI_END_OF_RECORD receive indicator. If Last
+ is FALSE, we simply return.
+
+ If more (uncopied) data remains in the frame, or if there is no active
+ receive outstanding, then an indication is issued to the owning address's
+ receive event handler. The event handler can take one of three actions:
+
+ 1. Return STATUS_SUCCESS, in which case the transport will assume that
+ all of the indicated data has been accepted by the client.
+
+ 3. Return STATUS_DATA_NOT_ACCEPTED, in which case the transport will
+ discard the data and set the CONNECTION_FLAGS_RECEIVE_WAKEUP bitflag
+ in the Connection, indicating that remaining data is to be discarded
+ until a receive becomes available.
+
+ NOTE: This routine is called with Connection->LinkSpinLock held,
+ and returns with it released. THIS ROUTINE MUST BE CALLED AT
+ DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ DlcHeader - The pointer handed to us as the start of the NBF header by NDIS;
+ use this to compute the offset into the packet to start the transfer
+ of data to user buffers.
+
+ DlcIndicatedLength - The amount of NBF data available at indicate.
+
+ DataHeader - A pointer to the start of the data in the packet.
+
+ DataTotalLength - The total length of the packet, starting at DataHeader.
+
+ ReceiveContext - An NDIS handle that identifies the packet we are currently
+ processing.
+
+ Last - Boolean value that indicates whether this is the last piece of data
+ in a message. The DATA_ONLY_LAST processor sets this flag to TRUE when
+ calling this routine, and the DATA_FIRST_MIDDLE processor resets this
+ flag to FALSE when calling this routine.
+
+ Loopback - Is this a loopback indication; used to determine whether
+ to call NdisTransferData or NbfTransferLoopbackData.
+
+
+Return Value:
+
+ STATUS_SUCCESS if we've consumed the packet,
+
+--*/
+
+{
+ NTSTATUS status, tmpstatus;
+ PDEVICE_CONTEXT deviceContext;
+ NDIS_STATUS ndisStatus;
+ PNDIS_PACKET ndisPacket;
+ PSINGLE_LIST_ENTRY linkage;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PNDIS_BUFFER ndisBuffer;
+ ULONG destBytes;
+ ULONG bufferChainLength;
+ ULONG indicateBytesTransferred;
+ ULONG ReceiveFlags;
+ ULONG ndisBytesTransferred;
+ UINT BytesToTransfer;
+ ULONG bytesIndicated;
+ ULONG DataOffset = (PUCHAR)DataHeader - (PUCHAR)DlcHeader;
+ PRECEIVE_PACKET_TAG receiveTag;
+ PTP_ADDRESS_FILE addressFile;
+ PMDL SavedCurrentMdl;
+ ULONG SavedCurrentByteOffset;
+ BOOLEAN ActivatedLongReceive = FALSE;
+ BOOLEAN CompleteReceiveBool, EndOfMessage;
+ ULONG DumpData[2];
+
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint4 (" ProcessIndicateData: Entered, PacketStart: %lx Offset: %lx \n TotalLength %ld DlcIndicatedLength: %ld\n",
+ DlcHeader, DataOffset, DataTotalLength, DlcIndicatedLength);
+ }
+
+
+ //
+ // copy this packet into our receive buffer.
+ //
+
+ deviceContext = Connection->Provider;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_RCV_CANCELLED) != 0) {
+
+ //
+ // A receive in progress was cancelled; we toss the data,
+ // but do send the DOL if it was the last piece of the
+ // send.
+ //
+
+ if (Last) {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_RCV_CANCELLED;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfSendDataAck (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Initialize this to zero, in case we do not indicate or
+ // the client does not fill it in.
+ //
+
+ indicateBytesTransferred = 0;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+
+ //
+ // check first to see if there is a receive available. If there is,
+ // use it before doing an indication.
+ //
+
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one and
+ // cycle around again.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation (Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ status = STATUS_SUCCESS;
+ goto NormalReceive;
+ }
+
+ //
+ // A receive is not active. Post a receive event.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ return STATUS_SUCCESS;
+ }
+
+ addressFile = Connection->AddressFile;
+
+ if ((!addressFile->RegisteredReceiveHandler) ||
+ (Connection->ReceiveBytesUnaccepted != 0)) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // no event handler. Set the RECEIVE_WAKEUP bit, so that when a
+ // receive does become available, it will restart the
+ // current send. Also send a NoReceive to tell the other
+ // guy he needs to resynch.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->IndicationInProgress = FALSE;
+
+ // NbfSendNoReceive (Connection);
+ return STATUS_SUCCESS;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Receive not active. Posting event.\n");
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ LEAVE_NBF;
+
+ //
+ // Indicate to the user. For BytesAvailable we
+ // always use DataTotalLength; for BytesIndicated we use
+ // MIN (DlcIndicatedLength - DataOffset, DataTotalLength).
+ //
+ // To clarify BytesIndicated, on an Ethernet packet
+ // which is padded DataTotalLength will be shorter; on an
+ // Ethernet packet which is not padded and which is
+ // completely indicated, the two will be equal; and
+ // on a long Ethernet packet DlcIndicatedLength - DataOffset
+ // will be shorter.
+ //
+
+ bytesIndicated = DlcIndicatedLength - DataOffset;
+ if (DataTotalLength <= bytesIndicated) {
+ bytesIndicated = DataTotalLength;
+ }
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (deviceContext->MacInfo.CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ status = (*addressFile->ReceiveHandler)(
+ addressFile->ReceiveHandlerContext,
+ Connection->Context,
+ ReceiveFlags,
+ bytesIndicated,
+ DataTotalLength, // BytesAvailable
+ &indicateBytesTransferred,
+ DataHeader,
+ &irp);
+ ENTER_NBF;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ ULONG SpecialIrpLength;
+ PTDI_REQUEST_KERNEL_RECEIVE Parameters;
+
+ //
+ // The client's event handler has returned an IRP in the
+ // form of a TdiReceive that is to be associated with this
+ // data. The request will be installed at the front of the
+ // ReceiveQueue, and then made the active receive request.
+ // This request will be used to accept the incoming data, which
+ // will happen below.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_MORE_PROCESSING_REQUIRED.\n");
+ NbfPrint4 (" ProcessIndicateData: Irp=%lx, Mdl=%lx, UserBuffer=%lx, Count=%ld.\n",
+ irp, irp->MdlAddress, irp->UserBuffer,
+ MmGetMdlByteCount (irp->MdlAddress));
+ }
+
+ //
+ // Queueing a receive of any kind causes a Connection reference;
+ // that's what we've just done here, so make the Connection stick
+ // around. We create a request to keep a packets outstanding ref
+ // count for the current IRP; we queue this on the connection's
+ // receive queue so we can treat it like a normal receive. If
+ // we can't get a request to describe this irp, we can't keep it
+ // around hoping for better later; we simple fail it with
+ // insufficient resources. Note this is only likely to happen if
+ // we've completely run out of transport memory.
+ //
+
+ irp->IoStatus.Information = 0; // byte transfer count.
+ irp->IoStatus.Status = STATUS_PENDING;
+ irpSp = IoGetCurrentIrpStackLocation (irp);
+
+ ASSERT (irpSp->FileObject->FsContext == Connection);
+
+ Parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
+ SpecialIrpLength = Parameters->ReceiveLength;
+
+ //
+ // If the packet is a DOL, and it will fit entirely
+ // inside this posted IRP, then we don't bother
+ // creating a request, because we don't need any of
+ // that overhead. We also don't set ReceiveBytes
+ // Unaccepted, since this receive would clear it
+ // anyway.
+ //
+
+ if (Last &&
+ (SpecialIrpLength >= (DataTotalLength - indicateBytesTransferred))) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->SpecialReceiveIrp = irp;
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = SpecialIrpLength;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveIrp = NULL;
+ Connection->CurrentReceiveSynchronous = TRUE;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+ if ((Parameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0) {
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ }
+
+#if DBG
+ //
+ // switch our reference from PROCESS_DATA to
+ // RECEIVE_IRP, this is OK because the RECEIVE_IRP
+ // reference won't be removed until Transfer
+ // DataComplete, which is the last thing
+ // we call.
+ //
+
+ NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
+ NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
+#endif
+
+ } else {
+ KIRQL cancelIrql;
+
+ //
+ // The normal path, for longer receives.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ IRP_RECEIVE_IRP(irpSp) = irp;
+ if (deviceContext->MacInfo.SingleReceive) {
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+ } else {
+#if DBG
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+ NbfReferenceReceiveIrpLocked ("Transfer Data", irpSp, RREF_RECEIVE);
+#else
+ IRP_RECEIVE_REFCOUNT(irpSp) = 2; // include one for first xfer
+#endif
+ }
+
+ //
+ // If the Connection is stopping, abort this request.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ Connection->IndicationInProgress = FALSE;
+
+ NbfReferenceConnection("Special IRP stopping", Connection, CREF_RECEIVE_IRP);
+ NbfCompleteReceiveIrp (
+ irp,
+ Connection->Status,
+ 0);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+ NbfDereferenceReceiveIrp ("Not ready", irpSp, RREF_RECEIVE);
+ }
+ return STATUS_SUCCESS; // we have consumed the packet
+
+ }
+
+ //
+ // If this IRP has been cancelled, complete it now.
+ //
+
+ if (irp->Cancel) {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+
+ Connection->IndicationInProgress = FALSE;
+
+ NbfReferenceConnection("Special IRP cancelled", Connection, CREF_RECEIVE_IRP);
+
+ //
+ // It is safe to call this with locks held.
+ //
+ NbfCompleteReceiveIrp (irp, STATUS_CANCELLED, 0);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+ NbfDereferenceReceiveIrp ("Cancelled", irpSp, RREF_RECEIVE);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Insert the request on the head of the connection's
+ // receive queue, so it can be handled like a normal
+ // receive.
+ //
+
+ InsertHeadList (&Connection->ReceiveQueue, &irp->Tail.Overlay.ListEntry);
+
+ IoSetCancelRoutine(irp, NbfCancelReceive);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // at DPC level when we acquired it, we don't have to fiddle
+ // with swapping irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = Parameters->ReceiveLength;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveIrp = irp;
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+
+#if DBG
+ //
+ // switch our reference from PROCESS_DATA to
+ // REQUEST, this is OK because the REQUEST
+ // reference won't be removed until Transfer
+ // DataComplete, which is the last thing
+ // we call.
+ //
+
+ NbfReferenceConnection("Special IRP", Connection, CREF_RECEIVE_IRP);
+ NbfDereferenceConnection("ProcessIIndicate done", Connection, CREF_PROCESS_DATA);
+#endif
+ //
+ // Make a note so we know what to do below.
+ //
+
+ ActivatedLongReceive = TRUE;
+
+#if DBG
+ NbfReceives[NbfReceivesNext].Irp = irp;
+ NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+ }
+
+ } else if (status == STATUS_SUCCESS) {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_SUCCESS.\n");
+ }
+
+ //
+ // The client has accepted some or all of the indicated data in
+ // the event handler. Update MessageBytesReceived variable in
+ // the Connection so that if we are called upon to ACK him
+ // at the byte level, then we can correctly report the
+ // number of bytes received thus far. If this is a DOL,
+ // then reset the number of bytes received, since this value
+ // always at zero for new messages. If the data indicated wasn't
+ // all the data in this packet, flow control to the sender that
+ // didn't get all of the data.
+ //
+
+ if (Last && (indicateBytesTransferred >= DataTotalLength)) {
+
+ ASSERT (indicateBytesTransferred == DataTotalLength);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // This will send a DATA ACK or queue a request for
+ // a piggyback ack.
+ //
+ // NOTE: It will also release the connection spinlock.
+ //
+
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // This gets gory.
+ // If this packet wasn't a DOL, we have no way of knowing how
+ // much the client will take of the data in this send that is
+ // now arriving. Pathological clients will break this protocol
+ // if they do things like taking part of the receive at indicate
+ // immediate and then return an irp (this would make the byte
+ // count wrong for the irp).
+ //
+ // Since the client did not take all the data that we
+ // told him about, he will eventually post a receive.
+ // If this has not already happened then we set the
+ // RECEIVE_WAKEUP bit and send a NO_RECEIVE.
+ //
+
+#if DBG
+ NbfPrint0("NBF: Indicate returned SUCCESS but did not take all data\n");
+#endif
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageInitAccepted = indicateBytesTransferred;
+ Connection->ReceiveBytesUnaccepted = DataTotalLength - indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+
+ if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
+
+ //
+ // There is no receive posted to the Connection.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+
+ if (indicateBytesTransferred == DataTotalLength) {
+
+ //
+ // This means he took everything, but it was not
+ // a DOL; there is no need to do anything since
+ // the rest of the data will be right behind.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ } else {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendNoReceive (Connection);
+
+ }
+
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one. This will cause
+ // an NdisTransferData below, so we don't dereference the
+ // Connection here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ }
+
+ } else { // STATUS_DATA_NOT_ACCEPTED or other
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Status=STATUS_DATA_NOT_ACCEPTED.\n");
+ }
+
+ //
+ // Either there is no event handler installed (the default
+ // handler returns this code) or the event handler is not
+ // able to process the received data at this time. If there
+ // is a TdiReceive request outstanding on this Connection's
+ // ReceiveQueue, then we may use it to receive this data.
+ // If there is no request outstanding, then we must initiate
+ // flow control at the transport level.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->ReceiveBytesUnaccepted = DataTotalLength;
+
+ if (Connection->ReceiveQueue.Flink == &Connection->ReceiveQueue) {
+
+ //
+ // There is no receive posted to the Connection, and
+ // the event handler didn't want to accept the incoming
+ // data. Set the RECEIVE_WAKEUP bit, so that when a
+ // receive does become available, it will restart the
+ // current send. Also send a NoReceive to tell the other
+ // guy he needs to resynch.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: ReceiveQueue empty. Setting RECEIVE_WAKEUP.\n");
+ }
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ Connection->IndicationInProgress = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ProcessIndicateData: Found receive. Prepping.\n");
+ }
+
+ //
+ // Found a receive, so make it the active one. This will cause
+ // an NdisTransferData below, so we don't dereference the
+ // Connection here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ IRP, Tail.Overlay.ListEntry);
+ Connection->CurrentReceiveSynchronous =
+ deviceContext->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveIrp->MdlAddress;
+ Connection->ReceiveLength =
+ IRP_RECEIVE_LENGTH (IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp));
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ }
+
+ } else {
+
+ //
+ // A receive is active, set the status to show
+ // that so far.
+ //
+
+ status = STATUS_SUCCESS;
+
+ }
+
+
+NormalReceive:;
+
+ //
+ // NOTE: The connection spinlock is held here.
+ //
+ // We should only get through here if a receive is active
+ // and we have not released the lock since checking or
+ // making one active.
+ //
+
+ ASSERT(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint2 (" ProcessIndicateData: Receive is active. ReceiveLengthLength: %ld Offset: %ld.\n",
+ Connection->ReceiveLength, Connection->MessageBytesReceived);
+ }
+
+ destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
+
+ //
+ // If we just activated a non-special receive IRP, we already
+ // added a refcount for this transfer.
+ //
+
+ if (!Connection->CurrentReceiveSynchronous && !ActivatedLongReceive) {
+ NbfReferenceReceiveIrpLocked ("Transfer Data", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ //
+ // Determine how much data remains to be transferred.
+ //
+
+ ASSERT (indicateBytesTransferred <= DataTotalLength);
+ BytesToTransfer = DataTotalLength - indicateBytesTransferred;
+
+ if (destBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceiveBool = TRUE;
+ BytesToTransfer = destBytes;
+
+ } else if (destBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceiveBool = TRUE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceiveBool = Last;
+
+ }
+
+
+ //
+ // If we can copy the data directly, then do so.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (DataOffset + indicateBytesTransferred + BytesToTransfer <= DlcIndicatedLength)) {
+
+ //
+ // All the data that we need to transfer is available in
+ // the indication, so copy it directly.
+ //
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PMDL CurMdl;
+ ULONG CurByteOffset;
+
+ //
+ // First we advance the connection pointers by the appropriate
+ // number of bytes, so that we can reallow indications (only
+ // do this if needed).
+ //
+
+ CurMdl = Connection->CurrentReceiveMdl;
+ CurByteOffset = Connection->ReceiveByteOffset;
+
+ if (!deviceContext->MacInfo.ReceiveSerialized) {
+
+ SavedCurrentMdl = CurMdl;
+ SavedCurrentByteOffset = CurByteOffset;
+
+ BytesLeft = BytesToTransfer;
+ CurTargetLen = MmGetMdlByteCount (CurMdl) - CurByteOffset;
+ while (TRUE) {
+ if (BytesLeft >= CurTargetLen) {
+ BytesLeft -= CurTargetLen;
+ CurMdl = CurMdl->Next;
+ CurByteOffset = 0;
+ if (BytesLeft == 0) {
+ break;
+ }
+ CurTargetLen = MmGetMdlByteCount (CurMdl);
+ } else {
+ CurByteOffset += BytesLeft;
+ break;
+ }
+ }
+
+ Connection->CurrentReceiveMdl = CurMdl;
+ Connection->ReceiveByteOffset = CurByteOffset;
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // Set this up, we know the transfer won't
+ // "fail" but another one at the same time
+ // might.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->TransferBytesPending == 0) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ } else {
+ Connection->TransferBytesPending += BytesToTransfer;
+ Connection->TotalTransferBytesPending += BytesToTransfer;
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->IndicationInProgress = FALSE;
+
+ //
+ // Restore these for the next section of code.
+ //
+
+ CurMdl = SavedCurrentMdl;
+ CurByteOffset = SavedCurrentByteOffset;
+
+ }
+
+ CurTarget = (PUCHAR)(MmGetSystemAddressForMdl(CurMdl)) + CurByteOffset;
+ CurTargetLen = MmGetMdlByteCount(CurMdl) - CurByteOffset;
+ CurSource = DataHeader + indicateBytesTransferred;
+
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ deviceContext->MacInfo.CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurMdl = CurMdl->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ CurTarget = MmGetSystemAddressForMdl(CurMdl);
+ CurTargetLen = MmGetMdlByteCount(CurMdl);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ ASSERT (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ if (deviceContext->MacInfo.ReceiveSerialized) {
+
+ //
+ // If we delayed updating these, do it now.
+ //
+
+ Connection->CurrentReceiveMdl = CurMdl;
+ Connection->ReceiveByteOffset = CurByteOffset;
+ Connection->MessageBytesReceived += BytesToTransfer;
+ Connection->IndicationInProgress = FALSE;
+
+ } else {
+
+ //
+ // Check if something else failed and we are the
+ // last to complete, if so then back up our
+ // receive pointers and send a receive
+ // outstanding to make him resend.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->TransferBytesPending -= BytesToTransfer;
+
+ if ((Connection->TransferBytesPending == 0) &&
+ (Connection->Flags & CONNECTION_FLAGS_TRANSFER_FAIL)) {
+
+ Connection->CurrentReceiveMdl = Connection->SavedCurrentReceiveMdl;
+ Connection->ReceiveByteOffset = Connection->SavedReceiveByteOffset;
+ Connection->MessageBytesReceived -= Connection->TotalTransferBytesPending;
+ Connection->Flags &= ~CONNECTION_FLAGS_TRANSFER_FAIL;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfSendReceiveOutstanding (Connection);
+
+ if (!Connection->SpecialReceiveIrp &&
+ !Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ return status;
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ }
+
+ //
+ // Now that the transfer is complete, simulate a call to
+ // TransferDataComplete.
+ //
+
+
+ if (!Connection->SpecialReceiveIrp) {
+
+ Connection->CurrentReceiveIrp->IoStatus.Information += BytesToTransfer;
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("TransferData complete", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ }
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (CompleteReceiveBool) {
+ CompleteReceive (Connection, EndOfMessage, BytesToTransfer);
+ }
+
+ return status;
+
+ }
+
+
+ //
+ // Get a packet for the coming transfer
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &deviceContext->ReceivePacketPool,
+ &deviceContext->Interlock);
+
+ if (linkage != NULL) {
+ ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ deviceContext->ReceivePacketExhausted++;
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("No receive packet", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ //
+ // We could not get a receive packet. We do have an active
+ // receive, so we just send a receive outstanding to
+ // get him to resend. Hopefully we will have a receive
+ // packet available when the data is resent.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+#if DBG
+ NbfPrint0 (" ProcessIndicateData: Discarding Packet, no receive packets\n");
+#endif
+ Connection->IndicationInProgress = FALSE;
+
+ return status;
+ }
+
+ //
+ // Initialize the receive packet.
+ //
+
+ receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
+ // receiveTag->PacketType = TYPE_AT_INDICATE;
+ receiveTag->Connection = Connection;
+ receiveTag->TransferDataPended = TRUE;
+
+ receiveTag->EndOfMessage = EndOfMessage;
+ receiveTag->CompleteReceive = CompleteReceiveBool;
+
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+ Connection->IndicationInProgress = FALSE;
+ receiveTag->TransferDataPended = FALSE;
+ receiveTag->AllocatedNdisBuffer = FALSE;
+ receiveTag->BytesToTransfer = 0;
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return status;
+ }
+
+ //
+ // describe the right part of the user buffer to NDIS. If we can't get
+ // the mdl for the packet, drop dead. Bump the request reference count
+ // so that we know we need to hold open receives until the NDIS transfer
+ // data requests complete.
+ //
+
+ SavedCurrentMdl = Connection->CurrentReceiveMdl;
+ SavedCurrentByteOffset = Connection->ReceiveByteOffset;
+
+ if ((Connection->ReceiveByteOffset == 0) &&
+ (CompleteReceiveBool)) {
+
+ //
+ // If we are transferring into the beginning of
+ // the current MDL, and we will be completing the
+ // receive after the transfer, then we don't need to
+ // copy it.
+ //
+
+ ndisBuffer = (PNDIS_BUFFER)Connection->CurrentReceiveMdl;
+ bufferChainLength = BytesToTransfer;
+ Connection->CurrentReceiveMdl = NULL;
+ // Connection->ReceiveByteOffset = 0;
+ receiveTag->AllocatedNdisBuffer = FALSE;
+ tmpstatus = STATUS_SUCCESS;
+
+ } else {
+
+ tmpstatus = BuildBufferChainFromMdlChain (
+ deviceContext,
+ Connection->CurrentReceiveMdl,
+ Connection->ReceiveByteOffset,
+ BytesToTransfer,
+ &ndisBuffer,
+ &Connection->CurrentReceiveMdl,
+ &Connection->ReceiveByteOffset,
+ &bufferChainLength);
+
+ receiveTag->AllocatedNdisBuffer = TRUE;
+
+ }
+
+
+ if ((!NT_SUCCESS (tmpstatus)) || (bufferChainLength != BytesToTransfer)) {
+
+ DumpData[0] = bufferChainLength;
+ DumpData[1] = BytesToTransfer;
+
+ NbfWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ tmpstatus,
+ NULL,
+ 2,
+ DumpData);
+
+ if (!Connection->CurrentReceiveSynchronous) {
+ NbfDereferenceReceiveIrp ("No MDL chain", IoGetCurrentIrpStackLocation(Connection->CurrentReceiveIrp), RREF_RECEIVE);
+ }
+
+ //
+ // Restore our old state and make him resend.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ Connection->IndicationInProgress = FALSE;
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ &receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ return status;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint3 (" ProcessIndicateData: Mdl: %lx user buffer: %lx user offset: %lx \n",
+ ndisBuffer, Connection->CurrentReceiveMdl, Connection->ReceiveByteOffset);
+ }
+
+ NdisChainBufferAtFront (ndisPacket, ndisBuffer);
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 (" ProcessIndicateData: Transferring Complete Packet: %lx\n",
+ ndisPacket);
+ }
+
+ //
+ // update the number of bytes received; OK to do this
+ // unprotected since IndicationInProgress is still FALSE.
+ //
+ //
+
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // We have to do this for two reasons: for MACs that
+ // are not receive-serialized, to keep track of it,
+ // and for MACs where transfer data can pend, so
+ // we have stuff saved to handle failure later (if
+ // the MAC is synchronous on transfers and it fails,
+ // we fill these fields in before calling CompleteTransferData).
+ //
+
+ if (!deviceContext->MacInfo.SingleReceive) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ receiveTag->BytesToTransfer = BytesToTransfer;
+ if (Connection->TransferBytesPending == 0) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ } else {
+ Connection->TransferBytesPending += BytesToTransfer;
+ Connection->TotalTransferBytesPending += BytesToTransfer;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // We have now updated all the connection counters (BUGBUG
+ // assuming the TransferData will succeed) and this
+ // packet's location in the request is secured, so we
+ // can be reentered.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ if (Loopback) {
+
+ NbfTransferLoopbackData(
+ &ndisStatus,
+ deviceContext,
+ ReceiveContext,
+ deviceContext->MacInfo.TransferDataOffset +
+ DataOffset + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred
+ );
+
+ } else {
+
+ NdisTransferData (
+ &ndisStatus,
+ deviceContext->NdisBindingHandle,
+ ReceiveContext,
+ deviceContext->MacInfo.TransferDataOffset +
+ DataOffset + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ }
+
+ //
+ // handle the various completion codes
+ //
+
+ if ((ndisStatus == NDIS_STATUS_SUCCESS) &&
+ (ndisBytesTransferred == BytesToTransfer)) {
+
+ //
+ // deallocate the buffers and such that we've used if at indicate
+ //
+
+ receiveTag->TransferDataPended = FALSE;
+
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+
+ } else if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // Because TransferDataPended stays TRUE, this reference will
+ // be removed in TransferDataComplete. It is OK to do this
+ // now, even though TransferDataComplete may already have been
+ // called, because we also hold the ProcessIIndicate reference
+ // so there will be no "bounce".
+ //
+
+ NbfReferenceConnection ("TransferData pended", Connection, CREF_TRANSFER_DATA);
+
+ } else {
+
+ //
+ // something broke; certainly we'll never get NdisTransferData
+ // asynch completion with this error status. We set things up
+ // to that NbfTransferDataComplete will do the right thing.
+ //
+
+ if (deviceContext->MacInfo.SingleReceive) {
+ Connection->TransferBytesPending = BytesToTransfer;
+ Connection->TotalTransferBytesPending = BytesToTransfer;
+ Connection->SavedCurrentReceiveMdl = SavedCurrentMdl;
+ Connection->SavedReceiveByteOffset = SavedCurrentByteOffset;
+ receiveTag->BytesToTransfer = BytesToTransfer;
+ }
+
+ receiveTag->TransferDataPended = FALSE;
+
+ NbfTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+
+ }
+
+ return status; // which only means we've dealt with the packet
+
+} /* ProcessIndicateData */
diff --git a/private/ntos/tdi/nbf/info.c b/private/ntos/tdi/nbf/info.c
new file mode 100644
index 000000000..f1cf8890b
--- /dev/null
+++ b/private/ntos/tdi/nbf/info.c
@@ -0,0 +1,3487 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Only the following routine is active in this module. All is is commented
+// out waiting for the definition of Get/Set info in TDI version 2.
+//
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define NbfGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+//
+// Local functions used to satisfy various requests.
+//
+
+VOID
+NbfStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ );
+
+VOID
+NbfStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ );
+
+VOID
+NbfStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ );
+
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PVOID adapterStatus;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PTA_NETBIOS_ADDRESS broadcastAddress;
+ PTDI_PROVIDER_STATISTICS ProviderStatistics;
+ PTDI_CONNECTION_INFO ConnectionInfo;
+ ULONG TargetBufferLength;
+ PFIND_NAME_HEADER FindNameHeader;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_REQUEST tpRequest;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ ULONG NamesWritten, TotalNameCount, BytesWritten;
+ BOOLEAN Truncated;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS TaAddressBuffer;
+ } AddressInfo;
+ PTRANSPORT_ADDRESS TaAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ BOOLEAN UsedConnection;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
+
+ switch (query->QueryType) {
+
+#if 0
+ case 0x12345678:
+
+ {
+ typedef struct _NBF_CONNECTION_STATUS {
+ UCHAR LocalName[16];
+ UCHAR RemoteName[16];
+ BOOLEAN SendActive;
+ BOOLEAN ReceiveQueued;
+ BOOLEAN ReceiveActive;
+ BOOLEAN ReceiveWakeUp;
+ ULONG Flags;
+ ULONG Flags2;
+ } NBF_CONNECTION_STATUS, *PNBF_CONNECTION_STATUS;
+
+ PNBF_CONNECTION_STATUS CurStatus;
+ ULONG TotalStatus;
+ ULONG AllowedStatus;
+ PLIST_ENRY q;
+
+ CurStatus = MmGetSystemAddressForMdl (Irp->MdlAddress);
+ TotalStatus = 0;
+ AllowedStatus = MmGetMdlByteCount (Irp->MdlAddress) / sizeof(NBF_CONNECTION_STATUS);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ for (q = Address->ConnectionDatabase.Flink;
+ q != &Address->ConnectionDatabase;
+ q = q->Flink) {
+
+ Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ continue;
+ }
+
+ if (TotalStatus >= AllowedStatus) {
+ continue;
+ }
+
+ RtlMoveMemory (CurStatus->LocalName, Address->NetworkName->NetbiosName, 16);
+ RtlMoveMemory (CurStatus->RemoteName, Connection->RemoteName, 16);
+
+ CurStatus->Flags = Connection->Flags;
+ CurStatus->Flags2 = Connection->Flags2;
+ CurStatus->SendActive = (BOOLEAN)(!IsListEmpty(&Connection->SendQueue));
+ CurStatus->ReceiveQueued = (BOOLEAN)(!IsListEmpty(&Connection->ReceiveQueue));
+ CurStatus->ReceiveActive = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0);
+ CurStatus->ReceiveWakeUp = (BOOLEAN)((Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) != 0);
+
+ ++CurStatus;
+ ++TotalStatus;
+
+ }
+ }
+
+ Irp->IoStatus.Information = TotalStatus * sizeof(NBF_CONNECTION_STATUS);
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+#endif
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
+#endif
+ return status;
+ }
+
+ ConnectionInfo = ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TDI_CONNECTION_INFO),
+ ' FBN');
+
+ if (ConnectionInfo == NULL) {
+
+ PANIC ("NbfQueryInfo: Cannot allocate connection info!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 6,
+ sizeof(TDI_CONNECTION_INFO),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ status = STATUS_INVALID_CONNECTION;
+ ExFreePool (ConnectionInfo);
+
+ } else {
+
+ PTP_LINK Link = Connection->Link;
+
+ RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+
+
+ //
+ // Get link delay and throughput.
+ //
+
+ if (Link->Delay == 0xffffffff) {
+
+ //
+ // If delay is not known, assume 0.
+ //
+
+ ConnectionInfo->Delay.HighPart = 0;
+ ConnectionInfo->Delay.LowPart = 0;
+
+ } else {
+
+ //
+ // Copy the delay as an NT relative time.
+ //
+
+ ConnectionInfo->Delay.HighPart = -1L;
+ ConnectionInfo->Delay.LowPart = (ULONG)-((LONG)(Link->Delay));
+
+ }
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ ULONG PacketsSent;
+ ULONG PacketsResent;
+ ULONG MultiplyFactor;
+
+ //
+ // Calculate the packets sent and resent since the
+ // last time the throughput was queried.
+ //
+
+ PacketsSent = Link->PacketsSent - Connection->LastPacketsSent;
+ PacketsResent = Link->PacketsResent - Connection->LastPacketsResent;
+
+ //
+ // Save these for next time.
+ //
+
+ Connection->LastPacketsSent = Link->PacketsSent;
+ Connection->LastPacketsResent = Link->PacketsResent;
+
+ //
+ // To convert exactly from 100 bits-per-second to
+ // bytes-per-second, we need to multiply by 12.5.
+ // Using lower numbers will give worse throughput.
+ // If there have been no errors we use 12, if there
+ // have been 20% or more errors we use 1, and in
+ // between we subtract 11 * (error%/20%) from 12
+ // and use that.
+ //
+
+ if (PacketsResent == 0 || PacketsSent <= 10) {
+
+ MultiplyFactor = 12;
+
+ } else if ((PacketsSent / PacketsResent) <= 5) {
+
+ MultiplyFactor = 1;
+
+ } else {
+
+ //
+ // error%/20% is error%/(1/5), which is 5*error%,
+ // which is 5 * (resent/send).
+ //
+
+ ASSERT (((11 * 5 * PacketsResent) / PacketsSent) <= 11);
+ MultiplyFactor = 12 - ((11 * 5 * PacketsResent) / PacketsSent);
+
+ }
+
+ ConnectionInfo->Throughput.QuadPart =
+ UInt32x32To64(DeviceContext->MediumSpeed, MultiplyFactor);
+
+ } else if (!Link->ThroughputAccurate) {
+
+ //
+ // If throughput is not known, then guess. We
+ // have MediumSpeed in units of 100 bps; we
+ // return four times that number as the throughput,
+ // which corresponds to about 1/3 of the
+ // maximum bandwidth expressed in bytes/sec.
+ //
+
+ ConnectionInfo->Throughput.QuadPart =
+ UInt32x32To64(DeviceContext->MediumSpeed, 4);
+
+ } else {
+
+ //
+ // Throughput is accurate, return it.
+ //
+
+ ConnectionInfo->Throughput = Link->Throughput;
+
+ }
+
+
+ //
+ // Calculate reliability using the sent/resent ratio,
+ // if there has been enough activity to make it
+ // worthwhile. >10% resent is unreliable.
+ //
+
+ if ((Link->PacketsResent > 0) &&
+ (Link->PacketsSent > 20)) {
+
+ ConnectionInfo->Unreliable =
+ ((Link->PacketsSent / Link->PacketsResent) < 10);
+
+ } else {
+
+ ConnectionInfo->Unreliable = FALSE;
+
+ }
+
+ ConnectionInfo->TransmittedTsdus = Connection->TransmittedTsdus;
+ ConnectionInfo->ReceivedTsdus = Connection->ReceivedTsdus;
+ ConnectionInfo->TransmissionErrors = Connection->TransmissionErrors;
+ ConnectionInfo->ReceiveErrors = Connection->ReceiveErrors;
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ConnectionInfo,
+ 0L,
+ sizeof(TDI_CONNECTION_INFO),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ConnectionInfo);
+ }
+
+ NbfDereferenceConnection ("query connection info", Connection, CREF_BY_ID);
+
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid AddressFile %lx Irp %lx\n", AddressFile, Irp);
+#endif
+ return status;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+#if DBG
+ NbfPrint2 ("TdiQueryInfo: Invalid Connection %lx Irp %lx\n", Connection, Irp);
+#endif
+ return status;
+ }
+
+ AddressFile = Connection->AddressFile;
+
+ UsedConnection = TRUE;
+
+ } else {
+
+ return STATUS_INVALID_ADDRESS;
+
+ }
+
+ Address = AddressFile->Address;
+
+ TdiBuildNetbiosAddress(
+ Address->NetworkName->NetbiosName,
+ (BOOLEAN)(Address->Flags & ADDRESS_FLAGS_GROUP ? TRUE : FALSE),
+ &AddressInfo.TaAddressBuffer);
+
+ //
+ // Count the active addresses.
+ //
+
+ AddressInfo.ActivityCount = 0;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+ ++AddressInfo.ActivityCount;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ status = TdiCopyBufferToMdl (
+ &AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (UsedConnection) {
+
+ NbfDereferenceConnection ("query address info", Connection, CREF_BY_ID);
+
+ } else {
+
+ NbfDereferenceAddress ("query address info", Address, AREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ broadcastAddress = ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TA_NETBIOS_ADDRESS),
+ ' FBN');
+ if (broadcastAddress == NULL) {
+ PANIC ("NbfQueryInfo: Cannot allocate broadcast address!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 2,
+ sizeof(TA_NETBIOS_ADDRESS),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+
+ broadcastAddress->TAAddressCount = 1;
+ broadcastAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ broadcastAddress->Address[0].AddressLength = 0;
+
+ Irp->IoStatus.Information =
+ sizeof (broadcastAddress->TAAddressCount) +
+ sizeof (broadcastAddress->Address[0].AddressType) +
+ sizeof (broadcastAddress->Address[0].AddressLength);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)broadcastAddress,
+ 0L,
+ Irp->IoStatus.Information,
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (broadcastAddress);
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(DeviceContext->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BUGBUG: This information is probablt available somewhere else.
+ //
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_BUFFER_OVERFLOW;
+
+ } else {
+
+ ProviderStatistics = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
+ ' FBN');
+
+ if (ProviderStatistics == NULL) {
+
+ PANIC ("NbfQueryInfo: Cannot allocate provider statistics!\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 7,
+ sizeof(TDI_PROVIDER_STATISTICS),
+ 0);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ NbfStoreProviderStatistics (DeviceContext, ProviderStatistics);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ProviderStatistics,
+ 0L,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((NBF_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ProviderStatistics);
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_SESSION_STATUS:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ //
+ // Determine if this is a local or remote query. It is
+ // local if there is no remote address specific at all,
+ // or if it is equal to our reserved address.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (query->RequestConnectionInformation != NULL) {
+
+ if (!NbfValidateTdiAddress(
+ query->RequestConnectionInformation->RemoteAddress,
+ query->RequestConnectionInformation->RemoteAddressLength)) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (!RemoteAddress) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the device context.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress, // the data to be received.
+ TargetBufferLength, // length of the data.
+ timeout, // do this ourselves here.
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Remote status", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+
+ //
+ // Allocate a temp buffer to hold our results.
+ //
+
+ tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (tpRequest->ResponseBuffer == NULL) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 12,
+ TargetBufferLength,
+ 0);
+ NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ InsertTailList (
+ &DeviceContext->StatusQueryQueue,
+ &tpRequest->Linkage);
+
+ tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The request is queued. Now send out the first packet and
+ // start the timer.
+ //
+
+ tpRequest->Retries = DeviceContext->GeneralRetries;
+ tpRequest->BytesWritten = 0;
+
+ //
+ // STATUS_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ NbfSendStatusQuery(
+ DeviceContext,
+ tpRequest,
+ &DeviceContext->NetBIOSAddress,
+ SingleSR,
+ SingleSRLength);
+
+ }
+
+ }
+
+ //
+ // As long as the request is created, pend here.
+ // The IRP will complete when the request completes.
+ //
+
+ status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Local.
+ //
+
+ adapterStatus = ExAllocatePoolWithTag (
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (adapterStatus == NULL) {
+ PANIC("NbfQueryInfo: PANIC! Could not allocate adapter status buffer\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 3,
+ TargetBufferLength,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NbfStoreAdapterStatus (
+ DeviceContext,
+ NULL,
+ 0,
+ adapterStatus);
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ (PUCHAR)adapterStatus + sizeof(ADAPTER_STATUS),
+ TargetBufferLength - sizeof(ADAPTER_STATUS),
+ 0,
+ &NamesWritten,
+ &TotalNameCount,
+ &Truncated);
+
+ ((PADAPTER_STATUS)adapterStatus)->name_count = (WORD)TotalNameCount;
+
+ BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
+
+ status = TdiCopyBufferToMdl (
+ adapterStatus,
+ 0,
+ BytesWritten,
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+
+ if (Truncated) {
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ ExFreePool (adapterStatus);
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ NbfGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if (!NbfValidateTdiAddress(
+ query->RequestConnectionInformation->RemoteAddress,
+ query->RequestConnectionInformation->RemoteAddressLength)) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ RemoteAddress = NbfParseTdiAddress(query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (!RemoteAddress) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the device context.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress, // the data to be received.
+ TargetBufferLength, // length of the data.
+ timeout, // do this ourselves here.
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Find name", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+
+ //
+ // Allocate a temp buffer to hold our results.
+ //
+
+ tpRequest->ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ TargetBufferLength,
+ ' FBN');
+
+ if (tpRequest->ResponseBuffer == NULL) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 4,
+ TargetBufferLength,
+ 0);
+ NbfCompleteRequest (tpRequest, STATUS_INSUFFICIENT_RESOURCES, 0);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ InsertTailList (
+ &DeviceContext->FindNameQueue,
+ &tpRequest->Linkage);
+
+ tpRequest->FrameContext = DeviceContext->UniqueIdentifier | 0x8000;
+ ++DeviceContext->UniqueIdentifier;
+ if (DeviceContext->UniqueIdentifier == 0x8000) {
+ DeviceContext->UniqueIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // The request is queued. Now send out the first packet and
+ // start the timer.
+ //
+ // We fill in the FIND_NAME_HEADER in the buffer, but
+ // set BytesWritten to 0; we don't include the header
+ // in BytesWritten until we get a response, so that
+ // a BytesWritten of 0 means "no response".
+ //
+
+ tpRequest->Retries = DeviceContext->GeneralRetries;
+ tpRequest->BytesWritten = 0;
+ FindNameHeader = (PFIND_NAME_HEADER)tpRequest->ResponseBuffer;
+ FindNameHeader->node_count = 0;
+ FindNameHeader->unique_group = NETBIOS_NAME_TYPE_UNIQUE;
+
+ NbfSendQueryFindName (DeviceContext, tpRequest);
+
+ }
+
+ }
+
+ //
+ // As long as the request is created, pend here.
+ // The IRP will complete when the request completes.
+ //
+
+ status = STATUS_PENDING;
+ }
+
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ TaAddress = (PTRANSPORT_ADDRESS)&AddressInfo.TaAddressBuffer;
+ TaAddress->TAAddressCount = 1;
+ TaAddress->Address[0].AddressLength = 6;
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ TaAddress->Address[0].AddressType =
+ DeviceContext->MacInfo.MediumAsync ?
+ NdisMediumWan : DeviceContext->MacInfo.MediumType;
+ } else {
+ TaAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ }
+ RtlCopyMemory (TaAddress->Address[0].Address, DeviceContext->LocalAddress.Address, 6);
+
+ status = TdiCopyBufferToMdl (
+ &AddressInfo.TaAddressBuffer,
+ 0,
+ sizeof(TRANSPORT_ADDRESS)+5,
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ DatagramInfo.MaximumDatagramBytes = 0;
+ DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &DatagramInfo,
+ 0,
+ sizeof(DatagramInfo),
+ Irp->MdlAddress,
+ 0,
+ &Irp->IoStatus.Information);
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* NbfTdiQueryInformation */
+
+//
+// Quick macros, assumes DeviceContext and ProviderStatistics exist.
+//
+
+#define STORE_RESOURCE_STATS_1(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## MaxInUse; \
+ if (DeviceContext->_ResourceName ## Samples > 0) { \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Total / DeviceContext->_ResourceName ## Samples; \
+ } else { \
+ RStats->AverageResourceUsed = 0; \
+ } \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+#define STORE_RESOURCE_STATS_2(_ResourceNum,_ResourceId,_ResourceName) \
+{ \
+ PTDI_PROVIDER_RESOURCE_STATS RStats = &ProviderStatistics->ResourceStats[_ResourceNum]; \
+ RStats->ResourceId = (_ResourceId); \
+ RStats->MaximumResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->AverageResourceUsed = DeviceContext->_ResourceName ## Allocated; \
+ RStats->ResourceExhausted = DeviceContext->_ResourceName ## Exhausted; \
+}
+
+
+VOID
+NbfStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the TDI_PROVIDER_STATISTICS structure
+ from the device context into ProviderStatistics.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ ProviderStatistics - The buffer that holds the result. It is assumed
+ that it is long enough.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Copy all the statistics up to NumberOfResources
+ // in one move.
+ //
+
+ RtlCopyMemory(
+ ProviderStatistics,
+ &DeviceContext->Statistics,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, NumberOfResources));
+
+ //
+ // Calculate AverageSendWindow.
+ //
+
+ if (DeviceContext->SendWindowSamples > 0) {
+ ProviderStatistics->AverageSendWindow =
+ DeviceContext->SendWindowTotal / DeviceContext->SendWindowSamples;
+ } else {
+ ProviderStatistics->AverageSendWindow = 1;
+ }
+
+ //
+ // Copy the resource statistics.
+ //
+
+ ProviderStatistics->NumberOfResources = NBF_TDI_RESOURCES;
+
+ STORE_RESOURCE_STATS_1 (0, LINK_RESOURCE_ID, Link);
+ STORE_RESOURCE_STATS_1 (1, ADDRESS_RESOURCE_ID, Address);
+ STORE_RESOURCE_STATS_1 (2, ADDRESS_FILE_RESOURCE_ID, AddressFile);
+ STORE_RESOURCE_STATS_1 (3, CONNECTION_RESOURCE_ID, Connection);
+ STORE_RESOURCE_STATS_1 (4, REQUEST_RESOURCE_ID, Request);
+
+ STORE_RESOURCE_STATS_2 (5, UI_FRAME_RESOURCE_ID, UIFrame);
+ STORE_RESOURCE_STATS_2 (6, PACKET_RESOURCE_ID, Packet);
+ STORE_RESOURCE_STATS_2 (7, RECEIVE_PACKET_RESOURCE_ID, ReceivePacket);
+ STORE_RESOURCE_STATS_2 (8, RECEIVE_BUFFER_RESOURCE_ID, ReceiveBuffer);
+
+} /* NbfStoreProviderStatistics */
+
+
+VOID
+NbfStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the ADAPTER_STATUS structure for the
+ device context into StatusBuffer. The name_count field is
+ initialized to zero; NbfStoreNameBuffers is used to write
+ name buffers.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ SourceRouting - If this is a remote request, the source
+ routing information from the frame.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ StatusBuffer - The buffer that holds the result. It is assumed
+ that it is at least sizeof(ADAPTER_STATUS) bytes long.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus = (PADAPTER_STATUS)StatusBuffer;
+ UINT MaxUserData;
+
+ RtlZeroMemory ((PVOID)AdapterStatus, sizeof(ADAPTER_STATUS));
+
+ RtlCopyMemory (AdapterStatus->adapter_address, DeviceContext->LocalAddress.Address, 6);
+ AdapterStatus->rev_major = 0x03;
+
+ switch (DeviceContext->MacInfo.MediumType) {
+ case NdisMedium802_5: AdapterStatus->adapter_type = 0xff; break;
+ default: AdapterStatus->adapter_type = 0xfe; break;
+ }
+
+ AdapterStatus->frmr_recv = (WORD)DeviceContext->FrmrReceived;
+ AdapterStatus->frmr_xmit = (WORD)DeviceContext->FrmrTransmitted;
+
+ AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
+ AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
+
+ AdapterStatus->xmit_success = (WORD)(DeviceContext->Statistics.DataFramesSent - DeviceContext->Statistics.DataFramesResent);
+ AdapterStatus->recv_success = (WORD)DeviceContext->Statistics.DataFramesReceived;
+ AdapterStatus->iframe_recv_err = (WORD)DeviceContext->Statistics.DataFramesRejected;
+ AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->Statistics.DataFramesResent;
+
+ AdapterStatus->t1_timeouts = (WORD)DeviceContext->Statistics.ResponseTimerExpirations;
+ AdapterStatus->ti_timeouts = (WORD)DeviceContext->TiExpirations;
+ AdapterStatus->xmit_aborts = (WORD)0;
+
+
+ AdapterStatus->free_ncbs = (WORD)0xffff;
+ AdapterStatus->max_cfg_ncbs = (WORD)0xffff;
+ AdapterStatus->max_ncbs = (WORD)0xffff;
+ AdapterStatus->pending_sess = (WORD)DeviceContext->Statistics.OpenConnections;
+ AdapterStatus->max_cfg_sess = (WORD)0xffff;
+ AdapterStatus->max_sess = (WORD)0xffff;
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ TRUE,
+ &MaxUserData);
+ AdapterStatus->max_dgram_size = (WORD)(MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS)));
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->MaxSendPacketSize,
+ FALSE,
+ &MaxUserData);
+ AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)));
+
+ return;
+
+} /* NbfStoreAdapterStatus */
+
+
+VOID
+NbfStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes NAME_BUFFER structures for the
+ device context into NameBuffer. It can skip a specified
+ number of names at the beginning, and returns the number
+ of names written into NameBuffer. If a name will only
+ partially fit, it is not written.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context.
+
+ NameBuffer - The buffer to write the names into.
+
+ NameBufferLength - The length of NameBuffer.
+
+ NamesToSkip - The number of names to skip.
+
+ NamesWritten - Returns the number of names written.
+
+ TotalNameCount - Returns the total number of names available,
+ if specified.
+
+ Truncated - More names are available than were written.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG NameCount = 0;
+ ULONG BytesWritten = 0;
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PNAME_BUFFER NameBuffer = (PNAME_BUFFER)Buffer;
+ PTP_ADDRESS address;
+
+
+ //
+ // Spin through the address list for this device context.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = DeviceContext->AddressDatabase.Flink;
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ //
+ // Check if we are still skipping.
+ //
+
+ if (NameCount < NamesToSkip) {
+ ++NameCount;
+ continue;
+ }
+
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > BufferLength) {
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ address->NetworkName->NetbiosName,
+ NETBIOS_NAME_LENGTH);
+
+ ++NameCount;
+ NameBuffer->name_num = (UCHAR)NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (address->Flags & ADDRESS_FLAGS_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ // BUGBUG: name_flags should be done more accurately.
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ *NamesWritten = NameBuffer - (PNAME_BUFFER)Buffer;
+
+ if (p == &DeviceContext->AddressDatabase) {
+
+ *Truncated = FALSE;
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+ *TotalNameCount = NameCount;
+ }
+
+ } else {
+
+ *Truncated = TRUE;
+
+ //
+ // If requested, continue through the list and count
+ // all the addresses.
+ //
+
+ if (ARGUMENT_PRESENT(TotalNameCount)) {
+
+ for ( ;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (address->NetworkName == NULL) {
+ continue;
+ }
+
+ //
+ // Ignore the reserved address, since we count it no matter what.
+ //
+
+ if ((address->NetworkName->NetbiosName[0] == 0) &&
+ (RtlEqualMemory(
+ address->NetworkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ continue;
+ }
+
+ ++NameCount;
+
+ }
+
+ *TotalNameCount = NameCount;
+
+ }
+
+ }
+
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ return;
+
+} /* NbfStoreNameBuffers */
+
+
+NTSTATUS
+NbfProcessStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address OPTIONAL,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a STATUS.QUERY packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ Address - The address we are responding from, or NULL if the STATUS.QUERY
+ was sent to the reserved address.
+
+ UiFrame - The packet in question, starting at the Netbios header.
+
+ SourceAddress - The source hardware address of the packet.
+
+ SourceRouting - Source routing data in the query.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PTP_UI_FRAME RawFrame;
+ PVOID ResponseBuffer;
+ UINT ResponseBufferLength;
+ ULONG NamesWritten, TotalNameCount;
+ ULONG BytesWritten;
+ UCHAR RequestType;
+ BOOLEAN Truncated, UsersBufferTooShort;
+ USHORT UsersBufferLength;
+ UINT HeaderLength;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+ PNDIS_BUFFER NdisBuffer;
+
+ //
+ // Allocate a buffer to hold the status.
+ //
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->CurSendPacketSize,
+ FALSE,
+ &ResponseBufferLength);
+
+ ResponseBufferLength -= (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+
+ UsersBufferLength = (UiFrame->Data2High * 256) + UiFrame->Data2Low;
+
+ //
+ // See how big to make our buffer; if the amount remaining in the user's
+ // buffer is less than our max size, chop it down.
+ //
+
+ if (UiFrame->Data1 <= 1) {
+
+ //
+ // This is the initial request.
+ //
+
+ if (ResponseBufferLength > (UINT)UsersBufferLength) {
+ ResponseBufferLength = UsersBufferLength;
+ }
+
+ } else {
+
+ //
+ // Subsequent request; compensate for already-sent data.
+ //
+
+ UsersBufferLength -= (sizeof(ADAPTER_STATUS) + (UiFrame->Data1 * sizeof(NAME_BUFFER)));
+
+ if (ResponseBufferLength > (UINT)UsersBufferLength) {
+ ResponseBufferLength = UsersBufferLength;
+ }
+
+ }
+
+ //
+ // If the remote station is asking for no data, ignore this request.
+ // This prevents us from trying to allocate 0 bytes of pool.
+ //
+
+ if ( (LONG)ResponseBufferLength <= 0 ) {
+ return STATUS_ABANDONED;
+ }
+
+ ResponseBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ ResponseBufferLength,
+ ' FBN');
+
+ if (ResponseBuffer == NULL) {
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 5,
+ ResponseBufferLength,
+ 0);
+ return STATUS_ABANDONED;
+ }
+
+
+ //
+ // Fill in the response buffer.
+ //
+
+ if (UiFrame->Data1 <= 1) {
+
+ //
+ // First request.
+ //
+
+ NbfStoreAdapterStatus (
+ DeviceContext,
+ SourceRouting,
+ SourceRoutingLength,
+ ResponseBuffer);
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ (PUCHAR)ResponseBuffer + sizeof(ADAPTER_STATUS),
+ ResponseBufferLength - sizeof(ADAPTER_STATUS),
+ 0,
+ &NamesWritten,
+ &TotalNameCount,
+ &Truncated);
+
+ BytesWritten = sizeof(ADAPTER_STATUS) + (NamesWritten * sizeof(NAME_BUFFER));
+
+ //
+ // If the data was truncated, but we are returning the maximum
+ // that the user requested, report that as "user's buffer
+ // too short" instead of "truncated".
+ //
+
+ if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
+ Truncated = FALSE;
+ UsersBufferTooShort = TRUE;
+ } else {
+ UsersBufferTooShort = FALSE;
+ }
+
+ ((PADAPTER_STATUS)ResponseBuffer)->name_count = (WORD)TotalNameCount;
+
+ } else {
+
+ NbfStoreNameBuffers (
+ DeviceContext,
+ ResponseBuffer,
+ ResponseBufferLength,
+ UiFrame->Data1,
+ &NamesWritten,
+ NULL,
+ &Truncated);
+
+ BytesWritten = NamesWritten * sizeof(NAME_BUFFER);
+
+ if (Truncated && (ResponseBufferLength >= (UINT)UsersBufferLength)) {
+ Truncated = FALSE;
+ UsersBufferTooShort = TRUE;
+ } else {
+ UsersBufferTooShort = FALSE;
+ }
+
+ }
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ ExFreePool (ResponseBuffer);
+ return STATUS_ABANDONED;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfProcessStatusQuery: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. STATUS_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) + BytesWritten,
+ ResponseSR,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ switch (UiFrame->Data1) {
+ case 0: // pre 2.1 request
+ RequestType = (UCHAR)0;
+ break;
+ case 1: // 2.1, first request
+ RequestType = (UCHAR)NamesWritten;
+ break;
+ default: // 2.1, subsequent request
+ RequestType = (UCHAR)(UiFrame->Data1 + NamesWritten);
+ break;
+ }
+
+ ConstructStatusResponse (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ RequestType, // request type.
+ Truncated, // more data.
+ UsersBufferTooShort, // user's buffer too small
+ (USHORT)BytesWritten, // bytes in response
+ RESPONSE_CORR(UiFrame), // correlator
+ UiFrame->SourceName, // receiver permanent name
+ (ARGUMENT_PRESENT(Address)) ?
+ Address->NetworkName->NetbiosName :
+ DeviceContext->ReservedNetBIOSAddress); // source name
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length (now, before we append the second
+ // buffer).
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+
+ //
+ // Now, if we have any name data, attach our buffer onto the frame.
+ // Note that it's possible at the end of the user's buffer for us
+ // to not have room for any names, and thus we'll have no data to
+ // send.
+ //
+
+ if ( BytesWritten != 0 ) {
+
+ RawFrame->DataBuffer = ResponseBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ ResponseBuffer,
+ BytesWritten);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC ("ConstructStatusResponse: NdisAllocateBuffer failed.\n");
+ NbfDestroyConnectionlessFrame (DeviceContext, RawFrame);
+ return STATUS_ABANDONED;
+ }
+
+ NdisChainBufferAtBack (RawFrame->NdisPacket, NdisBuffer);
+
+ } else {
+
+ RawFrame->DataBuffer = NULL;
+
+ }
+
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+ return STATUS_ABANDONED;
+
+} /* NbfProcessStatusQuery */
+
+
+VOID
+NbfSendQueryFindName(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will send a FIND.NAME packet for the specified
+ find name request, and start the request timer.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context to send the find name on.
+
+ Request - The find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS Status;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ LARGE_INTEGER Timeout;
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+
+ remoteAddress = NbfParseTdiAddress(
+ ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
+ RequestConnectionInformation->RemoteAddress, FALSE);
+
+ //
+ // Start the timer for this request.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
+ Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. NAME_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ ConstructNameQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ NETBIOS_NAME_TYPE_UNIQUE, // call from a unique name.
+ NAME_QUERY_LSN_FIND_NAME, // LSN
+ Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
+ DeviceContext->ReservedNetBIOSAddress,
+ (PNAME)remoteAddress->NetbiosName);
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendQueryFindName */
+
+
+NTSTATUS
+NbfProcessQueryNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Packet,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a NAME.RECOGNIZED request with a
+ correlator of 0, indicating it was a response to a previous
+ FIND.NAME packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ Packet - The packet in question, starting at the MAC header.
+
+ UiFrame - The packet, starting at the Netbios header.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PFIND_NAME_BUFFER FindNameBuffer;
+ PFIND_NAME_HEADER FindNameHeader;
+ PUCHAR DestinationAddress;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PUCHAR TargetBuffer;
+ USHORT FrameContext;
+ PLIST_ENTRY p;
+
+
+ MacReturnDestinationAddress(
+ &DeviceContext->MacInfo,
+ Packet,
+ &DestinationAddress);
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ Packet,
+ &SourceAddressBuffer,
+ &SourceAddress,
+ NULL);
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ Packet,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Find the request that this is for, using the frame context.
+ //
+
+ FrameContext = TRANSMIT_CORR(UiFrame);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (p=DeviceContext->FindNameQueue.Flink;
+ p != &DeviceContext->FindNameQueue;
+ p=p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->FrameContext == FrameContext) {
+
+ break;
+
+ }
+
+ }
+
+ if (p == &DeviceContext->FindNameQueue) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ NbfReferenceRequest ("Name Recognized", Request, RREF_FIND_NAME);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // Make sure that this physical address has not
+ // responded yet.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ //
+ // Make sure this request is not stopping.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is the first response, update BytesWritten to include
+ // the header that is already written in ResponseBuffer.
+ //
+
+ if (Request->BytesWritten == 0) {
+ Request->BytesWritten = sizeof(FIND_NAME_HEADER);
+ }
+
+ TargetBuffer = Request->ResponseBuffer;
+ FindNameBuffer = (PFIND_NAME_BUFFER)(TargetBuffer + sizeof(FIND_NAME_HEADER));
+
+ for ( ; FindNameBuffer < (PFIND_NAME_BUFFER)(TargetBuffer + Request->BytesWritten); FindNameBuffer++) {
+
+ if (RtlEqualMemory (FindNameBuffer->source_addr, SourceAddress->Address, 6)) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Duplicate NR", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+ }
+
+ }
+
+ //
+ // This is a new address, update if there is room.
+ //
+
+ if ((Request->BytesWritten + sizeof(FIND_NAME_BUFFER)) >
+ Request->Buffer2Length) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
+ NbfDereferenceRequest ("No Buffer", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+ }
+
+ FindNameHeader = (PFIND_NAME_HEADER)TargetBuffer;
+ FindNameHeader->unique_group = UiFrame->Data2High;
+
+ Request->BytesWritten += sizeof(FIND_NAME_BUFFER);
+ ++FindNameHeader->node_count;
+
+ RtlCopyMemory(FindNameBuffer->source_addr, SourceAddress->Address, 6);
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ RtlCopyMemory(FindNameBuffer->destination_addr, DestinationAddress, 6);
+ FindNameBuffer->length = 14;
+
+ if (DeviceContext->MacInfo.MediumType == NdisMedium802_5) {
+
+ //
+ // token-ring, copy the correct fields.
+ //
+
+ FindNameBuffer->access_control = Packet[0];
+ FindNameBuffer->frame_control = Packet[1];
+
+ if (SourceRouting != NULL) {
+ RtlCopyMemory (FindNameBuffer->routing_info, SourceRouting, SourceRoutingLength);
+ FindNameBuffer->length += SourceRoutingLength;
+ }
+
+ } else {
+
+ //
+ // non-token-ring, nothing else is significant.
+ //
+
+ FindNameBuffer->access_control = 0x0;
+ FindNameBuffer->frame_control = 0x0;
+
+ }
+
+
+ //
+ // If this is a unique name, complete the request now.
+ //
+
+ if (UiFrame->Data2High == NETBIOS_NAME_TYPE_UNIQUE) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfCompleteRequest(Request, STATUS_SUCCESS, Request->BytesWritten);
+
+ }
+
+ NbfDereferenceRequest ("NR processed", Request, RREF_FIND_NAME);
+ return STATUS_SUCCESS;
+
+} /* NbfProcessQueryNameRecognized */
+
+
+VOID
+NbfSendStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request,
+ IN PHARDWARE_ADDRESS DestinationAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will send a STATUS.NAME packet for the specified
+ find name request, and start the request timer.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context to send the status query on.
+
+ Request - The find name request.
+
+ DestinationAddress - The hardware destination address of the frame.
+
+ SourceRouting - Optional source routing information in the frame.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ TDI_ADDRESS_NETBIOS UNALIGNED * remoteAddress;
+ PIO_STACK_LOCATION irpSp;
+ NTSTATUS Status;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+ UINT HeaderLength;
+ LARGE_INTEGER Timeout;
+ UCHAR RequestType;
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+
+ remoteAddress = NbfParseTdiAddress(
+ ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)(&irpSp->Parameters))->
+ RequestConnectionInformation->RemoteAddress, FALSE);
+
+ //
+ // Start the timer for this request.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Find Name: timer", Request, RREF_TIMER); // one for the timer
+ Timeout.LowPart = (ULONG)(-(LONG)DeviceContext->GeneralTimeout);
+ Timeout.HighPart = -1;
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+
+ //
+ // Allocate a UI frame from the pool.
+ //
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint2 ("NbfSendFindNames: Sending Frame: %lx, NdisPacket: %lx\n",
+ RawFrame, RawFrame->NdisPacket);
+ }
+
+
+ //
+ // Build the MAC header. STATUS_QUERY frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ RawFrame->Header,
+ DeviceContext->NetBIOSAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS),
+ SingleSR,
+ SingleSRLength,
+ &HeaderLength);
+
+
+ //
+ // Build the DLC UI frame header.
+ //
+
+ NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]);
+ HeaderLength += sizeof(DLC_FRAME);
+
+
+ //
+ // Build the Netbios header.
+ //
+
+ //
+ // Determine what RequestType should be.
+ //
+
+ if (Request->BytesWritten == 0) {
+
+ //
+ // No way to know if he is 2.1 or not, so we put a 1 here
+ // instead of 0.
+ //
+
+ RequestType = 1;
+
+ } else {
+
+ RequestType = (UCHAR)((Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER));
+
+ }
+
+ ConstructStatusQuery (
+ (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]),
+ RequestType, // request status type.
+ (USHORT)Request->Buffer2Length, // user's buffer length
+ Request->FrameContext, // corr. in 1st NAME_RECOGNIZED.
+ (PNAME)remoteAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress);
+
+ HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS);
+
+
+ //
+ // Munge the packet length.
+ //
+
+ NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback (MC frame)
+
+} /* NbfSendStatusQuery */
+
+
+NTSTATUS
+NbfProcessStatusResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a STATUS.RESPONSE packet.
+
+Arguments:
+
+ DeviceContext - a pointer to the device context the frame was received on.
+
+ ReceiveContext - The context for calling NdisTransferData.
+
+ UiFrame - The packet in question, starting at the Netbios header.
+
+ SourceAddress - The source hardware address of the packet.
+
+ SourceRouting - Source routing data in the query.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PUCHAR TargetBuffer;
+ USHORT FrameContext;
+ USHORT NamesReceived;
+ USHORT ResponseLength, ResponseBytesToCopy;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY linkage;
+ NDIS_STATUS ndisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_PACKET ndisPacket;
+ ULONG ndisBytesTransferred;
+ PRECEIVE_PACKET_TAG receiveTag;
+ NDIS_STATUS NdisStatus;
+
+
+ //
+ // Find the request that this is for, using the frame context.
+ //
+
+ FrameContext = TRANSMIT_CORR(UiFrame);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (p=DeviceContext->StatusQueryQueue.Flink;
+ p != &DeviceContext->StatusQueryQueue;
+ p=p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->FrameContext == FrameContext) {
+
+ break;
+
+ }
+
+ }
+
+ if (p == &DeviceContext->StatusQueryQueue) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ NbfReferenceRequest ("Status Response", Request, RREF_STATUS);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ //
+ // Make sure this request is not stopping.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Stopping", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is packet has new data.
+ //
+
+ if (Request->BytesWritten == 0) {
+
+ NamesReceived = 0;
+
+ } else {
+
+ NamesReceived = (USHORT)(Request->BytesWritten - sizeof(ADAPTER_STATUS)) / sizeof(NAME_BUFFER);
+
+ }
+
+ if ((UiFrame->Data1 > 0) && (UiFrame->Data1 <= NamesReceived)) {
+
+ //
+ // If it is a post-2.1 response, but we already got
+ // this data, ignore it.
+ //
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Duplicate SR", Request, RREF_STATUS);
+ return STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // This is new data, append if there is room.
+ //
+
+ ResponseLength = ((UiFrame->Data2High & 0x3f) * 256) + UiFrame->Data2Low;
+
+ if ((ULONG)(Request->BytesWritten + ResponseLength) >
+ Request->Buffer2Length) {
+
+ ResponseBytesToCopy = (USHORT)(Request->Buffer2Length - Request->BytesWritten);
+
+ } else {
+
+ ResponseBytesToCopy = ResponseLength;
+
+ }
+
+ //
+ // Allocate a receive packer for this operation.
+ //
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ ndisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+
+ //
+ // Could not get a packet, oh well, it is connectionless.
+ //
+
+ DeviceContext->ReceivePacketExhausted++;
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ receiveTag = (PRECEIVE_PACKET_TAG)(ndisPacket->ProtocolReserved);
+ receiveTag->PacketType = TYPE_STATUS_RESPONSE;
+ receiveTag->Connection = (PTP_CONNECTION)Request;
+
+ TargetBuffer = (PUCHAR)Request->ResponseBuffer + Request->BytesWritten;
+
+ //
+ // Allocate an MDL to describe the part of the buffer we
+ // want transferred.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ TargetBuffer,
+ ResponseBytesToCopy);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ linkage,
+ &DeviceContext->Interlock);
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Assume success, if not we fail the request.
+ //
+
+ Request->BytesWritten += ResponseBytesToCopy;
+
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ NdisChainBufferAtFront(ndisPacket, NdisBuffer);
+
+ //
+ // See if the response was too big (we can complete the
+ // request here since we still reference it).
+ //
+
+ if ((ResponseLength > ResponseBytesToCopy) ||
+ (UiFrame->Data2High & 0x40)) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ receiveTag->CompleteReceive = TRUE;
+ receiveTag->EndOfMessage = FALSE;
+
+ } else {
+
+ //
+ // If we are done, complete the packet, otherwise send off
+ // the next request (unless it is a pre-2.1 response).
+ //
+
+ if ((UiFrame->Data1 > 0) && (UiFrame->Data2High & 0x80)) {
+
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+
+ receiveTag->CompleteReceive = FALSE;
+
+ //
+ // Try to cancel the timer, no harm if we fail.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
+
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ if (KeCancelTimer (&Request->Timer)) {
+ NbfDereferenceRequest ("Status Response: stop timer", Request, RREF_TIMER);
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Request->Retries = DeviceContext->GeneralRetries;
+
+ //
+ // Send a STATUS_QUERY directed.
+ //
+
+ if (SourceRouting != NULL) {
+
+ RtlCopyMemory(
+ TempSR,
+ SourceRouting,
+ SourceRoutingLength);
+
+ MacCreateNonBroadcastReplySR(
+ &DeviceContext->MacInfo,
+ TempSR,
+ SourceRoutingLength,
+ &ResponseSR);
+
+ } else {
+
+ ResponseSR = NULL;
+
+ }
+
+ NbfSendStatusQuery(
+ DeviceContext,
+ Request,
+ SourceAddress,
+ ResponseSR,
+ SourceRoutingLength);
+
+ } else {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ receiveTag->CompleteReceive = TRUE;
+ receiveTag->EndOfMessage = TRUE;
+
+ }
+
+ }
+
+ //
+ // Now do the actual data transfer.
+ //
+
+ NdisTransferData (
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ DeviceContext->MacInfo.TransferDataOffset +
+ 3 + sizeof(NBF_HDR_CONNECTIONLESS),
+ ResponseBytesToCopy,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ if (ndisStatus != NDIS_STATUS_PENDING) {
+
+ NbfTransferDataComplete(
+ (NDIS_HANDLE)DeviceContext,
+ ndisPacket,
+ ndisStatus,
+ ndisBytesTransferred);
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfProcessStatusResponse */
+
+
+NTSTATUS
+NbfTdiSetInformation(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Irp); // prevent compiler warnings
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbfTdiQueryInformation */
+
+#if 0
+
+NTSTATUS
+NbfQueryInfoEndpoint(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_ENDPOINT_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified endpoint.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_ENDPOINT_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
+
+ *InfoBuffer = Endpoint->Information; // structure copy.
+
+ RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Endpoint->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoEndpoint */
+
+
+NTSTATUS
+NbfQueryInfoConnection(
+ IN PTP_CONNECTION Connection,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_CONNECTION_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified connection.
+
+Arguments:
+
+ Connection - Pointer to transport connection object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_CONNECTION_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ *InfoBuffer = Connection->Information; // structure copy.
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Connection->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoConnection */
+
+
+NTSTATUS
+NbfQueryInfoAddress(
+ IN PTP_ADDRESS Address,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_ADDRESS_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified address. We
+ don't acquire a spinlock in this routine because there are no statistics
+ which must be read atomically.
+
+Arguments:
+
+ Address - Pointer to transport address object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ SHORT i;
+ PSZ p, q;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ //
+ // Calculate whether his buffer is big enough to return the entire
+ // information. The total size of the address information is the
+ // size of the fixed part, plus the size of the variable-length flat
+ // string in the NETWORK_NAME component of the TRANSPORT_ADDRESS
+ // component.
+ //
+
+ if (InfoBufferLength <
+ sizeof (TDI_ADDRESS_INFO) +
+ Address->NetworkName.Length)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy both the fixed part of the address information, and the variable
+ // part. The variable part comes from the NETWORK_NAME component of the
+ // TRANSPORT_ADDRESS structure. This component contains a FLAT_STRING,
+ // which is of variable length.
+ //
+
+ InfoBuffer->Address.AddressComponents = Address->AddressComponents;
+ InfoBuffer->Address.Tsap = Address->Tsap;
+
+ InfoBuffer->Address.NetworkName.Name.Length =
+ Address->NetworkName.Length;
+
+ p = Address->NetworkName.Buffer; // p = ptr, source string.
+ q = InfoBuffer->Address.NetworkName.Name.Buffer; // q = ptr, dest string.
+ for (i=0; i<InfoBuffer->Address.NetworkName.Name.Length; i++) {
+ *(q++) = *(p++);
+ }
+
+ *InformationSize = sizeof (TDI_ADDRESS_INFO) +
+ Address->NetworkName.Length;
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoAddress */
+
+
+NTSTATUS
+NbfQueryInfoProvider(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_PROVIDER_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context for provider.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ if (InfoBufferLength < sizeof (TDI_PROVIDER_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+
+ *InfoBuffer = Provider->Information; // structure copy.
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ *InformationSize = sizeof (Provider->Information);
+
+ return STATUS_SUCCESS;
+} /* NbfQueryInfoProvider */
+
+
+NTSTATUS
+NbfQueryInfoNetman(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_NETMAN_INFO InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns information for the specified network-managable
+ variable managed by the transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context for provider.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PFLAT_STRING p;
+ PTP_VARIABLE v;
+ PTDI_NETMAN_VARIABLE n;
+ USHORT i;
+ ULONG NameOffset, ValueOffset;
+
+ TdiRequest, TdiRequestLength; // prevent compiler warnings
+ InfoBufferLength, InformationSize;
+
+ //
+ // check param lengths here.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+ NbfReferenceDeviceContext ("Query InfoNetMan", Provider, DCREF_QUERY_INFO);
+ for (v=Provider->NetmanVariables; v != NULL; v=v->Fwdlink) {
+ if (TdiRequest->Identification == v->VariableSerialNumber) {
+
+ //
+ // Return the variable information here.
+ //
+
+ NameOffset = sizeof (TDI_NETMAN_INFO);
+ ValueOffset = NameOffset + (sizeof (FLAT_STRING)-1) +
+ v->VariableName.Length;
+
+ InfoBuffer->VariableName = NameOffset;
+ InfoBuffer->VariableValue = ValueOffset;
+
+ //
+ // Copy the variable name to the user's buffer.
+ //
+
+ p = (PFLAT_STRING)((PUCHAR)InfoBuffer + NameOffset);
+ p->MaximumLength = v->VariableName.Length;
+ p->Length = v->VariableName.Length;
+ for (i=0; i<v->VariableName.Length; i++) {
+ p->Buffer [i] = v->VariableName.Buffer [i];
+ }
+
+ //
+ // Now copy the variable's contents to the user's buffer.
+ //
+
+ n = (PTDI_NETMAN_VARIABLE)((PUCHAR)InfoBuffer + ValueOffset);
+ n->VariableType = v->VariableType;
+
+ switch (v->VariableType) {
+
+ case NETMAN_VARTYPE_ULONG:
+ n->Value.LongValue = v->Value.LongValue;
+ break;
+
+ case NETMAN_VARTYPE_HARDWARE_ADDRESS:
+ n->Value.HardwareAddressValue =
+ v->Value.HardwareAddressValue;
+ break;
+
+ case NETMAN_VARTYPE_STRING:
+ p = &n->Value.StringValue;
+ p->MaximumLength = v->Value.StringValue.Length;
+ p->Length = v->Value.StringValue.Length;
+ for (i=0; i<v->Value.StringValue.Length; i++) {
+ p->Buffer [i] = v->Value.StringValue.Buffer [i];
+ }
+
+ } /* switch */
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+ NbfDereferenceDeviceContext ("Query InfoNetMan success", Provider, DCREF_QUERY_INFO);
+ return STATUS_SUCCESS;
+ } /* if */
+ } /* for */
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Query InfoNetMan no exist", Provider, DCREF_QUERY_INFO);
+
+ return STATUS_INVALID_INFO_CLASS; // variable does not exist.
+} /* NbfQueryInfoNetman */
+
+
+NTSTATUS
+NbfSetInfoEndpoint(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified endpoint.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_ENDPOINT_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_ENDPOINT_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_ENDPOINT_INFO)&TdiRequest->InfoBuffer;
+
+ if ((InfoBuffer->MinimumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
+ (InfoBuffer->MaximumLookaheadData <= NBF_MAX_LOOKAHEAD_DATA) ||
+ (InfoBuffer->MinimumLookaheadData > InfoBuffer->MaximumLookaheadData)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Endpoint->SpinLock, &oldirql);
+
+ //
+ // Set minimum lookahead data size. This is the number of bytes of
+ // contiguous data that will be supplied to TDI_IND_RECEIVE and
+ // TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
+ //
+
+ Endpoint->Information.MinimumLookaheadData = InfoBuffer->MinimumLookaheadData;
+
+ //
+ // Set maximum lookahead data size. This is the number of bytes of
+ // contiguous data that will be supplied to TDI_IND_RECEIVE and
+ // TDI_IND_RECEIVE_DATAGRAM event handlers at indication time.
+ //
+
+ Endpoint->Information.MaximumLookaheadData = InfoBuffer->MaximumLookaheadData;
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Endpoint->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Endpoint->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Endpoint->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Endpoint->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Endpoint->Information.PriorityLevel = InfoBuffer->PriorityLevel;
+ Endpoint->Information.SecurityLevel = InfoBuffer->SecurityLevel;
+ Endpoint->Information.SecurityCompartment = InfoBuffer->SecurityCompartment;
+
+ //
+ // The State and Event fields are read-only, so we DON'T set them here.
+ //
+
+ RELEASE_SPIN_LOCK (&Endpoint->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoEndpoint */
+
+
+NTSTATUS
+NbfSetInfoAddress(
+ IN PTP_ADDRESS Address,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified address. Currently,
+ all the user-visible fields in the transport address object are read-only.
+
+Arguments:
+
+ Address - Pointer to transport address object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ Address, TdiRequest, TdiRequestLength; // prevent compiler warnings
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoAddress */
+
+
+NTSTATUS
+NbfSetInfoConnection(
+ IN PTP_CONNECTION Connection,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified connection.
+
+Arguments:
+
+ Connection - Pointer to transport connection object.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_CONNECTION_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_CONNECTION_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_CONNECTION_INFO)&TdiRequest->InfoBuffer;
+
+ ACQUIRE_C_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Connection->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Connection->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Connection->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Connection->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+
+ //
+ // The State and Event fields are read-only, so we DON'T set them here.
+ //
+
+ RELEASE_C_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoConnection */
+
+
+NTSTATUS
+NbfSetInfoProvider(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQUEST_KERNEL TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified transport provider.
+
+Arguments:
+
+ Provider - Pointer to device context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTDI_PROVIDER_INFO InfoBuffer;
+
+ if (TdiRequestLength !=
+ sizeof (TDI_PROVIDER_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_PROVIDER_INFO)&TdiRequest->InfoBuffer;
+
+ //
+ // By changing the service flags the caller can request additional
+ // or fewer services on the fly. Make sure that he is requesting
+ // services we can provide, or else fail the request.
+ //
+
+ if (InfoBuffer->ServiceFlags & ~NBF_SERVICE_FLAGS) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Provider->SpinLock, &oldirql);
+
+ //
+ // Reset all the statistics to his new values.
+ //
+
+ Provider->Information.TransmittedTsdus = InfoBuffer->TransmittedTsdus;
+ Provider->Information.ReceivedTsdus = InfoBuffer->ReceivedTsdus;
+ Provider->Information.TransmissionErrors = InfoBuffer->TransmissionErrors;
+ Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Provider->Information.DiscardedFrames = InfoBuffer->DiscardedFrames;
+ Provider->Information.ReceiveErrors = InfoBuffer->ReceiveErrors;
+ Provider->Information.OversizeTsdusReceived = InfoBuffer->OversizeTsdusReceived;
+ Provider->Information.UndersizeTsdusReceived = InfoBuffer->UndersizeTsdusReceived;
+ Provider->Information.MulticastTsdusReceived = InfoBuffer->MulticastTsdusReceived;
+ Provider->Information.BroadcastTsdusReceived = InfoBuffer->BroadcastTsdusReceived;
+ Provider->Information.MulticastTsdusTransmitted = InfoBuffer->MulticastTsdusTransmitted;
+ Provider->Information.BroadcastTsdusTransmitted = InfoBuffer->BroadcastTsdusTransmitted;
+ Provider->Information.SendTimeouts = InfoBuffer->SendTimeouts;
+ Provider->Information.ReceiveTimeouts = InfoBuffer->ReceiveTimeouts;
+ Provider->Information.ConnectionIndicationsReceived = InfoBuffer->ConnectionIndicationsReceived;
+ Provider->Information.ConnectionIndicationsAccepted = InfoBuffer->ConnectionIndicationsAccepted;
+ Provider->Information.ConnectionsInitiated = InfoBuffer->ConnectionsInitiated;
+ Provider->Information.ConnectionsAccepted = InfoBuffer->ConnectionsAccepted;
+
+ //
+ // The following fields are read-only, so we DON'T set them here:
+ // Version, MaxTsduSize, MaxConnectionUserData, MinimumLookaheadData,
+ // MaximumLookaheadData.
+ //
+
+ RELEASE_SPIN_LOCK (&Provider->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoProvider */
+
+
+NTSTATUS
+NbfSetInfoNetman(
+ IN PDEVICE_CONTEXT Provider,
+ IN PTDI_REQ_SET_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets information for the specified transport provider's
+ network-managable variable.
+
+Arguments:
+
+ Provider - Pointer to device context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTDI_NETMAN_INFO InfoBuffer;
+
+ Provider; // prevent compiler warnings
+
+ if (TdiRequestLength !=
+ sizeof (TDI_NETMAN_INFO) + sizeof (TDI_REQ_SET_INFORMATION) -
+ sizeof (TDI_INFO_BUFFER)) {
+ return STATUS_BUFFER_TOO_SMALL; // buffer sizes must match.
+ }
+
+ InfoBuffer = (PTDI_NETMAN_INFO)&TdiRequest->InfoBuffer;
+
+ //
+ // BUGBUG: set the network-managable variable here.
+ //
+
+ return STATUS_SUCCESS;
+} /* NbfSetInfoNetman */
+
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_QUERY_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength,
+ OUT PTDI_INFO_BUFFER InfoBuffer,
+ IN ULONG InfoBufferLength,
+ OUT PULONG InformationSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+ InfoBuffer - Pointer to output buffer to return information into.
+
+ InfoBufferLength - Length of output buffer.
+
+ InformationSize - Pointer to ulong where actual size of returned
+ information is to be stored.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_CONNECTION Connection;
+
+ switch (TdiRequest->InformationClass) {
+
+ //
+ // ENDPOINT information: return information about the endpoint
+ // to which this request was submitted.
+ //
+
+ case TDI_INFO_CLASS_ENDPOINT:
+ Status = NbfQueryInfoEndpoint (
+ Endpoint,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_ENDPOINT_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // CONNECTION information: return information about a connection
+ // that is associated with the endpoint on which this request was
+ // submitted.
+ //
+
+ case TDI_INFO_CLASS_CONNECTION:
+ // This causes a connection reference which is removed below.
+ Connection = NbfLookupConnectionById (
+ Endpoint,
+ TdiRequest->Identification);
+ if (Connection == NULL) {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ Status = NbfQueryInfoConnection (
+ Connection,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_CONNECTION_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+
+ NbfDereferenceConnection("Query Connection Info", Connection, CREF_BY_ID);
+ break;
+
+ //
+ // ADDRESS information: return information about the address object
+ // that is associated with the endpoint on which this request was
+ // submitted.
+ //
+
+ case TDI_INFO_CLASS_ADDRESS:
+ Status = NbfQueryInfoAddress (
+ Endpoint->BoundAddress,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_ADDRESS_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // PROVIDER information: return information about the transport
+ // provider itself.
+ //
+
+ case TDI_INFO_CLASS_PROVIDER:
+ Status = NbfQueryInfoProvider (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_PROVIDER_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ //
+ // NETMAN information: return information about the network-managable
+ // variables managed by the provider itself.
+ //
+
+ case TDI_INFO_CLASS_NETMAN:
+ Status = NbfQueryInfoNetman (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength,
+ (PTDI_NETMAN_INFO)InfoBuffer,
+ InfoBufferLength,
+ InformationSize);
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+
+ } /* switch */
+
+ return Status;
+} /* TdiQueryInformation */
+
+
+NTSTATUS
+TdiSetInformation(
+ IN PTP_ENDPOINT Endpoint,
+ IN PTDI_REQ_SET_INFORMATION TdiRequest,
+ IN ULONG TdiRequestLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Endpoint - Pointer to transport endpoint context.
+
+ TdiRequest - Pointer to request buffer.
+
+ TdiRequestLength - Length of request buffer.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTP_CONNECTION Connection;
+
+ switch (TdiRequest->InformationClass) {
+
+ //
+ // ENDPOINT information: set information on the endpoint
+ // to which this request was submitted.
+ //
+
+ case TDI_INFO_CLASS_ENDPOINT:
+ Status = NbfSetInfoEndpoint (
+ Endpoint,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // CONNECTION information: set information for a connection
+ // that is associated with the endpoint on which this request
+ // was submitted.
+ //
+
+ case TDI_INFO_CLASS_CONNECTION:
+ // This causes a connection reference which is removed below.
+ Connection = NbfLookupConnectionById (
+ Endpoint,
+ TdiRequest->Identification);
+ if (Connection == NULL) {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ Status = NbfSetInfoConnection (
+ Connection,
+ TdiRequest,
+ TdiRequestLength);
+
+ NbfDereferenceConnection("Set Connection Info", Connection, CREF_BY_ID);
+ break;
+
+ //
+ // ADDRESS information: set information for the address object
+ // that is associated with the endpoint on which this request
+ // was submitted.
+ //
+
+ case TDI_INFO_CLASS_ADDRESS:
+ Status = NbfSetInfoAddress (
+ Endpoint->BoundAddress,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // PROVIDER information: set information for the transport
+ // provider itself.
+ //
+
+ case TDI_INFO_CLASS_PROVIDER:
+ Status = NbfSetInfoProvider (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ //
+ // NETMAN information: set information for the network-managable
+ // variables managed by the provider itself.
+ //
+
+ case TDI_INFO_CLASS_NETMAN:
+ Status = NbfSetInfoNetman (
+ Endpoint->BoundAddress->Provider,
+ TdiRequest,
+ TdiRequestLength);
+ break;
+
+ default:
+ Status = STATUS_INVALID_INFO_CLASS;
+
+ } /* switch */
+
+ return Status;
+} /* TdiSetInformation */
+
+#endif
diff --git a/private/ntos/tdi/nbf/link.c b/private/ntos/tdi/nbf/link.c
new file mode 100644
index 000000000..e99bbb8f4
--- /dev/null
+++ b/private/ntos/tdi/nbf/link.c
@@ -0,0 +1,2315 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ link.c
+
+Abstract:
+
+ This module contains code which implements the TP_LINK object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport link objects.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+extern ULONG StartTimerLinkDeferredAdd;
+extern ULONG StartTimerLinkDeferredDelete;
+
+#if DBG
+// The following is here for debugging purposes to make it easy to change
+// the maximum packet size.
+
+ULONG MaxUserPacketData = 18000;
+#endif
+
+#if 0
+
+VOID
+DisconnectCompletionHandler(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called as an I/O completion handler at the time a
+ TdiDisconnect request is completed. Here we dereference the link
+ object, and optionally reference it again and start up the link if
+ some transport connection started up on the link during the time we
+ were trying to shut it down.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("DisconnectCompletionHandler: Entered for link %lx.\n",
+ TransportLink);
+ }
+
+ //
+ // The following call will dereference this link for the last time,
+ // unless another transport connection has been assigned to the link
+ // during the time the data link layer was bringing the link down and
+ // when we got here. If this condition exists, then now is the time
+ // to bring the link back up, else destroy it.
+ //
+
+ // BUGBUG: don't forget to check for bringing it back up again.
+
+ // BUGBUG: Is this right??? - ADB 6/26
+
+ NbfDereferenceLink ("Disconnecting", TransportLink, LREF_CONNECTION); // this makes it go away.
+#if DBG
+ NbfPrint0("Disconnecting Completion Handler\n");
+#endif
+
+} /* DisconnectCompletionHandler */
+#endif
+
+
+VOID
+NbfCompleteLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the UA-r/x handler, NbfWaitLink, and
+ NbfActivateLink to startup the NBF connections associated with
+ a link because they were waiting for the link to become established.
+
+ When we get here, the link has been established, so we need to
+ start the next set of connection-establishment protocols:
+
+ SESSION_INIT ----------------->
+ <----------------- SESSION_CONFIRM
+
+ (TdiConnect completes) (TdiListen completes)
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION Connection;
+ BOOLEAN TimerWasCleared;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCompleteLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ //
+ // Officially declare that this link is ready for I-frame business.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // We can now send and receive I-frames on this link. We are in ABME.
+ //
+
+ //
+ // This probably isn't necessary, but to be safe for now.. (adb 6/28)
+ //
+ if (Link->State == LINK_STATE_ADM) {
+ // Moving out of ADM, add special reference
+ NbfReferenceLinkSpecial("To READY in NbfCompleteLink", Link, LREF_NOT_ADM);
+ }
+
+ Link->State = LINK_STATE_READY;
+ Link->SendState = SEND_STATE_READY;
+ Link->ReceiveState = RECEIVE_STATE_READY;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // Complete all of the listens first, so they will be expecting
+ // incoming SESSION_INITIALIZEs. Then do the connects.
+ //
+
+ // This creates a connection reference which is removed below.
+ while ((Connection=NbfLookupPendingListenOnLink (Link)) != NULL) {
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // This loop looks unnecessary, let's make sure... - adb 9/11/91
+ //
+ ASSERT(Connection->Flags & CONNECTION_FLAGS_WAIT_SI);
+
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SI; // wait session initialize.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("Pending listen", Connection, CREF_P_LINK);
+ } /* while */
+
+ //
+ // And do the connects. If there are connections in progress, they'll
+ // also have timers associated with them. Cancel those timers.
+ //
+
+ while ((Connection=NbfLookupPendingConnectOnLink (Link)) != NULL) {
+ TimerWasCleared = KeCancelTimer (&Connection->Timer);
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfCompleteLink: Timer for connection %lx %s canceled.\n",
+ Connection, TimerWasCleared ? "was" : "was NOT" );
+ }
+ if (TimerWasCleared) {
+ NbfDereferenceConnection("Cancel timer", Connection, CREF_TIMER);
+ }
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ Connection->Flags |= CONNECTION_FLAGS_WAIT_SC; // wait session confirm.
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // No timeout for this frame is required since the link is responsible
+ // for reliable delivery. If we can't send this frame, however, the
+ // data link connection will happily keep quiet without timeouts.
+ //
+
+ NbfSendSessionInitialize (Connection);
+ NbfDereferenceConnection ("NbfCompleteLink", Connection, CREF_P_CONNECT);
+ } /* while */
+
+} /* NbfCompleteLink */
+
+
+VOID
+NbfAllocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_LINK *TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a data link connection. It
+ performs minimal initialization of the object.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ TransportLink - Pointer to a place where this routine will return a
+ pointer to an allocated transport link structure. Returns
+ NULL if no storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_LINK Link;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_LINK)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate link: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 105,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ *TransportLink = NULL;
+ return;
+ }
+ Link = (PTP_LINK)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_LINK),
+ 'lFBN');
+ if (Link == NULL) {
+ PANIC("NBF: Could not allocate link: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 205,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ *TransportLink = NULL;
+ return;
+ }
+ RtlZeroMemory (Link, sizeof(TP_LINK));
+
+ ++DeviceContext->LinkAllocated;
+ DeviceContext->MemoryUsage += sizeof(TP_LINK);
+
+ Link->Type = NBF_LINK_SIGNATURE;
+ Link->Size = sizeof (TP_LINK);
+
+ KeInitializeSpinLock (&Link->SpinLock);
+ Link->Provider = DeviceContext;
+ Link->ProviderInterlock = &DeviceContext->Interlock;
+
+ InitializeListHead (&Link->Linkage);
+ InitializeListHead (&Link->ConnectionDatabase);
+ InitializeListHead (&Link->WackQ);
+ InitializeListHead (&Link->NdisSendQueue);
+ InitializeListHead (&Link->ShortList);
+ Link->OnShortList = FALSE;
+ InitializeListHead (&Link->LongList);
+ Link->OnLongList = FALSE;
+ InitializeListHead (&Link->PurgeList);
+
+ Link->T1 = 0; // 0 indicates they are not in the list
+ Link->T2 = 0;
+ Link->Ti = 0;
+
+ NbfAddSendPacket (DeviceContext);
+ NbfAddReceivePacket (DeviceContext);
+
+ *TransportLink = Link;
+
+} /* NbfAllocateLink */
+
+
+VOID
+NbfDeallocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a data link connection.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ TransportLink - Pointer to the transport link structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportLink);
+ --DeviceContext->LinkAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_LINK);
+
+ NbfRemoveSendPacket (DeviceContext);
+ NbfRemoveReceivePacket (DeviceContext);
+
+} /* NbfDeallocateLink */
+
+
+NTSTATUS
+NbfCreateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS HardwareAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN USHORT LoopbackLinkIndex,
+ OUT PTP_LINK *TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a data link connection between the local
+ data link station and the specified remote data link address.
+ As an option (Passive=TRUE), the caller may specify that instead
+ of a Connect activity, a Listen is to be performed instead.
+
+ Normally, if a link to the remote address is not already active,
+ then a link object is allocated, the reference count in the link
+ is set to 1, and the reference count of the device context is
+ incremented.
+
+ If a link is already active to the remote address, then the existing
+ link object is referenced with NbfReferenceLink() so that it can be
+ shared between the transport connections.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ link.
+
+ HardwareAddress - Pointer to a HARDWARE_ADDRESS type containing the
+ hardware address of the REMOTE link station to connect to/listen for.
+
+ LoopbackLinkIndex - In the case that this turns out to be created
+ as one of the LoopbackLinks, this will indicate which one to
+ use.
+
+ TransportLink - Pointer to a place where this routine will return a
+ pointer to an allocated transport link structure.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PLIST_ENTRY p;
+ UCHAR TempSR[MAX_SOURCE_ROUTING];
+ PUCHAR ResponseSR;
+ USHORT i;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCreateLink: Entered, DeviceContext: %lx\n", DeviceContext);
+ }
+
+ //
+ // Walk the list of addresses to see if we already have a link to this
+ // remote address.
+ //
+
+ // This adds a reference if the link is found.
+
+ Link = NbfFindLink (DeviceContext, HardwareAddress->Address);
+
+
+ if (Link == (PTP_LINK)NULL) {
+
+ //
+ // If necessary, check whether we are looking for one of
+ // the loopback links (NbfFindLink won't find those).
+ //
+
+ if (RtlEqualMemory(
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ Link = DeviceContext->LoopbackLinks[LoopbackLinkIndex];
+
+ if (Link != (PTP_LINK)NULL) {
+
+ //
+ // Add a reference to simulate the one from NbfFindLink
+ //
+ // BUGBUG: This needs to be atomically done with
+ // the assignment above.
+ //
+
+ NbfReferenceLink ("Found loopback link", Link, LREF_TREE);
+
+ } else {
+
+ //
+ // May have the first loopback link; need to make sure the
+ // buffer for indications is allocated.
+ //
+
+ if (DeviceContext->LookaheadContiguous == NULL) {
+
+ DeviceContext->LookaheadContiguous =
+ ExAllocatePoolWithTag (
+ NonPagedPool,
+ NBF_MAX_LOOPBACK_LOOKAHEAD,
+ ' FBN');
+ if (DeviceContext->LookaheadContiguous == NULL) {
+ PANIC ("NbfCreateLink: Could not allocate loopback buffer!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+ if (Link != (PTP_LINK)NULL) {
+
+ //
+ // Found the link structure here, so use the existing link.
+ //
+
+#if DBG
+ //
+ // These two operations have no net effect, so if not in debug
+ // mode we can remove them.
+ //
+
+ // This reference is removed by NbfDisconnectFromLink
+ // (this assumes that NbfConnectToLink is always called
+ // if this function returns success).
+
+ NbfReferenceLink ("New Ref, Found existing link", Link, LREF_CONNECTION); // extra reference.
+
+ // Now we can remove the NbfFindLinkInTree reference.
+
+ NbfDereferenceLink ("Found link in tree", Link, LREF_TREE);
+#endif
+
+ *TransportLink = Link; // return pointer to the link.
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfCreateLink: returning ptr to existing link object.\n");
+ }
+ return STATUS_SUCCESS; // all done.
+
+ } /* if LINK != NULL */
+
+
+ //
+ // We don't have an existing link, so we have to create one.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfCreateLink: using new link object.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ p = RemoveHeadList (&DeviceContext->LinkPool);
+ if (p == &DeviceContext->LinkPool) {
+
+ if ((DeviceContext->LinkMaxAllocated == 0) ||
+ (DeviceContext->LinkAllocated < DeviceContext->LinkMaxAllocated)) {
+
+ NbfAllocateLink (DeviceContext, &Link);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated link at %lx\n", Link);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 405,
+ sizeof(TP_LINK),
+ LINK_RESOURCE_ID);
+ Link = NULL;
+
+ }
+
+ if (Link == NULL) {
+ ++DeviceContext->LinkExhausted;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ PANIC ("NbfCreateConnection: Could not allocate link object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, Linkage);
+
+ }
+
+ ++DeviceContext->LinkInUse;
+ ASSERT(DeviceContext->LinkInUse > 0);
+
+ if (DeviceContext->LinkInUse > DeviceContext->LinkMaxInUse) {
+ ++DeviceContext->LinkMaxInUse;
+ }
+
+ DeviceContext->LinkTotal += DeviceContext->LinkInUse;
+ ++DeviceContext->LinkSamples;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfCreateLink: Link at %lx.\n", Link);
+ }
+
+ //
+ // Initialize all of the static data for this link.
+ //
+
+ Link->SpecialRefCount = 1;
+ Link->ReferenceCount = 0;
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_LREFS; Counter++) {
+ Link->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfDisconnectFromLink
+ // (this assumes that NbfConnectToLink is always called
+ // if this function returns success).
+ //
+
+ Link->RefTypes[LREF_CONNECTION] = 1;
+ Link->RefTypes[LREF_SPECIAL_TEMP] = 1;
+ }
+ Link->Destroyed = FALSE;
+ Link->TotalReferences = 0;
+ Link->TotalDereferences = 0;
+ Link->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalLinkList, &Link->GlobalLinkage, &NbfGlobalInterlock);
+ StoreLinkHistory (Link, TRUE);
+#endif
+ Link->Flags = 0; // in the beginning, the link is closed.
+ Link->DeferredFlags = 0;
+ Link->State = LINK_STATE_ADM; // async disconnected mode.
+
+ Link->NdisSendsInProgress = 0;
+ Link->ResendingPackets = FALSE;
+
+ //
+ // Initialize the counters
+ //
+
+ Link->FrmrsReceived = 0;
+ Link->FrmrsTransmitted = 0;
+ Link->ErrorIFramesReceived = 0;
+ Link->ErrorIFramesTransmitted = 0;
+ Link->AbortedTransmissions = 0;
+ Link->BuffersNotAvailable = 0;
+ Link->SuccessfulTransmits = 0;
+ Link->SuccessfulReceives = 0;
+ Link->T1Expirations = 0;
+ Link->TiExpirations = 0;
+
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+
+ //
+ // At first, the delay and throughput are unknown.
+ //
+
+ Link->Delay = 0xffffffff;
+ Link->Throughput.HighPart = 0xffffffff;
+ Link->Throughput.LowPart = 0xffffffff;
+ Link->ThroughputAccurate = FALSE;
+ Link->CurrentT1Backoff = FALSE;
+
+ Link->OnDeferredRrQueue = FALSE;
+ InitializeListHead (&Link->DeferredRrLinkage);
+
+
+ //
+ // Determine the maximum sized data frame that can be sent
+ // on this link, based on the source routing information and
+ // the size of the MAC header ("data frame" means the frame
+ // without the MAC header). We don't assume the worst case
+ // about source routing since we create a link in response
+ // to a received frame, so if there is no source routing it
+ // is because we are not going over a bridge. The exception
+ // is if we are creating a link to a group name, in which
+ // case we come back later and hack the MaxFrameSize in.
+ //
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->CurSendPacketSize,
+ FALSE,
+ (PUINT)&(Link->MaxFrameSize));
+
+
+#if DBG
+ if (Link->MaxFrameSize > MaxUserPacketData) {
+ Link->MaxFrameSize = MaxUserPacketData;
+ }
+#endif
+
+ // Link->Provider = DeviceContext;
+
+ //
+ // Build the default MAC header. I-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,
+ Link->Header,
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ 0, // PacketLength, filled in later
+ ResponseSR,
+ SourceRoutingLength,
+ (PUINT)&(Link->HeaderLength));
+
+ //
+ // We optimize for fourteen-byte headers by putting
+ // the correct Dsap/Ssap at the end, so we can fill
+ // in new packets as one 16-byte move.
+ //
+
+ if (Link->HeaderLength <= 14) {
+ Link->Header[Link->HeaderLength] = DSAP_NETBIOS_OVER_LLC;
+ Link->Header[Link->HeaderLength+1] = DSAP_NETBIOS_OVER_LLC;
+ }
+
+ Link->RespondToPoll = FALSE;
+ Link->NumberOfConnectors = 0;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfResetLink (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ Link->ActiveConnectionCount = 0;
+ if (!IsListEmpty(&Link->ConnectionDatabase)) {
+
+ //
+ // Not good; we've got something left over...
+ //
+#if DBG
+ NbfPrint1 ("NbfCreateLink: Link 0x%lx has connections at startup, disconnecting...\n", Link);
+ DbgBreakPoint();
+#endif
+ //
+ // BUGBUG: This won't work, the link ref count will be bad.
+ //
+ NbfStopLink (Link);
+ }
+
+ for (i=0; i<(USHORT)DeviceContext->MacInfo.AddressLength; i++) {
+ Link->HardwareAddress.Address[i] = HardwareAddress->Address[i];
+ }
+ MacReturnMagicAddress (&DeviceContext->MacInfo, HardwareAddress, &Link->MagicAddress);
+
+ //
+ // Determine if this is a loopback link.
+ //
+
+ if (RtlEqualMemory(
+ HardwareAddress->Address,
+ DeviceContext->LocalAddress.Address,
+ DeviceContext->MacInfo.AddressLength)) {
+
+ //
+ // Yes, just fill it in, no need to do deferred processing
+ // since this link does not go in the tree.
+ //
+
+ if (LoopbackLinkIndex == LISTENER_LINK) {
+ Link->LoopbackDestinationIndex = LOOPBACK_TO_CONNECTOR;
+ } else {
+ Link->LoopbackDestinationIndex = LOOPBACK_TO_LISTENER;
+ }
+
+ Link->Loopback = TRUE;
+ DeviceContext->LoopbackLinks[LoopbackLinkIndex] = Link;
+
+ } else {
+
+ Link->Loopback = FALSE;
+
+ //
+ // Now put the link in the deferred operations queue and go away. We'll
+ // insert this link in the tree at some future time (soon).
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfCreateLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
+ DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
+ Link->Flags);
+ }
+
+ //
+ // We should not have any deferred flags yet!
+ //
+
+ ASSERT ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) == 0) {
+ Link->DeferredFlags |= LINK_FLAGS_DEFERRED_ADD;
+ InsertTailList (&DeviceContext->LinkDeferred, &Link->DeferredList);
+
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredAdd++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ }
+ else {
+ Link->DeferredFlags = LINK_FLAGS_DEFERRED_ADD;
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredAdd++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfCreateLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ Link, Link->DeferredList.Flink, Link->DeferredList.Blink,
+ DeviceContext->LinkDeferred.Flink, DeviceContext->LinkDeferred.Blink,
+ Link->DeferredFlags);
+ }
+
+ }
+
+ NbfReferenceDeviceContext ("Create Link", DeviceContext, DCREF_LINK); // count refs to the device context.
+ *TransportLink = Link; // return a pointer to the link object.
+ return STATUS_SUCCESS;
+} /* NbfCreateLink */
+
+
+NTSTATUS
+NbfDestroyLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport link and removes all references
+ made to it by other objects in the transport. The link is expected
+ to still be on the splay tree of links. This routine merely marks the
+ link as needing to be deleted and pushes it onto the deferred operations
+ queue. The deferred operations processor actually removes the link from
+ tree and returns the link to pool.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_PACKET packet;
+ PLIST_ENTRY pkt;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfDestroyLink: Entered for link %lx.\n", TransportLink);
+ }
+
+#if DBG
+ if (TransportLink->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed link 0x%lx\n", TransportLink);
+ DbgBreakPoint ();
+ }
+ TransportLink->Destroyed = TRUE;
+#if 1
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&TransportLink->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#else
+ ExInterlockedRemoveHeadList (TransportLink->GlobalLinkage.Blink, &NbfGlobalInterlock);
+#endif
+#endif
+
+ DeviceContext = TransportLink->Provider;
+
+ //
+ // In case there's a holdover from the DISC link shutdown protocol
+ //
+
+ //
+ // We had better be in ADM, otherwise the reference count should
+ // be non-zero and what are we doing in NbfDestroyLink?
+ //
+
+ ASSERT(TransportLink->State == LINK_STATE_ADM);
+ // TransportLink->State = LINK_STATE_ADM;
+
+ StopT1 (TransportLink);
+ StopT2 (TransportLink);
+ StopTi (TransportLink);
+
+
+ //
+ // Make sure we are not in the deferred timer queue.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
+
+ if (TransportLink->OnShortList) {
+ TransportLink->OnShortList = FALSE;
+ RemoveEntryList (&TransportLink->ShortList);
+ }
+
+ if (TransportLink->OnLongList) {
+ TransportLink->OnLongList = FALSE;
+ RemoveEntryList (&TransportLink->LongList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
+
+ ASSERT (!TransportLink->OnDeferredRrQueue);
+
+ //
+ // Now free this link object's resources.
+ // BUGBUG: later, we'll spin through the WackQ and verify that sequencing
+ // is correct and we've gotten an implicit ack for these packets. This
+ // maybe should be handled in ResendLlcPackets for non-final, non-command
+ // packets.
+ //
+
+ while (!IsListEmpty (&TransportLink->WackQ)) {
+ pkt = RemoveHeadList (&TransportLink->WackQ);
+ packet = CONTAINING_RECORD (pkt, TP_PACKET, Linkage);
+#if DBG
+ // IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfDereferenceLink: Destroying packets on Link WackQ! %lx\n", packet);
+ // }
+#endif
+ NbfDereferencePacket (packet);
+
+ }
+
+ //
+ // The NDIS send queue should be empty!!
+ //
+
+ ASSERT (IsListEmpty (&TransportLink->NdisSendQueue));
+
+#if DBG
+ if (!IsListEmpty (&TransportLink->ConnectionDatabase)) {
+ NbfPrint1 ("NbfDestroyLink: link 0x%lx still has connections\n", TransportLink);
+ DbgBreakPoint ();
+ }
+#endif
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ DeviceContext->LinkTotal += DeviceContext->LinkInUse;
+ ++DeviceContext->LinkSamples;
+ ASSERT(DeviceContext->LinkInUse > 0);
+ --DeviceContext->LinkInUse;
+
+ ASSERT(DeviceContext->LinkAllocated > DeviceContext->LinkInUse);
+
+ if ((DeviceContext->LinkAllocated - DeviceContext->LinkInUse) >
+ DeviceContext->LinkInitAllocated) {
+ NbfDeallocateLink (DeviceContext, TransportLink);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated link at %lx\n", TransportLink);
+ }
+ } else {
+ InsertTailList (&DeviceContext->LinkPool, &TransportLink->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ NbfDereferenceDeviceContext ("Destroy Link", DeviceContext, DCREF_LINK); // just housekeeping.
+
+ return STATUS_SUCCESS;
+
+} /* NbfDestroyLink */
+
+
+VOID
+NbfDisconnectLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the data link provider to disconnect a data link
+ connection associated with a TP_LINK object.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfDisconnectLink: Entered for link %lx.\n", Link);
+ }
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+
+ if ((Link->Flags & LINK_FLAGS_LOCAL_DISC) != 0) {
+
+ Link->Flags &= ~LINK_FLAGS_LOCAL_DISC;
+
+ if (Link->State == LINK_STATE_ADM) {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ } else {
+
+ PLIST_ENTRY p;
+ PTP_PACKET packet;
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is in W_DISC_RSP.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+ }
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ }
+
+} /* NbfDisconnectLink */
+
+#if DBG
+
+VOID
+NbfRefLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport link. If we are
+ currently in the state waiting for disconnect response, we do not
+ reference; this avoids the link "bouncing" during disconnect (trying to
+ disconnect multiple times).
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfReferenceLink: Entered for link %lx, current level=%ld.\n",
+ TransportLink, TransportLink->ReferenceCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, TRUE );
+#endif
+
+ result = InterlockedIncrement (&TransportLink->ReferenceCount);
+
+ if (result == 0) {
+
+ //
+ // The first increment causes us to increment the
+ // "ref count is not zero" special ref.
+ //
+
+ NbfReferenceLinkSpecial ("first ref", TransportLink, LREF_SPECIAL_TEMP);
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* NbfRefLink */
+#endif
+
+
+VOID
+NbfDerefLink(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport link by decrementing the
+ reference count contained in the structure.
+
+ There are two special reference counts, 1 and 0. If, after dereferencing,
+ the reference count is one (1), then we initiate a disconnect protocol
+ sequence (DISC/UA) to terminate the connection. When this request
+ completes, the completion routine will dereference the link object again.
+ While this protocol is in progress, we will not allow the link to be
+ incremented again.
+
+ If the reference count becomes 0 after dereferencing, then we are in
+ the disconnection request completion handler, and we should actually
+ destroy the link object. We place the link on the deferred operations
+ queue and let the link get deleted later at a safe time.
+
+ Warning: Watch out for cases where a link is going down, and it is
+ suddenly needed again. Keep a bitflag for that in the link object.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfDereferenceLink: Entered for link %lx, current level=%ld.\n",
+ TransportLink, TransportLink->ReferenceCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, FALSE );
+#endif
+
+ result = InterlockedDecrement(&TransportLink->ReferenceCount);
+
+ //
+ // If all the normal references to this link are gone, then
+ // we can remove the special reference that stood for
+ // "the regular ref count is non-zero".
+ //
+
+
+ if (result < 0) {
+
+ //
+ // If the refcount is -1 we want to call DisconnectLink,
+ // we do this before removing the special ref so that
+ // the link does not go away during the call.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfDereferenceLink: refcnt=1, disconnecting Link object.\n");
+ }
+
+ NbfDisconnectLink (TransportLink);
+
+ //
+ // Now it is OK to let the link go away.
+ //
+
+ NbfDereferenceLinkSpecial ("Regular ref 0", TransportLink, LREF_SPECIAL_TEMP);
+
+ }
+
+} /* NbfDerefLink */
+
+
+VOID
+NbfRefLinkSpecial(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the special reference count on a transport link.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint3 ("NbfRefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
+ TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, TRUE );
+#endif
+
+ result = ExInterlockedAddUlong (
+ (PULONG)&TransportLink->SpecialRefCount,
+ 1,
+ TransportLink->ProviderInterlock);
+
+} /* NbfRefLinkSpecial */
+
+
+VOID
+NbfDerefLinkSpecial(
+ IN PTP_LINK TransportLink
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport link by decrementing the
+ special reference count contained in the structure.
+
+ The special reference may be decremented at any time, however
+ the effect of those dereferences only happen when the normal
+ reference count is 0, to prevent the link from going away
+ while the operations due to the ->0 transition of the
+ normal reference count are done.
+
+ If the special reference count becomes 0 after dereferencing, then we
+ are in the disconnection request completion handler, and we should actually
+ destroy the link object. We place the link on the deferred operations
+ queue and let the link get deleted later at a safe time.
+
+ Warning: Watch out for cases where a link is going down, and it is
+ suddenly needed again. Keep a bitflag for that in the link object.
+
+Arguments:
+
+ TransportLink - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ ULONG OldRefCount;
+ PDEVICE_CONTEXT DeviceContext = TransportLink->Provider;
+
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint3 ("NbfDerefLinkSpecial: Entered for link %lx, current level=%ld (%ld).\n",
+ TransportLink, TransportLink->ReferenceCount, TransportLink->SpecialRefCount);
+ }
+
+#if DBG
+ StoreLinkHistory( TransportLink, FALSE );
+#endif
+
+ //
+ // Links stay in the device context tree with a ref count
+ // of 0. Routines that scan this queue check the DEFERRED_DELETE
+ // flag, so we need to synchronize the decrementing of the
+ // ref count with setting that flag. DeviceContext->LinkSpinLock
+ // is used to synchronize this.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->LinkSpinLock, &oldirql1);
+
+ OldRefCount = ExInterlockedAddUlong (
+ (PULONG)&TransportLink->SpecialRefCount,
+ (ULONG)-1,
+ TransportLink->ProviderInterlock);
+
+ ASSERT (OldRefCount > 0);
+
+ if ((OldRefCount == 1) &&
+ (TransportLink->ReferenceCount == -1)) {
+
+ if (TransportLink->Loopback) {
+
+ //
+ // It is a loopback link, hence not in the link
+ // tree so we don't need to queue a deferred removal.
+ //
+
+ if (TransportLink == DeviceContext->LoopbackLinks[0]) {
+ DeviceContext->LoopbackLinks[0] = NULL;
+ } else if (TransportLink == DeviceContext->LoopbackLinks[1]) {
+ DeviceContext->LoopbackLinks[1] = NULL;
+ } else {
+#if DBG
+ NbfPrint0("Destroying unknown loopback link!!\n");
+#endif
+ ASSERT(FALSE);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ NbfDestroyLink (TransportLink);
+
+ } else {
+
+ //
+ // Not only are all transport connections gone, but the data link
+ // provider does not have a reference to this object, so we can
+ // safely delete it from the system. Make sure we haven't already
+ // been here before we try to insert this link.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfDerefLink: link to deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ TransportLink, TransportLink->DeferredList.Flink,
+ TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, TransportLink->Flags);
+ }
+
+ if ((TransportLink->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0) {
+
+ TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->TimerSpinLock, &oldirql);
+ InsertTailList (&DeviceContext->LinkDeferred, &TransportLink->DeferredList);
+ if (!(DeviceContext->a.i.LinkDeferredActive)) {
+ StartTimerLinkDeferredDelete++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.LinkDeferredActive = TRUE;
+ }
+ RELEASE_SPIN_LOCK (&DeviceContext->TimerSpinLock, oldirql);
+
+ } else {
+
+ TransportLink->DeferredFlags |= LINK_FLAGS_DEFERRED_DELETE;
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint0 ("NbfDereferenceLink: refcnt=0, link placed on deferred operations queue.\n");
+ }
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint6 ("NbfDerefLink: link on deferred queue %lx %lx %lx %lx %lx Flags: %lx \n",
+ TransportLink, TransportLink->DeferredList.Flink,
+ TransportLink->DeferredList.Blink, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, TransportLink->DeferredFlags);
+ }
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->LinkSpinLock, oldirql1);
+
+ }
+
+} /* NbfDerefLinkSpecial */
+
+
+NTSTATUS
+NbfAssignGroupLsn(
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a global LSN to the connection
+ in question. If successful, it fills in the connection's LSN
+ appropriately.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ STATUS_SUCCESS if we got an LSN for the connection;
+ STATUS_INSUFFICIENT_RESOURCES if we didn't.
+
+--*/
+
+{
+ KIRQL oldirql;
+ UCHAR Lsn;
+ PDEVICE_CONTEXT DeviceContext;
+ BOOLEAN FoundLsn = FALSE;
+
+ DeviceContext = TransportConnection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ //
+ // Scan through the device context tables to find an LSN that
+ // is not in use, starting with NextLsnStart+128.
+ //
+
+ Lsn = (UCHAR)DeviceContext->NextLsnStart;
+
+ do {
+
+ if (DeviceContext->LsnTable[Lsn] == 0) {
+ DeviceContext->LsnTable[Lsn] = LSN_TABLE_MAX;
+ FoundLsn = TRUE;
+ break;
+ }
+
+ Lsn = (Lsn % NETBIOS_SESSION_LIMIT) + 1;
+
+ } while (Lsn != DeviceContext->NextLsnStart);
+
+ DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
+
+ if (!FoundLsn) {
+
+ //
+ // Could not find an empty LSN; have to fail.
+ //
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ TransportConnection->Lsn = Lsn;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+NbfConnectToLink(
+ IN PTP_LINK Link,
+ IN PTP_CONNECTION TransportConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to establish a linkage between a transport
+ connection and a transport link. We find a session number in one
+ of two ways. If the last connection on the link's list has a number less
+ than the maximum session number, we simply increment it's number and
+ assign it to this session. If that doesn't work, we scan through the
+ sessions associated with this link until we find a hole in the LSNs;
+ we then use the first number in that hole. If that fails, we've used
+ the number of sessions we can create on this link and we fail.
+
+ It is assumed that the caller holds at least temporary references
+ on both the connection and link objects, or they could go away during
+ the call sequence or during this routine's execution.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ STATUS_SUCCESS if we got an LSN for the connection;
+ STATUS_INSUFFICIENT_RESOURCES if we didn't.
+
+--*/
+
+{
+ KIRQL oldirql;
+ UCHAR lastSession=0;
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+ PDEVICE_CONTEXT DeviceContext;
+ UCHAR Lsn;
+ BOOLEAN FoundLsn;
+
+ //
+ // Assign an LSN for a new connection. If this connection makes for more
+ // connections than the maximum, blow off the creation.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfConnectToLink: Entered for connection %lx, link %lx.\n",
+ TransportConnection, Link);
+ }
+
+ DeviceContext = Link->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql);
+#if DBG
+ if (!(IsListEmpty(&TransportConnection->LinkList)) ||
+ (TransportConnection->Link != NULL)) {
+ DbgPrint ("Connecting C %lx to L %lx, appears to be in use\n", TransportConnection, Link);
+ DbgBreakPoint();
+ }
+#endif
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0) {
+
+ //
+ // This connection is to a remote unique name, which means
+ // we need to assign the LSN here based on the link. We
+ // scan through our LSN table starting with NextLsnStart
+ // (which cycles from 1 to 64) to find an LSN which is not
+ // used by any connections on this link.
+ //
+
+ ASSERT (TransportConnection->Lsn == 0);
+
+ FoundLsn = FALSE;
+ Lsn = (UCHAR)DeviceContext->NextLsnStart;
+
+ //
+ // First scan through the database until we reach
+ // Lsn (or hit the end of the database).
+ //
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (connection->Lsn >= Lsn) {
+ break;
+ }
+ }
+
+ //
+ // p now points to the first element after Lsn's spot.
+ // We now scan forwards until we hit NETBIOS_SESSION_LIMIT,
+ // looking for an Lsn that is available.
+ //
+
+ for ( ; Lsn <= NETBIOS_SESSION_LIMIT; ++Lsn) {
+
+ //
+ // At some point (perhaps right away) we may
+ // pass the end of the database without finding
+ // an LSN. If we have not yet done this, see
+ // if we need to skip this lsn because it is
+ // in use by a connection on this link.
+ //
+
+ if (p != &Link->ConnectionDatabase) {
+ if (connection->Lsn == Lsn) {
+ p = p->Flink;
+ if (p != &Link->ConnectionDatabase) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ }
+ continue;
+ }
+ }
+
+ //
+ // This lsn is not in use on this link, see if
+ // there is room for it to be used.
+ //
+
+ if (DeviceContext->LsnTable[Lsn] < LSN_TABLE_MAX) {
+ ++(DeviceContext->LsnTable[Lsn]);
+ TransportConnection->Lsn = Lsn;
+ InsertTailList (p, &TransportConnection->LinkList);
+ FoundLsn = TRUE;
+ break;
+ }
+
+ }
+
+ DeviceContext->NextLsnStart = (DeviceContext->NextLsnStart % 64) + 1;
+
+ } else {
+
+ //
+ // This connection is to a group name; we already assigned
+ // the LSN on a global basis.
+ //
+
+ FoundLsn = TRUE;
+
+ //
+ // Find the spot for this LSN in the database.
+ //
+
+ p = Link->ConnectionDatabase.Flink;
+ while (p != &Link->ConnectionDatabase) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if (TransportConnection->Lsn < connection->Lsn) {
+ InsertTailList (p, &TransportConnection->LinkList);
+ break;
+ }
+ p = p->Flink;
+
+ }
+
+ if (p == &Link->ConnectionDatabase) {
+ InsertTailList (&Link->ConnectionDatabase, &TransportConnection->LinkList);
+ }
+
+ }
+
+ if (!FoundLsn) {
+
+ ULONG DumpData = NETBIOS_SESSION_LIMIT;
+
+ ASSERT (Link->ActiveConnectionCount == NETBIOS_SESSION_LIMIT);
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ PANIC ("NbfConnectToLink: PANIC! too many active connections!\n");
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TOO_MANY_LINKS,
+ 602,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 1,
+ &DumpData);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ TransportConnection->Link = Link;
+ TransportConnection->LinkSpinLock = &Link->SpinLock;
+ TransportConnection->Flags |= CONNECTION_FLAGS_WAIT_LINK_UP;
+
+ TransportConnection->LastPacketsSent = Link->PacketsSent;
+ TransportConnection->LastPacketsResent = Link->PacketsResent;
+
+ Link->ActiveConnectionCount++;
+
+ //
+ // Note that the connection is already inserted in the
+ // link's ConnectionDatabase.
+ //
+
+ // This reference is removed in NbfDisconnectFromLink
+ NbfReferenceConnection("Adding link", TransportConnection, CREF_LINK);
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql);
+
+ return STATUS_SUCCESS; // we did it!
+
+} /* NbfConnectToLink */
+
+
+BOOLEAN
+NbfDisconnectFromLink(
+ IN PTP_CONNECTION TransportConnection,
+ IN BOOLEAN VerifyReferenceCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate a linkage between a transport
+ connection and its associated transport link. If it turns out that
+ this is the last connection to be removed from this link, then the
+ link's disconnection protocol is engaged.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+ VerifyReferenceCount - TRUE if we should check that the refcount
+ is still -1 before removing the connection from the link.
+ If it is not, it means someone just referenced us and we
+ exit.
+
+Return Value:
+
+ FALSE if VerifyReferenceCount was TRUE but the refcount was
+ not -1; TRUE otherwise.
+
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_LINK Link;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint2 ("NbfDisconnectFromLink: Entered for connection %lx, link %lx.\n",
+ TransportConnection, TransportConnection->Link);
+ }
+
+ ACQUIRE_C_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+ Link = TransportConnection->Link;
+ if (Link != NULL) {
+
+ ACQUIRE_SPIN_LOCK (&Link->SpinLock, &oldirql1);
+
+ if ((VerifyReferenceCount) &&
+ (TransportConnection->ReferenceCount != -1)) {
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+ return FALSE;
+
+ }
+
+ TransportConnection->Link = NULL;
+ TransportConnection->LinkSpinLock = NULL;
+ RemoveEntryList (&TransportConnection->LinkList);
+#if DBG
+ InitializeListHead (&TransportConnection->LinkList);
+#endif
+
+ //
+ // If this was the last connection being serviced by this link,
+ // then we can shut the link down. It still has a reference
+ // from the device context, which will go away in the DM/UA
+ // DLC frame handler.
+ //
+
+ if (--Link->ActiveConnectionCount == 0) {
+
+ //
+ // only want to send DISC if the remote was NOT the originator
+ // of the disconnect.
+ //
+
+ if ((TransportConnection->Status == STATUS_LOCAL_DISCONNECT) ||
+ (TransportConnection->Status == STATUS_CANCELLED)) {
+
+ //
+ // This is a local disconnect of the last connection
+ // on the link, let's get the disconnect ball rolling.
+ //
+
+ Link->Flags |= LINK_FLAGS_LOCAL_DISC;
+
+ //
+ // When the link reference count drops down to 1,
+ // that will cause the DISC to get sent.
+ //
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Link->SpinLock, oldirql1);
+
+ //
+ // Clear these now that we are off the link's database.
+ //
+
+ NbfClearConnectionLsn (TransportConnection);
+ TransportConnection->Rsn = 0;
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) != 0) {
+
+ (VOID)InterlockedDecrement(&Link->NumberOfConnectors);
+ }
+
+ //
+ // All done with this connection's reference to link.
+ //
+
+ NbfDereferenceLink ("Disconnecting connection",Link, LREF_CONNECTION);
+
+ } else {
+
+ //
+ // A group LSN may have been assigned even though Link is NULL.
+ //
+
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) != 0) {
+ NbfClearConnectionLsn (TransportConnection);
+ }
+
+ RELEASE_C_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+ return TRUE;
+
+} /* NbfDisconnectFromLink */
+
+
+PTP_CONNECTION
+NbfLookupPendingListenOnLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the LSN database on a transport link object to find
+ a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
+ CONNECTION_FLAGS2_LISTENER flags set. It returns a pointer to the found
+ connection object (and simultaneously resets the LINK_UP flag) or NULL
+ if it could not be found. The reference count is also incremented
+ atomically on the connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_LISTENER) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found Pending Listen", connection, CREF_P_LINK);
+ connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return connection;
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ return NULL;
+
+} /* NbfLookupPendingListenOnLink */
+
+
+PTP_CONNECTION
+NbfLookupPendingConnectOnLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the LSN database on a transport link object to find
+ a TP_CONNECTION object which has the CONNECTION_FLAGS_WAIT_LINK_UP and
+ CONNECTION_FLAGS2_CONNECTOR flags set. It returns a pointer to the found
+ connection object (and simultaneously resets the LINK_UP flag) or NULL
+ if it could not be found. The reference count is also incremented
+ atomically on the connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ if ((connection->Flags & CONNECTION_FLAGS_WAIT_LINK_UP) &&
+ (connection->Flags2 & CONNECTION_FLAGS2_CONNECTOR) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_STOPPING) == 0)) {
+ // This reference is removed by the calling function
+ NbfReferenceConnection ("Found pending Connect", connection, CREF_P_CONNECT);
+ connection->Flags &= ~CONNECTION_FLAGS_WAIT_LINK_UP;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return connection;
+ }
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ return NULL;
+
+} /* NbfLookupPendingConnectOnLink */
+
+
+VOID
+NbfActivateLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine activates a link if it is not already active. The other
+ related routines, NbfCreateLink and NbfConnectToLink, simply set up data
+ structures which represent active links so that we can reuse links
+ wherever possible.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfActivateLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ switch (Link->State) {
+ case LINK_STATE_READY:
+ NbfCompleteLink (Link);
+ break;
+
+ case LINK_STATE_ADM:
+
+ // Moving out of ADM, add reference
+
+ NbfReferenceLinkSpecial("Wait on ADM", Link, LREF_NOT_ADM);
+
+ //
+ // Intentionally fall through to the next case.
+ //
+
+ case LINK_STATE_W_DISC_RSP:
+ case LINK_STATE_CONNECTING:
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ break;
+
+ }
+} /* NbfActivateLink */
+
+
+VOID
+NbfWaitLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for a remote link activation if it is not already
+ active.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfWaitLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ switch (Link->State) {
+ case LINK_STATE_READY:
+ NbfCompleteLink (Link);
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ Link->State = LINK_STATE_CONNECTING;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ break;
+
+ }
+} /* NbfWaitLink */
+
+
+VOID
+NbfStopLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine terminates a link and all outstanding connections attached
+ to the link. It is called from routines such as ExpireT2Timer, because
+ the remote connection partner seems dead or inoperative. As a consequence
+ of this routine being called, every outstanding connection will have its
+ disconnect handler called (in NbfStopConnection).
+
+ NOTE: THIS ROUTINE MUST BE CALLED FROM DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_PACKET packet;
+ PTP_CONNECTION connection;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfStopLink: Entered for link %lx.\n", Link);
+ }
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ // Take a reference so the link won't go away inside this function
+
+ NbfReferenceLink("Temp in NbfStopLink", Link, LREF_STOPPING);
+
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+ p = RemoveHeadList (&Link->ConnectionDatabase);
+
+ while (p != &Link->ConnectionDatabase) {
+
+ //
+ // This will allow this connection to be "removed"
+ // from its link's list in NbfDisconnectFromLink, even if
+ // its not on a list.
+ //
+ InitializeListHead (p);
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("NbfStopLink stopping connection, refcnt=%ld",
+ connection->ReferenceCount);
+ }
+#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( "TpStopLink stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ NbfStopConnection (connection, STATUS_LINK_FAILED);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = RemoveHeadList (&Link->ConnectionDatabase);
+ }
+
+ //
+ // We hold the link spinlock here.
+ //
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is in ADM mode.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ StopT1 (Link);
+ StopT2 (Link);
+ StopTi (Link);
+
+
+ //
+ // Make sure we are not waiting for a deferred RR to be sent.
+ //
+
+ if (Link->OnDeferredRrQueue) {
+
+ ACQUIRE_DPC_SPIN_LOCK (Link->ProviderInterlock);
+ if (Link->OnDeferredRrQueue) {
+ RemoveEntryList (&Link->DeferredRrLinkage);
+ Link->OnDeferredRrQueue = FALSE;
+ }
+ RELEASE_DPC_SPIN_LOCK (Link->ProviderInterlock);
+
+ }
+
+ // Remove the temporary reference.
+
+ NbfDereferenceLink ("Temp in NbfStopLink", Link, LREF_STOPPING);
+
+
+} /* NbfStopLink */
+
+
+VOID
+NbfResetLink(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by DLC.C routines only to reset this link
+ object and restart in-progress transport data transfers.
+
+ NOTE: This routine is called with the link spinlock acquired
+ at *OldIrqlP, and will return with it held, although it may
+ release it in the interim.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ OldIrqlP - Pointer to where the IRQL at which Link->SpinLock
+ was acquired is stored.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_PACKET packet;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_LINK) {
+ NbfPrint1 ("NbfResetLink: Entered for link %lx.\n", Link);
+ }
+
+ //
+ // Reset the link state to waiting for connection to start.
+ // Note that this is NOT the same as initiating a new link, as some things
+ // don't change, such as provider (devicecontext binding stays the same),
+ // Max Packet Length (can't change if provider doesn't), and other things
+ // that would bind this link structure to a different provider or provider
+ // type. Note also that we acquire the spinlock because, in the case of a
+ // link that's dropped (remotely) and is restarting, activities on this
+ // link could be occurring while we're in this routine.
+ //
+
+ StopT1 (Link);
+ StopT2 (Link);
+ // StopTi (Link);
+ Link->Flags = 0; // clear this, keep DeferredFlags
+
+ Link->SendState = SEND_STATE_DOWN; // send side is down.
+ Link->NextSend = 0;
+ Link->LastAckReceived = 0;
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Link->SendWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
+ Link->PrevWindowSize = (UCHAR)Link->Provider->RecommendedSendWindow;
+ } else {
+ Link->SendWindowSize = (UCHAR)1;
+ Link->PrevWindowSize = (UCHAR)1;
+ }
+ Link->WindowsUntilIncrease = 1;
+ Link->LinkBusy = FALSE;
+ Link->ConsecutiveLastPacketLost = 0;
+
+ //
+ // check for left over packets on the link WackQ; we'll never get
+ // acked for these if the link is resetting.
+ //
+
+ while (!IsListEmpty (&Link->WackQ)) {
+ p = RemoveHeadList (&Link->WackQ);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ NbfDereferencePacket (packet);
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ Link->ReceiveState = RECEIVE_STATE_DOWN; // receive side down.
+ Link->NextReceive = 0;
+ Link->LastAckSent = 0;
+ Link->ReceiveWindowSize = 1;
+
+ Link->WindowErrors = 0;
+ Link->BestWindowSize = 1;
+ Link->WorstWindowSize = (UCHAR)Link->MaxWindowSize;
+ Link->Flags |= LINK_FLAGS_JUMP_START;
+
+ //
+ // This must be accurate before we set up timeouts.
+ //
+
+ Link->CurrentT1Timeout = Link->Provider->DefaultT1Timeout;
+ Link->BaseT1Timeout = Link->Provider->DefaultT1Timeout << DLC_TIMER_ACCURACY;
+ Link->MinimumBaseT1Timeout = Link->Provider->MinimumT1Timeout << DLC_TIMER_ACCURACY;
+ Link->BaseT1RecalcThreshhold = Link->MaxFrameSize / 2;
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentT1Backoff = FALSE;
+ Link->CurrentPollOutstanding = FALSE;
+ Link->RemoteNoPoll = TRUE;
+ Link->ConsecutiveIFrames = 0;
+ Link->T2Timeout = Link->Provider->DefaultT2Timeout;
+ Link->TiTimeout = Link->Provider->DefaultTiTimeout;
+ Link->LlcRetries = Link->Provider->LlcRetries;
+ Link->MaxWindowSize = Link->Provider->LlcMaxWindowSize;
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+} /* NbfResetLink */
+
+
+VOID
+NbfDumpLinkInfo (
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when any of the link timers fire and the
+ link send state is not ready. This gives us a way to track the
+ link state when strange things are happening.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ Link; // avoid compiler warnings in non-debug versions
+
+#if DBG
+ NbfPrint4 ("NbfDumpLinkInfo: Link %lx : State: %x SendState: %x ReceiveState: %x\n",
+ Link, Link->State, Link->SendState, Link->ReceiveState);
+ NbfPrint1 (" Flags: %lx\n",Link->Flags);
+ NbfPrint4 (" NextReceive: %d LastAckRcvd: %d NextSend: %d LastAckSent: %d\n",
+ Link->NextReceive, Link->LastAckReceived, Link->NextSend, Link->LastAckSent);
+#endif
+
+}
diff --git a/private/ntos/tdi/nbf/linktree.c b/private/ntos/tdi/nbf/linktree.c
new file mode 100644
index 000000000..5c62fd8b8
--- /dev/null
+++ b/private/ntos/tdi/nbf/linktree.c
@@ -0,0 +1,537 @@
+/*++
+
+Copyright (c) 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ linktree.c
+
+Abstract:
+
+ This module contains code which implements the management of the link
+ splay tree. This splay tree is maintained to minimize the lookup time
+ needed with each individual packet that comes in. To this end, we create a
+ ULARGE_INTEGER that contains the transport address of the remote and
+ do a ULARGE_INTEGER comaprison of the addresses (rather than comparing
+ the bytes 1 by 1). Assuming that the ULARGE_INTEGER comparison routines are
+ optimized for the hardware on the machine, this should be as fast as or
+ faster than comparing bytes.
+
+ DEBUG: there is currently code in the comparison routines that will let
+ me fine-tune the search and ordering algorithm as we gain more
+ experience with it.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfAddLinkToTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a link to the tree of links maintained for this device.
+ Note that since this routine needs to modify the link tree, it is called
+ in the context of a deferred processing routine, and must have exclusive
+ access to the tree. The spinlock is taken by the routine that calls this
+ one, as this operation must be atomic in the eyes of the rest of NBF.
+ Note further that this routine insists that there not be a link with this
+ address in the tree.
+
+ As the final operation of this insertion, the splay tree is balanced.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ STATUS_SUCCESS if the link is successfully added,
+ STATUS_DRIVER_INTERNAL_ERROR if there was a problem adding
+ the link (implying the tree was in a bad state).
+
+--*/
+{
+ PTP_LINK treeLink;
+ PRTL_SPLAY_LINKS linkLink;
+
+ //
+ // initialize the link and check for the trivial case.
+ //
+
+ RtlInitializeSplayLinks (Link);
+ linkLink = DeviceContext->LinkTreeRoot;
+ if (linkLink == NULL) { // null tree, make this the parent
+ DeviceContext->LinkTreeRoot = (PRTL_SPLAY_LINKS)Link;
+ DeviceContext->LinkTreeElements++;
+ DeviceContext->LastLink = Link;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Wasn't a null tree, so set up for the addition
+ //
+
+ treeLink = (PTP_LINK) linkLink;
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint1 ("NbfAddLinkToTree: starting insert, Elements: %ld \n",DeviceContext->LinkTreeElements);
+ }
+
+ //
+ // find the proper spot to put this link.
+ //
+
+ do {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfAddLinkToTree: searching, Link: %lx LC: %lx RC: %lx\n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+
+ //
+ // Bad news == means we already have this link, someone is messed up.
+ // it's possible to be adding and deleting things at the same time;
+ // that's
+ //
+
+ if ((treeLink->MagicAddress).QuadPart == (Link->MagicAddress).QuadPart) {
+
+ //
+ // First make sure we don't have the splay tree in a loop.
+ //
+
+ ASSERT (treeLink != Link);
+
+ //
+ // This link is already in the tree. This is OK if it is
+ // due to be deleted; we can just do the delete right now,
+ // since AddLinkToTree is only called from the deferred
+ // timer routine.
+ //
+
+ if (treeLink->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) {
+
+ //
+ // It will be in the deferred list. We remove it,
+ // we don't worry about LinkDeferredActive since
+ // the timeout routine that is calling us handles
+ // that.
+ //
+
+ RemoveEntryList (&treeLink->DeferredList);
+
+ treeLink->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfRemoveLinkFromTree (DeviceContext, treeLink);
+ NbfDestroyLink (treeLink);
+
+#if DBG
+ NbfPrint2 ("NbfAddLinkToTree: Link %lx removed for %lx\n",
+ treeLink, Link);
+#endif
+
+ //
+ // Now that that link is out of the tree, call
+ // ourselves recursively to do the insert.
+ //
+
+ return NbfAddLinkToTree (DeviceContext, Link);
+
+ } else {
+
+ ASSERTMSG ("NbfAddLinkToTree: Found identical Link in tree!\n", FALSE);
+ return STATUS_DRIVER_INTERNAL_ERROR;
+
+ }
+
+ }
+
+ //
+ // traverse the tree for the correct spot
+ //
+
+ if ((Link->MagicAddress).QuadPart < (treeLink->MagicAddress).QuadPart) {
+ if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfAddLinkToTree: Adding link as LC.\n");
+ }
+ RtlInsertAsLeftChild ((PRTL_SPLAY_LINKS)treeLink,
+ (PRTL_SPLAY_LINKS)Link);
+ // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
+ DeviceContext->LinkTreeElements++;
+ return STATUS_SUCCESS;
+
+ } else {
+ treeLink = (PTP_LINK) linkLink;
+ continue;
+ } // Left Child
+
+ } else { // is greater
+ if ((linkLink = RtlRightChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfAddLinkToTree: Adding link as RC.\n");
+ }
+ RtlInsertAsRightChild ((PRTL_SPLAY_LINKS)treeLink,
+ (PRTL_SPLAY_LINKS)Link);
+ // DeviceContext->LinkTreeRoot = RtlSplay (DeviceContext->LinkTreeRoot);
+ DeviceContext->LinkTreeElements++;
+ return STATUS_SUCCESS;
+
+ } else {
+ treeLink = (PTP_LINK) linkLink;
+ continue;
+ } // Right Child
+
+ } // end else addresses comparison
+
+ } while (TRUE);
+
+
+} // NbfAddLinkToTree
+
+
+NTSTATUS
+NbfRemoveLinkFromTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a link from the tree of links.
+ Note that since this routine needs to modify the link tree, it is called
+ in the context of a deferred processing routine, and must have exclusive
+ access to the tree. The spinlock is taken by the routine that calls this
+ one, as this operation must be atomic in the eyes of the rest of NBF.
+ Note further that this routine insists that there not be a link with this
+ address in the tree.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+ DeviceContext - pointer to the device context on which this
+
+Return Value:
+
+ STATUS_SUCCESS if the link was removed,
+ STATUS_DRIVER_INTERNAL_ERROR if there was a problem removing
+ the link (implying the tree was in a bad state).
+
+--*/
+{
+ DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
+ DeviceContext->LinkTreeElements--;
+ if (DeviceContext->LastLink == Link) {
+ DeviceContext->LastLink = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ }
+ return STATUS_SUCCESS;
+
+} //NbfRemoveLinkFromTree
+
+
+
+PTP_LINK
+NbfFindLinkInTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ )
+
+/*++
+
+Routine Description:
+
+ This routine traverses the link tree looking for the given remote address.
+ The link tree spinlock is held while looking for the link. After the link
+ is found, it's reference count is incremented.
+
+ NOTE: This function is called with the device context LinkSpinLock
+ held.
+
+Arguments:
+
+ DeviceContext - pointer to the device this address is associated with.
+
+ Remote - pointer to the hardware address of the remote node.
+
+Return Value:
+
+ Pointer to the link in the tree that matches this remote address. If
+ no link is found, NULL is returned.
+
+--*/
+{
+ PTP_LINK link;
+ PRTL_SPLAY_LINKS linkLink;
+ ULARGE_INTEGER Magic = {0,0};
+
+
+ //
+ // Are there even any links in the tree?
+ //
+
+ if (DeviceContext->LinkTreeElements <= 0) {
+ return NULL;
+ }
+
+ linkLink = DeviceContext->LinkTreeRoot;
+
+ //
+ // Make a magic number for this link
+ //
+
+ MacReturnMagicAddress (&DeviceContext->MacInfo, Remote, &Magic);
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint1 ("NbfFindLinkInTree: starting search, Elements: %ld \n",
+ DeviceContext->LinkTreeElements);
+ }
+
+ //
+ // Do a quick check if the last link found is this one.
+ //
+
+ ASSERT (DeviceContext->LastLink != NULL);
+
+ if ((DeviceContext->LastLink->MagicAddress).QuadPart == Magic.QuadPart) {
+
+ link = DeviceContext->LastLink;
+
+ } else {
+
+ //
+ // find the link.
+ //
+
+ link = (PTP_LINK) linkLink; // depends upon splay links being first
+ // subfield in link!
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: searching, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+
+ do {
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint4 ("NbfFindLinkInTree: Comparing: %lx%lx to %lx%lx\n",
+ link->MagicAddress.HighPart,link->MagicAddress.LowPart,
+ Magic.HighPart, Magic.LowPart);
+ }
+
+ if ((link->MagicAddress).QuadPart == Magic.QuadPart) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: equal, going to end.\n");
+ }
+ break;
+
+ } else {
+ if ((link->MagicAddress).QuadPart < Magic.QuadPart) {
+ if ((linkLink = RtlRightChild (linkLink)) == NULL) {
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
+ }
+ return NULL;
+
+ } else {
+ link = (PTP_LINK) linkLink;
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: less, took right child, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+ continue;
+ }
+
+ } else { // is greater
+ if ((linkLink = RtlLeftChild (linkLink)) == NULL) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Not Found.\n");
+ }
+ return NULL;
+
+ } else {
+ link = (PTP_LINK) linkLink;
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint3 ("NbfFindLinkInTree: greater, took left child, Link: %lx LC: %lx RC: %lx \n",
+ linkLink, RtlLeftChild (linkLink), RtlRightChild (linkLink));
+ }
+ continue;
+ } // got left child branch
+ } // greater branch
+ } // equal to branch
+ } while (TRUE);
+
+ DeviceContext->LastLink = link;
+
+ }
+
+ //
+ // Only break out when we've actually found a match..
+ //
+
+ if ((link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Found but delete pending.\n");
+ }
+ return NULL;
+ }
+
+ //
+ // Mark the link as in use and say we don't need the tree stable any more.
+ //
+
+ NbfReferenceLink ("Found in tree", link, LREF_TREE);
+
+ IF_NBFDBG(NBF_DEBUG_LINKTREE) {
+ NbfPrint0 ("NbfFindLinkInTree: Link Found.\n");
+ }
+
+ return link;
+
+} // NbfFindLinkInTree
+
+
+PTP_LINK
+NbfFindLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for a link in the link tree, and if
+ not found there in the deferred queue.
+
+Arguments:
+
+ DeviceContext - pointer to the device this address is associated with.
+
+ Remote - pointer to the hardware address of the remote node.
+
+Return Value:
+
+ Pointer to the link in the tree that matches this remote address. If
+ no link is found, NULL is returned.
+
+--*/
+
+{
+ PTP_LINK Link;
+ BOOLEAN MatchedLink;
+ PLIST_ENTRY p;
+ UINT i;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ Link = NbfFindLinkInTree (DeviceContext, Remote);
+
+ if (Link == NULL) {
+
+ //
+ // Not found there, try in deferred queue.
+ //
+
+ MatchedLink = FALSE; // Assume failure
+
+ //
+ // Hold the spinlock while we walk the deferred list. We need
+ // TimerSpinLock to stop the list from changing, and we need
+ // LinkSpinLock to synchronize checking DEFERRED_DELETE and
+ // referencing the link.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ for (p = DeviceContext->LinkDeferred.Flink;
+ p != &DeviceContext->LinkDeferred;
+ p = p->Flink) {
+
+ //
+ // BUGBUG: What about taking a lock while we walk
+ // this list? It won't be removed from at the front,
+ // but it may be added to at the back.
+ //
+
+ //
+ // We're probably still getting this link to the splay tree.
+ // find it and process normally.
+ //
+
+ Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
+
+ //
+ // NOTE: We know that the link is not going to be destroyed
+ // now, because we have increased the semaphore. We
+ // reference the link if DEFERRED_DELETE is not on; the
+ // setting of this flag is synchronized (also using
+ // DeviceContext->LinkSpinLock) with the refcount going
+ // to 0).
+ //
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ continue; // we're deleting link, can't handle
+ }
+
+ for (i=0; i<(UINT)DeviceContext->MacInfo.AddressLength; i++) {
+ if (Remote[i] != Link->HardwareAddress.Address[i]){
+ break;
+ }
+ }
+
+ if (i == (UINT)DeviceContext->MacInfo.AddressLength) { // addresses match. Deliver packet.
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfFindLink: Found link on deferred queue, Link: %lx\n",
+ Link);
+ }
+ NbfReferenceLink ("Got Frame on Deferred", Link, LREF_TREE);
+ MatchedLink = TRUE;
+ break;
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If this didn't find the link, make note of that.
+ //
+
+ if (MatchedLink == FALSE) {
+
+ Link = (PTP_LINK)NULL;
+
+ }
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_DLC) {
+ NbfPrint1 ("NbfFindLink: Found link in tree, Link: %lx\n", Link);
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ return Link;
+
+}
diff --git a/private/ntos/tdi/nbf/makefile b/private/ntos/tdi/nbf/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/nbf/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/nbf/nbf.h b/private/ntos/tdi/nbf/nbf.h
new file mode 100644
index 000000000..2efb3f50d
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbf.h
@@ -0,0 +1,166 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbf.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport
+ provider subcomponent of the NTOS project.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove PDI and PC586-specific support; add NDIS support
+
+--*/
+
+#ifndef _NBF_
+#define _NBF_
+
+#include <ntddk.h>
+
+typedef struct _RTL_SPLAY_LINKS {
+ struct _RTL_SPLAY_LINKS *Parent;
+ struct _RTL_SPLAY_LINKS *LeftChild;
+ struct _RTL_SPLAY_LINKS *RightChild;
+} RTL_SPLAY_LINKS;
+typedef RTL_SPLAY_LINKS *PRTL_SPLAY_LINKS;
+
+#define RtlInitializeSplayLinks(Links) { \
+ PRTL_SPLAY_LINKS _SplayLinks; \
+ _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \
+ _SplayLinks->Parent = _SplayLinks; \
+ _SplayLinks->LeftChild = NULL; \
+ _SplayLinks->RightChild = NULL; \
+ }
+
+#define RtlLeftChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->LeftChild \
+ )
+
+#define RtlRightChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->RightChild \
+ )
+
+#define RtlInsertAsLeftChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->LeftChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+#define RtlInsertAsRightChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->RightChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+
+PRTL_SPLAY_LINKS
+NTAPI
+RtlDelete (
+ PRTL_SPLAY_LINKS Links
+ );
+
+
+VOID
+NTAPI
+RtlGetCallersAddress(
+ OUT PVOID *CallersAddress,
+ OUT PVOID *CallersCaller
+ );
+
+#include <tdikrnl.h> // Transport Driver Interface.
+
+#include <ndis.h> // Physical Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "nbfconst.h" // private NETBEUI constants.
+#include "nbfmac.h" // mac-specific definitions
+#include "nbfhdrs.h" // private NETBEUI protocol headers.
+#include "nbftypes.h" // private NETBEUI types.
+#include "nbfcnfg.h" // configuration information.
+#include "nbfprocs.h" // private NETBEUI function prototypes.
+#ifdef MEMPRINT
+#include "memprint.h" // drt's memory debug print
+#endif
+
+
+#ifndef NBF_LOCKS
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+
+#if 0
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { KIRQL OldIrql; ASSERT ((lock != NULL) && (KeGetCurrentIrql() == DISPATCH_LEVEL)); KeAcquireSpinLock(lock,&OldIrql); }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ { ASSERT(lock != NULL); KeReleaseSpinLock(lock,DISPATCH_LEVEL); }
+#else
+#define ACQUIRE_DPC_SPIN_LOCK(lock) KeAcquireSpinLockAtDpcLevel(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock) KeReleaseSpinLockFromDpcLevel(lock)
+#endif
+
+#define ENTER_NBF
+#define LEAVE_NBF
+
+#else
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) \
+ NbfAcquireSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+#define RELEASE_SPIN_LOCK(lock,irql) \
+ NbfReleaseSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { \
+ KIRQL OldIrql; \
+ NbfAcquireSpinLock( lock, &OldIrql, #lock, __FILE__, __LINE__ ); \
+ }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ NbfReleaseSpinLock( lock, DISPATCH_LEVEL, #lock, __FILE__, __LINE__ )
+
+#define ENTER_NBF \
+ NbfAcquireSpinLock( (PKSPIN_LOCK)NULL, (PKIRQL)NULL, "(Global)", __FILE__, __LINE__ )
+#define LEAVE_NBF \
+ NbfReleaseSpinLock( (PKSPIN_LOCK)NULL, (KIRQL)-1, "(Global)", __FILE__, __LINE__ )
+
+#endif
+
+
+#endif // def _NBF_
diff --git a/private/ntos/tdi/nbf/nbf.rc b/private/ntos/tdi/nbf/nbf.rc
new file mode 100644
index 000000000..be3b9d409
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbf.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NetBEUI Frames Protocol Driver"
+#define VER_INTERNALNAME_STR "nbf.sys"
+#define VER_ORIGINALFILENAME_STR "nbf.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/nbf/nbfcnfg.c b/private/ntos/tdi/nbf/nbfcnfg.c
new file mode 100644
index 000000000..30d0a02f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfcnfg.c
@@ -0,0 +1,1155 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfconfig.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of NBF. Note that the parts of this file that are
+ called at initialization time will be replaced by calls to the configuration manager over time.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modified to use new tdi interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local functions used to access the registry.
+//
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+NbfOpenParametersKey(
+ IN HANDLE NbfConfigHandle,
+ OUT PHANDLE ParametersHandle
+ );
+
+VOID
+NbfCloseParametersKey(
+ IN HANDLE ParametersHandle
+ );
+
+NTSTATUS
+NbfCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbfAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbfAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+NbfReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ );
+
+ULONG
+NbfReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ );
+
+VOID
+NbfWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ );
+
+UINT
+NbfWstrLength(
+ IN PWSTR Wstr
+ );
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfWstrLength)
+#pragma alloc_text(INIT,NbfConfigureTransport)
+#pragma alloc_text(INIT,NbfFreeConfigurationInfo)
+#pragma alloc_text(INIT,NbfOpenParametersKey)
+#pragma alloc_text(INIT,NbfCloseParametersKey)
+#pragma alloc_text(INIT,NbfCountEntries)
+#pragma alloc_text(INIT,NbfAddBind)
+#pragma alloc_text(INIT,NbfAddExport)
+#pragma alloc_text(INIT,NbfReadLinkageInformation)
+#pragma alloc_text(INIT,NbfReadSingleParameter)
+#pragma alloc_text(INIT,NbfWriteSingleParameter)
+#else
+#pragma alloc_text(PAGE,NbfWstrLength)
+#pragma alloc_text(PAGE,NbfConfigureTransport)
+#pragma alloc_text(PAGE,NbfFreeConfigurationInfo)
+#pragma alloc_text(PAGE,NbfOpenParametersKey)
+#pragma alloc_text(PAGE,NbfCloseParametersKey)
+#pragma alloc_text(PAGE,NbfCountEntries)
+#pragma alloc_text(PAGE,NbfAddBind)
+#pragma alloc_text(PAGE,NbfAddExport)
+#pragma alloc_text(PAGE,NbfReadLinkageInformation)
+#pragma alloc_text(PAGE,NbfReadSingleParameter)
+#pragma alloc_text(PAGE,NbfWriteSingleParameter)
+#endif
+#endif
+
+UINT
+NbfWstrLength(
+ IN PWSTR Wstr
+ )
+{
+ UINT Length = 0;
+ while (*Wstr++) {
+ Length += sizeof(WCHAR);
+ }
+ return Length;
+}
+
+#define InsertAdapter(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = NbfWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, _L, ' FBN'); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[Subscript], _S); \
+ } \
+}
+
+#define InsertDevice(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = NbfWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePoolWithTag(NonPagedPool, _L, ' FBN'); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript], _S); \
+ } \
+}
+
+
+#define RemoveAdapter(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[Subscript].Buffer)
+
+#define RemoveDevice(ConfigurationInfo, Subscript) \
+ ExFreePool ((ConfigurationInfo)->Names[(ConfigurationInfo)->DevicesOffset+Subscript].Buffer)
+
+
+
+//
+// These strings are used in various places by the registry.
+//
+
+#define DECLARE_STRING(_str_) WCHAR Str ## _str_[] = L#_str_
+
+
+#define READ_HIDDEN_CONFIG(_Field) \
+{ \
+ ConfigurationInfo->_Field = \
+ NbfReadSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+#define WRITE_HIDDEN_CONFIG(_Field) \
+{ \
+ NbfWriteSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+
+
+NTSTATUS
+NbfConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in nbfcnfg.h file.
+
+Arguments:
+
+ RegistryPath - The name of NBF's node in the registry.
+
+ ConfigurationInfoPtr - A pointer to the configuration information structure.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+
+ NTSTATUS OpenStatus;
+ HANDLE ParametersHandle;
+ HANDLE NbfConfigHandle;
+ NTSTATUS Status;
+ ULONG Disposition;
+ PWSTR RegistryPathBuffer;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+ PCONFIG_DATA ConfigurationInfo;
+
+ DECLARE_STRING(InitRequests);
+ DECLARE_STRING(InitLinks);
+ DECLARE_STRING(InitConnections);
+ DECLARE_STRING(InitAddressFiles);
+ DECLARE_STRING(InitAddresses);
+
+ DECLARE_STRING(MaxRequests);
+ DECLARE_STRING(MaxLinks);
+ DECLARE_STRING(MaxConnections);
+ DECLARE_STRING(MaxAddressFiles);
+ DECLARE_STRING(MaxAddresses);
+
+ DECLARE_STRING(InitPackets);
+ DECLARE_STRING(InitReceivePackets);
+ DECLARE_STRING(InitReceiveBuffers);
+ DECLARE_STRING(InitUIFrames);
+
+ DECLARE_STRING(SendPacketPoolSize);
+ DECLARE_STRING(ReceivePacketPoolSize);
+ DECLARE_STRING(MaxMemoryUsage);
+
+ DECLARE_STRING(DefaultT1Timeout);
+ DECLARE_STRING(DefaultT2Timeout);
+ DECLARE_STRING(DefaultTiTimeout);
+ DECLARE_STRING(LlcRetries);
+ DECLARE_STRING(LlcMaxWindowSize);
+ DECLARE_STRING(MaximumIncomingFrames);
+
+ DECLARE_STRING(NameQueryRetries);
+ DECLARE_STRING(NameQueryTimeout);
+ DECLARE_STRING(AddNameQueryRetries);
+ DECLARE_STRING(AddNameQueryTimeout);
+ DECLARE_STRING(GeneralRetries);
+ DECLARE_STRING(GeneralTimeout);
+ DECLARE_STRING(WanNameQueryRetries);
+
+ DECLARE_STRING(UseDixOverEthernet);
+ DECLARE_STRING(QueryWithoutSourceRouting);
+ DECLARE_STRING(AllRoutesNameRecognized);
+ DECLARE_STRING(MinimumSendWindowLimit);
+
+ //
+ // Open the registry.
+ //
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ RegistryPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwCreateKey(
+ &NbfConfigHandle,
+ KEY_WRITE,
+ &TmpObjectAttributes,
+ 0, // title index
+ NULL, // class
+ 0, // create options
+ &Disposition); // disposition
+
+ if (!NT_SUCCESS(Status)) {
+ NbfPrint1("NBF: Could not open/create NBF key: %lx\n", Status);
+ return Status;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint2("%s NBF key: %lx\n",
+ (Disposition == REG_CREATED_NEW_KEY) ? "created" : "opened",
+ NbfConfigHandle);
+ }
+
+
+ OpenStatus = NbfOpenParametersKey (NbfConfigHandle, &ParametersHandle);
+
+ if (OpenStatus != STATUS_SUCCESS) {
+ return OpenStatus;
+ }
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbfReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePoolWithTag(
+ NonPagedPool,
+ RegistryPath->Length + sizeof(WCHAR),
+ ' FBN');
+ if (RegistryPathBuffer == NULL) {
+ NbfCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ NbfReadLinkageInformation (RegistryPathBuffer, ConfigurationInfoPtr);
+
+ if (*ConfigurationInfoPtr == NULL) {
+ ExFreePool (RegistryPathBuffer);
+ NbfCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ ConfigurationInfo = *ConfigurationInfoPtr;
+
+
+ //
+ // Configure the initial values for some NBF resources.
+ //
+
+ ConfigurationInfo->InitRequests = 1;
+ ConfigurationInfo->InitLinks = 2;
+ ConfigurationInfo->InitConnections = 2;
+ ConfigurationInfo->InitAddressFiles = 0;
+ ConfigurationInfo->InitAddresses = 0;
+
+ //
+ // These are the initial values; remember that the
+ // resources above also allocate some of these each
+ // time they are allocated (shown in the comment).
+ //
+
+ ConfigurationInfo->InitPackets = 30; // + link + 2*conn
+ ConfigurationInfo->InitReceivePackets = 10; // + link + addr
+ ConfigurationInfo->InitReceiveBuffers = 5; // + addr
+ ConfigurationInfo->InitUIFrames = 5; // + addr + conn
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by NBF.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 100;
+ ConfigurationInfo->ReceivePacketPoolSize = 30;
+ ConfigurationInfo->MaxMemoryUsage = 0; // no limit
+
+
+ //
+ // Now initialize the timeout etc. values.
+ //
+
+ ConfigurationInfo->DefaultT1Timeout = DLC_DEFAULT_T1;
+ ConfigurationInfo->DefaultT2Timeout = DLC_DEFAULT_T2;
+ ConfigurationInfo->DefaultTiTimeout = DLC_DEFAULT_TI;
+ ConfigurationInfo->LlcRetries = DLC_RETRIES;
+ ConfigurationInfo->LlcMaxWindowSize = DLC_WINDOW_LIMIT;
+ ConfigurationInfo->MaximumIncomingFrames = 4;
+ ConfigurationInfo->NameQueryRetries = NAME_QUERY_RETRIES;
+ ConfigurationInfo->NameQueryTimeout = NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->AddNameQueryRetries = ADD_NAME_QUERY_RETRIES;
+ ConfigurationInfo->AddNameQueryTimeout = ADD_NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->GeneralRetries = NAME_QUERY_RETRIES;
+ ConfigurationInfo->GeneralTimeout = NAME_QUERY_TIMEOUT;
+ ConfigurationInfo->WanNameQueryRetries = WAN_NAME_QUERY_RETRIES;
+
+ ConfigurationInfo->UseDixOverEthernet = 0;
+ ConfigurationInfo->QueryWithoutSourceRouting = 0;
+ ConfigurationInfo->AllRoutesNameRecognized = 0;
+ ConfigurationInfo->MinimumSendWindowLimit = 2;
+
+
+ //
+ // Now read the optional "hidden" parameters; if these do
+ // not exist then the current values are used. Note that
+ // the current values will be 0 unless they have been
+ // explicitly initialized above.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ READ_HIDDEN_CONFIG (InitRequests);
+ READ_HIDDEN_CONFIG (InitLinks);
+ READ_HIDDEN_CONFIG (InitConnections);
+ READ_HIDDEN_CONFIG (InitAddressFiles);
+ READ_HIDDEN_CONFIG (InitAddresses);
+
+ READ_HIDDEN_CONFIG (MaxRequests);
+ READ_HIDDEN_CONFIG (MaxLinks);
+ READ_HIDDEN_CONFIG (MaxConnections);
+ READ_HIDDEN_CONFIG (MaxAddressFiles);
+ READ_HIDDEN_CONFIG (MaxAddresses);
+
+ READ_HIDDEN_CONFIG (InitPackets);
+ READ_HIDDEN_CONFIG (InitReceivePackets);
+ READ_HIDDEN_CONFIG (InitReceiveBuffers);
+ READ_HIDDEN_CONFIG (InitUIFrames);
+
+ READ_HIDDEN_CONFIG (SendPacketPoolSize);
+ READ_HIDDEN_CONFIG (ReceivePacketPoolSize);
+ READ_HIDDEN_CONFIG (MaxMemoryUsage);
+
+ READ_HIDDEN_CONFIG (DefaultT1Timeout);
+ READ_HIDDEN_CONFIG (DefaultT2Timeout);
+ READ_HIDDEN_CONFIG (DefaultTiTimeout);
+ READ_HIDDEN_CONFIG (LlcRetries);
+ READ_HIDDEN_CONFIG (LlcMaxWindowSize);
+ READ_HIDDEN_CONFIG (MaximumIncomingFrames);
+
+ READ_HIDDEN_CONFIG (NameQueryRetries);
+ READ_HIDDEN_CONFIG (NameQueryTimeout);
+ READ_HIDDEN_CONFIG (AddNameQueryRetries);
+ READ_HIDDEN_CONFIG (AddNameQueryTimeout);
+ READ_HIDDEN_CONFIG (GeneralRetries);
+ READ_HIDDEN_CONFIG (GeneralTimeout);
+ READ_HIDDEN_CONFIG (WanNameQueryRetries);
+
+ READ_HIDDEN_CONFIG (UseDixOverEthernet);
+ READ_HIDDEN_CONFIG (QueryWithoutSourceRouting);
+ READ_HIDDEN_CONFIG (AllRoutesNameRecognized);
+ READ_HIDDEN_CONFIG (MinimumSendWindowLimit);
+
+
+ //
+ // Print out some config info, to make sure it is read right.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint2("Links: init %d, max %d\n",
+ ConfigurationInfo->InitLinks,
+ ConfigurationInfo->MaxLinks);
+ NbfPrint3("Timeouts (NBF ticks): T1 %d, T2 %d, Ti %d\n",
+ ConfigurationInfo->DefaultT1Timeout / SHORT_TIMER_DELTA,
+ ConfigurationInfo->DefaultT2Timeout / SHORT_TIMER_DELTA,
+ ConfigurationInfo->DefaultTiTimeout / LONG_TIMER_DELTA);
+ NbfPrint2("Pools: send %d, receive %d\n",
+ ConfigurationInfo->SendPacketPoolSize,
+ ConfigurationInfo->ReceivePacketPoolSize);
+ NbfPrint1("Max mem %d\n",
+ ConfigurationInfo->MaxMemoryUsage);
+ NbfPrint2("NQRetries %d, NQTimeout %d\n",
+ ConfigurationInfo->NameQueryRetries,
+ ConfigurationInfo->NameQueryTimeout / SHORT_TIMER_DELTA);
+ }
+
+ //
+ // Save the "hidden" parameters, these may not exist in
+ // the registry.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ //
+ // 5/22/92 - don't write the parameters that are set
+ // based on Size, since otherwise these will overwrite
+ // those values since hidden parameters are set up
+ // after the Size-based configuration is done.
+ //
+
+ WRITE_HIDDEN_CONFIG (MaxRequests);
+ WRITE_HIDDEN_CONFIG (MaxLinks);
+ WRITE_HIDDEN_CONFIG (MaxConnections);
+ WRITE_HIDDEN_CONFIG (MaxAddressFiles);
+ WRITE_HIDDEN_CONFIG (MaxAddresses);
+
+ WRITE_HIDDEN_CONFIG (DefaultT1Timeout);
+ WRITE_HIDDEN_CONFIG (DefaultT2Timeout);
+ WRITE_HIDDEN_CONFIG (DefaultTiTimeout);
+ WRITE_HIDDEN_CONFIG (LlcRetries);
+ WRITE_HIDDEN_CONFIG (LlcMaxWindowSize);
+ WRITE_HIDDEN_CONFIG (MaximumIncomingFrames);
+
+ WRITE_HIDDEN_CONFIG (NameQueryRetries);
+ WRITE_HIDDEN_CONFIG (NameQueryTimeout);
+ WRITE_HIDDEN_CONFIG (AddNameQueryRetries);
+ WRITE_HIDDEN_CONFIG (AddNameQueryTimeout);
+ WRITE_HIDDEN_CONFIG (GeneralRetries);
+ WRITE_HIDDEN_CONFIG (GeneralTimeout);
+ WRITE_HIDDEN_CONFIG (WanNameQueryRetries);
+
+ WRITE_HIDDEN_CONFIG (UseDixOverEthernet);
+ WRITE_HIDDEN_CONFIG (QueryWithoutSourceRouting);
+ WRITE_HIDDEN_CONFIG (AllRoutesNameRecognized);
+
+ // ZwFlushKey (ParametersHandle);
+
+ ExFreePool (RegistryPathBuffer);
+ NbfCloseParametersKey (ParametersHandle);
+ ZwClose (NbfConfigHandle);
+
+ return STATUS_SUCCESS;
+
+} /* NbfConfigureTransport */
+
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to get free any storage that was allocated
+ by NbfConfigureTransport in producing the specified CONFIG_DATA structure.
+
+Arguments:
+
+ ConfigurationInfo - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i=0; i<ConfigurationInfo->NumAdapters; i++) {
+ RemoveAdapter (ConfigurationInfo, i);
+ RemoveDevice (ConfigurationInfo, i);
+ }
+ ExFreePool (ConfigurationInfo);
+
+} /* NbfFreeConfigurationInfo */
+
+
+NTSTATUS
+NbfOpenParametersKey(
+ IN HANDLE NbfConfigHandle,
+ OUT PHANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to open the NBF "Parameters" key.
+
+Arguments:
+
+ ParametersHandle - Returns the handle used to read parameters.
+
+Return Value:
+
+ The status of the request.
+
+--*/
+{
+
+ NTSTATUS Status;
+ HANDLE ParamHandle;
+ PWSTR ParametersString = L"Parameters";
+ UNICODE_STRING ParametersKeyName;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+
+ //
+ // Open the NBF parameters key.
+ //
+
+ RtlInitUnicodeString (&ParametersKeyName, ParametersString);
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ &ParametersKeyName, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NbfConfigHandle, // root
+ NULL // security descriptor
+ );
+
+
+ Status = ZwOpenKey(
+ &ParamHandle,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NbfPrint1("Could not open parameters key: %lx\n", Status);
+ return Status;
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REGISTRY) {
+ NbfPrint1("Opened parameters key: %lx\n", ParamHandle);
+ }
+
+
+ *ParametersHandle = ParamHandle;
+
+
+ //
+ // All keys successfully opened or created.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* NbfOpenParametersKey */
+
+VOID
+NbfCloseParametersKey(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to close the "Parameters" key.
+ It closes the handles passed in and does any other work needed.
+
+Arguments:
+
+ ParametersHandle - The handle used to read other parameters.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ZwClose (ParametersHandle);
+
+} /* NbfCloseParametersKey */
+
+
+NTSTATUS
+NbfCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called with the "Bind" and "Export" multi-strings.
+ It counts the number of name entries required in the
+ CONFIGURATION_DATA structure and then allocates it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" or "Export" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to a pointer to the ConfigurationInfo structure.
+ When the "Export" callback is made this is filled in
+ with the allocate structure.
+
+ EntryContext - A pointer to a counter holding the total number
+ of name entries required.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ ULONG StringCount;
+ PWCHAR ValuePointer = (PWCHAR)ValueData;
+ PCONFIG_DATA * ConfigurationInfo = (PCONFIG_DATA *)Context;
+ PULONG TotalCount = ((PULONG)EntryContext);
+ ULONG OldTotalCount = *TotalCount;
+
+#if DBG
+ ASSERT (ValueType == REG_MULTI_SZ);
+#else
+ UNREFERENCED_PARAMETER(ValueType);
+#endif
+
+ //
+ // Count the number of strings in the multi-string; first
+ // check that it is NULL-terminated to make the rest
+ // easier.
+ //
+
+ if ((ValueLength < 2) ||
+ (ValuePointer[(ValueLength/2)-1] != (WCHAR)'\0')) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ StringCount = 0;
+ while (*ValuePointer != (WCHAR)'\0') {
+ while (*ValuePointer != (WCHAR)'\0') {
+ ++ValuePointer;
+ }
+ ++StringCount;
+ ++ValuePointer;
+ if ((ULONG)((PUCHAR)ValuePointer - (PUCHAR)ValueData) >= ValueLength) {
+ break;
+ }
+ }
+
+ (*TotalCount) += StringCount;
+
+ if (*ValueName == (WCHAR)'E') {
+
+ //
+ // This is "Export", allocate the config data structure.
+ //
+
+ *ConfigurationInfo = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof (CONFIG_DATA) +
+ ((*TotalCount-1) * sizeof(NDIS_STRING)),
+ ' FBN');
+
+ if (*ConfigurationInfo == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(
+ *ConfigurationInfo,
+ sizeof(CONFIG_DATA) + ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ (*ConfigurationInfo)->DevicesOffset = OldTotalCount;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbfCountEntries */
+
+
+NTSTATUS
+NbfAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertAdapter(
+ ConfigurationInfo,
+ *CurBindNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurBindNum);
+
+ return STATUS_SUCCESS;
+
+} /* NbfAddBind */
+
+
+NTSTATUS
+NbfAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the ConfigurationInfo structure.
+
+ EntryContext - A pointer to a count of exports that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG_DATA ConfigurationInfo = *(PCONFIG_DATA *)Context;
+ PULONG CurExportNum = ((PULONG)EntryContext);
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ InsertDevice(
+ ConfigurationInfo,
+ *CurExportNum,
+ (PWSTR)(ValueData));
+
+ ++(*CurExportNum);
+
+ return STATUS_SUCCESS;
+
+} /* NbfAddExport */
+
+
+VOID
+NbfReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to read its linkage information
+ from the registry. If there is none present, then ConfigData
+ is filled with a list of all the adapters that are known
+ to NBF.
+
+Arguments:
+
+ RegistryPathBuffer - The null-terminated root of the NBF registry tree.
+
+ ConfigurationInfo - Returns NBF's current configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT ConfigBindings;
+ UINT NameCount = 0;
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[6];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG BindCount, ExportCount;
+ UINT i;
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below NBF
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call NbfCountEntries for the "Bind" multi-string
+ //
+
+ QueryTable[1].QueryRoutine = NbfCountEntries;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&NameCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call NbfCountEntries for the "Export" multi-string
+ //
+
+ QueryTable[2].QueryRoutine = NbfCountEntries;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[2].Name = Export;
+ QueryTable[2].EntryContext = (PVOID)&NameCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4) Call NbfAddBind for each string in "Bind"
+ //
+
+ QueryTable[3].QueryRoutine = NbfAddBind;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = Bind;
+ QueryTable[3].EntryContext = (PVOID)&BindCount;
+ QueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Call NbfAddExport for each string in "Export"
+ //
+
+ QueryTable[4].QueryRoutine = NbfAddExport;
+ QueryTable[4].Flags = 0;
+ QueryTable[4].Name = Export;
+ QueryTable[4].EntryContext = (PVOID)&ExportCount;
+ QueryTable[4].DefaultType = REG_NONE;
+
+ //
+ // 6) Stop
+ //
+
+ QueryTable[5].QueryRoutine = NULL;
+ QueryTable[5].Flags = 0;
+ QueryTable[5].Name = NULL;
+
+
+ BindCount = 0;
+ ExportCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ RegistryPathBuffer,
+ QueryTable,
+ (PVOID)ConfigurationInfo,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ return;
+ }
+
+ //
+ // Make sure that BindCount and ExportCount match, if not
+ // remove the extras.
+ //
+
+ if (BindCount < ExportCount) {
+
+ for (i=BindCount; i<ExportCount; i++) {
+ RemoveDevice (*ConfigurationInfo, i);
+ }
+ ConfigBindings = BindCount;
+
+ } else if (ExportCount < BindCount) {
+
+ for (i=ExportCount; i<BindCount; i++) {
+ RemoveAdapter (*ConfigurationInfo, i);
+ }
+ ConfigBindings = ExportCount;
+
+ } else {
+
+ ConfigBindings = BindCount; // which is equal to ExportCount
+
+ }
+
+ (*ConfigurationInfo)->NumAdapters = ConfigBindings;
+
+} /* NbfReadLinkageInformation */
+
+
+ULONG
+NbfReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to read a single parameter
+ from the registry. If the parameter is found it is stored
+ in Data.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to search for.
+
+ DefaultValue - The default value.
+
+Return Value:
+
+ The value to use; will be the default if the value is not
+ found or is not in the correct range.
+
+--*/
+
+{
+ ULONG InformationBuffer[32]; // declare ULONG to get it aligned
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ UNICODE_STRING ValueKeyName;
+ ULONG InformationLength;
+ ULONG ReturnValue;
+ NTSTATUS Status;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+ if ((Status == STATUS_SUCCESS) &&
+ (Information->DataLength == sizeof(ULONG))) {
+
+ RtlCopyMemory(
+ (PVOID)&ReturnValue,
+ ((PUCHAR)Information) + Information->DataOffset,
+ sizeof(ULONG));
+
+ if (ReturnValue < 0) {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ } else {
+
+ ReturnValue = DefaultValue;
+
+ }
+
+ return ReturnValue;
+
+} /* NbfReadSingleParameter */
+
+
+VOID
+NbfWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to write a single parameter
+ from the registry.
+
+Arguments:
+
+ ParametersHandle - A pointer to the open registry.
+
+ ValueName - The name of the value to store.
+
+ ValueData - The data to store at the value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING ValueKeyName;
+ NTSTATUS Status;
+ ULONG TmpValueData = ValueData;
+
+ RtlInitUnicodeString (&ValueKeyName, ValueName);
+
+ Status = ZwSetValueKey(
+ ParametersHandle,
+ &ValueKeyName,
+ 0,
+ REG_DWORD,
+ (PVOID)&TmpValueData,
+ sizeof(ULONG));
+
+ if (!NT_SUCCESS(Status)) {
+ NbfPrint1("NBF: Could not write dword key: %lx\n", Status);
+ }
+
+} /* NbfWriteSingleParameter */
+
diff --git a/private/ntos/tdi/nbf/nbfcnfg.h b/private/ntos/tdi/nbf/nbfcnfg.h
new file mode 100644
index 000000000..ca8c382f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfcnfg.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfcnfg.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport. This
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of NBF. Note that this file will be replaced
+ by calls to the configuration manager over time.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFCONFIG_
+#define _NBFCONFIG_
+
+//
+// Define the devices we support; this is in leiu of a real configuration
+// manager.
+//
+
+#define NBF_SUPPORTED_ADAPTERS 10
+
+#define NE3200_ADAPTER_NAME L"\\Device\\NE320001"
+#define ELNKII_ADAPTER_NAME L"\\Device\\Elnkii" // adapter we will talk to
+#define ELNKMC_ADAPTER_NAME L"\\Device\\Elnkmc01"
+#define ELNK16_ADAPTER_NAME L"\\Device\\Elnk1601"
+#define SONIC_ADAPTER_NAME L"\\Device\\Sonic01"
+#define LANCE_ADAPTER_NAME L"\\Device\\Lance01"
+#define PC586_ADAPTER_NAME L"\\Device\\Pc586"
+#define IBMTOK_ADAPTER_NAME L"\\Device\\Ibmtok01"
+#define PROTEON_ADAPTER_NAME L"\\Device\\Proteon01"
+#define WDLAN_ADAPTER_NAME L"\\Device\\Wdlan01"
+
+
+//
+// configuration structure.
+//
+
+typedef struct {
+
+ ULONG InitRequests;
+ ULONG InitLinks;
+ ULONG InitConnections;
+ ULONG InitAddressFiles;
+ ULONG InitAddresses;
+ ULONG MaxRequests;
+ ULONG MaxLinks;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ ULONG InitPackets;
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG InitUIFrames;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxMemoryUsage;
+ ULONG DefaultT1Timeout;
+ ULONG DefaultT2Timeout;
+ ULONG DefaultTiTimeout;
+ ULONG LlcRetries;
+ ULONG LlcMaxWindowSize;
+ ULONG MaximumIncomingFrames;
+ ULONG NameQueryRetries;
+ ULONG NameQueryTimeout;
+ ULONG AddNameQueryRetries;
+ ULONG AddNameQueryTimeout;
+ ULONG GeneralRetries;
+ ULONG GeneralTimeout;
+ ULONG WanNameQueryRetries;
+
+ ULONG UseDixOverEthernet;
+ ULONG QueryWithoutSourceRouting;
+ ULONG AllRoutesNameRecognized;
+ ULONG MinimumSendWindowLimit;
+
+ //
+ // Names contains NumAdapters pairs of NDIS adapter names (which
+ // nbf binds to) and device names (which nbf exports). The nth
+ // adapter name is in location n and the device name is in
+ // DevicesOffset+n (DevicesOffset may be different from NumAdapters
+ // if the registry Bind and Export strings are different sizes).
+ //
+
+ ULONG NumAdapters;
+ ULONG DevicesOffset;
+ NDIS_STRING Names[1];
+
+} CONFIG_DATA, *PCONFIG_DATA;
+
+#endif
diff --git a/private/ntos/tdi/nbf/nbfconst.h b/private/ntos/tdi/nbf/nbfconst.h
new file mode 100644
index 000000000..9ca5f4072
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfconst.h
@@ -0,0 +1,436 @@
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbfconst.h
+
+Abstract:
+
+ This header file defines manifest constants for the NT NBF transport
+ provider. It is included by nbf.h.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove pc586- and PDI-specific support. Add NDIS support. Note
+ changes to be made here if MAC dependence of NDIS changes. (search
+ for (PDI)
+
+--*/
+
+#ifndef _NBFCONST_
+#define _NBFCONST_
+
+
+//
+// DEBUGGING SUPPORT. DBG is a macro that is turned on at compile time
+// to enable debugging code in the system. If this is turned on, then
+// you can use the IF_NBFDBG(flags) macro in the NBF code to selectively
+// enable a piece of debugging code in the transport. This macro tests
+// NbfDebug, a global ULONG defined in NBFDRVR.C.
+//
+
+#if DBG
+
+#define NBF_DEBUG_SENDENG 0x00000001 // sendeng.c debugging.
+#define NBF_DEBUG_RCVENG 0x00000002 // rcveng.c debugging.
+#define NBF_DEBUG_IFRAMES 0x00000004 // displays sent/rec'd iframes.
+#define NBF_DEBUG_UFRAMES 0x00000008 // displays sent/rec'd uframes.
+#define NBF_DEBUG_DLCFRAMES 0x00000010 // displays sent/rec'd dlc frames.
+#define NBF_DEBUG_ADDRESS 0x00000020 // address.c debugging.
+#define NBF_DEBUG_CONNECT 0x00000040 // connect.c debugging.
+#define NBF_DEBUG_CONNOBJ 0x00000080 // connobj.c debugging.
+#define NBF_DEBUG_DEVCTX 0x00000100 // devctx.c debugging.
+#define NBF_DEBUG_DLC 0x00000200 // dlc.c data link engine debugging.
+#define NBF_DEBUG_INFO 0x00000400 // info.c debugging
+#define NBF_DEBUG_EVENT 0x00000800 // event.c debugging.
+#define NBF_DEBUG_FRAMECON 0x00001000 // framecon.c debugging.
+#define NBF_DEBUG_FRAMESND 0x00002000 // framesnd.c debugging.
+#define NBF_DEBUG_DYNAMIC 0x00004000 // dynamic allocation debugging.
+#define NBF_DEBUG_LINK 0x00008000 // link.c debugging.
+#define NBF_DEBUG_RESOURCE 0x00010000 // resource allocation debugging.
+#define NBF_DEBUG_DISPATCH 0x00020000 // IRP request dispatching.
+#define NBF_DEBUG_PACKET 0x00040000 // packet.c debugging.
+#define NBF_DEBUG_REQUEST 0x00080000 // request.c debugging.
+#define NBF_DEBUG_TIMER 0x00100000 // timer.c debugging.
+#define NBF_DEBUG_DLCRETRANSMIT 0x00200000 // DLC REJ debugging.
+#define NBF_DEBUG_REGISTRY 0x00400000 // registry access.
+#define NBF_DEBUG_NDIS 0x00800000 // NDIS related information
+#define NBF_DEBUG_LINKTREE 0x01000000 // Link splay tree debugging
+#define NBF_DEBUG_TEARDOWN 0x02000000 // link/connection teardown info
+#define NBF_DEBUG_REFCOUNTS 0x04000000 // link/connection ref/deref information
+#define NBF_DEBUG_IRP 0x08000000 // irp completion debugging
+#define NBF_DEBUG_DATAGRAMS 0x10000000 // datagram send/receive
+#define NBF_DEBUG_SETUP 0x20000000 // debug session setup
+#define NBF_DEBUG_CONFIG 0x40000000 // debug configuration
+
+//
+// past here are debug things that are really frequent; don't use them
+// unless you want LOTS of output
+//
+#define NBF_DEBUG_TIMERDPC 0x10000000 // the timer DPC
+#define NBF_DEBUG_PKTCONTENTS 0x20000000 // dump packet contents in dbg
+#define NBF_DEBUG_TIMERCODE 0x40000000 // enable check code in timer
+#define NBF_DEBUG_TRACKTDI 0x80000000 // store tdi info when set
+
+
+extern ULONG NbfDebug; // in NBFDRVR.C.
+extern BOOLEAN NbfDisconnectDebug; // in NBFDRVR.C.
+
+#define TRACK_TDI_LIMIT 25
+#define TRACK_TDI_CAPTURE 36 // chosen to make debug line up nice
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ PVOID Connection;
+ UCHAR Contents[TRACK_TDI_CAPTURE];
+ } NBF_SEND;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ NTSTATUS Status;
+ PVOID NothingYet;
+ } NBF_SEND_COMPLETE;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ PVOID Connection;
+ PVOID NothingYet;
+ } NBF_RECEIVE;
+
+typedef struct {
+ PVOID Request;
+ PIRP Irp;
+ NTSTATUS Status;
+ UCHAR Contents[TRACK_TDI_CAPTURE];
+ } NBF_RECEIVE_COMPLETE;
+
+extern NBF_SEND NbfSends[TRACK_TDI_LIMIT+1];
+extern LONG NbfSendsNext;
+
+extern NBF_SEND_COMPLETE NbfCompletedSends[TRACK_TDI_LIMIT+1];
+extern LONG NbfCompletedSendsNext;
+
+extern NBF_RECEIVE NbfReceives[TRACK_TDI_LIMIT+1];
+extern LONG NbfReceivesNext;
+
+extern NBF_RECEIVE_COMPLETE NbfCompletedReceives[TRACK_TDI_LIMIT+1];
+extern LONG NbfCompletedReceivesNext;
+
+#endif
+
+//
+// some convenient constants used for timing. All values are in clock ticks.
+//
+
+#define MICROSECONDS 10
+#define MILLISECONDS 10000 // MICROSECONDS*1000
+#define SECONDS 10000000 // MILLISECONDS*1000
+
+
+//
+// BUGBUG: temporary things used by nbf that are caused by the change-over from
+// (never implimented) PDI support to NDIS support. They may be removed pending
+// resolution of NDIS issues about MAC support.
+//
+
+#define PDI_SOURCE_ROUTE 0x00000002 // source routing field is specified.
+#define PDI_HARDWARE_ADDRESS 0x00000004 // hardware address field is specified.
+#define PDI_TRUNCATED 0x00000001 // PSDU was truncated.
+#define PDI_FRAGMENT 0x00000002 // PSDU was fragmented.
+#define PDI_BROADCAST 0x00000004 // PSDU was broadcast.
+#define PDI_MULTICAST 0x00000008 // PSDU was multicast/functional.
+#define PDI_SOURCE_ROUTING 0x00000010 // PSDU contained source routing information.
+
+
+
+//
+// MAJOR PROTOCOL IDENTIFIERS THAT CHARACTERIZE THIS DRIVER.
+//
+
+#define NBF_DEVICE_NAME L"\\Device\\Nbf"// name of our driver.
+#ifdef _PNP_POWER
+#define NBF_NAME L"Nbf" // name for protocol chars.
+#endif
+#define DSAP_NETBIOS_OVER_LLC 0xf0 // NETBEUI always has DSAP 0xf0.
+#define PSAP_LLC 0 // LLC always runs over PSAP 0.
+#define MAX_SOURCE_ROUTE_LENGTH 32 // max. bytes of SR. info.
+#define MAX_NETWORK_NAME_LENGTH 128 // # bytes in netname in TP_ADDRESS.
+#define MAX_USER_PACKET_DATA 1500 // max. user bytes per DFM/DOL.
+
+#define NBF_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// MAJOR CONFIGURATION PARAMETERS THAT WILL BE MOVED TO THE INIT-LARGE_INTEGER
+// CONFIGURATION MANAGER.
+//
+
+#define MAX_REQUESTS 30
+#define MAX_UI_FRAMES 25
+#define MAX_SEND_PACKETS 40
+#define MAX_RECEIVE_PACKETS 30
+#define MAX_RECEIVE_BUFFERS 15
+#define MAX_LINKS 10
+#define MAX_CONNECTIONS 10
+#define MAX_ADDRESSFILES 10
+#define MAX_ADDRESSES 10
+
+#define MIN_UI_FRAMES 5 // + one per address + one per connection
+#define MIN_SEND_PACKETS 20 // + one per link + one per connection
+#define MIN_RECEIVE_PACKETS 10 // + one per link + one per address
+#define MIN_RECEIVE_BUFFERS 5 // + one per address
+
+#define SEND_PACKET_RESERVED_LENGTH (sizeof (SEND_PACKET_TAG))
+#define RECEIVE_PACKET_RESERVED_LENGTH (sizeof (RECEIVE_PACKET_TAG))
+
+
+#define ETHERNET_HEADER_SIZE 14 // BUGBUG: used for current NDIS compliance
+#define ETHERNET_PACKET_SIZE 1514
+
+#define MAX_DEFERRED_TRAVERSES 6 // number of times we can go through
+ // the deferred operations queue and
+ // not do anything without causing an
+ // error indication
+
+
+//
+// NETBIOS PROTOCOL CONSTANTS.
+//
+
+#define NETBIOS_NAME_LENGTH 16
+#define NETBIOS_SESSION_LIMIT 254 // max # of sessions/link. (abs limit is 254)
+
+#define NAME_QUERY_RETRIES 3 // 2 retrie(s), plus the first one.
+#define ADD_NAME_QUERY_RETRIES 3 // 1 retrie(s) plus the first one.
+#define WAN_NAME_QUERY_RETRIES 5 // for NdisMediumWan only.
+
+#define NAME_QUERY_TIMEOUT (500*MILLISECONDS)
+#define ADD_NAME_QUERY_TIMEOUT (500*MILLISECONDS)
+
+//
+// DATA LINK PROTOCOL CONSTANTS.
+//
+// There are two timers, short and long. T1, T2, and the purge
+// timer are run off of the short timer, Ti and the adaptive timer
+// is run off of the long one.
+//
+
+#define SHORT_TIMER_DELTA (50*MILLISECONDS)
+#define LONG_TIMER_DELTA (1*SECONDS)
+
+#define DLC_DEFAULT_T1 (600 * MILLISECONDS)
+#define DLC_DEFAULT_T2 (150 * MILLISECONDS)
+#define DLC_DEFAULT_TI (30 * SECONDS)
+#define DLC_RETRIES (8) // number of poll retries at LLC level.
+#define DLC_RETRANSMIT_THRESHOLD (10) // up to n retransmissions acceptable.
+#define DLC_WINDOW_LIMIT (10) // incr. to 127 when packet pool expanded.
+
+#define DLC_TIMER_ACCURACY 8 // << between BaseT1Timeout and CurrentT1Timeout
+
+
+#define TIMER_ADAPTIVE_TICKS ((DLC_DEFAULT_T1*60)/LONG_TIMER_DELTA) // time between adaptive runs.
+#define TIMER_PURGE_TICKS ((DLC_DEFAULT_T1*10)/SHORT_TIMER_DELTA) // time between adaptive purges.
+
+
+//
+// TDI defined timeouts
+//
+
+#define TDI_TIMEOUT_SEND 60L // sends go 120 seconds
+#define TDI_TIMEOUT_RECEIVE 0L // receives
+#define TDI_TIMEOUT_CONNECT 60L
+#define TDI_TIMEOUT_LISTEN 0L // listens default to never.
+#define TDI_TIMEOUT_DISCONNECT 60L // should be 30
+#define TDI_TIMEOUT_NAME_REGISTRATION 60L
+
+
+
+//
+// GENERAL CAPABILITIES STATEMENTS THAT CANNOT CHANGE.
+//
+
+#define NBF_MAX_TSDU_SIZE 65535 // maximum TSDU size supported by NetBIOS.
+#define NBF_MAX_DATAGRAM_SIZE 512 // maximum Datagram size supported by NetBIOS.
+#define NBF_MAX_CONNECTION_USER_DATA 0 // no user data supported on connect.
+#define NBF_SERVICE_FLAGS ( \
+ TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_MESSAGE_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY | \
+ TDI_SERVICE_BROADCAST_SUPPORTED | \
+ TDI_SERVICE_MULTICAST_SUPPORTED | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE )
+
+#define NBF_MIN_LOOKAHEAD_DATA 256 // minimum guaranteed lookahead data.
+#define NBF_MAX_LOOKAHEAD_DATA 256 // maximum guaranteed lookahead data.
+
+#define NBF_MAX_LOOPBACK_LOOKAHEAD 192 // how much is copied over for loopback
+
+//
+// Number of TDI resources that we report.
+//
+
+#define NBF_TDI_RESOURCES 9
+
+
+//
+// NetBIOS name types used in the NetBIOS Frames Protocol Connectionless PDUs.
+//
+
+#define NETBIOS_NAME_TYPE_UNIQUE 0x00 // name is unique on the network.
+#define NETBIOS_NAME_TYPE_GROUP 0x01 // name is a group name.
+#define NETBIOS_NAME_TYPE_EITHER 0x02 // used in NbfMatchNetbiosAddress
+
+//
+// STATUS_QUERY request types. If the sender is following pre-2.1 protocol,
+// then a simple request-response exchange is performed. Later versions
+// store the "total number of names received so far" in the request type
+// field, except for the first request, which must contain a 1 in this field.
+//
+
+#define STATUS_QUERY_REQUEST_TYPE_PRE21 0x00 // request is 1.x or 2.0.
+#define STATUS_QUERY_REQUEST_TYPE_FIRST 0x01 // first request, 2.1 or above.
+
+//
+// If the LocalSessionNumber field contains a 0, then the request is really
+// a FIND.NAME. If the field is non-zero, then it is the local session
+// number that will be provided in all connection-oriented headers thereafter.
+//
+
+#define NAME_QUERY_LSN_FIND_NAME 0x00 // LSN for FIND.NAME request.
+
+//
+// NAME_RECOGNIZED LocalSessionNumber status values. If the connection
+// request was rejected, then one of the following values is placed in
+// the LocalSessionNumber field. NAME_RECOGNIZED can also be used as a
+// FIND.NAME response, in which case the NO_LISTENS status is overloaded
+// to also mean a FIND.NAME.
+//
+
+#define NAME_RECOGNIZED_LSN_NO_LISTENS 0x00 // no listens available.
+#define NAME_RECOGNIZED_LSN_FIND_NAME 0x00 // this is a find name response.
+#define NAME_RECOGNIZED_LSN_NO_RESOURCE 0xff // listen available, but no resources.
+
+//
+// STATUS_RESPONSE response types. If the sender is following pre-2.1
+// protocol, then a simple request-response exchange is performed. Later
+// versions store the "total number of names sent so far" in the request
+// type field. This value is cumulative, and includes the count of names
+// sent with the current response, as well as from previous responses.
+//
+
+#define STATUS_RESPONSE_PRE21 0x00 // request is 1.x or 2.0.
+#define STATUS_RESPONSE_FIRST 0x01 // first request, 2.1 or above.
+
+//
+// DATA_FIRST_MIDDLE option bitflags.
+//
+
+#define DFM_OPTIONS_RECEIVE_CONTINUE 0x01 // RECEIVE_CONTINUE requested.
+#define DFM_OPTIONS_NO_ACK 0x02 // no DATA_ACK frame expected.
+#define DFM_OPTIONS_RESYNCH 0x04 // set resynch indicator/this frame.
+#define DFM_OPTIONS_ACK_INCLUDED 0x08 // piggyback ack included.
+
+//
+// DATA_ONLY_LAST option bitflags.
+//
+
+#define DOL_OPTIONS_RESYNCH 0x01 // set resynch indicator/this frame.
+#define DOL_OPTIONS_NO_ACK 0x02 // no DATA_ACK frame expected.
+#define DOL_OPTIONS_ACK_W_DATA_ALLOWED 0x04 // piggyback ack allowed.
+#define DOL_OPTIONS_ACK_INCLUDED 0x08 // piggyback ack included.
+
+//
+// SESSION_CONFIRM option bitflags.
+//
+
+#define SESSION_CONFIRM_OPTIONS_20 0x01 // set if NETBIOS 2.0 or above.
+#define SESSION_CONFIRM_NO_ACK 0x80 // set if NO.ACK protocol supported.
+
+//
+// SESSION_END reason codes.
+//
+
+#define SESSION_END_REASON_HANGUP 0x0000 // normal termination via HANGUP.
+#define SESSION_END_REASON_ABEND 0x0001 // abnormal session termination.
+
+//
+// SESSION_INITIALIZE option bitflags.
+//
+
+#define SESSION_INIT_OPTIONS_20 0x01 // set if NETBIOS 2.0 or above.
+#define SESSION_INIT_OPTIONS_LF 0x0E // Maximum largest frame value
+#define SESSION_INIT_NO_ACK 0x80 // set if NO.ACK protocol supported.
+
+//
+// NO_RECEIVE option bitflags.
+//
+
+#define NO_RECEIVE_PARTIAL_NO_ACK 0x02 // NO.ACK data partially received.
+
+//
+// Resource IDs for query and error logging.
+//
+
+#define LINK_RESOURCE_ID 11
+#define ADDRESS_RESOURCE_ID 12
+#define ADDRESS_FILE_RESOURCE_ID 13
+#define CONNECTION_RESOURCE_ID 14
+#define REQUEST_RESOURCE_ID 15
+
+#define UI_FRAME_RESOURCE_ID 21
+#define PACKET_RESOURCE_ID 22
+#define RECEIVE_PACKET_RESOURCE_ID 23
+#define RECEIVE_BUFFER_RESOURCE_ID 24
+
+
+//
+// memory management additions
+//
+
+//
+// Fake IOCTLs used for kernel mode testing.
+//
+
+#define IOCTL_NBF_BASE FILE_DEVICE_TRANSPORT
+
+#define _NBF_CONTROL_CODE(request,method) \
+ ((IOCTL_NBF_BASE)<<16 | (request<<2) | method)
+
+#define IOCTL_TDI_SEND_TEST _NBF_CONTROL_CODE(26,0)
+#define IOCTL_TDI_RECEIVE_TEST _NBF_CONTROL_CODE(27,0)
+#define IOCTL_TDI_SERVER_TEST _NBF_CONTROL_CODE(28,0)
+
+//
+// More debugging stuff
+//
+
+#define NBF_REQUEST_SIGNATURE ((CSHORT)0x4702)
+#define NBF_LINK_SIGNATURE ((CSHORT)0x4703)
+#define NBF_CONNECTION_SIGNATURE ((CSHORT)0x4704)
+#define NBF_ADDRESSFILE_SIGNATURE ((CSHORT)0x4705)
+#define NBF_ADDRESS_SIGNATURE ((CSHORT)0x4706)
+#define NBF_DEVICE_CONTEXT_SIGNATURE ((CSHORT)0x4707)
+#define NBF_PACKET_SIGNATURE ((CSHORT)0x4708)
+
+#if DBG
+extern PVOID * NbfConnectionTable;
+extern PVOID * NbfRequestTable;
+extern PVOID * NbfUiFrameTable;
+extern PVOID * NbfSendPacketTable;
+extern PVOID * NbfLinkTable;
+extern PVOID * NbfAddressFileTable;
+extern PVOID * NbfAddressTable;
+#endif
+
+#endif // _NBFCONST_
diff --git a/private/ntos/tdi/nbf/nbfdebug.c b/private/ntos/tdi/nbf/nbfdebug.c
new file mode 100644
index 000000000..2f5aadbd7
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfdebug.c
@@ -0,0 +1,646 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfdebug.c
+
+Abstract:
+
+ This module contains code that implements debug things for NBF. It is
+ compiled only if debug is on in the compile phase.
+
+Author:
+
+ David Beaver (dbeaver) 18-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modified to use new TDI interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+
+VOID
+DisplayOneFrame(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a temporary debugging aid that displays an I-frame
+ before it is sent. This ensures that we have formatted all our packets
+ correctly.
+
+Arguments:
+
+ Packet - Pointer to a TP_PACKET representing an I-frame to be displayed.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCH s, e;
+ ULONG ns, nr; // I-frame (NetBIOS) cracking.
+ PNBF_HDR_CONNECTION NbfHeader;
+ PDLC_I_FRAME DlcHeader;
+ BOOLEAN Command, PollFinal;
+ BOOLEAN IsUFrame=FALSE;
+ UCHAR CmdByte;
+
+ PDLC_S_FRAME SFrame; // DLC frame cracking.
+ PDLC_U_FRAME UFrame;
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[14]);
+ NbfHeader = (PNBF_HDR_CONNECTION)&(Packet->Header[18]);
+ ns = DlcHeader->SendSeq >> 1;
+ nr = DlcHeader->RcvSeq >> 1;
+ PollFinal = (BOOLEAN)(DlcHeader->RcvSeq & DLC_I_PF);
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+
+ if (DlcHeader->SendSeq & DLC_I_INDICATOR) {
+ IF_NBFDBG (NBF_DEBUG_DLCFRAMES) {
+ } else {
+ return; // if DLCFRAMES not set, don't print.
+ }
+
+ SFrame = (PDLC_S_FRAME)DlcHeader; // alias.
+ UFrame = (PDLC_U_FRAME)DlcHeader; // alias.
+ CmdByte = SFrame->Command;
+ IsUFrame = (BOOLEAN)((UFrame->Command & DLC_U_INDICATOR) == DLC_U_INDICATOR);
+ if (IsUFrame) {
+ CmdByte = (UCHAR)(UFrame->Command & ~DLC_U_PF);
+ }
+
+ switch (CmdByte) {
+ case DLC_CMD_RR:
+ s = "RR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_RNR:
+ s = "RNR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_REJ:
+ s = "REJ";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_SABME:
+ s = "SABME";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DISC:
+ s = "DISC";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_UA:
+ s = "UA";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DM:
+ s = "DM";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_FRMR:
+ s = "FRMR";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_XID:
+ s = "XID";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_TEST:
+ s = "TEST";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ default:
+ s = "(UNKNOWN)";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ }
+ return;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ } else {
+ return; // if IFRAMES not set, don't print.
+ }
+
+ switch (NbfHeader->Command) {
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ s = "ADD_GROUP_NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+ s = "ADD_NAME_QUERY"; break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+ s = "NAME_IN_CONFLICT"; break;
+
+ case NBF_CMD_STATUS_QUERY:
+ s = "STATUS_QUERY"; break;
+
+ case NBF_CMD_TERMINATE_TRACE:
+ s = "TERMINATE_TRACE"; break;
+
+ case NBF_CMD_DATAGRAM:
+ s = "DATAGRAM"; break;
+
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ s = "BROADCAST_DATAGRAM"; break;
+
+ case NBF_CMD_NAME_QUERY:
+ s = "NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ s = "ADD_NAME_RESPONSE"; break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+ s = "NAME_RECOGNIZED"; break;
+
+ case NBF_CMD_STATUS_RESPONSE:
+ s = "STATUS_RESPONSE"; break;
+
+ case NBF_CMD_TERMINATE_TRACE2:
+ s = "TERMINATE_TRACE2"; break;
+
+ case NBF_CMD_DATA_ACK:
+ s = "DATA_ACK"; break;
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ s = "DATA_FIRST_MIDDLE"; break;
+
+ case NBF_CMD_DATA_ONLY_LAST:
+ s = "DATA_ONLY_LAST"; break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+ s = "SESSION_CONFIRM"; break;
+
+ case NBF_CMD_SESSION_END:
+ s = "SESSION_END"; break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+ s = "SESSION_INITIALIZE"; break;
+
+ case NBF_CMD_NO_RECEIVE:
+ s = "NO_RECEIVE"; break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+ s = "RECEIVE_OUTSTANDING"; break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+ s = "RECEIVE_CONTINUE"; break;
+
+ case NBF_CMD_SESSION_ALIVE:
+ s = "SESSION_ALIVE"; break;
+
+ default:
+ s = "<<<<UNKNOWN I PACKET TYPE>>>>";
+ } /* switch */
+
+ if (HEADER_LENGTH(NbfHeader) != 14) {
+ e = "(LENGTH IN ERROR) ";
+ } else if (HEADER_SIGNATURE(NbfHeader) != NETBIOS_SIGNATURE) {
+ e = "(SIGNATURE IN ERROR) ";
+ } else {
+ e = "";
+ }
+
+ DbgPrint ("DLC: I-%s/%s, N(S)=%ld, N(R)=%ld %s",
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ ns, nr, e);
+ DbgPrint (s);
+ DbgPrint (" ( D1=%ld, D2=%ld, XC=%ld, RC=%ld )\n",
+ (ULONG)NbfHeader->Data1,
+ (ULONG)(NbfHeader->Data2Low+NbfHeader->Data2High*256),
+ TRANSMIT_CORR(NbfHeader),
+ RESPONSE_CORR(NbfHeader));
+} /* DisplayOneFrame */
+
+
+VOID
+NbfDisplayUIFrame(
+ PTP_UI_FRAME OuterFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a temporary debugging aid that displays a UI frame
+ before it is sent by NbfSendUIFrame. This ensures that we have formatted
+ all our UI frames correctly.
+
+Arguments:
+
+ RawFrame - Pointer to a connectionless frame to be sent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCH s, e;
+ UCHAR ReceiverName [17];
+ UCHAR SenderName [17];
+ BOOLEAN PollFinal, Command;
+ PDLC_S_FRAME SFrame;
+ PDLC_U_FRAME UFrame;
+ USHORT i;
+ PDLC_FRAME DlcHeader;
+ PNBF_HDR_CONNECTIONLESS NbfHeader;
+
+ //
+
+ DlcHeader = (PDLC_FRAME)&(OuterFrame->Header[14]);
+ NbfHeader = (PNBF_HDR_CONNECTIONLESS)&(OuterFrame->Header[17]);
+
+ if (DlcHeader->Byte1 != DLC_CMD_UI) {
+
+ IF_NBFDBG (NBF_DEBUG_DLCFRAMES) {
+ } else {
+ return; // don't print this if DLCFRAMES is off.
+ }
+
+ Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
+ SFrame = (PDLC_S_FRAME)DlcHeader; // alias.
+ UFrame = (PDLC_U_FRAME)DlcHeader; // alias.
+ switch (DlcHeader->Byte1) {
+ case DLC_CMD_RR:
+ s = "RR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_RNR:
+ s = "RNR";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_REJ:
+ s = "REJ";
+ PollFinal = (BOOLEAN)(SFrame->RcvSeq & DLC_S_PF);
+ DbgPrint ("DLC: %s-%s/%s(%ld) ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0",
+ (ULONG)(SFrame->RcvSeq >> 1));
+ break;
+
+ case DLC_CMD_SABME:
+ s = "SABME";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DISC:
+ s = "DISC";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_UA:
+ s = "UA";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_DM:
+ s = "DM";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_FRMR:
+ s = "FRMR";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_XID:
+ s = "XID";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ case DLC_CMD_TEST:
+ s = "TEST";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ break;
+
+ default:
+ s = "(UNKNOWN)";
+ PollFinal = (BOOLEAN)(UFrame->Command & DLC_U_PF);
+ DbgPrint ("DLC: %s-%s/%s ---->\n",
+ s,
+ Command ? "c" : "r",
+ PollFinal ? (Command ? "p" : "f") : "0");
+ }
+ return;
+ }
+
+ //
+ // We know that this is an I-frame, because the bottom bit of the
+ // first byte in the DLC header is cleared. Go ahead and print it
+ // as though it were a NetBIOS packet, which it should be.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IFRAMES) {
+ } else {
+ return; // don't print this if IFRAMES is off.
+ }
+
+ switch (NbfHeader->Command) {
+ case NBF_CMD_ADD_GROUP_NAME_QUERY:
+ s = "ADD_GROUP_NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_QUERY:
+ s = "ADD_NAME_QUERY"; break;
+
+ case NBF_CMD_NAME_IN_CONFLICT:
+ s = "NAME_IN_CONFLICT"; break;
+
+ case NBF_CMD_STATUS_QUERY:
+ s = "STATUS_QUERY"; break;
+
+ case NBF_CMD_TERMINATE_TRACE:
+ s = "TERMINATE_TRACE"; break;
+
+ case NBF_CMD_DATAGRAM:
+ s = "DATAGRAM"; break;
+
+ case NBF_CMD_DATAGRAM_BROADCAST:
+ s = "BROADCAST_DATAGRAM"; break;
+
+ case NBF_CMD_NAME_QUERY:
+ s = "NAME_QUERY"; break;
+
+ case NBF_CMD_ADD_NAME_RESPONSE:
+ s = "ADD_NAME_RESPONSE"; break;
+
+ case NBF_CMD_NAME_RECOGNIZED:
+ s = "NAME_RECOGNIZED"; break;
+
+ case NBF_CMD_STATUS_RESPONSE:
+ s = "STATUS_RESPONSE"; break;
+
+ case NBF_CMD_TERMINATE_TRACE2:
+ s = "TERMINATE_TRACE2"; break;
+
+ case NBF_CMD_DATA_ACK:
+ s = "DATA_ACK"; break;
+
+ case NBF_CMD_DATA_FIRST_MIDDLE:
+ s = "DATA_FIRST_MIDDLE"; break;
+
+ case NBF_CMD_DATA_ONLY_LAST:
+ s = "DATA_ONLY_LAST"; break;
+
+ case NBF_CMD_SESSION_CONFIRM:
+ s = "SESSION_CONFIRM"; break;
+
+ case NBF_CMD_SESSION_END:
+ s = "SESSION_END"; break;
+
+ case NBF_CMD_SESSION_INITIALIZE:
+ s = "SESSION_INITIALIZE"; break;
+
+ case NBF_CMD_NO_RECEIVE:
+ s = "NO_RECEIVE"; break;
+
+ case NBF_CMD_RECEIVE_OUTSTANDING:
+ s = "RECEIVE_OUTSTANDING"; break;
+
+ case NBF_CMD_RECEIVE_CONTINUE:
+ s = "RECEIVE_CONTINUE"; break;
+
+ case NBF_CMD_SESSION_ALIVE:
+ s = "SESSION_ALIVE"; break;
+
+ default:
+ s = "<<<<UNKNOWN UI PACKET TYPE>>>>";
+ } /* switch */
+
+ for (i=0; i<16; i++) { // copy NetBIOS names.
+ SenderName [i] = NbfHeader->SourceName [i];
+ ReceiverName [i] = NbfHeader->DestinationName [i];
+ }
+ SenderName [16] = 0; // install zero bytes.
+ ReceiverName [16] = 0;
+
+ if (HEADER_LENGTH(NbfHeader) != 44) {
+ e = "(LENGTH IN ERROR) ";
+ } else if (HEADER_SIGNATURE(NbfHeader) != NETBIOS_SIGNATURE) {
+ e = "(SIGNATURE IN ERROR) ";
+ } else {
+ e = "";
+ }
+
+ DbgPrint ("[UI] %s", e);
+ DbgPrint (s);
+ DbgPrint (" ( D1=%ld, D2=%ld, XC=%ld, RC=%ld, ",
+ (ULONG)NbfHeader->Data1,
+ (ULONG)(NbfHeader->Data2Low+NbfHeader->Data2High*256),
+ TRANSMIT_CORR(NbfHeader),
+ RESPONSE_CORR(NbfHeader));
+ DbgPrint ("'%s'->'%s' ) ---->\n", SenderName, ReceiverName);
+} /* NbfDisplayUIFrame */
+
+
+VOID
+NbfHexDumpLine(
+ PCHAR pch,
+ ULONG len,
+ PCHAR s,
+ PCHAR t
+ )
+/*++
+
+Routine Description:
+
+ This routine builds a line of text containing hex and printable characters.
+
+Arguments:
+
+ IN pch - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+ IN s - Supplies the start of the buffer to be loaded with the string
+ of hex characters.
+ IN t - Supplies the start of the buffer to be loaded with the string
+ of printable ascii characters.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ static UCHAR rghex[] = "0123456789ABCDEF";
+
+ UCHAR c;
+ UCHAR *hex, *asc;
+
+
+ hex = s;
+ asc = t;
+
+ *(asc++) = '*';
+ while (len--) {
+ c = *(pch++);
+ *(hex++) = rghex [c >> 4] ;
+ *(hex++) = rghex [c & 0x0F];
+ *(hex++) = ' ';
+ *(asc++) = (c < ' ' || c > '~') ? (CHAR )'.' : c;
+ }
+ *(asc++) = '*';
+ *asc = 0;
+ *hex = 0;
+
+}
+
+
+VOID
+NbfFormattedDump(
+ PCHAR far_p,
+ ULONG len
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs a buffer in lines of text containing hex and
+ printable characters.
+
+Arguments:
+
+ IN far_p - Supplies buffer to be displayed.
+ IN len - Supplies the length of the buffer in bytes.
+
+Return Value:
+
+ none.
+
+--*/
+{
+ ULONG l;
+ char s[80], t[80];
+
+ while (len) {
+ l = len < 16 ? len : 16;
+
+ DbgPrint ("\n%lx ", far_p);
+ NbfHexDumpLine (far_p, l, s, t);
+ DbgPrint ("%s%.*s%s", s, 1 + ((16 - l) * 3), "", t);
+
+ len -= l;
+ far_p += l;
+ }
+ DbgPrint ("\n");
+}
+
+#endif
diff --git a/private/ntos/tdi/nbf/nbfdrvr.c b/private/ntos/tdi/nbf/nbfdrvr.c
new file mode 100644
index 000000000..2f42766ff
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfdrvr.c
@@ -0,0 +1,2493 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfdrvr.c
+
+Abstract:
+
+ This module contains code which defines the NetBIOS Frames Protocol
+ transport provider's device object.
+
+Author:
+
+ David Beaver (dbeaver) 2-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+//#pragma warning(error:4101) // Unreferenced local variable
+
+//
+// This is a list of all the device contexts that NBF owns,
+// used while unloading.
+//
+
+LIST_ENTRY NbfDeviceList = {0,0}; // initialized for real at runtime.
+
+#ifdef _PNP_POWER
+
+//
+// Global variables this is a copy of the path in the registry for
+// configuration data.
+//
+
+UNICODE_STRING NbfRegistryPath;
+
+//
+// We need the driver object to create device context structures.
+//
+
+PDRIVER_OBJECT NbfDriverObject;
+
+#endif
+
+
+#ifdef NBF_LOCKS // see spnlckdb.c
+
+extern KSPIN_LOCK NbfGlobalLock;
+
+#endif // def NBF_LOCKS
+
+//
+// The debugging longword, containing a bitmask as defined in NBFCONST.H.
+// If a bit is set, then debugging is turned on for that component.
+//
+
+#if DBG
+
+ULONG NbfDebug = 0;
+BOOLEAN NbfDisconnectDebug;
+
+NBF_SEND NbfSends[TRACK_TDI_LIMIT+1];
+LONG NbfSendsNext;
+
+NBF_SEND_COMPLETE NbfCompletedSends[TRACK_TDI_LIMIT+1];
+LONG NbfCompletedSendsNext;
+
+NBF_RECEIVE NbfReceives[TRACK_TDI_LIMIT+1];
+LONG NbfReceivesNext;
+
+NBF_RECEIVE_COMPLETE NbfCompletedReceives[TRACK_TDI_LIMIT+1];
+LONG NbfCompletedReceivesNext=0;
+
+PVOID * NbfConnectionTable;
+PVOID * NbfRequestTable;
+PVOID * NbfUiFrameTable;
+PVOID * NbfSendPacketTable;
+PVOID * NbfLinkTable;
+PVOID * NbfAddressFileTable;
+PVOID * NbfAddressTable;
+
+
+LIST_ENTRY NbfGlobalRequestList;
+LIST_ENTRY NbfGlobalLinkList;
+LIST_ENTRY NbfGlobalConnectionList;
+KSPIN_LOCK NbfGlobalInterlock;
+KSPIN_LOCK NbfGlobalHistoryLock;
+
+PVOID
+TtdiSend ();
+
+PVOID
+TtdiReceive ();
+
+PVOID
+TtdiServer ();
+
+KEVENT TdiSendEvent;
+KEVENT TdiReceiveEvent;
+KEVENT TdiServerEvent;
+
+#endif
+
+#if MAGIC
+
+BOOLEAN NbfEnableMagic = FALSE; // Controls sending of magic bullets.
+
+#endif // MAGIC
+
+//
+// This prevents us from having a bss section
+//
+
+ULONG _setjmpexused = 0;
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbfUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+VOID
+NbfFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+NbfDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfDeallocateResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#ifdef RASAUTODIAL
+VOID
+NbfAcdBind();
+
+VOID
+NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#ifdef _PNP_POWER
+#pragma alloc_text(PAGE,NbfInitializeOneDeviceContext)
+#endif
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the NetBIOS Frames Protocol
+ transport driver. It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of NBF's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ ULONG j;
+ UNICODE_STRING nameString;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+
+ PCONFIG_DATA NbfConfig = NULL;
+
+ //
+
+ ASSERT (sizeof (SHORT) == 2);
+
+#ifdef MEMPRINT
+ MemPrintInitialize ();
+#endif
+
+#ifdef NBF_LOCKS
+ KeInitializeSpinLock( &NbfGlobalLock );
+#endif
+
+#if DBG
+ InitializeListHead (&NbfGlobalRequestList);
+ InitializeListHead (&NbfGlobalLinkList);
+ InitializeListHead (&NbfGlobalConnectionList);
+ KeInitializeSpinLock (&NbfGlobalInterlock);
+ KeInitializeSpinLock (&NbfGlobalHistoryLock);
+#endif
+
+#ifdef _PNP_POWER
+
+ NbfRegistryPath = *RegistryPath;
+ NbfRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
+ RegistryPath->MaximumLength,
+ ' FBN');
+
+ if (NbfRegistryPath.Buffer == NULL) {
+ PANIC(" Failed to allocate Registry Path!\n");
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlCopyMemory(NbfRegistryPath.Buffer, RegistryPath->Buffer,
+ RegistryPath->MaximumLength);
+ NbfDriverObject = DriverObject;
+ RtlInitUnicodeString( &nameString, NBF_NAME);
+ TdiInitialize();
+
+#else // NOT _PNP_POWER
+
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in NbfConfig.
+ //
+
+ status = NbfConfigureTransport(RegistryPath, &NbfConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, Nbf initialization failed.\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ RtlInitUnicodeString( &nameString, NBF_DEVICE_NAME );
+#endif
+
+ status = NbfRegisterProtocol (&nameString);
+
+ if (!NT_SUCCESS (status)) {
+
+#ifdef _PNP_POWER
+
+ //
+ // No configuration info read at startup when using PNP
+ //
+
+ ExFreePool(NbfRegistryPath.Buffer);
+#else
+ //
+ // Free up config info for non PNP mode operation.
+ //
+
+ NbfFreeConfigurationInfo(NbfConfig);
+#endif
+ PANIC ("NbfInitialize: RegisterProtocol failed!\n");
+
+ NbfWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbfDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbfDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbfDispatch;
+
+ DriverObject->DriverUnload = NbfUnload;
+
+ //
+ // Initialize the global list of devices.
+ //
+
+ InitializeListHead (&NbfDeviceList);
+
+#ifndef _PNP_POWER
+
+#if DBG
+
+ //
+ // Allocate the debugging tables. In the PNP case we don't need these
+ // until we are activated by ProtocolBindAdapter
+ //
+
+ NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PVOID) *
+ (NbfConfig->InitConnections + 2 +
+ NbfConfig->InitRequests + 2 +
+ NbfConfig->InitUIFrames + 2 +
+ NbfConfig->InitPackets + 2 +
+ NbfConfig->InitLinks + 2 +
+ NbfConfig->InitAddressFiles + 2 +
+ NbfConfig->InitAddresses + 2),
+ ' FBN');
+
+ ASSERT (NbfConnectionTable);
+
+ NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
+ NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
+ NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
+ NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
+ NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
+ NbfAddressTable = NbfAddressFileTable + (NbfConfig->InitAddressFiles + 2);
+#endif
+
+
+ SuccessfulOpens = 0;
+
+ for (j=0;j<NbfConfig->NumAdapters;j++ ) {
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+ SuccessfulOpens += NbfInitializeOneDeviceContext(&status,
+ DriverObject,
+ NbfConfig, j
+ );
+
+ }
+
+ NbfFreeConfigurationInfo(NbfConfig);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ if (SuccessfulOpens > 0)
+ NbfAcdBind();
+#endif // RASAUTODIAL
+
+ return ((SuccessfulOpens>0) ? STATUS_SUCCESS :STATUS_DEVICE_DOES_NOT_EXIST);
+#else // _PNP_POWER
+ return(status);
+#endif
+
+}
+
+VOID
+NbfUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the NetBIOS Frames Protocol transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has NBF open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ while (!IsListEmpty (&NbfDeviceList)) {
+
+ p = RemoveHeadList (&NbfDeviceList);
+ DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
+
+ DeviceContext->State = DEVICECONTEXT_STATE_STOPPING;
+
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ NbfFreeResources (DeviceContext);
+
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ NbfCloseNdis (DeviceContext);
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
+
+ }
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ NbfDeregisterProtocol();
+
+ return;
+
+}
+
+
+VOID
+NbfFreeResources (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by NBF to clean up the data structures associated
+ with a given DeviceContext. When this routine exits, the DeviceContext
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ DeviceContext - Pointer to the DeviceContext we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PTP_UI_FRAME uiFrame;
+ PTP_ADDRESS address;
+ PTP_CONNECTION connection;
+ PTP_REQUEST request;
+ PTP_LINK link;
+ PTP_ADDRESS_FILE addressFile;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+
+
+ //
+ // Stop the timers.
+ //
+
+ NbfStopTimerSystem (DeviceContext);
+
+
+ //
+ // Clean up packet pool.
+ //
+
+ while ( DeviceContext->PacketPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbfDeallocateSendPacket (DeviceContext, packet);
+ }
+
+ //
+ // Clean up UI frame pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->UIFramePool ) ) {
+ p = RemoveHeadList( &DeviceContext->UIFramePool );
+ uiFrame = CONTAINING_RECORD (p, TP_UI_FRAME, Linkage );
+
+ NbfDeallocateUIFrame (DeviceContext, uiFrame);
+ }
+
+ //
+ // Clean up address pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ NbfDeallocateAddress (DeviceContext, address);
+ }
+
+ //
+ // Clean up address file pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ NbfDeallocateAddressFile (DeviceContext, addressFile);
+ }
+
+ //
+ // Clean up connection pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ NbfDeallocateConnection (DeviceContext, connection);
+ }
+
+ //
+ // Clean up link pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->LinkPool) ) {
+ p = RemoveHeadList (&DeviceContext->LinkPool);
+ link = CONTAINING_RECORD (p, TP_LINK, Linkage);
+
+ NbfDeallocateLink (DeviceContext, link);
+ }
+
+ //
+ // Clean up request pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
+ p = RemoveHeadList( &DeviceContext->RequestPool );
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
+
+ NbfDeallocateRequest (DeviceContext, request);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( DeviceContext->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&DeviceContext->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbfDeallocateReceivePacket (DeviceContext, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbfDeallocateReceiveBuffer (DeviceContext, BufferTag);
+ }
+
+
+ return;
+
+} /* NbfFreeResources */
+
+
+NTSTATUS
+NbfDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the NBF device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ ENTER_NBF;
+
+ //
+ // Check to see if NBF has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_DEVICE_CONTROL.\n");
+ }
+
+ Status = NbfDeviceControl (DeviceObject, Irp, IrpSp);
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
+ }
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+ return Status;
+} /* NbfDispatch */
+
+
+NTSTATUS
+NbfDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the NBF device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpSp;
+ PFILE_FULL_EA_INFORMATION openType;
+ USHORT i;
+ BOOLEAN found;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_CONNECTION Connection;
+
+ ENTER_NBF;
+
+ //
+ // Check to see if NBF has been initialized; if not, don't allow any use.
+ // Note that this only covers any user mode code use; kernel TDI clients
+ // will fail on their creation of an endpoint.
+ //
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (IrpSp->MajorFunction) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CREATE.\n");
+ }
+
+ openType =
+ (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbfOpenAddress (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<(USHORT)openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbfOpenConnection (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchOpenClose: IRP_MJ_CREATE on invalid type, type was: %s\n",
+ openType->EaName);
+ }
+
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchOpenClose: IRP_MJ_CREATE on control channel!\n");
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ IrpSp->FileObject->FsContext = (PVOID)(DeviceContext->ControlChannelIdentifier);
+ ++DeviceContext->ControlChannelIdentifier;
+ if (DeviceContext->ControlChannelIdentifier == 0) {
+ DeviceContext->ControlChannelIdentifier = 1;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ IrpSp->FileObject->FsContext2 = (PVOID)NBF_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CLOSE.\n");
+ }
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by NbfCloseAddress.
+ //
+
+ Status = NbfVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbfCloseAddress (DeviceObject, Irp, IrpSp);
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ //
+ // This is a connection
+ //
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+
+ Status = NbfCloseConnection (DeviceObject, Irp, IrpSp);
+ NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
+
+ }
+
+ break;
+
+ case NBF_FILE_TYPE_CONTROL:
+
+ //
+ // this always succeeds
+ //
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatch: IRP_MJ_CLOSE on unknown file type %lx.\n",
+ IrpSp->FileObject->FsContext2);
+ }
+
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: IRP_MJ_CLEANUP.\n");
+ }
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyAddressObject(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbfStopAddressFile (AddressFile, AddressFile->Address);
+ NbfDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address, AREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = NbfVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ NbfStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+ KeLowerIrql (oldirql);
+ Status = STATUS_SUCCESS;
+ NbfDereferenceConnection ("Temporary Use",Connection, CREF_BY_ID);
+ }
+
+ break;
+
+ case NBF_FILE_TYPE_CONTROL:
+
+ NbfStopControlChannel(
+ (PDEVICE_CONTEXT)DeviceObject,
+ (USHORT)IrpSp->FileObject->FsContext
+ );
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatch: IRP_MJ_CLEANUP on unknown file type %lx.\n",
+ IrpSp->FileObject->FsContext2);
+ }
+
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: OTHER (DEFAULT).\n");
+ }
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatch: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+ return Status;
+} /* NbfDispatchOpenClose */
+
+
+NTSTATUS
+NbfDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+ IrpSp - Pointer to current IRP stack frame.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Entered.\n");
+ }
+
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+#if MAGIC
+ case IOCTL_TDI_MAGIC_BULLET:
+
+ //
+ // Special: send the magic bullet (to trigger the Sniffer).
+ //
+
+ NbfPrint1 ("NBF: Sending user MagicBullet on %lx\n", DeviceContext);
+ {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+
+ if (IrpSp->Parameters.DeviceIoControl.Type3InputBuffer != NULL) {
+ NbfPrint0 ("NBF: DbgBreakPoint after MagicBullet\n");
+ DbgBreakPoint();
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+#endif
+
+#if DBG
+ case IOCTL_TDI_SEND_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start send side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiSendEvent, 0, FALSE );
+
+ break;
+
+ case IOCTL_TDI_RECEIVE_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiReceiveEvent, 0, FALSE );
+
+ break;
+
+ case IOCTL_TDI_SERVER_TEST:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: Internal IOCTL: start receive side test\n");
+ }
+
+ (VOID) KeSetEvent( &TdiServerEvent, 0, FALSE );
+
+ break;
+#endif
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDeviceControl: invalid request type.\n");
+ }
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+ // NbfDispatchInternal expects to complete the IRP,
+ // so we change Status to PENDING so we don't.
+ //
+
+ (VOID)NbfDispatchInternal (DeviceObject, Irp);
+ Status = STATUS_PENDING;
+
+ }
+ }
+
+ return Status;
+} /* NbfDeviceControl */
+
+
+NTSTATUS
+NbfDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PIO_STACK_LOCATION IrpSp;
+#if DBG
+ KIRQL IrqlOnEnter = KeGetCurrentIrql();
+#endif
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfInternalDeviceControl: Entered.\n");
+ }
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+ LEAVE_NBF;
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ {
+ PULONG Temp=(PULONG)&IrpSp->Parameters;
+ NbfPrint5 ("Got IrpSp %lx %lx %lx %lx %lx\n", Temp++, Temp++,
+ Temp++, Temp++, Temp++);
+ }
+ }
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->MinorFunction) {
+
+ case TDI_ACCEPT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
+ }
+
+ Status = NbfTdiAccept (Irp);
+ break;
+
+ case TDI_ACTION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAction request.\n");
+ }
+
+ Status = NbfTdiAction (DeviceContext, Irp);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiAccept request.\n");
+ }
+
+ Status = NbfTdiAssociateAddress (Irp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiDisassociateAddress request.\n");
+ }
+
+ Status = NbfTdiDisassociateAddress (Irp);
+ break;
+
+ case TDI_CONNECT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiConnect request\n");
+ }
+
+ Status = NbfTdiConnect (Irp);
+
+ break;
+
+ case TDI_DISCONNECT:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiDisconnect request.\n");
+ }
+
+ Status = NbfTdiDisconnect (Irp);
+ break;
+
+ case TDI_LISTEN:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiListen request.\n");
+ }
+
+ Status = NbfTdiListen (Irp);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiQueryInformation request.\n");
+ }
+
+ Status = NbfTdiQueryInformation (DeviceContext, Irp);
+ break;
+
+ case TDI_RECEIVE:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiReceive request.\n");
+ }
+
+ Status = NbfTdiReceive (Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiReceiveDatagram request.\n");
+ }
+
+ Status = NbfTdiReceiveDatagram (Irp);
+ break;
+
+ case TDI_SEND:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSend request.\n");
+ }
+
+ Status = NbfTdiSend (Irp);
+ break;
+
+ case TDI_SEND_DATAGRAM:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSendDatagram request.\n");
+ }
+
+ Status = NbfTdiSendDatagram (Irp);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSetEventHandler request.\n");
+ }
+
+ //
+ // Because this request will enable direct callouts from the
+ // transport provider at DISPATCH_LEVEL to a client-specified
+ // routine, this request is only valid in kernel mode, denying
+ // access to this request in user mode.
+ //
+
+ Status = NbfTdiSetEventHandler (Irp);
+ break;
+
+ case TDI_SET_INFORMATION:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: TdiSetInformation request.\n");
+ }
+
+ Status = NbfTdiSetInformation (Irp);
+ break;
+
+#if DBG
+ case 0x7f:
+
+ //
+ // Special: send the magic bullet (to trigger the Sniffer).
+ //
+
+ NbfPrint1 ("NBF: Sending MagicBullet on %lx\n", DeviceContext);
+ {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (DeviceContext, NULL);
+ }
+
+ Status = STATUS_SUCCESS;
+ break;
+#endif
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchInternal: invalid request type %lx\n",
+ IrpSp->MinorFunction);
+ }
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (Status == STATUS_PENDING) {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: request PENDING from handler.\n");
+ }
+ } else {
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint0 ("NbfDispatchInternal: request COMPLETED by handler.\n");
+ }
+
+ LEAVE_NBF;
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_DISPATCH) {
+ NbfPrint1 ("NbfDispatchInternal: exiting, status: %lx\n",Status);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ LEAVE_NBF;
+#if DBG
+ ASSERT (KeGetCurrentIrql() == IrqlOnEnter);
+#endif
+
+ return Status;
+
+} /* NbfDispatchInternal */
+
+
+VOID
+NbfWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN ULONG BytesNeeded,
+ IN ULONG ResourceId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition. It will handle event codes
+ RESOURCE_POOL, RESOURCE_LIMIT, and RESOURCE_SPECIFIC.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ ResourceId - The resource ID of the allocated structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PWSTR SecondString;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ WCHAR ResourceIdBuffer[3];
+ WCHAR SizeBuffer[2];
+ WCHAR SpecificMaxBuffer[11];
+ ULONG SpecificMax;
+ INT i;
+
+ switch (ErrorCode) {
+
+ case EVENT_TRANSPORT_RESOURCE_POOL:
+ SecondString = NULL;
+ SecondStringSize = 0;
+ break;
+
+ case EVENT_TRANSPORT_RESOURCE_LIMIT:
+ SecondString = SizeBuffer;
+ SecondStringSize = sizeof(SizeBuffer);
+
+ switch (DeviceContext->MemoryLimit) {
+ case 100000: SizeBuffer[0] = L'1'; break;
+ case 250000: SizeBuffer[0] = L'2'; break;
+ case 0: SizeBuffer[0] = L'3'; break;
+ default: SizeBuffer[0] = L'0'; break;
+ }
+ SizeBuffer[1] = 0;
+ break;
+
+ case EVENT_TRANSPORT_RESOURCE_SPECIFIC:
+ switch (ResourceId) {
+ case UI_FRAME_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
+ case PACKET_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize; break;
+ case RECEIVE_PACKET_RESOURCE_ID: SpecificMax = DeviceContext->ReceivePacketPoolSize; break;
+ case RECEIVE_BUFFER_RESOURCE_ID: SpecificMax = DeviceContext->SendPacketPoolSize+DeviceContext->ReceivePacketPoolSize; break;
+ case ADDRESS_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddresses; break;
+ case ADDRESS_FILE_RESOURCE_ID: SpecificMax = DeviceContext->MaxAddressFiles; break;
+ case CONNECTION_RESOURCE_ID: SpecificMax = DeviceContext->MaxConnections; break;
+ case LINK_RESOURCE_ID: SpecificMax = DeviceContext->MaxLinks; break;
+ case REQUEST_RESOURCE_ID: SpecificMax = DeviceContext->MaxRequests; break;
+ }
+
+ for (i=9; i>=0; i--) {
+ SpecificMaxBuffer[i] = (WCHAR)((SpecificMax % 10) + L'0');
+ SpecificMax /= 10;
+ if (SpecificMax == 0) {
+ break;
+ }
+ }
+ SecondString = SpecificMaxBuffer + i;
+ SecondStringSize = sizeof(SpecificMaxBuffer) - (i * sizeof(WCHAR));
+ SpecificMaxBuffer[10] = 0;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ DeviceContext->DeviceNameLength +
+ sizeof(ResourceIdBuffer) +
+ SecondStringSize;
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the resource ID into a buffer.
+ //
+
+ ResourceIdBuffer[1] = (WCHAR)((ResourceId % 10) + L'0');
+ ResourceId /= 10;
+ ASSERT(ResourceId <= 9);
+ ResourceIdBuffer[0] = (WCHAR)((ResourceId % 10) + L'0');
+ ResourceIdBuffer[2] = 0;
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 2 : 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, ResourceIdBuffer, sizeof(ResourceIdBuffer));
+ StringLoc += sizeof(ResourceIdBuffer);
+
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteResourceErrorLog */
+
+
+VOID
+NbfWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PWSTR DriverName;
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
+ } else {
+ DriverName = L"Nbf";
+ EntrySize += 4 * sizeof(WCHAR);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, 4 * sizeof(WCHAR));
+ StringLoc += 4 * sizeof(WCHAR);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteGeneralErrorLog */
+
+
+VOID
+NbfWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ WCHAR OidBuffer[9];
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ DeviceContext->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+ OidBuffer[8] = 0;
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
+ StringLoc += DeviceContext->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbfWriteOidErrorLog */
+
+ULONG
+NbfInitializeOneDeviceContext(
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCONFIG_DATA NbfConfig,
+ IN INT AdapterIndex
+ )
+/*++
+
+Routine Description:
+
+ This routine creates and initializes one nbf device context. In order to
+ do this it must successfully open and bind to the adapter described by
+ nbfconfig->names[adapterindex].
+
+Arguments:
+
+ NdisStatus - The outputted status of the operations.
+
+ DriverObject - the nbf driver object.
+
+ NbfConfig - the transport configuration information from the registry.
+
+ AdapterIndex - which adapter to bind with.
+
+Return Value:
+
+ The number of successful binds.
+
+--*/
+
+{
+ ULONG i, j;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PTP_UI_FRAME UIFrame;
+ PTP_PACKET Packet;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+ UINT MaxUserData;
+ ULONG InitReceivePackets;
+ BOOLEAN UniProcessor;
+#ifdef _PNP_POWER
+ PDEVICE_OBJECT DeviceObject;
+ UNICODE_STRING DeviceString;
+ UCHAR PermAddr[sizeof(TA_ADDRESS)+TDI_ADDRESS_LENGTH_NETBIOS];
+ PTA_ADDRESS pAddress = (PTA_ADDRESS)PermAddr;
+ PTDI_ADDRESS_NETBIOS NetBIOSAddress =
+ (PTDI_ADDRESS_NETBIOS)pAddress->Address;
+
+ pAddress->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+ pAddress->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ NetBIOSAddress->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+#endif
+ //
+ // Determine if we are on a uniprocessor.
+ //
+
+ if (*KeNumberProcessors == 1) {
+ UniProcessor = TRUE;
+ } else {
+ UniProcessor = FALSE;
+ }
+
+ {
+ j = AdapterIndex;
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+
+ status = NbfCreateDeviceContext(
+ DriverObject,
+ &NbfConfig->Names[NbfConfig->DevicesOffset+j],
+ &DeviceContext
+ );
+
+ if (!NT_SUCCESS (status)) {
+ NbfWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 707,
+ status,
+ NbfConfig->Names[j].Buffer,
+ 0,
+ NULL);
+ *NdisStatus = status;
+ return(0);
+ }
+
+ DeviceContext->UniProcessor = UniProcessor;
+
+ //
+ // Initialize the timer and retry values (note that the link timeouts
+ // are converted from NT ticks to NBF ticks). These values may
+ // be modified by NbfInitializeNdis.
+ //
+
+ DeviceContext->DefaultT1Timeout = NbfConfig->DefaultT1Timeout / SHORT_TIMER_DELTA;
+ DeviceContext->DefaultT2Timeout = NbfConfig->DefaultT2Timeout / SHORT_TIMER_DELTA;
+ DeviceContext->DefaultTiTimeout = NbfConfig->DefaultTiTimeout / LONG_TIMER_DELTA;
+ DeviceContext->LlcRetries = NbfConfig->LlcRetries;
+ DeviceContext->LlcMaxWindowSize = NbfConfig->LlcMaxWindowSize;
+ DeviceContext->MaxConsecutiveIFrames = (UCHAR)NbfConfig->MaximumIncomingFrames;
+ DeviceContext->NameQueryRetries = NbfConfig->NameQueryRetries;
+ DeviceContext->NameQueryTimeout = NbfConfig->NameQueryTimeout;
+ DeviceContext->AddNameQueryRetries = NbfConfig->AddNameQueryRetries;
+ DeviceContext->AddNameQueryTimeout = NbfConfig->AddNameQueryTimeout;
+ DeviceContext->GeneralRetries = NbfConfig->GeneralRetries;
+ DeviceContext->GeneralTimeout = NbfConfig->GeneralTimeout;
+ DeviceContext->MinimumSendWindowLimit = NbfConfig->MinimumSendWindowLimit;
+
+ //
+ // Initialize our counter that records memory usage.
+ //
+
+ DeviceContext->MemoryUsage = 0;
+ DeviceContext->MemoryLimit = NbfConfig->MaxMemoryUsage;
+
+ DeviceContext->MaxRequests = NbfConfig->MaxRequests;
+ DeviceContext->MaxLinks = NbfConfig->MaxLinks;
+ DeviceContext->MaxConnections = NbfConfig->MaxConnections;
+ DeviceContext->MaxAddressFiles = NbfConfig->MaxAddressFiles;
+ DeviceContext->MaxAddresses = NbfConfig->MaxAddresses;
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = NbfInitializeNdis (DeviceContext,
+ NbfConfig,
+ j);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error if we were failed to
+ // open this adapter.
+ //
+
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ NbfConfig->Names[j].Buffer,
+ 0,
+ NULL);
+
+ NbfDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext, DCREF_CREATION);
+ *NdisStatus = status;
+ return(0);
+
+ }
+
+#if 0
+ DbgPrint("Opened %S as %S\n", &NbfConfig->Names[j], &nameString);
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint6 ("NbfInitialize: NDIS returned: %x %x %x %x %x %x as local address.\n",
+ DeviceContext->LocalAddress.Address[0],
+ DeviceContext->LocalAddress.Address[1],
+ DeviceContext->LocalAddress.Address[2],
+ DeviceContext->LocalAddress.Address[3],
+ DeviceContext->LocalAddress.Address[4],
+ DeviceContext->LocalAddress.Address[5]);
+ }
+
+ //
+ // Initialize our provider information structure; since it
+ // doesn't change, we just keep it around and copy it to
+ // whoever requests it.
+ //
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ TRUE,
+ &MaxUserData);
+
+ DeviceContext->Information.Version = 0x0100;
+ DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
+ DeviceContext->Information.MaxConnectionUserData = 0;
+ DeviceContext->Information.MaxDatagramSize =
+ MaxUserData - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+ DeviceContext->Information.ServiceFlags = NBF_SERVICE_FLAGS;
+ if (DeviceContext->MacInfo.MediumAsync) {
+ DeviceContext->Information.ServiceFlags |= TDI_SERVICE_POINT_TO_POINT;
+ }
+ DeviceContext->Information.MinimumLookaheadData =
+ 240 - (sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS));
+ DeviceContext->Information.MaximumLookaheadData =
+ DeviceContext->MaxReceivePacketSize - (sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+ DeviceContext->Information.NumberOfResources = NBF_TDI_RESOURCES;
+ KeQuerySystemTime (&DeviceContext->Information.StartTime);
+
+
+ //
+ // Allocate various structures we will need.
+ //
+
+ ENTER_NBF;
+
+ //
+ // The TP_UI_FRAME structure has a CHAR[1] field at the end
+ // which we expand upon to include all the headers needed;
+ // the size of the MAC header depends on what the adapter
+ // told us about its max header size.
+ //
+
+ DeviceContext->UIFrameHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof(DLC_FRAME) +
+ sizeof(NBF_HDR_CONNECTIONLESS);
+
+ DeviceContext->UIFrameLength =
+ FIELD_OFFSET(TP_UI_FRAME, Header[0]) +
+ DeviceContext->UIFrameHeaderLength;
+
+
+ //
+ // The TP_PACKET structure has a CHAR[1] field at the end
+ // which we expand upon to include all the headers needed;
+ // the size of the MAC header depends on what the adapter
+ // told us about its max header size. TP_PACKETs are used
+ // for connection-oriented frame as well as for
+ // control frames, but since DLC_I_FRAME and DLC_S_FRAME
+ // are the same size, the header is the same size.
+ //
+
+ ASSERT (sizeof(DLC_I_FRAME) == sizeof(DLC_S_FRAME));
+
+ DeviceContext->PacketHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof(DLC_I_FRAME) +
+ sizeof(NBF_HDR_CONNECTION);
+
+ DeviceContext->PacketLength =
+ FIELD_OFFSET(TP_PACKET, Header[0]) +
+ DeviceContext->PacketHeaderLength;
+
+
+ //
+ // The BUFFER_TAG structure has a CHAR[1] field at the end
+ // which we expand upong to include all the frame data.
+ //
+
+ DeviceContext->ReceiveBufferLength =
+ DeviceContext->MaxReceivePacketSize +
+ FIELD_OFFSET(BUFFER_TAG, Buffer[0]);
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: pre-allocating requests.\n");
+ }
+ for (i=0; i<NbfConfig->InitRequests; i++) {
+
+ NbfAllocateRequest (DeviceContext, &Request);
+
+ if (Request == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate requests.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+#if DBG
+ NbfRequestTable[i+1] = (PVOID)Request;
+#endif
+ }
+#if DBG
+ NbfRequestTable[0] = (PVOID)NbfConfig->InitRequests;
+ NbfRequestTable[NbfConfig->InitRequests + 1] = (PVOID)
+ ((NBF_REQUEST_SIGNATURE << 16) | sizeof (TP_REQUEST));
+ InitializeListHead (&NbfGlobalRequestList);
+#endif
+
+ DeviceContext->RequestInitAllocated = NbfConfig->InitRequests;
+ DeviceContext->RequestMaxAllocated = NbfConfig->MaxRequests;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d requests, %ld\n", NbfConfig->InitRequests, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating links.\n");
+ }
+ for (i=0; i<NbfConfig->InitLinks; i++) {
+
+ NbfAllocateLink (DeviceContext, &Link);
+
+ if (Link == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate links.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->LinkPool, &Link->Linkage);
+#if DBG
+ NbfLinkTable[i+1] = (PVOID)Link;
+#endif
+ }
+#if DBG
+ NbfLinkTable[0] = (PVOID)NbfConfig->InitLinks;
+ NbfLinkTable[NbfConfig->InitLinks+1] = (PVOID)
+ ((NBF_LINK_SIGNATURE << 16) | sizeof (TP_LINK));
+#endif
+
+ DeviceContext->LinkInitAllocated = NbfConfig->InitLinks;
+ DeviceContext->LinkMaxAllocated = NbfConfig->MaxLinks;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d links, %ld\n", NbfConfig->InitLinks, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating connections.\n");
+ }
+ for (i=0; i<NbfConfig->InitConnections; i++) {
+
+ NbfAllocateConnection (DeviceContext, &Connection);
+
+ if (Connection == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate connections.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
+#if DBG
+ NbfConnectionTable[i+1] = (PVOID)Connection;
+#endif
+ }
+#if DBG
+ NbfConnectionTable[0] = (PVOID)NbfConfig->InitConnections;
+ NbfConnectionTable[NbfConfig->InitConnections+1] = (PVOID)
+ ((NBF_CONNECTION_SIGNATURE << 16) | sizeof (TP_CONNECTION));
+#endif
+
+ DeviceContext->ConnectionInitAllocated = NbfConfig->InitConnections;
+ DeviceContext->ConnectionMaxAllocated = NbfConfig->MaxConnections;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d connections, %ld\n", NbfConfig->InitConnections, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating AddressFiles.\n");
+ }
+ for (i=0; i<NbfConfig->InitAddressFiles; i++) {
+
+ NbfAllocateAddressFile (DeviceContext, &AddressFile);
+
+ if (AddressFile == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate Address Files.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+#if DBG
+ NbfAddressFileTable[i+1] = (PVOID)AddressFile;
+#endif
+ }
+#if DBG
+ NbfAddressFileTable[0] = (PVOID)NbfConfig->InitAddressFiles;
+ NbfAddressFileTable[NbfConfig->InitAddressFiles + 1] = (PVOID)
+ ((NBF_ADDRESSFILE_SIGNATURE << 16) |
+ sizeof (TP_ADDRESS_FILE));
+#endif
+
+ DeviceContext->AddressFileInitAllocated = NbfConfig->InitAddressFiles;
+ DeviceContext->AddressFileMaxAllocated = NbfConfig->MaxAddressFiles;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d address files, %ld\n", NbfConfig->InitAddressFiles, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating addresses.\n");
+ }
+ for (i=0; i<NbfConfig->InitAddresses; i++) {
+
+ NbfAllocateAddress (DeviceContext, &Address);
+ if (Address == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate addresses.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+#if DBG
+ NbfAddressTable[i+1] = (PVOID)Address;
+#endif
+ }
+#if DBG
+ NbfAddressTable[0] = (PVOID)NbfConfig->InitAddresses;
+ NbfAddressTable[NbfConfig->InitAddresses + 1] = (PVOID)
+ ((NBF_ADDRESS_SIGNATURE << 16) | sizeof (TP_ADDRESS));
+#endif
+
+ DeviceContext->AddressInitAllocated = NbfConfig->InitAddresses;
+ DeviceContext->AddressMaxAllocated = NbfConfig->MaxAddresses;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d addresses, %ld\n", NbfConfig->InitAddresses, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating UI frames.\n");
+ }
+
+ for (i=0; i<NbfConfig->InitUIFrames; i++) {
+
+ NbfAllocateUIFrame (DeviceContext, &UIFrame);
+
+ if (UIFrame == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate UI frames.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&(DeviceContext->UIFramePool), &UIFrame->Linkage);
+#if DBG
+ NbfUiFrameTable[i+1] = UIFrame;
+#endif
+ }
+#if DBG
+ NbfUiFrameTable[0] = (PVOID)NbfConfig->InitUIFrames;
+#endif
+
+ DeviceContext->UIFrameInitAllocated = NbfConfig->InitUIFrames;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d UI frames, %ld\n", NbfConfig->InitUIFrames, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating I frames.\n");
+ NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->PacketPool);
+ }
+
+ for (i=0; i<NbfConfig->InitPackets; i++) {
+
+ NbfAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+#if DBG
+ NbfSendPacketTable[i+1] = Packet;
+#endif
+ }
+#if DBG
+ NbfSendPacketTable[0] = (PVOID)NbfConfig->InitPackets;
+ NbfSendPacketTable[NbfConfig->InitPackets+1] = (PVOID)
+ ((NBF_PACKET_SIGNATURE << 16) | sizeof (TP_PACKET));
+#endif
+
+ DeviceContext->PacketInitAllocated = NbfConfig->InitPackets;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d send packets, %ld\n", NbfConfig->InitPackets, DeviceContext->MemoryUsage);
+ }
+
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating RR frames.\n");
+ NbfPrint1 ("NBFDRVR: Packet pool header: %lx\n",&DeviceContext->RrPacketPool);
+ }
+
+ for (i=0; i<10; i++) {
+
+ NbfAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ Packet->Action = PACKET_ACTION_RR;
+ PushEntryList (&DeviceContext->RrPacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d send packets, %ld\n", 10, DeviceContext->MemoryUsage);
+ }
+
+
+ // Allocate receive Ndis packets
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating Ndis Receive packets.\n");
+ }
+ if (DeviceContext->MacInfo.SingleReceive) {
+ InitReceivePackets = 2;
+ } else {
+ InitReceivePackets = NbfConfig->InitReceivePackets;
+ }
+ for (i=0; i<InitReceivePackets; i++) {
+
+ NbfAllocateReceivePacket (DeviceContext, &NdisPacket);
+
+ if (NdisPacket == NULL) {
+ PANIC ("NbfInitialize: insufficient memory to allocate packet MDLs.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
+ PushEntryList (&DeviceContext->ReceivePacketPool, &ReceiveTag->Linkage);
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ PNDIS_BUFFER NdisBuffer;
+ NdisQueryPacket(NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+ NbfPrint2 ("NbfInitialize: Created NDIS Pkt: %x Buffer: %x\n",
+ NdisPacket, NdisBuffer);
+ }
+ }
+
+ DeviceContext->ReceivePacketInitAllocated = InitReceivePackets;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d receive packets, %ld\n", InitReceivePackets, DeviceContext->MemoryUsage);
+ }
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NBFDRVR: allocating Ndis Receive buffers.\n");
+ }
+
+ for (i=0; i<NbfConfig->InitReceiveBuffers; i++) {
+
+ NbfAllocateReceiveBuffer (DeviceContext, &BufferTag);
+
+ if (BufferTag == NULL) {
+ PANIC ("NbfInitialize: Unable to allocate receive packet.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->ReceiveBufferPool, (PSINGLE_LIST_ENTRY)&BufferTag->Linkage);
+
+ }
+
+ DeviceContext->ReceiveBufferInitAllocated = NbfConfig->InitReceiveBuffers;
+
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint2 ("%d receive buffers, %ld\n", NbfConfig->InitReceiveBuffers, DeviceContext->MemoryUsage);
+ }
+
+ DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
+
+ //
+ // Start the link-level timers running.
+ //
+
+ NbfInitializeTimerSystem (DeviceContext);
+
+
+ //
+ // Now link the device into the global list.
+ //
+
+ InsertTailList (&NbfDeviceList, &DeviceContext->Linkage);
+
+ ++SuccessfulOpens;
+
+#ifdef _PNP_POWER
+ DeviceObject = (PDEVICE_OBJECT) DeviceContext;
+ DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
+ status = TdiRegisterDeviceObject(&DeviceString,
+ &DeviceContext->TdiDeviceHandle);
+
+ if (!NT_SUCCESS (status)) {
+ --SuccessfulOpens;
+ RemoveEntryList(&DeviceContext->Linkage);
+ goto cleanup;
+ }
+
+ RtlCopyMemory(NetBIOSAddress->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress, 16);
+
+
+ status = TdiRegisterNetAddress(pAddress,
+ &DeviceContext->ReservedAddressHandle);
+
+ if (!NT_SUCCESS (status)) {
+ --SuccessfulOpens;
+ RemoveEntryList(&DeviceContext->Linkage);
+ goto cleanup;
+ }
+#endif
+
+ LEAVE_NBF;
+ *NdisStatus = NDIS_STATUS_SUCCESS;
+
+ return(1);;
+
+cleanup:
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 501,
+ DeviceContext->MemoryUsage,
+ 0);
+
+ //
+ // Cleanup whatever device context we were initializing
+ // when we failed.
+ //
+ *NdisStatus = status;
+ ASSERT(status != STATUS_SUCCESS);
+
+ NbfFreeResources (DeviceContext);
+ NbfCloseNdis (DeviceContext);
+ NbfDereferenceDeviceContext ("Load failed", DeviceContext, DCREF_CREATION);
+
+
+ LEAVE_NBF;
+ }
+ return(0);
+}
diff --git a/private/ntos/tdi/nbf/nbfhdrs.h b/private/ntos/tdi/nbf/nbfhdrs.h
new file mode 100644
index 000000000..9dfa5966f
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfhdrs.h
@@ -0,0 +1,257 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbfhdrs.h
+
+Abstract:
+
+ This module defines private structure definitions describing the layout
+ of the NetBIOS Frames Protocol headers for the NT NBF transport
+ provider.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ remove pc586 and PDI specific code; add NDIS support
+
+--*/
+
+#ifndef _NBFHDRS_
+#define _NBFHDRS_
+
+//
+// Pack these headers, as they are sent fully packed on the network.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Off(Align_members)
+#else
+#pragma pack(1)
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#define NETBIOS_SIGNATURE_1 0xef // signature in NetBIOS frames.
+#define NETBIOS_SIGNATURE_0 0xff // 1st byte.
+#define NETBIOS_SIGNATURE 0xefff
+
+//
+// NetBIOS Frames Protocol Command Codes.
+//
+
+#define NBF_CMD_ADD_GROUP_NAME_QUERY 0x00
+#define NBF_CMD_ADD_NAME_QUERY 0x01
+#define NBF_CMD_NAME_IN_CONFLICT 0x02
+#define NBF_CMD_STATUS_QUERY 0x03
+#define NBF_CMD_TERMINATE_TRACE 0x07
+#define NBF_CMD_DATAGRAM 0x08
+#define NBF_CMD_DATAGRAM_BROADCAST 0x09
+#define NBF_CMD_NAME_QUERY 0x0a
+#define NBF_CMD_ADD_NAME_RESPONSE 0x0d
+#define NBF_CMD_NAME_RECOGNIZED 0x0e
+#define NBF_CMD_STATUS_RESPONSE 0x0f
+#define NBF_CMD_TERMINATE_TRACE2 0x13
+#define NBF_CMD_DATA_ACK 0x14
+#define NBF_CMD_DATA_FIRST_MIDDLE 0x15
+#define NBF_CMD_DATA_ONLY_LAST 0x16
+#define NBF_CMD_SESSION_CONFIRM 0x17
+#define NBF_CMD_SESSION_END 0x18
+#define NBF_CMD_SESSION_INITIALIZE 0x19
+#define NBF_CMD_NO_RECEIVE 0x1a
+#define NBF_CMD_RECEIVE_OUTSTANDING 0x1b
+#define NBF_CMD_RECEIVE_CONTINUE 0x1c
+#define NBF_CMD_SESSION_ALIVE 0x1f
+
+//
+// NBF Transport Layer Header.
+//
+
+typedef struct _NBF_HDR_GENERIC {
+ USHORT Length; // Length of this header in bytes.
+ UCHAR Signature [2]; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ USHORT Data2; // optional parameter.
+ USHORT TransmitCorrelator; // transmit correlator parameter.
+ USHORT ResponseCorrelator; // response correlator parameter.
+} NBF_HDR_GENERIC;
+typedef NBF_HDR_GENERIC UNALIGNED *PNBF_HDR_GENERIC;
+
+typedef struct _NBF_HDR_CONNECTION {
+ USHORT Length; // length of the header in bytes (14).
+ USHORT Signature; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ UCHAR Data2Low, Data2High; // Intel-formatted DW parameter.
+ USHORT TransmitCorrelator; // Intel-formatted DW param. (transmit correlator).
+ USHORT ResponseCorrelator; // Intel-formatted DW param. (response correlator).
+ UCHAR DestinationSessionNumber; // connection identifier of packet receiver.
+ UCHAR SourceSessionNumber; // connection identifier of packet sender.
+} NBF_HDR_CONNECTION;
+typedef NBF_HDR_CONNECTION UNALIGNED *PNBF_HDR_CONNECTION;
+
+typedef struct _NBF_HDR_CONNECTIONLESS {
+ USHORT Length; // length of the header in bytes (44).
+ USHORT Signature; // always {0xef, 0xff} for NBF.
+ UCHAR Command; // command code, NBF_CMD_xxx.
+ UCHAR Data1; // optional parameter.
+ UCHAR Data2Low, Data2High; // Intel-formatted DW parameter.
+ USHORT TransmitCorrelator; // Intel-formatted DW param. (transmit correlator).
+ USHORT ResponseCorrelator; // Intel-formatted DW param. (response correlator).
+ UCHAR DestinationName [NETBIOS_NAME_LENGTH]; // name of packet receiver.
+ UCHAR SourceName [NETBIOS_NAME_LENGTH]; // name of packet sender.
+} NBF_HDR_CONNECTIONLESS;
+typedef NBF_HDR_CONNECTIONLESS UNALIGNED *PNBF_HDR_CONNECTIONLESS;
+
+//
+// These macros are used to retrieve the transmit and response
+// correlators from an NBF_HDR_CONNECTION(LESS). The first two
+// are general, the second two are used when the correlators
+// are known to be WORD aligned.
+//
+
+#define TRANSMIT_CORR(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->TransmitCorrelator))
+#define RESPONSE_CORR(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->ResponseCorrelator))
+
+#define TRANSMIT_CORR_A(_Hdr) ((_Hdr)->TransmitCorrelator)
+#define RESPONSE_CORR_A(_Hdr) ((_Hdr)->ResponseCorrelator)
+
+#define HEADER_LENGTH(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->Length))
+#define HEADER_SIGNATURE(_Hdr) (*(USHORT UNALIGNED *)(&(_Hdr)->Signature))
+
+#define HEADER_LENGTH_A(_Hdr) ((_Hdr)->Length)
+#define HEADER_SIGNATURE_A(_Hdr) ((_Hdr)->Signature)
+
+typedef union _NBF_HDR {
+ NBF_HDR_GENERIC Generic;
+ NBF_HDR_CONNECTION ConnectionOrientedFrame;
+ NBF_HDR_CONNECTIONLESS ConnectionlessFrame;
+} NBF_HDR;
+typedef NBF_HDR UNALIGNED *PNBF_HDR;
+
+//
+// The following structures define I-frame, U-frame, and S-frame DLC headers.
+//
+
+#define DLC_SSAP_RESPONSE 0x0001 // if (ssap & DLC_SSAP_RESP), it's a response.
+#define DLC_SSAP_GLOBAL 0x00ff // the global SAP.
+#define DLC_SSAP_NULL 0x0000 // the null SAP.
+#define DLC_SSAP_MASK 0x00fe // mask to wipe out the response bit.
+#define DLC_DSAP_MASK 0x00fe // mask to wipe out the group SAP bit.
+
+#define DLC_CMD_RR 0x01 // command code for RR.
+#define DLC_CMD_RNR 0x05 // command code for RNR.
+#define DLC_CMD_REJ 0x09 // command code for REJ.
+
+#define DLC_CMD_SABME 0x6f // command code for SABME.
+#define DLC_CMD_DISC 0x43 // command code for DISC.
+#define DLC_CMD_UA 0x63 // command code for UA.
+#define DLC_CMD_DM 0x0f // command code for DM.
+#define DLC_CMD_FRMR 0x87 // command code for FRMR.
+#define DLC_CMD_UI 0x03 // command code for UI.
+#define DLC_CMD_XID 0xaf // command code for XID.
+#define DLC_CMD_TEST 0xe3 // command code for TEST.
+
+typedef struct _DLC_XID_INFORMATION {
+ UCHAR FormatId; // format of this XID frame.
+ UCHAR Info1; // first information byte.
+ UCHAR Info2; // second information byte.
+} DLC_XID_INFORMATION;
+typedef DLC_XID_INFORMATION UNALIGNED *PDLC_XID_INFORMATION;
+
+typedef struct _DLC_TEST_INFORMATION {
+ UCHAR Buffer [10]; // this buffer is actually arbitrarily large.
+} DLC_TEST_INFORMATION;
+typedef DLC_TEST_INFORMATION UNALIGNED *PDLC_TEST_INFORMATION;
+
+typedef struct _DLC_FRMR_INFORMATION {
+ UCHAR Command; // format: mmmpmm11, m=modifiers, p=poll/final.
+ UCHAR Ctrl; // control field of rejected frame.
+ UCHAR Vs; // our next send when error was detected.
+ UCHAR Vr; // our next receive when error was detected.
+ UCHAR Reason; // reason for sending FRMR: 000VZYXW.
+} DLC_FRMR_INFORMATION;
+typedef DLC_FRMR_INFORMATION UNALIGNED *PDLC_FRMR_INFORMATION;
+
+typedef struct _DLC_U_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Command; // command code.
+ union { // information field for FRMR, TEST, XID.
+ DLC_XID_INFORMATION XidInfo; // XID information.
+ DLC_TEST_INFORMATION TestInfo; // TEST information.
+ DLC_FRMR_INFORMATION FrmrInfo; // FRMR information.
+ NBF_HDR_CONNECTIONLESS NbfHeader; // UI frame contains NetBIOS header.
+ } Information;
+} DLC_U_FRAME;
+typedef DLC_U_FRAME UNALIGNED *PDLC_U_FRAME;
+
+#define DLC_U_INDICATOR 0x03 // (cmd & DLC_U_IND) == DLC_U_IND --> U-frame.
+#define DLC_U_PF 0x10 // (cmd & DLC_U_PF) -> poll/final set.
+
+typedef struct _DLC_S_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Command; // RR, RNR, REJ command code.
+ UCHAR RcvSeq; // receive seq #, bottom bit is poll/final.
+} DLC_S_FRAME;
+typedef DLC_S_FRAME UNALIGNED *PDLC_S_FRAME;
+
+#define DLC_S_PF 0x01 // (rcvseq & DLC_S_PF) means poll/final set.
+
+typedef struct _DLC_I_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR SendSeq; // send sequence number, bottom bit 0.
+ UCHAR RcvSeq; // rcv sequence number, bottom bit p/f.
+} DLC_I_FRAME;
+typedef DLC_I_FRAME UNALIGNED *PDLC_I_FRAME;
+
+#define DLC_I_PF 0x01 // (rcvseq & DLC_I_PF) means poll/final set.
+#define DLC_I_INDICATOR 0x01 // !(sndseq & DLC_I_INDICATOR) indicates I-frame.
+
+typedef struct _DLC_FRAME {
+ UCHAR Dsap; // Destination Service Access Point.
+ UCHAR Ssap; // Source Service Access Point.
+ UCHAR Byte1; // command byte.
+} DLC_FRAME;
+typedef DLC_FRAME UNALIGNED *PDLC_FRAME;
+
+
+//
+// This macro builds a DLC UI-frame header.
+//
+
+#define NbfBuildUIFrameHeader(_Header) \
+{ \
+ PDLC_FRAME DlcHeader = (PDLC_FRAME)(_Header); \
+ DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; \
+ DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC; \
+ DlcHeader->Byte1 = DLC_CMD_UI; \
+}
+
+
+//
+// Resume previous structure packing method.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Pop(Align_members)
+#else
+#pragma pack()
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#endif // def _NBFHDRS_
diff --git a/private/ntos/tdi/nbf/nbfmac.c b/private/ntos/tdi/nbf/nbfmac.c
new file mode 100644
index 000000000..bbc418c19
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfmac.c
@@ -0,0 +1,417 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfmac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the NBF transport.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR SingleRouteSourceRouting[] = { 0xc2, 0x70 };
+UCHAR GeneralRouteSourceRouting[] = { 0x82, 0x70 };
+ULONG DefaultSourceRoutingLength = 2;
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,MacInitializeMacInfo)
+#pragma alloc_text(PAGE,MacSetNetBIOSMulticast)
+#endif
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ IN BOOLEAN UseDix,
+ OUT PNBF_NDIS_IDENTIFICATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ UseDix - TRUE if we should use DIX encoding on 802.3.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->DestinationOffset = 0;
+ MacInfo->SourceOffset = 6;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ if (UseDix) {
+ MacInfo->TransferDataOffset = 3;
+ MacInfo->MaxHeaderLength = 17;
+ MacInfo->MediumType = NdisMediumDix;
+ } else {
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ }
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMedium802_5:
+ MacInfo->DestinationOffset = 2;
+ MacInfo->SourceOffset = 8;
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MediumType = NdisMedium802_5;
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMediumFddi:
+ MacInfo->DestinationOffset = 1;
+ MacInfo->SourceOffset = 7;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ MacInfo->MediumAsync = FALSE;
+ break;
+ case NdisMediumWan:
+ MacInfo->DestinationOffset = 0;
+ MacInfo->SourceOffset = 6;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->TransferDataOffset = 0;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ MacInfo->MediumAsync = TRUE;
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+VOID
+MacConstructHeader (
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to construct the Mac header for the particular
+ network type we're talking to.
+
+Arguments:
+
+ MacInfo - Describes the mac we wish to build a header for.
+
+ Buffer - Where to build the header.
+
+ DestinationAddress - the address this packet is to be sent to.
+
+ SourceAddress - Our address. Passing it in as a parameter allows us to play
+ games with source if we need to.
+
+ PacketLength - The length of this packet. Note that this does not
+ includes the Mac header.
+
+ SourceRouting - Optional source routing information.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ HeaderLength - Returns the length of the constructed header.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Note network order of bytes.
+ //
+
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ *(ULONG UNALIGNED *)&Buffer[6] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[10] = SourceAddress[4];
+ Buffer[11] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[0] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[4] = DestinationAddress[4];
+ Buffer[5] = DestinationAddress[5];
+
+ Buffer[12] = (UCHAR)(PacketLength >> 8);
+ Buffer[13] = (UCHAR)PacketLength;
+
+ *HeaderLength = 14;
+
+ break;
+
+ case NdisMediumDix:
+
+ *(ULONG UNALIGNED *)&Buffer[6] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[10] = SourceAddress[4];
+ Buffer[11] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[0] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[4] = DestinationAddress[4];
+ Buffer[5] = DestinationAddress[5];
+
+ Buffer[12] = 0x80;
+ Buffer[13] = 0xd5;
+
+ Buffer[14] = (UCHAR)(PacketLength >> 8);
+ Buffer[15] = (UCHAR)PacketLength;
+
+ Buffer[16] = 0x00;
+ *HeaderLength = 17;
+
+ break;
+
+ case NdisMedium802_5:
+
+ Buffer[0] = TR_HEADER_BYTE_0;
+ Buffer[1] = TR_HEADER_BYTE_1;
+
+ ASSERT (TR_ADDRESS_LENGTH == 6);
+
+ *(ULONG UNALIGNED *)&Buffer[8] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[12] = SourceAddress[4];
+ Buffer[13] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[2] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[6] = DestinationAddress[4];
+ Buffer[7] = DestinationAddress[5];
+
+ *HeaderLength = 14;
+ if (SourceRouting != NULL) {
+ RtlCopyMemory (&Buffer[14], SourceRouting, SourceRoutingLength);
+ Buffer[8] |= 0x80; // add SR bit in source address
+ *HeaderLength = 14 + SourceRoutingLength;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ Buffer[0] = FDDI_HEADER_BYTE;
+
+ *(ULONG UNALIGNED *)&Buffer[7] = *(ULONG UNALIGNED *)&SourceAddress[0];
+ Buffer[11] = SourceAddress[4];
+ Buffer[12] = SourceAddress[5];
+
+ *(ULONG UNALIGNED *)&Buffer[1] = *(ULONG UNALIGNED *)&DestinationAddress[0];
+ Buffer[5] = DestinationAddress[4];
+ Buffer[6] = DestinationAddress[5];
+
+ *HeaderLength = 13;
+
+ break;
+
+ default:
+ PANIC ("MacConstructHeader: PANIC! called with unsupported Mac type.\n");
+ }
+}
+
+
+VOID
+MacReturnMaxDataSize(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ IN BOOLEAN AssumeWorstCase,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all LLC and NBF
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ AssumeWorstCase - TRUE if we should be pessimistic.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMediumDix:
+
+ //
+ // For DIX, we have the 14-byte MAC header plus
+ // the three-byte DIX header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 17;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst if told to.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & 0x70) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+ if (!AssumeWorstCase) {
+ *MaxFrameSize = DeviceMaxFrameSize - 16;
+ } else if (DeviceMaxFrameSize < (544+sizeof(DLC_FRAME)+sizeof(NBF_HDR_CONNECTIONLESS))) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 512 + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ }
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ }
+}
+
+
+
+VOID
+MacSetNetBIOSMulticast (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the NetBIOS broadcast address into a buffer provided
+ by the user.
+
+Arguments:
+
+ Type the Mac Medium type.
+
+ Buffer the buffer to put the multicast address in.
+
+
+Return Value:
+
+ none.
+
+--*/
+{
+ switch (Type) {
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ Buffer[0] = 0x03;
+ Buffer[ETHERNET_ADDRESS_LENGTH-1] = 0x01;
+ break;
+
+ case NdisMedium802_5:
+ Buffer[0] = 0xc0;
+ Buffer[TR_ADDRESS_LENGTH-1] = 0x80;
+ break;
+
+ case NdisMediumFddi:
+ Buffer[0] = 0x03;
+ Buffer[FDDI_ADDRESS_LENGTH-1] = 0x01;
+ break;
+
+ default:
+ PANIC ("MacSetNetBIOSAddress: PANIC! called with unsupported Mac type.\n");
+ }
+}
diff --git a/private/ntos/tdi/nbf/nbfmac.h b/private/ntos/tdi/nbf/nbfmac.h
new file mode 100644
index 000000000..8710f1d20
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfmac.h
@@ -0,0 +1,766 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Author:
+
+ David Beaver (dbeaver) 02-Oct-1990
+
+Revision History:
+
+--*/
+
+#ifndef _MAC_
+#define _MAC_
+
+//
+// MAC-specific definitions, some of which get used below
+//
+
+#define MAX_MAC_HEADER_LENGTH 32
+#define MAX_SOURCE_ROUTING 18
+#define MAX_DEFAULT_SR 2
+
+#define ETHERNET_ADDRESS_LENGTH 6
+#define ETHERNET_PACKET_LENGTH 1514 // max size of an ethernet packet
+#define ETHERNET_HEADER_LENGTH 14 // size of the ethernet MAC header
+#define ETHERNET_DATA_LENGTH_OFFSET 12
+#define ETHERNET_DESTINATION_OFFSET 0
+#define ETHERNET_SOURCE_OFFSET 6
+
+#define TR_ADDRESS_LENGTH 6
+#define TR_ADDRESS_OFFSET 2
+#define TR_SPECIFIC_OFFSET 0
+#define TR_PACKET_LENGTH 1514 // max size of a TR packet //BUGBUG
+#define TR_HEADER_LENGTH 36 // size of the MAC header w/o source routing
+#define TR_DATA_LENGTH_OFFSET 0
+#define TR_DESTINATION_OFFSET 2
+#define TR_SOURCE_OFFSET 8
+#define TR_ROUTING_OFFSET 14 // starts at the 14th byte
+#define TR_GR_BCAST_LENGTH 2
+#define TR_GR_BROADCAST 0xC270 // what a general route b'cast looks like
+#define TR_ROUTING_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+
+#define TR_PREAMBLE_AC 0x10 // how would these be specified?
+#define TR_PREAMBLE_FC 0x40
+
+#define TR_HEADER_BYTE_0 0x10
+#define TR_HEADER_BYTE_1 0x40
+
+#define FDDI_ADDRESS_LENGTH 6
+#define FDDI_HEADER_BYTE 0x57
+
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the nbfmac routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NBF_NDIS_IDENTIFICATION {
+ NDIS_MEDIUM MediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ BOOLEAN QueryWithoutSourceRouting;
+ BOOLEAN AllRoutesNameRecognized;
+ ULONG DestinationOffset;
+ ULONG SourceOffset;
+ ULONG AddressLength;
+ ULONG TransferDataOffset;
+ ULONG MaxHeaderLength;
+ BOOLEAN CopyLookahead;
+ BOOLEAN ReceiveSerialized;
+ BOOLEAN TransferSynchronous;
+ BOOLEAN SingleReceive;
+} NBF_NDIS_IDENTIFICATION, *PNBF_NDIS_IDENTIFICATION;
+
+
+
+VOID
+MacConstructHeader(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR Buffer,
+ IN PUCHAR DestinationAddress,
+ IN PUCHAR SourceAddress,
+ IN UINT PacketLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PUINT HeaderLength
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNBF_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ IN BOOLEAN AssumeWorstCase,
+ OUT PUINT MaxFrameSize
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ IN BOOLEAN UseDix,
+ OUT PNBF_NDIS_IDENTIFICATION MacInfo
+ );
+
+
+extern UCHAR SingleRouteSourceRouting[];
+extern UCHAR GeneralRouteSourceRouting[];
+extern ULONG DefaultSourceRoutingLength;
+
+
+//++
+//
+// VOID
+// MacReturnDestinationAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * DestinationAddress
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the destination address in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// DestinationAddress - Returns the start of the destination address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnDestinationAddress(_MacInfo, _Packet, _DestinationAddress) \
+ *(_DestinationAddress) = ((PUCHAR)(_Packet)) + (_MacInfo)->DestinationOffset
+
+
+//++
+//
+// VOID
+// MacReturnSourceAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PHARDWARE_ADDRESS SourceAddressBuffer,
+// OUT PHARDWARE_ADDRESS * SourceAddress,
+// OUT BOOLEAN * Multicast OPTIONAL
+// );
+//
+// Routine Description:
+//
+// Copies the source address in the packet into SourceAddress.
+// NOTE THAT IT MAY COPY THE DATA, UNLIKE ReturnDestinationAddress
+// AND ReturnSourceRouting. Optionally, indicates whether the
+// destination address is a multicast address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceAddressBuffer - A buffer to hold the source address,
+// if needed.
+//
+// SourceAddress - Returns a pointer to the source address.
+//
+// Multicast - Optional pointer to a BOOLEAN to receive indication
+// of whether the destination was a multicast address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+//
+// NOTE: The default case below handles Ethernet and FDDI.
+//
+
+#define MacReturnSourceAddress(_MacInfo, _Packet, _SourceAddressBuffer, \
+ _SourceAddress, _Multicast) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ PUCHAR SrcBuffer = (PUCHAR)(_SourceAddressBuffer); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ if (ARGUMENT_PRESENT(_Multicast)) { \
+ *(PBOOLEAN)(_Multicast) = TmpPacket[2] & 0x80; \
+ } \
+ if (TmpPacket[8] & 0x80) { \
+ *(PULONG)SrcBuffer = *(ULONG UNALIGNED *)(&TmpPacket[8]) & ~0x80;\
+ SrcBuffer[4] = TmpPacket[12]; \
+ SrcBuffer[5] = TmpPacket[13]; \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)SrcBuffer; \
+ } else { \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + 8); \
+ } \
+ break; \
+ default: \
+ if (ARGUMENT_PRESENT(_Multicast)) { \
+ *(PBOOLEAN)(_Multicast) = TmpPacket[0] & 0x01; \
+ } \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + \
+ (_MacInfo)->SourceOffset); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnSourceRouting(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID * SourceRouting
+// OUT PUINT SourceRoutingLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the source routing info in the packet.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// SourceRouting - Returns the start of the source routing information,
+// or NULL if none is present.
+//
+// SourceRoutingLength - Returns the length of the source routing
+// information.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSourceRouting(_MacInfo, _Packet, _SourceRouting, _SourceRoutingLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ *(_SourceRoutingLength) = 0; \
+ if ((_MacInfo)->SourceRouting) { \
+ if (TmpPacket[8] & 0x80) { \
+ *(_SourceRouting) = TmpPacket + 14; \
+ *(_SourceRoutingLength) = TmpPacket[14] & 0x1f; \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacIsMulticast(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PBOOLEAN Multicast
+// );
+//
+// Routine Description:
+//
+// Returns TRUE if the packet is sent to the multicast address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Packet - The packet data.
+//
+// Multicast - Returns the result.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacIsMulticast(_MacInfo, _Packet, _Multicast) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_Multicast) = ((TmpPacket[2] & 0x80) != 0); \
+ break; \
+ default: \
+ *(_Multicast) = ((TmpPacket[0] & 0x01) != 0); \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnPacketLength(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Header,
+// IN UINT PacketLength,
+// OUT PUINT DataLength
+// );
+//
+// Routine Description:
+//
+// Returns the length of data in the packet given the header.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// PacketLength - The length of the data (not including header).
+//
+// DataLength - Returns the length of the data. Unchanged if the
+// packet is not recognized. Should be initialized by caller to 0.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnPacketLength(_MacInfo, _Header, _HeaderLength, _PacketLength, _DataLength, _LookaheadBuffer, _LookaheadBufferLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ UINT TmpLength; \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ if ((_HeaderLength) >= 14) { \
+ TmpLength = (TmpPacket[12] << 8) | TmpPacket[13]; \
+ if (TmpLength <= 0x600) { \
+ if (TmpLength <= (_PacketLength)) { \
+ *(_DataLength) = TmpLength; \
+ } \
+ } \
+ } \
+ break; \
+ case NdisMedium802_5: \
+ if (((_HeaderLength) >= 14) && \
+ (!(TmpPacket[8] & 0x80) || \
+ ((_HeaderLength) >= \
+ (UINT)(14 + (TmpPacket[14] & 0x1f))))) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ if ((_HeaderLength) >= 13) { \
+ *(_DataLength) = (_PacketLength); \
+ } \
+ break; \
+ case NdisMediumDix: \
+ if ((TmpPacket[12] == 0x80) && (TmpPacket[13] == 0xd5)) { \
+ if (*(_LookaheadBufferLength) >= 3) { \
+ TmpPacket = (PUCHAR)(*(_LookaheadBuffer)); \
+ TmpLength = (TmpPacket[0] << 8) | TmpPacket[1]; \
+ if (TmpLength <= (_PacketLength)-3) { \
+ *(_DataLength) = TmpLength; \
+ *(_LookaheadBuffer) = (PVOID)(TmpPacket + 3); \
+ *(_LookaheadBufferLength) -= 3; \
+ } \
+ } \
+ } \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnHeaderLength(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PVOID HeaderLength,
+// );
+//
+// Routine Description:
+//
+// Returns the length of the MAC header in a packet (this
+// is used for loopback indications to separate header
+// and data).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The packet header.
+//
+// HeaderLength - Returns the length of the header.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnHeaderLength(_MacInfo, _Header, _HeaderLength) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Header); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ case NdisMediumDix: \
+ *(_HeaderLength) = 14; \
+ break; \
+ case NdisMedium802_5: \
+ if (TmpPacket[8] & 0x80) { \
+ *(_HeaderLength) = (TmpPacket[14] & 0x1f) + 14; \
+ } else { \
+ *(_HeaderLength) = 14; \
+ } \
+ break; \
+ case NdisMediumFddi: \
+ *(_HeaderLength) = 13; \
+ break; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnSingleRouteSR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * SingleRouteSR,
+// OUT PUINT SingleRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard single route broadcast
+// source routing information for the media type. This is used
+// for ADD_NAME_QUERY, DATAGRAM, NAME_IN_CONFLICT, NAME_QUERY,
+// and STATUS_QUERY frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// SingleRouteSR - Returns a pointer to the data.
+//
+// SingleRouteSRLength - The length of SingleRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnSingleRouteSR(_MacInfo, _SingleRouteSR, _SingleRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_SingleRouteSR) = SingleRouteSourceRouting; \
+ *(_SingleRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_SingleRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnGeneralRouteSR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// OUT PVOID * GeneralRouteSR,
+// OUT PUINT GeneralRouteSRLength
+// );
+//
+// Routine Description:
+//
+// Returns the a pointer to the standard general route broadcast
+// source routing information for the media type. This is used
+// for NAME_RECOGNIZED frames.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// GeneralRouteSR - Returns a pointer to the data.
+//
+// GeneralRouteSRLength - The length of GeneralRouteSR.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnGeneralRouteSR(_MacInfo, _GeneralRouteSR, _GeneralRouteSRLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(_GeneralRouteSR) = GeneralRouteSourceRouting; \
+ *(_GeneralRouteSRLength) = DefaultSourceRoutingLength; \
+ break; \
+ default: \
+ *(_GeneralRouteSR) = NULL; \
+ break; \
+ } \
+}
+
+#if 0
+
+//++
+//
+// VOID
+// MacCreateGeneralRouteReplySR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a general-route source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateGeneralRouteReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ TmpSR[0] = (TmpSR[0] & 0x1f) | 0x80; \
+ TmpSR[1] = (TmpSR[1] ^ 0x80); \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+#endif
+
+
+//++
+//
+// VOID
+// MacCreateNonBroadcastReplySR(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR ExistingSR,
+// IN UINT ExistingSRLength,
+// OUT PUCHAR * NewSR
+// );
+//
+// Routine Description:
+//
+// This modifies an existing source routing entry to make
+// it into a non-broadcast source routing entry. The assumption
+// is that is to reply to existing source routing, so the
+// direction bit is also reversed. In addition, if it is
+// determined that no source routing is needed in the reply,
+// then NULL is returned.
+//
+// Note that the information is modified in-place, but a
+// separate pointer is returned (to allow NULL to be returned).
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// ExistingSR - The existing source routing to be modified.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacCreateNonBroadcastReplySR(_MacInfo, _ExistingSR, _ExistingSRLength, _NewSR) \
+{ \
+ if (_ExistingSR) { \
+ PUCHAR TmpSR = (PUCHAR)(_ExistingSR); \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ if ((_ExistingSRLength) == 2) { \
+ *(_NewSR) = NULL; \
+ } else { \
+ TmpSR[0] = (TmpSR[0] & 0x1f); \
+ TmpSR[1] = (TmpSR[1] ^ 0x80); \
+ *(_NewSR) = (_ExistingSR); \
+ } \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacModifyHeader(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PUCHAR Header,
+// IN UINT PacketLength
+// );
+//
+// Routine Description:
+//
+// Modifies a pre-built packet header to include the
+// packet length. Used for connection-oriented traffic
+// where the header is pre-built.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Header - The header to modify.
+//
+// PacketLength - Packet length (not including the header).
+// Currently this is the only field that cannot be pre-built.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacModifyHeader(_MacInfo, _Header, _PacketLength) \
+{ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_3: \
+ (_Header)[12] = (UCHAR)((_PacketLength) >> 8); \
+ (_Header)[13] = (UCHAR)((_PacketLength) & 0xff); \
+ break; \
+ case NdisMediumDix: \
+ (_Header)[14] = (UCHAR)((_PacketLength) >> 8); \
+ (_Header)[15] = (UCHAR)((_PacketLength) & 0xff); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnMagicAddress(
+// IN PNBF_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Address,
+// OUT PULARGE_INTEGER Magic
+// );
+//
+// Routine Description:
+//
+// MacReturnMagicAddress returns the link as a 64 bit number.
+// We then find the link in the link trees by doing a large
+// integer comparison.
+//
+// The number is constructed by assigning the last four bytes of
+// the address as the low longword, and the first two bytes as
+// the high one. For 802_5 we need to mask off the source routing
+// bit in byte 0 of the address.
+//
+// Arguments:
+//
+// MacInfo - Describes the MAC we wish to decode.
+//
+// Address - The address we are encoding.
+//
+// Magic - Returns the magic number for this address.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+#define MacReturnMagicAddress(_MacInfo, _Address, _Magic) \
+{ \
+ PUCHAR TempAddr = (PUCHAR)(_Address); \
+ \
+ (_Magic)->LowPart = *((LONG UNALIGNED *)(TempAddr + 2)); \
+ if ((_MacInfo)->MediumType == NdisMedium802_5) { \
+ (_Magic)->HighPart = ((TempAddr[0] & 0x7f) << 8) + TempAddr[1]; \
+ } else { \
+ (_Magic)->HighPart = (TempAddr[0] << 8) + TempAddr[1]; \
+ } \
+}
+
+
+VOID
+MacSetNetBIOSMulticast (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ );
+
+
+
+// VOID
+// NbfSetNdisPacketLength (
+// IN NDIS_PACKET Packet,
+// IN ULONG Length
+// );
+//
+// NB: This is not a general purpose macro; it assumes that we are setting the
+// length of an NDIS packet with only one NDIS_BUFFER chained. We do
+// this to save time during the sending of short control packets.
+//
+
+#define NbfSetNdisPacketLength(_packet,_length) { \
+ PNDIS_BUFFER NdisBuffer; \
+ NdisQueryPacket((_packet), NULL, NULL, &NdisBuffer, NULL); \
+ NdisAdjustBufferLength(NdisBuffer, (_length)); \
+ NdisRecalculatePacketCounts(_packet); \
+}
+
+#endif // ifdef _MAC_
+
diff --git a/private/ntos/tdi/nbf/nbfndis.c b/private/ntos/tdi/nbf/nbfndis.c
new file mode 100644
index 000000000..9dd7902bd
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfndis.c
@@ -0,0 +1,1956 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to interface
+ NBF and NDIS. All callback routines (except for Transfer Data,
+ Send Complete, and ReceiveIndication) are here, as well as those routines
+ called to initialize NDIS.
+
+Author:
+
+ David Beaver (dbeaver) 13-Feb-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ David Beaver (dbeaver) 1-July-1991
+ modify to use new TDI interface
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef NBF_LOCKS // see spnlckdb.c
+
+VOID
+NbfFakeSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+NbfFakeTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+#endif
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE NbfNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+
+NDIS_STATUS
+NbfSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterName
+ );
+
+VOID
+NbfOpenAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+NbfCloseAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbfResetComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbfRequestComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+NbfStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbfProcessStatusClosing(
+ IN PVOID Parameter
+ );
+
+VOID
+NbfStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+NbfProtocolBindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+VOID
+NbfProtocolUnbindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE ProtocolBindContext,
+ IN PNDIS_HANDLE UnbindContext
+ );
+#endif
+
+#ifdef ALLOC_PRAGMA
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,NbfRegisterProtocol)
+#pragma alloc_text(INIT,NbfSubmitNdisRequest)
+#pragma alloc_text(INIT,NbfInitializeNdis)
+#else // PNP_POWER
+#pragma alloc_text(PAGE,NbfProtocolBindAdapter)
+#pragma alloc_text(PAGE,NbfProtocolUnbindAdapter)
+#pragma alloc_text(PAGE,NbfRegisterProtocol)
+#pragma alloc_text(PAGE,NbfSubmitNdisRequest)
+#pragma alloc_text(PAGE,NbfInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+NbfRegisterProtocol (
+ IN PUNICODE_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ PNDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+ ProtChars = ExAllocatePoolWithTag(
+ NonPagedPool,
+#ifndef _PNP_POWER
+ sizeof(NDIS_PROTOCOL_CHARACTERISTICS) +
+#else
+ sizeof(NDIS40_PROTOCOL_CHARACTERISTICS) +
+#endif
+ NameString->MaximumLength,
+ ' FBN');
+
+ if (ProtChars == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#ifndef _PNP_POWER
+ ProtChars->MajorNdisVersion = 3;
+#else
+ ProtChars->MajorNdisVersion = 4;
+ ProtChars->ReceivePacketHandler = NULL;
+ ProtChars->TranslateHandler = NULL;
+ ProtChars->BindAdapterHandler = NbfProtocolBindAdapter; // FIX ME!!!
+ ProtChars->UnbindAdapterHandler = NbfProtocolUnbindAdapter; // FIX ME!!!
+#endif
+ ProtChars->MinorNdisVersion = 0;
+
+ ProtChars->Name.Length = NameString->Length;
+ ProtChars->Name.Buffer = (PWCHAR)(ProtChars+1);
+ RtlCopyMemory (ProtChars->Name.Buffer, NameString->Buffer, NameString->Length);
+ ProtChars->Name.Buffer[NameString->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ ProtChars->OpenAdapterCompleteHandler = NbfOpenAdapterComplete;
+ ProtChars->CloseAdapterCompleteHandler = NbfCloseAdapterComplete;
+ ProtChars->ResetCompleteHandler = NbfResetComplete;
+ ProtChars->RequestCompleteHandler = NbfRequestComplete;
+
+#ifdef NBF_LOCKS
+ ProtChars->SendCompleteHandler = NbfFakeSendCompletionHandler;
+ ProtChars->TransferDataCompleteHandler = NbfFakeTransferDataComplete;
+#else
+ ProtChars->SendCompleteHandler = NbfSendCompletionHandler;
+ ProtChars->TransferDataCompleteHandler = NbfTransferDataComplete;
+#endif
+
+ ProtChars->ReceiveHandler = NbfReceiveIndication;
+ ProtChars->ReceiveCompleteHandler = NbfReceiveComplete;
+ ProtChars->StatusHandler = NbfStatusIndication;
+ ProtChars->StatusCompleteHandler = NbfStatusComplete;
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &NbfNdisProtocolHandle,
+ ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->MaximumLength);
+
+ ExFreePool (ProtChars);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1("NbfInitialize: NdisRegisterProtocol failed: %s\n",
+ NbfGetNdisStatus(ndisStatus));
+ }
+#endif
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+NbfDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (NbfNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ NbfNdisProtocolHandle);
+ NbfNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+}
+
+
+NDIS_STATUS
+NbfSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("OID %lx pended.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus == STATUS_SUCCESS) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ if (NdisRequest->RequestType == NdisRequestSetInformation) {
+ NbfPrint1 ("Nbfdrvr: Set OID %lx succeeded.\n",
+ NdisRequest->DATA.SET_INFORMATION.Oid);
+ } else {
+ NbfPrint1 ("Nbfdrvr: Query OID %lx succeeded.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+ }
+
+ } else {
+#if DBG
+ if (NdisRequest->RequestType == NdisRequestSetInformation) {
+ NbfPrint2 ("Nbfdrvr: Set OID %lx failed: %s.\n",
+ NdisRequest->DATA.SET_INFORMATION.Oid, NbfGetNdisStatus(NdisStatus));
+ } else {
+ NbfPrint2 ("Nbfdrvr: Query OID %lx failed: %s.\n",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid, NbfGetNdisStatus(NdisStatus));
+ }
+#endif
+ NbfWriteOidErrorLog(
+ DeviceContext,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+ }
+
+ return NdisStatus;
+}
+
+
+NTSTATUS
+NbfInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA NbfConfig,
+ IN UINT ConfigInfoNameIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ ULONG SendPacketReservedLength;
+ ULONG ReceivePacketReservedLen;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM NbfSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST NbfRequest;
+ UCHAR NbfDataBuffer[6];
+ NDIS_OID NbfOid;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x80, 0xd5 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ ULONG MinimumLookahead = 128 + sizeof(DLC_FRAME) + sizeof(NBF_HDR_CONNECTIONLESS);
+ ULONG MacOptions;
+ PNDIS_STRING AdapterString;
+
+
+ //
+ // Initialize this adapter for NBF use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ DeviceContext->NdisBindingHandle = NULL;
+ AdapterString = (PNDIS_STRING)&NbfConfig->Names[ConfigInfoNameIndex];
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &DeviceContext->NdisBindingHandle,
+ &SelectedMedium,
+ NbfSupportedMedia,
+ sizeof (NbfSupportedMedia) / sizeof(NDIS_MEDIUM),
+ NbfNdisProtocolHandle,
+ (NDIS_HANDLE)DeviceContext,
+ AdapterString,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Adapter %S open pended.\n", AdapterString);
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Adapter %S successfully opened.\n", AdapterString);
+ }
+#endif
+ } else {
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint2 ("Adapter open %S failed, status: %s.\n",
+ AdapterString,
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+ NbfWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 0,
+ NULL);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ NbfSupportedMedia[SelectedMedium],
+ (BOOLEAN)(NbfConfig->UseDixOverEthernet != 0),
+ &DeviceContext->MacInfo);
+ DeviceContext->MacInfo.QueryWithoutSourceRouting =
+ NbfConfig->QueryWithoutSourceRouting ? TRUE : FALSE;
+ DeviceContext->MacInfo.AllRoutesNameRecognized =
+ NbfConfig->AllRoutesNameRecognized ? TRUE : FALSE;
+
+
+ //
+ // Set the multicast/functional addresses first so we avoid windows where we
+ // receive only part of the addresses.
+ //
+
+ MacSetNetBIOSMulticast (
+ DeviceContext->MacInfo.MediumType,
+ DeviceContext->NetBIOSAddress.Address);
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, DeviceContext->NetBIOSAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ //
+ // Fill in the OVB for our functional address.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, ((PUCHAR)(DeviceContext->NetBIOSAddress.Address)) + 2, 4);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 4;
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(NbfDataBuffer, DeviceContext->NetBIOSAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ }
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+ NbfOid = OID_WAN_CURRENT_ADDRESS;
+ } else {
+ NbfOid = OID_802_3_CURRENT_ADDRESS;
+ }
+ break;
+
+ case NdisMedium802_5:
+
+ NbfOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ NbfOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = NbfOid;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = DeviceContext->LocalAddress.Address;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Set up the reserved Netbios address.
+ //
+
+ RtlZeroMemory(DeviceContext->ReservedNetBIOSAddress, 10);
+ RtlCopyMemory(&DeviceContext->ReservedNetBIOSAddress[10], DeviceContext->LocalAddress.Address, 6);
+
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxReceivePacketSize);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxSendPacketSize);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->CurSendPacketSize = DeviceContext->MaxSendPacketSize;
+
+
+ //
+ // Now set the minimum lookahead size.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed for non-wan media
+ //
+
+ if (!DeviceContext->MacInfo.MediumAsync) {
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MediumSpeed);
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MediumSpeedAccurate = TRUE;
+
+ DeviceContext->MinimumT1Timeout = 8; // == 400 ms
+
+ } else {
+
+ //
+ // On an wan media, this isn't valid until we get an
+ // WAN_LINE_UP indication. Set the timeouts to
+ // low values for now.
+ //
+
+ DeviceContext->DefaultT1Timeout = 8;
+ DeviceContext->MinimumT1Timeout = 8;
+
+ DeviceContext->MediumSpeedAccurate = FALSE;
+
+
+ //
+ // Back off our connectionless timeouts to 2 seconds.
+ //
+
+ DeviceContext->NameQueryTimeout = 2 * SECONDS;
+ DeviceContext->AddNameQueryTimeout = 2 * SECONDS;
+ DeviceContext->GeneralTimeout = 2 * SECONDS;
+
+ //
+ // Use the WAN parameter for name query retries.
+ //
+
+ DeviceContext->NameQueryRetries = NbfConfig->WanNameQueryRetries;
+
+ //
+ // Use this until we know better.
+ //
+
+ DeviceContext->RecommendedSendWindow = 1;
+
+ }
+
+ //
+ // On media that use source routing, we double our name query
+ // retry count if we are configured to try both ways (with and
+ // without source routing).
+ //
+
+ if ((DeviceContext->MacInfo.QueryWithoutSourceRouting) &&
+ (DeviceContext->MacInfo.SourceRouting)) {
+ DeviceContext->NameQueryRetries *= 2;
+ }
+
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ NbfRequest.RequestType = NdisRequestQueryInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if 1
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+#else
+ MacOptions = 0;
+#endif
+ }
+
+ DeviceContext->MacInfo.CopyLookahead =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0);
+ DeviceContext->MacInfo.ReceiveSerialized =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_RECEIVE_SERIALIZED) != 0);
+ DeviceContext->MacInfo.TransferSynchronous =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+ DeviceContext->MacInfo.SingleReceive =
+ (BOOLEAN)(DeviceContext->MacInfo.ReceiveSerialized && DeviceContext->MacInfo.TransferSynchronous);
+
+
+#if 0
+ //
+ // Now set our options if needed.
+ //
+ // Don't allow early indications because we can't determine
+ // if the CRC has been checked yet.
+ //
+
+ if ((DeviceContext->MacInfo.MediumType == NdisMedium802_3) ||
+ (DeviceContext->MacInfo.MediumType == NdisMediumDix)) {
+
+ ULONG ProtocolOptions = NDIS_PROT_OPTION_ESTIMATED_LENGTH;
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_PROTOCOL_OPTIONS;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBuffer = &ProtocolOptions;
+ NbfRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+#endif
+
+
+ //
+ // Calculate the NDIS-related stuff.
+ //
+
+ SendPacketReservedLength = sizeof (SEND_PACKET_TAG);
+ ReceivePacketReservedLen = sizeof (RECEIVE_PACKET_TAG);
+
+
+ //
+ // The send packet pool is used for UI frames and regular packets.
+ //
+
+ SendPacketPoolSize = NbfConfig->SendPacketPoolSize;
+
+ //
+ // The receive packet pool is used in transfer data.
+ //
+ // For a MAC that will only have one receive active, we
+ // don't need multiple receive packets. Allow an extra
+ // one for loopback.
+ //
+
+ if (DeviceContext->MacInfo.SingleReceive) {
+ ReceivePacketPoolSize = 2;
+ } else {
+ ReceivePacketPoolSize = NbfConfig->ReceivePacketPoolSize;
+ }
+
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ DeviceContext->SendPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->SendPacketPoolDesc == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(DeviceContext->SendPacketPoolDesc,
+ sizeof(NBF_POOL_LIST_DESC));
+
+ DeviceContext->SendPacketPoolDesc->NumElements =
+ DeviceContext->SendPacketPoolDesc->TotalElements = (USHORT)SendPacketPoolSize;
+
+ NdisAllocatePacketPool (
+ &NdisStatus,
+ &DeviceContext->SendPacketPoolDesc->PoolHandle,
+ SendPacketPoolSize,
+ SendPacketReservedLength);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NdisInitializePacketPool successful.\n");
+ }
+
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 109,
+ SendPacketPoolSize,
+ 0);
+ ExFreePool (DeviceContext->SendPacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->SendPacketPoolSize = SendPacketPoolSize;
+
+ DeviceContext->MemoryUsage +=
+ (SendPacketPoolSize *
+ (sizeof(NDIS_PACKET) + SendPacketReservedLength));
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ DbgPrint ("send pool %d hdr %d, %ld\n",
+ SendPacketPoolSize,
+ SendPacketReservedLength,
+ DeviceContext->MemoryUsage);
+ }
+#endif
+
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ DeviceContext->ReceivePacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->ReceivePacketPoolDesc == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(DeviceContext->ReceivePacketPoolDesc,
+ sizeof(NBF_POOL_LIST_DESC));
+
+ DeviceContext->ReceivePacketPoolDesc->NumElements =
+ DeviceContext->ReceivePacketPoolDesc->TotalElements = (USHORT)ReceivePacketPoolSize;
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &DeviceContext->ReceivePacketPoolDesc->PoolHandle,
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("NdisInitializePacketPool successful, Pool: %lx\n",
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+ }
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ExFreePool (DeviceContext->SendPacketPoolDesc);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ NbfCloseNdis (DeviceContext);
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 209,
+ ReceivePacketPoolSize,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->ReceivePacketPoolSize = ReceivePacketPoolSize;
+
+ DeviceContext->MemoryUsage +=
+ (ReceivePacketPoolSize *
+ (sizeof(NDIS_PACKET) + ReceivePacketReservedLen));
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ DbgPrint ("receive pool %d hdr %d, %ld\n",
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen,
+ DeviceContext->MemoryUsage);
+ }
+#endif
+
+
+ //
+ // Allocate the buffer pool; as an estimate, allocate
+ // one per send or receive packet.
+ //
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &DeviceContext->NdisBufferPool,
+ SendPacketPoolSize + ReceivePacketPoolSize);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("NdisAllocateBufferPool successful.\n");
+ }
+
+ } else {
+#if DBG
+ NbfPrint1 ("NbfInitialize: NdisAllocateBufferPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ ExFreePool(DeviceContext->SendPacketPoolDesc);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ DeviceContext->NdisBufferPool = NULL;
+ NbfCloseNdis (DeviceContext);
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 309,
+ SendPacketPoolSize + ReceivePacketPoolSize,
+ 0);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ //
+ // Fill in the OVB for packet filter.
+ //
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumDix:
+ case NdisMediumFddi:
+
+ RtlStoreUlong((PULONG)NbfDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST));
+ break;
+
+ case NdisMedium802_5:
+
+ RtlStoreUlong((PULONG)NbfDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL));
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ NbfRequest.RequestType = NdisRequestSetInformation;
+ NbfRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ NbfRequest.DATA.SET_INFORMATION.InformationBuffer = &NbfDataBuffer;
+ NbfRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NbfSubmitNdisRequest (DeviceContext, &NbfRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbfInitializeNdis */
+
+
+VOID
+NbfCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in NbfInitializeNdis.
+ It is written so that it can be called from within NbfInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (DeviceContext->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("Adapter close pended.\n");
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+ if (DeviceContext->SendPacketPoolDesc != NULL &&
+ DeviceContext->SendPacketPoolDesc->PoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->SendPacketPoolDesc->PoolHandle);
+ ExFreePool(DeviceContext->SendPacketPoolDesc);
+ DeviceContext->SendPacketPoolDesc = NULL;
+ }
+
+ if (DeviceContext->ReceivePacketPoolDesc != NULL &&
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+ ExFreePool(DeviceContext->ReceivePacketPoolDesc);
+ DeviceContext->ReceivePacketPoolDesc = NULL;
+ }
+
+ if (DeviceContext->NdisBufferPool != NULL) {
+ NdisFreeBufferPool (DeviceContext->NdisBufferPool);
+ }
+
+} /* NbfCloseNdis */
+
+
+VOID
+NbfOpenAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfOpenAdapterCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfCloseAdapterComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfCloseAdapterCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfResetComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint1 ("Nbfdrvr: NbfResetCompleteNDIS Status: %s\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ return;
+}
+
+VOID
+NbfRequestComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint2 ("Nbfdrvr: NbfRequestComplete request: %i, NDIS Status: %s\n",
+ NdisRequest->RequestType,NbfGetNdisStatus (NdisStatus));
+ }
+#endif
+
+ ENTER_NBF;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ LEAVE_NBF;
+ return;
+}
+
+VOID
+NbfStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PNDIS_WAN_LINE_UP LineUp;
+ KIRQL oldirql;
+ PTP_LINK Link;
+
+ DeviceContext = (PDEVICE_CONTEXT)NdisBindingContext;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+ //
+ // A wan line is connected.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ //
+ // If this happens before we are ready, then make
+ // a note of it, otherwise make the device ready.
+ //
+
+ DeviceContext->MediumSpeedAccurate = TRUE;
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // See if this is a new lineup for this protocol type
+ //
+ if (LineUp->ProtocolType == 0x80D5) {
+ NDIS_HANDLE TransportHandle;
+
+ *((ULONG UNALIGNED *)(&TransportHandle)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+ //
+ // See if this is a new lineup
+ //
+ if (TransportHandle == NULL) {
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) = *((ULONG UNALIGNED *)(&DeviceContext));
+// ETH_COPY_NETWORK_ADDRESS(DeviceContext->LocalAddress.Address, LineUp->LocalAddress);
+// ETH_COPY_NETWORK_ADDRESS(&DeviceContext->ReservedNetBIOSAddress[10], DeviceContext->LocalAddress.Address);
+ }
+
+ //
+ // Calculate minimum link timeouts based on the speed,
+ // which is passed in StatusBuffer.
+ //
+ // The formula is (max_frame_size * 2) / speed + 0.4 sec.
+ // This expands to
+ //
+ // MFS (bytes) * 2 8 bits
+ // ------------------- x ------ == timeout (sec),
+ // speed (100 bits/sec) byte
+ //
+ // which is (MFS * 16 / 100) / speed. We then convert it into
+ // the 50 ms units that NBF uses and add 8 (which is
+ // 0.4 seconds in 50 ms units).
+ //
+ // As a default timeout we use the min + 0.2 seconds
+ // unless the configured default is more.
+ //
+
+ if (LineUp->LinkSpeed > 0) {
+ DeviceContext->MediumSpeed = LineUp->LinkSpeed;
+ }
+
+ if (LineUp->MaximumTotalSize > 0) {
+#if DBG
+ if (LineUp->MaximumTotalSize > DeviceContext->MaxSendPacketSize) {
+ DbgPrint ("Nbf: Bad LINE_UP size, %d (> %d)\n",
+ LineUp->MaximumTotalSize, DeviceContext->MaxSendPacketSize);
+ }
+ if (LineUp->MaximumTotalSize < 128) {
+ DbgPrint ("NBF: Bad LINE_UP size, %d (< 128)\n",
+ LineUp->MaximumTotalSize);
+ }
+#endif
+ DeviceContext->CurSendPacketSize = LineUp->MaximumTotalSize;
+ }
+
+ if (LineUp->SendWindow == 0) {
+ DeviceContext->RecommendedSendWindow = 3;
+ } else {
+ DeviceContext->RecommendedSendWindow = LineUp->SendWindow + 1;
+ }
+
+ DeviceContext->MinimumT1Timeout =
+ ((((DeviceContext->CurSendPacketSize * 16) / 100) / DeviceContext->MediumSpeed) *
+ ((1 * SECONDS) / (50 * MILLISECONDS))) + 8;
+
+ if (DeviceContext->DefaultT1Timeout < DeviceContext->MinimumT1Timeout) {
+ DeviceContext->DefaultT1Timeout = DeviceContext->MinimumT1Timeout + 4;
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ //
+ // An wan line is disconnected.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ DeviceContext->MediumSpeedAccurate = FALSE;
+
+ //
+ // Set the timeouts to small values (0.4 seconds)
+ //
+
+ DeviceContext->DefaultT1Timeout = 8;
+ DeviceContext->MinimumT1Timeout = 8;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+
+ //
+ // Stop the link on this device context (there
+ // will only be one).
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ if (DeviceContext->LinkTreeElements > 0) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) == 0) {
+
+ NbfReferenceLink ("Wan line down", Link, LREF_TREE);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ //
+ // Put the link in ADM to shut it down.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->State != LINK_STATE_ADM) {
+ Link->State = LINK_STATE_ADM;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfDereferenceLinkSpecial ("Wan line down", Link, LREF_NOT_ADM);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+
+ //
+ // Now stop it to destroy all connections on it.
+ //
+
+ NbfStopLink (Link);
+
+ NbfDereferenceLink ("Wan line down", Link, LREF_TREE);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // A fragment has been received on the wan line.
+ // Send a reject back to him.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ if (DeviceContext->LinkTreeElements > 0) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ NbfReferenceLink ("Async line down", Link, LREF_TREE);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfSendRej (Link, FALSE, FALSE); // release lock
+ NbfDereferenceLink ("Async line down", Link, LREF_TREE);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ break;
+
+ case NDIS_STATUS_CLOSING:
+
+ //
+ // The adapter is shutting down. We queue a worker
+ // thread to handle this.
+ //
+
+ ExInitializeWorkItem(
+ &DeviceContext->StatusClosingQueueItem,
+ NbfProcessStatusClosing,
+ (PVOID)DeviceContext);
+ ExQueueWorkItem(&DeviceContext->StatusClosingQueueItem, DelayedWorkQueue);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ KeLowerIrql (oldirql);
+
+}
+
+
+VOID
+NbfProcessStatusClosing(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the thread routine which restarts packetizing
+ that has been delayed on WAN to allow RRs to come in.
+ This is very similar to PacketizeConnections.
+
+Arguments:
+
+ Parameter - A pointer to the device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+#if 0
+ PTP_ADDRESS Address;
+#endif
+ PTP_LINK Link;
+ PTP_REQUEST Request;
+ NDIS_STATUS ndisStatus;
+ KIRQL oldirql;
+
+ DeviceContext = (PDEVICE_CONTEXT)Parameter;
+
+ //
+ // Prevent new activity on the connection.
+ //
+
+ DeviceContext->State = DEVICECONTEXT_STATE_DOWN;
+
+
+#if 0
+ //
+ // Stop all the addresses.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->AddressDatabase,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+ InitializeListHead(p);
+
+ NbfStopAddress (Address);
+
+ }
+#endif
+
+ //
+ // To speed things along, stop all the links too.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ DeviceContext->LastLink = NULL;
+
+ while (DeviceContext->LinkTreeRoot != NULL) {
+
+ Link = (PTP_LINK)DeviceContext->LinkTreeRoot;
+ DeviceContext->LinkTreeRoot = RtlDelete ((PRTL_SPLAY_LINKS)Link);
+ DeviceContext->LinkTreeElements--;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ if (Link->OnShortList) {
+ RemoveEntryList (&Link->ShortList);
+ }
+ if (Link->OnLongList) {
+ RemoveEntryList (&Link->LongList);
+ }
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if (Link->State != LINK_STATE_ADM) {
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in CONNECTING mode", Link, LREF_NOT_ADM);
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ }
+ NbfStopLink (Link);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ KeLowerIrql (oldirql);
+
+
+ //
+ // Shutdown the control channel.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->QueryIndicationQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->DatagramIndicationQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->StatusQueryQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &DeviceContext->FindNameQueue,
+ &DeviceContext->SpinLock)) != NULL) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ NbfCompleteRequest (Request, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+
+ //
+ // Close the NDIS binding.
+ //
+
+ KeInitializeEvent(
+ &DeviceContext->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ DeviceContext->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint0 ("Adapter close pended.\n");
+ }
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &DeviceContext->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = DeviceContext->NdisRequestStatus;
+
+ KeResetEvent(
+ &DeviceContext->NdisRequestEvent
+ );
+
+ }
+
+ DeviceContext->NdisBindingHandle = NULL;
+
+ //
+ // We ignore ndisStatus.
+ //
+
+#if 0
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ NbfFreeResources (DeviceContext);
+
+ NdisFreePacketPool (DeviceContext->SendPacketPoolHandle);
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolHandle);
+ NdisFreeBufferPool (DeviceContext->NdisBufferPoolHandle);
+#endif
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
+
+} /* NbfProcessStatusClosing */
+
+
+VOID
+NbfStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+}
+
+#if DBG
+
+PUCHAR
+NbfGetNdisStatus(
+ NDIS_STATUS GeneralStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the string describing the NDIS error
+ denoted by GeneralStatus.
+
+Arguments:
+
+ GeneralStatus - the status you wish to make readable.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ static NDIS_STATUS Status[] = {
+ NDIS_STATUS_SUCCESS,
+ NDIS_STATUS_PENDING,
+
+ NDIS_STATUS_ADAPTER_NOT_FOUND,
+ NDIS_STATUS_ADAPTER_NOT_OPEN,
+ NDIS_STATUS_ADAPTER_NOT_READY,
+ NDIS_STATUS_ADAPTER_REMOVED,
+ NDIS_STATUS_BAD_CHARACTERISTICS,
+ NDIS_STATUS_BAD_VERSION,
+ NDIS_STATUS_CLOSING,
+ NDIS_STATUS_DEVICE_FAILED,
+ NDIS_STATUS_FAILURE,
+ NDIS_STATUS_INVALID_DATA,
+ NDIS_STATUS_INVALID_LENGTH,
+ NDIS_STATUS_INVALID_OID,
+ NDIS_STATUS_INVALID_PACKET,
+ NDIS_STATUS_MULTICAST_FULL,
+ NDIS_STATUS_NOT_INDICATING,
+ NDIS_STATUS_NOT_RECOGNIZED,
+ NDIS_STATUS_NOT_RESETTABLE,
+ NDIS_STATUS_NOT_SUPPORTED,
+ NDIS_STATUS_OPEN_FAILED,
+ NDIS_STATUS_OPEN_LIST_FULL,
+ NDIS_STATUS_REQUEST_ABORTED,
+ NDIS_STATUS_RESET_IN_PROGRESS,
+ NDIS_STATUS_RESOURCES,
+ NDIS_STATUS_UNSUPPORTED_MEDIA
+ };
+ static PUCHAR String[] = {
+ "SUCCESS",
+ "PENDING",
+
+ "ADAPTER_NOT_FOUND",
+ "ADAPTER_NOT_OPEN",
+ "ADAPTER_NOT_READY",
+ "ADAPTER_REMOVED",
+ "BAD_CHARACTERISTICS",
+ "BAD_VERSION",
+ "CLOSING",
+ "DEVICE_FAILED",
+ "FAILURE",
+ "INVALID_DATA",
+ "INVALID_LENGTH",
+ "INVALID_OID",
+ "INVALID_PACKET",
+ "MULTICAST_FULL",
+ "NOT_INDICATING",
+ "NOT_RECOGNIZED",
+ "NOT_RESETTABLE",
+ "NOT_SUPPORTED",
+ "OPEN_FAILED",
+ "OPEN_LIST_FULL",
+ "REQUEST_ABORTED",
+ "RESET_IN_PROGRESS",
+ "RESOURCES",
+ "UNSUPPORTED_MEDIA"
+ };
+
+ static UCHAR BadStatus[] = "UNDEFINED";
+#define StatusCount (sizeof(Status)/sizeof(NDIS_STATUS))
+ INT i;
+
+ for (i=0; i<StatusCount; i++)
+ if (GeneralStatus == Status[i])
+ return String[i];
+ return BadStatus;
+#undef StatusCount
+}
+#endif
diff --git a/private/ntos/tdi/nbf/nbfpnp.c b/private/ntos/tdi/nbf/nbfpnp.c
new file mode 100644
index 000000000..844abf8ad
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfpnp.c
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ nbfpnp.c
+
+Abstract:
+
+ This module contains code which allocates and initializes all data
+ structures needed to activate a plug and play binding. It also informs
+ tdi (and thus nbf clients) of new devices and protocol addresses.
+
+Author:
+
+ Jim McNelis (jimmcn) 1-Jan-1996
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef _PNP_POWER
+PCONFIG_DATA NbfConfig = NULL;
+SuccessfulOpens = 0;
+
+#ifdef RASAUTODIAL
+VOID
+NbfAcdBind();
+
+VOID
+NbfAcdUnbind();
+#endif // RASAUTODIAL
+
+VOID
+NbfProtocolBindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+/*++
+
+Routine Description:
+
+ This routine activates a transport binding and exposes the new device
+ and associated addresses to transport clients. This is done by reading
+ the registry, and performing any one time initialization of the transport
+ and then natching the device to bind to with the linkage information from
+ the registry. If we have a match for that device the bind will be
+ performed.
+
+Arguments:
+
+ NdisStatus - The status of the bind.
+
+ BindContext - A context used for NdisCompleteBindAdapter() if
+ STATUS_PENDING is returned.
+
+ DeviceName - The name of the device that we are binding with.
+
+ SystemSpecific1 - Unused (a pointer to an NDIS_STRING to use with
+ NdisOpenProtocolConfiguration. This is not used by nbf
+ since there is no adapter specific information when
+ configuring the protocol via the registry.
+
+ SystemSpecific2 - Currently unused.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG j;
+ NTSTATUS status;
+
+ if (NbfConfig == NULL) {
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in NbfConfig.
+ //
+
+
+
+ status = NbfConfigureTransport(&NbfRegistryPath, &NbfConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, Nbf binding failed.\n");
+ *NdisStatus = NDIS_STATUS_RESOURCES;
+ return;
+ }
+
+#if DBG
+
+ //
+ // Allocate the debugging tables.
+ //
+
+ NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(PVOID) *
+ (NbfConfig->InitConnections + 2 +
+ NbfConfig->InitRequests + 2 +
+ NbfConfig->InitUIFrames + 2 +
+ NbfConfig->InitPackets + 2 +
+ NbfConfig->InitLinks + 2 +
+ NbfConfig->InitAddressFiles + 2 +
+ NbfConfig->InitAddresses + 2),
+ ' FBN');
+
+ ASSERT (NbfConnectionTable);
+
+#if 0
+ if (NbfConnectionTable == NULL) {
+ *NdisStatus = NDIS_STATUS_RESOURCES;
+ return;
+ }
+#endif
+
+
+ NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
+ NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
+ NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
+ NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
+ NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
+ NbfAddressTable = NbfAddressFileTable +
+ (NbfConfig->InitAddressFiles + 2);
+#endif
+ }
+
+ for (j=0;j<NbfConfig->NumAdapters;j++ ) {
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure until we find the one that ndis is calling
+ // Protocol bind adapter for.
+ //
+ if (NdisEqualString(DeviceName, &NbfConfig->Names[j], TRUE)) {
+ break;
+ }
+
+ }
+
+ SuccessfulOpens += NbfInitializeOneDeviceContext(NdisStatus,
+ NbfDriverObject,
+ NbfConfig, j
+ );
+
+ if (SuccessfulOpens == 1 && *NdisStatus == NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("Calling NbfAcdBind()\n");
+#endif
+ //
+ // If this is the first successful open.
+ //
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbfAcdBind();
+#endif // RASAUTODIAL
+ }
+ return;
+}
+VOID
+NbfProtocolUnbindAdapter(
+ OUT PNDIS_STATUS NdisStatus,
+ IN NDIS_HANDLE ProtocolBindContext,
+ IN PNDIS_HANDLE UnbindContext
+ )
+/*++
+
+Routine Description:
+
+ This routine deactivates a transport binding. Currently unimplemented.
+
+Arguments:
+
+ NdisStatus - The status of the bind.
+
+ ProtocolBindContext - the context from the openadapter call
+
+ UnbindContext - A context for async unbinds.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ *NdisStatus = STATUS_NOT_IMPLEMENTED;
+ return;
+}
+
+#endif // _PNP_POWER
diff --git a/private/ntos/tdi/nbf/nbfprocs.h b/private/ntos/tdi/nbf/nbfprocs.h
new file mode 100644
index 000000000..9449f0563
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbfprocs.h
@@ -0,0 +1,2322 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ nbfprocs.h
+
+Abstract:
+
+ This header file defines private functions for the NT NBF transport
+ provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFPROCS_
+#define _NBFPROCS_
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// IF_NBFDBG(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define IF_NBFDBG(flags) \
+ if (NbfDebug & (flags))
+#else
+#define IF_NBFDBG(flags) \
+ if (0)
+#endif
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ DbgPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow DbgPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbfPrint0(fmt) DbgPrint(fmt)
+#define NbfPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbfPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbfPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbfPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbfPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbfPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbfPrint0(fmt)
+#define NbfPrint1(fmt,v0)
+#define NbfPrint2(fmt,v0,v1)
+#define NbfPrint3(fmt,v0,v1,v2)
+#define NbfPrint4(fmt,v0,v1,v2,v3)
+#define NbfPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbfPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+//
+// The REFCOUNTS message take up a lot of room, so make
+// removing them easy.
+//
+
+#if 1
+#define IF_REFDBG IF_NBFDBG (NBF_DEBUG_REFCOUNTS)
+#else
+#define IF_REFDBG if (0)
+#endif
+
+#if DBG
+#define NbfReferenceLink( Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefL %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->ReferenceCount);\
+ }\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefLink (Link)
+
+#define NbfDereferenceLink(Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefL %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefLink (Link)
+
+#define NbfDereferenceLinkMacro(Reason, Link, Type)\
+ NbfDereferenceLink(Reason, Link, Type)
+
+#define NbfReferenceLinkSpecial( Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to special reference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefLS %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->SpecialRefCount);\
+ }\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefLinkSpecial (Link)
+
+#define NbfDereferenceLinkSpecial(Reason, Link, Type)\
+ if ((Link)->Destroyed) { \
+ DbgPrint("NBF: Attempt to special dereference destroyed link %lx\n", Link); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefLS %x: %s %s, %ld : %ld\n", Link, Reason, __FILE__, __LINE__, (Link)->SpecialRefCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Link)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefLinkSpecial (Link)
+
+#define NbfReferenceConnection(Reason, Connection, Type)\
+ if ((Connection)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed conn %lx\n", Connection); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefC %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Connection)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefConnection (Connection)
+
+#define NbfDereferenceConnection(Reason, Connection, Type)\
+ if ((Connection)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed conn %lx\n", Connection); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefC %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)&((Connection)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefConnection (Connection)
+
+#define NbfDereferenceConnectionMacro(Reason, Connection, Type)\
+ NbfDereferenceConnection(Reason, Connection, Type)
+
+#define NbfDereferenceConnectionSpecial(Reason, Connection, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefCL %x: %s %s, %ld : %ld\n", Connection, Reason, __FILE__, __LINE__, (Connection)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)&((Connection)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefConnectionSpecial (Connection)
+
+#define NbfReferenceRequest( Reason, Request, Type)\
+ if ((Request)->Destroyed) { \
+ DbgPrint("NBF: Attempt to reference destroyed req %lx\n", Request); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("RefR %x: %s %s, %ld : %ld\n", Request, Reason, __FILE__, __LINE__, (Request)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Request)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefRequest (Request)
+
+#define NbfDereferenceRequest(Reason, Request, Type)\
+ if ((Request)->Destroyed) { \
+ DbgPrint("NBF: Attempt to dereference destroyed req %lx\n", Request); \
+ DbgBreakPoint(); \
+ } \
+ IF_REFDBG { \
+ DbgPrint ("DeRefR %x: %s %s, %ld : %ld\n", Request, Reason, __FILE__, __LINE__, (Request)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Request)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefRequest (Request)
+
+#define NbfReferenceSendIrp( Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefSI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_SEND_REFCOUNT(IrpSp));}\
+ NbfRefSendIrp (IrpSp)
+
+#define NbfDereferenceSendIrp(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefSI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_SEND_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefSendIrp (IrpSp)
+
+#define NbfReferenceReceiveIrpLocked( Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefRI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));}\
+ NbfRefReceiveIrpLocked (IrpSp)
+
+#define NbfDereferenceReceiveIrp(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefRI %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefReceiveIrp (IrpSp)
+
+#define NbfDereferenceReceiveIrpLocked(Reason, IrpSp, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefRILocked %x: %s %s, %ld : %ld\n", IrpSp, Reason, __FILE__, __LINE__, IRP_RECEIVE_REFCOUNT(IrpSp));\
+ } \
+ NbfDerefReceiveIrpLocked (IrpSp)
+
+#define NbfReferenceAddress( Reason, Address, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefA %x: %s %s, %ld : %ld\n", Address, Reason, __FILE__, __LINE__, (Address)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Address)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefAddress (Address)
+
+#define NbfDereferenceAddress(Reason, Address, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefA %x: %s %s, %ld : %ld\n", Address, Reason, __FILE__, __LINE__, (Address)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(Address)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefAddress (Address)
+
+#define NbfReferenceDeviceContext( Reason, DeviceContext, Type)\
+ IF_REFDBG { \
+ DbgPrint ("RefDC %x: %s %s, %ld : %ld\n", DeviceContext, Reason, __FILE__, __LINE__, (DeviceContext)->ReferenceCount);}\
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(DeviceContext)->RefTypes[Type]), \
+ 1, \
+ &NbfGlobalInterlock); \
+ NbfRefDeviceContext (DeviceContext)
+
+#define NbfDereferenceDeviceContext(Reason, DeviceContext, Type)\
+ IF_REFDBG { \
+ DbgPrint ("DeRefDC %x: %s %s, %ld : %ld\n", DeviceContext, Reason, __FILE__, __LINE__, (DeviceContext)->ReferenceCount);\
+ } \
+ (VOID)ExInterlockedAddUlong ( \
+ (PULONG)(&(DeviceContext)->RefTypes[Type]), \
+ (ULONG)-1, \
+ &NbfGlobalInterlock); \
+ NbfDerefDeviceContext (DeviceContext)
+
+#else
+#if defined(NBF_UP)
+#define NbfReferenceLink(Reason, Link, Type) \
+ { \
+ ULONG _ref; \
+ _ref = ++(Link)->ReferenceCount; \
+ if ( _ref == 0 ) { \
+ NbfReferenceLinkSpecial ("first ref", (Link), LREF_SPECIAL_TEMP); \
+ } \
+ }
+#else
+#define NbfReferenceLink(Reason, Link, Type) \
+ if (InterlockedIncrement( \
+ &(Link)->ReferenceCount) == 0) { \
+ NbfReferenceLinkSpecial ("first ref", (Link), LREF_SPECIAL_TEMP); \
+ }
+#endif
+
+#define NbfDereferenceLink(Reason, Link, Type)\
+ NbfDereferenceLinkMacro(Reason,Link,Type)
+
+#if defined(NBF_UP)
+#define NbfDereferenceLinkMacro(Reason, Link, Type){ \
+ ULONG _ref; \
+ _ref = --(Link)->ReferenceCount; \
+ if (_ref < 0) { \
+ NbfDisconnectLink (Link); \
+ NbfDerefLinkSpecial (Link); \
+ } \
+}
+#else
+#define NbfDereferenceLinkMacro(Reason, Link, Type){ \
+ if (InterlockedDecrement( \
+ &(Link)->ReferenceCount) < 0) { \
+ NbfDisconnectLink (Link); \
+ NbfDerefLinkSpecial (Link); \
+ } \
+}
+#endif
+
+#define NbfReferenceLinkSpecial(Reason, Link, Type)\
+ NbfRefLinkSpecial (Link)
+
+#define NbfDereferenceLinkSpecial(Reason, Link, Type)\
+ NbfDerefLinkSpecial (Link)
+
+#define NbfReferenceConnection(Reason, Connection, Type)\
+ if (InterlockedIncrement( \
+ &(Connection)->ReferenceCount) == 0) { \
+ ExInterlockedAddUlong( \
+ (PULONG)(&(Connection)->SpecialRefCount), \
+ 1, \
+ (Connection)->ProviderInterlock); \
+ }
+
+#define NbfDereferenceConnection(Reason, Connection, Type)\
+ NbfDerefConnection (Connection)
+
+#define NbfDereferenceConnectionMacro(Reason, Connection, Type){ \
+ if (InterlockedDecrement( \
+ &(Connection)->ReferenceCount) < 0) { \
+ if (NbfDisconnectFromLink (Connection, TRUE)) { \
+ NbfIndicateDisconnect (Connection); \
+ } \
+ NbfDerefConnectionSpecial (Connection); \
+ } \
+}
+
+#define NbfDereferenceConnectionSpecial(Reason, Connection, Type)\
+ NbfDerefConnectionSpecial (Connection)
+
+#define NbfReferenceRequest(Reason, Request, Type)\
+ (VOID)InterlockedIncrement( \
+ &(Request)->ReferenceCount)
+
+#define NbfDereferenceRequest(Reason, Request, Type)\
+ NbfDerefRequest (Request)
+
+#define NbfReferenceSendIrp(Reason, IrpSp, Type)\
+ (VOID)InterlockedIncrement( \
+ &IRP_SEND_REFCOUNT(IrpSp))
+
+#define NbfDereferenceSendIrp(Reason, IrpSp, Type) {\
+ PIO_STACK_LOCATION _IrpSp = (IrpSp); \
+ if (InterlockedDecrement( \
+ &IRP_SEND_REFCOUNT(_IrpSp)) == 0) { \
+ PIRP _Irp = IRP_SEND_IRP(_IrpSp); \
+ IRP_SEND_REFCOUNT(_IrpSp) = 0; \
+ IRP_SEND_IRP (_IrpSp) = NULL; \
+ IoCompleteRequest (_Irp, IO_NETWORK_INCREMENT); \
+ } \
+}
+
+#define NbfReferenceReceiveIrpLocked(Reason, IrpSp, Type)\
+ ++IRP_RECEIVE_REFCOUNT(IrpSp)
+
+#define NbfDereferenceReceiveIrp(Reason, IrpSp, Type)\
+ NbfDerefReceiveIrp (IrpSp)
+
+#define NbfDereferenceReceiveIrpLocked(Reason, IrpSp, Type) { \
+ if (--IRP_RECEIVE_REFCOUNT(IrpSp) == 0) { \
+ ExInterlockedInsertTailList( \
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue), \
+ &(IRP_RECEIVE_IRP(IrpSp))->Tail.Overlay.ListEntry, \
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock)); \
+ } \
+}
+
+#define NbfReferenceAddress(Reason, Address, Type)\
+ (VOID)InterlockedIncrement(&(Address)->ReferenceCount)
+
+#define NbfDereferenceAddress(Reason, Address, Type)\
+ NbfDerefAddress (Address)
+
+#define NbfReferenceDeviceContext(Reason, DeviceContext, Type)\
+ NbfRefDeviceContext (DeviceContext)
+
+#define NbfDereferenceDeviceContext(Reason, DeviceContext, Type)\
+ NbfDerefDeviceContext (DeviceContext)
+
+#define NbfReferencePacket(Packet) \
+ (VOID)InterlockedIncrement(&(Packet)->ReferenceCount)
+
+#define NbfDereferencePacket(Packet){ \
+ if (InterlockedDecrement ( \
+ &(Packet)->ReferenceCount) == 0) { \
+ NbfDestroyPacket (Packet); \
+ } \
+}
+
+#endif
+
+
+//
+// Error and statistics Macros
+//
+
+
+// VOID
+// LogErrorToSystem(
+// NTSTATUS ErrorType,
+// PUCHAR ErrorDescription
+// )
+
+/*++
+
+Routine Description:
+
+ This routine is called to log an error from the transport to the system.
+ Errors that are of system interest should be logged using this interface.
+ For now, this macro is defined trivially. (BUGBUG)
+
+Arguments:
+
+ ErrorType - The error type, a conventional NT status
+
+ ErrorDescription - A pointer to a string describing the error.
+
+Return Value:
+
+ none.
+
+--*/
+
+#if DBG
+#define LogErrorToSystem( ErrorType, ErrorDescription) \
+ DbgPrint ("Logging error: File: %s Line: %ld \n Description: %s\n",__FILE__, __LINE__, ErrorDescription)
+#else
+#define LogErrorToSystem( ErrorType, ErrorDescription)
+#endif
+
+
+//
+// Routines in TIMER.C (lightweight timer system package).
+// Note that all the start and stop routines for the timers assume that you
+// have the link spinlock when you call them!
+// Note also that, with the latest revisions, the timer system now works by
+// putting those links that have timers running on a list of links to be looked
+// at for each clock tick. This list is ordered, with the most recently inserted
+// elements at the tail of the list. Note further that anything already on the
+// is moved to the end of the list if the timer is restarted; thus, the list
+// order is preserved.
+//
+
+VOID
+NbfStartShortTimer(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfInitializeTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfStopTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+VOID
+StartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ );
+
+VOID
+StartT2(
+ IN PTP_LINK Link
+ );
+
+VOID
+StartTi(
+ IN PTP_LINK Link
+ );
+
+#if DBG
+
+VOID
+StopT1(
+ IN PTP_LINK Link
+ );
+
+VOID
+StopT2(
+ IN PTP_LINK Link
+ );
+
+VOID
+StopTi(
+ IN PTP_LINK Link
+ );
+
+#else
+
+#define StopT1(_Link) \
+ { \
+ (_Link)->CurrentPollOutstanding = FALSE; \
+ (_Link)->T1 = 0; \
+ }
+
+#define StopT2(_Link) \
+ { \
+ (_Link)->ConsecutiveIFrames = 0; \
+ (_Link)->T2 = 0; \
+ }
+
+#define StopTi(_Link) \
+ (_Link)->Ti = 0;
+
+#endif
+
+
+//
+// These functions may become macros once they are finished.
+//
+
+ULONG
+GetTimerInterval(
+ IN PTP_LINK Link
+ );
+
+VOID
+BackoffCurrentT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+UpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+CancelT1Timeout(
+ IN PTP_LINK Link
+ );
+
+VOID
+UpdateDelayAndThroughput(
+ IN PTP_LINK Link,
+ IN ULONG TimerInterval
+ );
+
+VOID
+FakeStartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ );
+
+VOID
+FakeUpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ );
+
+
+//
+// These macros are used to create and destroy packets, due
+// to the allocation or deallocation of structure which
+// need them.
+//
+
+#define NbfAddUIFrame(DeviceContext) { \
+ PTP_UI_FRAME _UIFrame; \
+ NbfAllocateUIFrame ((DeviceContext), &_UIFrame); \
+ if (_UIFrame != NULL) { \
+ ExInterlockedInsertTailList( \
+ &(DeviceContext)->UIFramePool, \
+ &_UIFrame->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define NbfRemoveUIFrame(DeviceContext) { \
+ PLIST_ENTRY p; \
+ if (DeviceContext->UIFrameAllocated > DeviceContext->UIFrameInitAllocated) { \
+ p = ExInterlockedRemoveHeadList( \
+ &(DeviceContext)->UIFramePool, \
+ &(DeviceContext)->Interlock); \
+ if (p != NULL) { \
+ NbfDeallocateUIFrame((DeviceContext), \
+ (PTP_UI_FRAME)CONTAINING_RECORD(p, TP_UI_FRAME, Linkage)); \
+ } \
+ } \
+}
+
+
+#define NbfAddSendPacket(DeviceContext) { \
+ PTP_PACKET _SendPacket; \
+ NbfAllocateSendPacket ((DeviceContext), &_SendPacket); \
+ if (_SendPacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->PacketPool, \
+ (PSINGLE_LIST_ENTRY)&_SendPacket->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define NbfRemoveSendPacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->PacketAllocated > DeviceContext->PacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->PacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateSendPacket((DeviceContext), \
+ (PTP_PACKET)CONTAINING_RECORD(s, TP_PACKET, Linkage)); \
+ } \
+ } \
+}
+
+
+#define NbfAddReceivePacket(DeviceContext) { \
+ if (!(DeviceContext)->MacInfo.SingleReceive) { \
+ PNDIS_PACKET _ReceivePacket; \
+ NbfAllocateReceivePacket ((DeviceContext), &_ReceivePacket); \
+ if (_ReceivePacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &((PRECEIVE_PACKET_TAG)_ReceivePacket->ProtocolReserved)->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+ } \
+}
+
+#define NbfRemoveReceivePacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceivePacketAllocated > DeviceContext->ReceivePacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateReceivePacket((DeviceContext), \
+ (PNDIS_PACKET)CONTAINING_RECORD(s, NDIS_PACKET, ProtocolReserved[0])); \
+ } \
+ } \
+}
+
+
+#define NbfAddReceiveBuffer(DeviceContext) { \
+ if (!(DeviceContext)->MacInfo.SingleReceive) { \
+ PBUFFER_TAG _ReceiveBuffer; \
+ NbfAllocateReceiveBuffer ((DeviceContext), &_ReceiveBuffer); \
+ if (_ReceiveBuffer != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ (PSINGLE_LIST_ENTRY)&_ReceiveBuffer->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+ } \
+}
+
+#define NbfRemoveReceiveBuffer(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceiveBufferAllocated > DeviceContext->ReceiveBufferInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ NbfDeallocateReceiveBuffer(DeviceContext, \
+ (PBUFFER_TAG)CONTAINING_RECORD(s, BUFFER_TAG, Linkage)); \
+ } \
+ } \
+}
+
+
+//
+// These routines are used to maintain counters.
+//
+
+#define INCREMENT_COUNTER(_DeviceContext,_Field) \
+ ++(_DeviceContext)->Statistics._Field
+
+#define DECREMENT_COUNTER(_DeviceContext,_Field) \
+ --(_DeviceContext)->Statistics._Field
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger), (ULONG)(_Ulong))
+
+
+
+//
+// Routines in PACKET.C (TP_PACKET object manager).
+//
+
+VOID
+NbfAllocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *TransportUIFrame
+ );
+
+VOID
+NbfAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ );
+
+VOID
+NbfAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ );
+
+VOID
+NbfAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ );
+
+VOID
+NbfDeallocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME TransportUIFrame
+ );
+
+VOID
+NbfDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ );
+
+VOID
+NbfDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ );
+
+VOID
+NbfDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ );
+
+NTSTATUS
+NbfCreatePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link,
+ OUT PTP_PACKET *Packet
+ );
+
+NTSTATUS
+NbfCreateRrPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link,
+ OUT PTP_PACKET *Packet
+ );
+
+VOID
+NbfDestroyPacket(
+ IN PTP_PACKET Packet
+ );
+VOID
+NbfGrowSendPacketPool(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#if DBG
+VOID
+NbfReferencePacket(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+NbfDereferencePacket(
+ IN PTP_PACKET Packet
+ );
+#endif
+
+VOID
+NbfWaitPacket(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+
+#if DBG
+#define MAGIC 1
+extern BOOLEAN NbfEnableMagic;
+#else
+#define MAGIC 0
+#endif
+
+#if MAGIC
+VOID
+NbfSendMagicBullet (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+#endif
+
+//
+// Routines in RCVENG.C (Receive engine).
+//
+
+VOID
+AwakenReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+ActivateReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+CompleteReceive (
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN ULONG BytesTransferred
+ );
+
+VOID
+NbfCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbfCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routines in SEND.C (Receive engine).
+//
+
+NTSTATUS
+NbfTdiSend(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiSendDatagram(
+ IN PIRP Irp
+ );
+
+//
+// Routines in SENDENG.C (Send engine).
+//
+
+#if DBG
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ );
+
+#else
+
+// See SENDENG.C for the fully-commented description of InitializeSend.
+
+#define InitializeSend(_conn_) { \
+ PIRP _irp_; \
+ (_conn_)->SendState = CONNECTION_SENDSTATE_PACKETIZE; \
+ _irp_ = CONTAINING_RECORD ((_conn_)->SendQueue.Flink, \
+ IRP, \
+ Tail.Overlay.ListEntry); \
+ (_conn_)->FirstSendIrp = (_conn_)->sp.CurrentSendIrp = _irp_; \
+ (_conn_)->FirstSendMdl = (_conn_)->sp.CurrentSendMdl = \
+ _irp_->MdlAddress; \
+ (_conn_)->FirstSendByteOffset = (_conn_)->sp.SendByteOffset = 0; \
+ (_conn_)->sp.MessageBytesSent = 0; \
+ (_conn_)->CurrentSendLength = \
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(_irp_)); \
+ (_conn_)->StallCount = 0; \
+ (_conn_)->StallBytesSent = 0; \
+ if ((_conn_)->NetbiosHeader.ResponseCorrelator == 0xffff) { \
+ (_conn_)->NetbiosHeader.ResponseCorrelator = 1; \
+ } else { \
+ ++((_conn_)->NetbiosHeader.ResponseCorrelator); \
+ } \
+}
+
+#endif
+
+// See SENDENG.C for the fully-commented description of
+// StartPacketizingConnection. On a free build this is a
+// macro for speed.
+
+#if DBG
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate
+ );
+
+#else
+
+#define StartPacketizingConnection(_conn_,_immed_) { \
+ PDEVICE_CONTEXT _devctx_; \
+ _devctx_ = (_conn_)->Provider; \
+ if (((_conn_)->SendState == CONNECTION_SENDSTATE_PACKETIZE) && \
+ !((_conn_)->Flags & CONNECTION_FLAGS_PACKETIZE)) { \
+ (_conn_)->Flags |= CONNECTION_FLAGS_PACKETIZE; \
+ if (!(_immed_)) { \
+ NbfReferenceConnection("Packetize", \
+ (_conn_), \
+ CREF_PACKETIZE_QUEUE); \
+ } \
+ ExInterlockedInsertTailList (&_devctx_->PacketizeQueue, \
+ &(_conn_)->PacketizeLinkage, \
+ &_devctx_->SpinLock); \
+ RELEASE_DPC_SPIN_LOCK ((_conn_)->LinkSpinLock); \
+ } else { \
+ RELEASE_DPC_SPIN_LOCK ((_conn_)->LinkSpinLock); \
+ if (_immed_) { \
+ NbfDereferenceConnection("temp TdiSend", (_conn_), CREF_BY_ID); \
+ } \
+ } \
+ if (_immed_) { \
+ PacketizeConnections (_devctx_); \
+ } \
+}
+
+#endif
+
+VOID
+PacketizeConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Direct
+ );
+
+BOOLEAN
+ResendLlcPackets(
+ IN PTP_LINK Link,
+ IN UCHAR AckSequenceNumber,
+ IN BOOLEAN Resend
+ );
+
+VOID
+CompleteSend(
+ IN PTP_CONNECTION Connection,
+ IN USHORT Correlator
+ );
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ );
+
+VOID
+ReframeSend(
+ IN PTP_CONNECTION Connection,
+ IN ULONG BytesReceived
+ );
+
+VOID
+NbfCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+SendOnePacket(
+ IN PTP_CONNECTION Connection,
+ IN PTP_PACKET Packet,
+ IN BOOLEAN ForceAck,
+ OUT PBOOLEAN LinkCheckpoint OPTIONAL
+ );
+
+VOID
+SendControlPacket(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ );
+
+VOID
+NbfNdisSend(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ );
+
+VOID
+RestartLinkTraffic(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ );
+
+//
+// Routines in DEVCTX.C (TP_DEVCTX object manager).
+//
+
+VOID
+NbfRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+NbfDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+NbfCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ );
+
+VOID
+NbfDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in ADDRESS.C (TP_ADDRESS object manager).
+//
+
+#if DBG
+VOID
+NbfRefAddress(
+ IN PTP_ADDRESS Address
+ );
+#endif
+
+VOID
+NbfDerefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ );
+
+VOID
+NbfDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ );
+
+NTSTATUS
+NbfCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ );
+
+VOID
+NbfReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+NbfDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+NbfDestroyAddress(
+ IN PVOID Parameter
+ );
+
+NTSTATUS
+NbfOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+NbfCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfStopAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfRegisterAddress(
+ IN PTP_ADDRESS Address
+ );
+
+BOOLEAN
+NbfMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN UCHAR NameType,
+ IN PUCHAR NetBIOSName
+ );
+
+VOID
+NbfAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ );
+
+VOID
+NbfDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ );
+
+NTSTATUS
+NbfCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ );
+
+PTP_ADDRESS
+NbfLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_NETBIOS_ADDRESS NetworkName
+ );
+
+PTP_CONNECTION
+NbfLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN UCHAR RemoteSessionNumber
+ );
+
+NTSTATUS
+NbfStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+AddressTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbfParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+);
+
+BOOLEAN
+NbfValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+);
+
+NTSTATUS
+NbfVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+NbfSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ );
+
+//
+// Routines in CONNECT.C.
+//
+
+NTSTATUS
+NbfTdiAccept(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiConnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiDisconnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiDisassociateAddress (
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiAssociateAddress(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiListen(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfOpenConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+NbfCloseConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+//
+//
+// Routines in CONNOBJ.C (TP_CONNECTION object manager).
+//
+
+#if DBG
+VOID
+NbfRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+#endif
+
+VOID
+NbfDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfClearConnectionLsn(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+NbfStopConnection(
+ IN PTP_CONNECTION TransportConnection,
+ IN NTSTATUS Status
+ );
+
+VOID
+NbfCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbfStartConnectionTimer(
+ IN PTP_CONNECTION TransportConnection,
+ IN PKDEFERRED_ROUTINE TimeoutFunction,
+ IN ULONG WaitTime
+ );
+
+PTP_CONNECTION
+NbfLookupListeningConnection(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ );
+
+PTP_CONNECTION
+NbfLookupConnectingConnection(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+VOID
+NbfDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+NbfCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+PTP_CONNECTION
+NbfLookupConnectionById(
+ IN PTP_ADDRESS Address,
+ IN USHORT ConnectionId
+ );
+
+PTP_CONNECTION
+NbfLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+#if 0
+VOID
+NbfWaitConnectionOnLink(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+#endif
+
+VOID
+ConnectionEstablishmentTimeout(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NTSTATUS
+NbfVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+NbfIndicateDisconnect(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+//
+// Routines in INFO.C (QUERY_INFO manager).
+//
+
+NTSTATUS
+NbfTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiSetInformation(
+ IN PIRP Irp
+ );
+
+VOID
+NbfSendQueryFindName(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request
+ );
+
+NTSTATUS
+NbfProcessQueryNameRecognized(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Packet,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ );
+
+VOID
+NbfSendStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST Request,
+ IN PHARDWARE_ADDRESS DestinationAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+NTSTATUS
+NbfProcessStatusResponse(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+NTSTATUS
+NbfProcessStatusQuery(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address OPTIONAL,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+//
+// Routines in EVENT.C.
+//
+
+NTSTATUS
+NbfTdiSetEventHandler(
+ IN PIRP Irp
+ );
+
+//
+// Routines in REQUEST.C (TP_REQUEST object manager).
+//
+
+
+VOID
+TdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+#if DBG
+VOID
+NbfRefRequest(
+ IN PTP_REQUEST Request
+ );
+#endif
+
+VOID
+NbfDerefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+NbfCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+#if DBG
+VOID
+NbfRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+NbfDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+#if DBG
+VOID
+NbfRefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfDerefReceiveIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+#if DBG
+VOID
+NbfDerefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+#endif
+
+VOID
+NbfCompleteReceiveIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+NbfAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ );
+
+VOID
+NbfDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ );
+
+NTSTATUS
+NbfCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ );
+
+//
+// Routines in LINK.C (TP_LINK object manager).
+//
+
+NTSTATUS
+NbfDestroyLink(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfDisconnectLink(
+ IN PTP_LINK Link
+ );
+
+#if DBG
+VOID
+NbfRefLink(
+ IN PTP_LINK TransportLink
+ );
+#endif
+
+VOID
+NbfDerefLink(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfRefLinkSpecial(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfDerefLinkSpecial(
+ IN PTP_LINK TransportLink
+ );
+
+VOID
+NbfResetLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfStopLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfCompleteLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfActivateLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfWaitLink(
+ IN PTP_LINK Link
+ );
+
+BOOLEAN
+NbfDisconnectFromLink(
+ IN PTP_CONNECTION TransportConnection,
+ IN BOOLEAN VerifyReferenceCount
+ );
+
+NTSTATUS
+NbfAssignGroupLsn(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+NbfConnectToLink(
+ IN PTP_LINK Link,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+PTP_CONNECTION
+NbfLookupPendingConnectOnLink(
+ IN PTP_LINK Link
+ );
+
+PTP_CONNECTION
+NbfLookupPendingListenOnLink(
+ IN PTP_LINK Link
+ );
+
+VOID
+NbfAllocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_LINK *TransportLink
+ );
+
+VOID
+NbfDeallocateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK TransportLink
+ );
+
+NTSTATUS
+NbfCreateLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS HardwareAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN USHORT LoopbackLinkIndex,
+ OUT PTP_LINK *TransportLink
+ );
+
+VOID
+NbfDumpLinkInfo (
+ IN PTP_LINK Link
+ );
+
+//
+// routines in linktree.c
+//
+
+
+NTSTATUS
+NbfAddLinkToTree (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+
+NTSTATUS
+NbfRemoveLinkFromTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ );
+
+PTP_LINK
+NbfFindLinkInTree(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ );
+
+PTP_LINK
+NbfFindLink(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR Remote
+ );
+
+//
+// Routines in DLC.C (LLC frame cracker, entrypoints from NDIS interface).
+//
+
+VOID
+NbfInsertInLoopbackQueue (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN UCHAR LinkIndex
+ );
+
+VOID
+NbfProcessLoopbackQueue (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NDIS_STATUS
+NbfReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+NbfGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PTP_LINK Link,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PDLC_FRAME DlcHeader,
+ IN UINT DlcSize,
+ IN BOOLEAN Loopback
+ );
+
+VOID
+NbfReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ );
+
+VOID
+NbfProcessWanDelayedQueue(
+ IN PVOID Parameter
+ );
+
+VOID
+NbfTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+NbfTransferLoopbackData (
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+
+//
+// Routines in UFRAMES.C, the UI-frame NBF frame processor.
+//
+
+NTSTATUS
+NbfIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Dsdu,
+ IN ULONG Length
+ );
+
+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
+ );
+
+//
+// Routines in IFRAMES.C, the I-frame NBF frame processor.
+//
+
+VOID
+NbfAcknowledgeDataOnlyLast(
+ IN PTP_CONNECTION Connection,
+ IN ULONG MessageLength
+ );
+
+VOID
+NbfProcessIIndicate(
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PTP_LINK Link,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN UINT DlcTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Loopback
+ );
+
+NTSTATUS
+ProcessIndicateData(
+ IN PTP_CONNECTION Connection,
+ IN PUCHAR DlcHeader,
+ IN UINT DlcIndicatedLength,
+ IN PUCHAR DataHeader,
+ IN UINT DataTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last,
+ IN BOOLEAN Loopback
+ );
+
+//
+// Routines in RCV.C (data copying routines for receives).
+//
+
+NTSTATUS
+NbfTdiReceive(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbfTdiReceiveDatagram(
+ IN PIRP Irp
+ );
+
+//
+// Routines in FRAMESND.C, the UI-frame (non-link) shipper.
+//
+
+VOID
+NbfSendNameQuery(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN SourceRoutingOptional
+ );
+
+VOID
+NbfSendNameRecognized(
+ IN PTP_ADDRESS Address,
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN PNBF_HDR_CONNECTIONLESS Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ );
+
+VOID
+NbfSendNameInConflict(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR ConflictingName
+ );
+
+NTSTATUS
+NbfSendAddNameQuery(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfSendSessionInitialize(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSessionConfirm(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSessionEnd(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Abort
+ );
+
+VOID
+NbfSendNoReceive(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendReceiveContinue(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendReceiveOutstanding(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendDataAck(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+NbfSendSabme(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendDisc(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendUa(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendDm(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendRr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+#if 0
+
+//
+// These functions are not currently called, so they are commented
+// out.
+//
+
+VOID
+NbfSendRnr(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendTest(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal,
+ IN PMDL Psdu
+ );
+
+VOID
+NbfSendFrmr(
+ IN PTP_LINK Link,
+ IN BOOLEAN PollFinal
+ );
+
+#endif
+
+VOID
+NbfSendXid(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+VOID
+NbfSendRej(
+ IN PTP_LINK Link,
+ IN BOOLEAN Command,
+ IN BOOLEAN PollFinal
+ );
+
+NTSTATUS
+NbfCreateConnectionlessFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *OuterFrame
+ );
+
+VOID
+NbfDestroyConnectionlessFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME RawFrame
+ );
+
+VOID
+NbfSendUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME RawFrame,
+ IN BOOLEAN Loopback
+ );
+
+VOID
+NbfSendUIMdlFrame(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+NbfSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+//
+// Routines in FRAMECON.C, the NetBIOS Frames Protocol Frame Constructors.
+// To understand the various constant parameters to these functions (such
+// as special data1 & data2 values, see NBFCONST.H for details.
+//
+
+VOID
+ConstructAddGroupNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME GroupName // NetBIOS group name to be added.
+ );
+
+VOID
+ConstructAddNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN USHORT Correlator, // correlator for ADD_NAME_RESPONSE.
+ IN PNAME Name // NetBIOS name to be added.
+ );
+
+VOID
+ConstructNameInConflict(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ConflictingName, // NetBIOS name that is conflicting.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ );
+
+VOID
+ConstructStatusQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN USHORT BufferLength, // length of user's status buffer.
+ IN USHORT Correlator, // correlator for STATUS_RESPONSE.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SendingPermanentName // NetBIOS permanent node name of sender.
+ );
+
+VOID
+ConstructTerminateTrace(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame // frame buffer to format.
+ );
+
+VOID
+ConstructDatagram(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME ReceiverName, // NetBIOS name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructDatagramBroadcast(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructNameQuery(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session (0=FIND_NAME).
+ IN USHORT Correlator, // correlator in NAME_RECOGNIZED.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructAddNameResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN USHORT Correlator, // correlator from ADD_[GROUP_]NAME_QUERY.
+ IN PNAME Name // NetBIOS name being responded to.
+ );
+
+VOID
+ConstructNameRecognized(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR NameType, // type of name.
+ IN UCHAR LocalSessionNumber, // LSN assigned to session.
+ IN USHORT NameQueryCorrelator, // correlator from NAME_QUERY.
+ IN USHORT Correlator, // correlator expected from next response.
+ IN PNAME SenderName, // NetBIOS name of sender.
+ IN PNAME ReceiverName // NetBIOS name of receiver.
+ );
+
+VOID
+ConstructStatusResponse(
+ IN PNBF_HDR_CONNECTIONLESS RawFrame,// frame buffer to format.
+ IN UCHAR RequestType, // type of request, defined below.
+ IN BOOLEAN Truncated, // data is truncated.
+ IN BOOLEAN DataOverflow, // too much data for user's buffer.
+ IN USHORT DataLength, // length of data sent.
+ IN USHORT Correlator, // correlator from STATUS_QUERY.
+ IN PNAME ReceivingPermanentName, // NetBIOS permanent node name of receiver.
+ IN PNAME SenderName // NetBIOS name of sender.
+ );
+
+VOID
+ConstructDataAck(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_ONLY_LAST.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructDataOnlyLast(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN BOOLEAN Resynched, // TRUE if we are resynching.
+ IN USHORT Correlator, // correlator for RECEIVE_CONTINUE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionConfirm(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT Correlator, // correlator from SESSION_INITIALIZE.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionEnd(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Reason, // reason for termination, defined below.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructSessionInitialize(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN UCHAR Options, // bitflag options, defined below.
+ IN USHORT MaximumUserBufferSize, // max size of user frame on session.
+ IN USHORT NameRecognizedCorrelator, // correlator from NAME_RECOGNIZED.
+ IN USHORT Correlator, // correlator for SESSION_CONFIRM.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructNoReceive(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Options, // option bitflags, defined below.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructReceiveOutstanding(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT BytesAccepted, // number of bytes accepted.
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+VOID
+ConstructReceiveContinue(
+ IN PNBF_HDR_CONNECTION RawFrame, // frame buffer to format.
+ IN USHORT Correlator, // correlator from DATA_FIRST_MIDDLE
+ IN UCHAR LocalSessionNumber, // session number of SENDER.
+ IN UCHAR RemoteSessionNumber // session number of RECEIVER.
+ );
+
+#if 0
+VOID
+ConstructSessionAlive(
+ IN PNBF_HDR_CONNECTION RawFrame // frame buffer to format.
+ );
+#endif
+
+//
+// Routines in nbfndis.c.
+//
+
+#if DBG
+PUCHAR
+NbfGetNdisStatus (
+ IN NDIS_STATUS NdisStatus
+ );
+#endif
+
+//
+// Routines in nbfdrvr.c
+//
+
+VOID
+NbfWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN ULONG BytesNeeded,
+ IN ULONG ResourceId
+ );
+
+VOID
+NbfWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbfWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+VOID
+NbfFreeResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+extern
+ULONG
+NbfInitializeOneDeviceContext(
+ OUT PNDIS_STATUS NdisStatus,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PCONFIG_DATA NbfConfig,
+ IN INT AdapterIndex
+ );
+//
+// routines in nbfcnfg.c
+//
+
+NTSTATUS
+NbfConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigData
+ );
+
+//
+// Routines in nbfndis.c
+//
+
+NTSTATUS
+NbfRegisterProtocol (
+ IN PUNICODE_STRING NameString
+ );
+
+VOID
+NbfDeregisterProtocol (
+ VOID
+ );
+
+
+NTSTATUS
+NbfInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA ConfigInfo,
+ IN UINT ConfigInfoNameIndex
+ );
+
+VOID
+NbfCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbfTdiAction(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+VOID
+NbfActionQueryIndication(
+ PDEVICE_CONTEXT DeviceContext,
+ PNBF_HDR_CONNECTIONLESS UiFrame
+ );
+
+VOID
+NbfActionDatagramIndication(
+ PDEVICE_CONTEXT DeviceContext,
+ PNBF_HDR_CONNECTIONLESS UiFrame,
+ ULONG Length
+ );
+
+VOID
+NbfStopControlChannel(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN USHORT ChannelIdentifier
+ );
+
+
+//
+// Routines in nbfdebug.c
+//
+
+#if DBG
+
+VOID
+DisplayOneFrame(
+ PTP_PACKET Packet
+ );
+
+VOID
+NbfDisplayUIFrame(
+ PTP_UI_FRAME OuterFrame
+ );
+
+VOID
+NbfFormattedDump(
+ PCHAR far_p,
+ ULONG len
+ );
+
+#endif
+
+#endif // def _NBFPROCS_
diff --git a/private/ntos/tdi/nbf/nbftypes.h b/private/ntos/tdi/nbf/nbftypes.h
new file mode 100644
index 000000000..a72e9fe1b
--- /dev/null
+++ b/private/ntos/tdi/nbf/nbftypes.h
@@ -0,0 +1,2202 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbftypes.h
+
+Abstract:
+
+ This module defines private data structures and types for the NT
+ NBF transport provider.
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Revision History:
+
+--*/
+
+#ifndef _NBFTYPES_
+#define _NBFTYPES_
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+#define NETBIOS_NAME_SIZE 16
+
+typedef struct _NBF_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[NETBIOS_NAME_SIZE];
+ USHORT NetbiosNameType;
+} NBF_NETBIOS_ADDRESS, *PNBF_NETBIOS_ADDRESS;
+
+typedef UCHAR NAME;
+typedef NAME UNALIGNED *PNAME;
+
+
+//
+// This structure defines things associated with a TP_REQUEST, or outstanding
+// TDI request, maintained on a queue somewhere in the transport. All
+// requests other than open/close require that a TP_REQUEST block be built.
+//
+
+#if DBG
+#define REQUEST_HISTORY_LENGTH 20
+extern KSPIN_LOCK NbfGlobalInterlock;
+#endif
+
+//
+// the types of potential owners of requests
+//
+
+typedef enum _REQUEST_OWNER {
+ ConnectionType,
+ AddressType,
+ DeviceContextType
+} REQUEST_OWNER;
+
+//typedef
+//NTSTATUS
+//(*PTDI_TIMEOUT_ACTION)(
+// IN PTP_REQUEST Request
+// );
+
+//
+// The request itself
+//
+
+#if DBG
+#define RREF_CREATION 0
+#define RREF_PACKET 1
+#define RREF_TIMER 2
+#define RREF_RECEIVE 3
+#define RREF_FIND_NAME 4
+#define RREF_STATUS 5
+
+#define NUMBER_OF_RREFS 8
+#endif
+
+typedef struct _TP_REQUEST {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ LIST_ENTRY Linkage; // used by ExInterlocked routines.
+ KSPIN_LOCK SpinLock; // spinlock for other fields.
+ // (used in KeAcquireSpinLock calls)
+#if DBG
+ LONG RefTypes[NUMBER_OF_RREFS];
+#endif
+ LONG ReferenceCount; // reasons why we can't destroy this req.
+
+ struct _DEVICE_CONTEXT *Provider; // pointer to the device context.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock.
+
+ PIRP IoRequestPacket; // pointer to IRP for this request.
+
+ //
+ // The following two fields are used to quickly reference the basic
+ // components of the requests without worming through the IRP's stack.
+ //
+
+ PVOID Buffer2; // second buffer in the request.
+ ULONG Buffer2Length; // length of the second buffer.
+
+ //
+ // The following two fields (Flags and Context) are used to clean up
+ // queued requests which must be canceled or abnormally completed.
+ // The Flags field contains bitflags indicating the state of the request,
+ // and the specific queue type that the request is located on. The
+ // Context field contains a pointer to the owning structure (TP_CONNECTION
+ // or TP_ADDRESS) so that the cleanup routines can perform post-cleanup
+ // operations on the owning structure, such as dereferencing, etc.
+ //
+
+ ULONG Flags; // disposition of this request.
+ PVOID Context; // context of this request.
+ REQUEST_OWNER Owner; // what type of owner this request has.
+
+#if DBG
+ LARGE_INTEGER Time; // time when request created
+#endif
+
+ KTIMER Timer; // kernel timer for this request.
+ KDPC Dpc; // DPC object for timeouts.
+
+ //
+ // These fields are used for FIND.NAME and STATUS.QUERY requests.
+ //
+
+ ULONG Retries; // timeouts remaining.
+ USHORT BytesWritten; // usage varies.
+ USHORT FrameContext; // identifies request.
+ PVOID ResponseBuffer; // temp alloc to hold data.
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[REQUEST_HISTORY_LENGTH];
+ BOOLEAN Completed;
+ BOOLEAN Destroyed;
+#endif
+
+} TP_REQUEST, *PTP_REQUEST;
+
+#ifdef _PNP_POWER
+//
+// in nbfdrvr.c
+//
+
+extern UNICODE_STRING NbfRegistryPath;
+
+//
+// We need the driver object to create device context structures.
+//
+
+extern PDRIVER_OBJECT NbfDriverObject;
+
+#endif // _PNP_POWER
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalRequestList;
+#define StoreRequestHistory(_req,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_req)->Destroyed) { \
+ DbgPrint ("request touched after being destroyed 0x%lx\n", \
+ (_req)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_req)->History[(_req)->NextRefLoc].Caller, \
+ &(_req)->History[(_req)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_req)->TotalReferences++; \
+ } else { \
+ (_req)->TotalDereferences++; \
+ (_req)->History[(_req)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_req)->History[(_req)->NextRefLoc].Caller & \
+ ~0x80000000); \
+ } \
+ if (++(_req)->NextRefLoc == REQUEST_HISTORY_LENGTH) { \
+ (_req)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define NBF_ALLOCATION_TYPE_REQUEST 1
+
+#define REQUEST_FLAGS_TIMER 0x0001 // a timer is active for this request.
+#define REQUEST_FLAGS_TIMED_OUT 0x0002 // a timer expiration occured on this request.
+#define REQUEST_FLAGS_ADDRESS 0x0004 // request is attached to a TP_ADDRESS.
+#define REQUEST_FLAGS_CONNECTION 0x0008 // request is attached to a TP_CONNECTION.
+#define REQUEST_FLAGS_STOPPING 0x0010 // request is being killed.
+#define REQUEST_FLAGS_EOR 0x0020 // TdiSend request has END_OF_RECORD mark.
+#define REQUEST_FLAGS_PIGGYBACK 0x0040 // TdiSend that can be piggyback ack'ed.
+#define REQUEST_FLAGS_DC 0x0080 // request is attached to a TP_DEVICE_CONTEXT
+
+//
+// This defines the TP_SEND_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a send IRP's stack location.
+//
+
+typedef struct _TP_SEND_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_SEND Request;
+ LONG ReferenceCount;
+ PVOID Irp;
+} TP_SEND_IRP_PARAMETERS, *PTP_SEND_IRP_PARAMETERS;
+
+#define IRP_SEND_LENGTH(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendLength)
+
+#define IRP_SEND_FLAGS(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendFlags)
+
+#define IRP_SEND_REFCOUNT(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_SEND_IRP(_IrpSp) \
+ (((PTP_SEND_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Irp)
+
+#define IRP_SEND_CONNECTION(_IrpSp) \
+ ((PTP_CONNECTION)((_IrpSp)->FileObject->FsContext))
+
+#define IRP_DEVICE_CONTEXT(_IrpSp) \
+ ((PDEVICE_CONTEXT)((_IrpSp)->DeviceObject))
+
+
+//
+// This defines the TP_RECEIVE_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a receive IRP's stack location.
+//
+
+typedef struct _TP_RECEIVE_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_RECEIVE Request;
+ LONG ReferenceCount;
+ PIRP Irp;
+} TP_RECEIVE_IRP_PARAMETERS, *PTP_RECEIVE_IRP_PARAMETERS;
+
+#define IRP_RECEIVE_LENGTH(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.ReceiveLength)
+
+#define IRP_RECEIVE_FLAGS(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.ReceiveFlags)
+
+#define IRP_RECEIVE_REFCOUNT(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_RECEIVE_IRP(_IrpSp) \
+ (((PTP_RECEIVE_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Irp)
+
+#define IRP_RECEIVE_CONNECTION(_IrpSp) \
+ ((PTP_CONNECTION)((_IrpSp)->FileObject->FsContext))
+
+
+
+//
+// This structure defines a TP_UI_FRAME, or connectionless frame header,
+// that is manipulated by the FRAME.C routines.
+//
+
+typedef struct _TP_UI_FRAME {
+ PNDIS_PACKET NdisPacket;
+ LIST_ENTRY Linkage; // used by ExInterLocked routines.
+ PVOID DataBuffer; // for transport-created data.
+ UCHAR Header[1]; // the header in the frame (MAC + DLC + NBF)
+} TP_UI_FRAME, *PTP_UI_FRAME;
+
+
+//
+// This structure defines a TP_VARIABLE, or network managable variable,
+// maintained in a linked list on the device context.
+//
+
+typedef struct _TP_VARIABLE {
+
+ struct _TP_VARIABLE *Fwdlink; // next variable in provider's chain.
+
+ ULONG VariableSerialNumber; // identifier for this variable.
+ ULONG VariableType; // type of this variable (see TDI.H).
+ STRING VariableName; // allocated variable name.
+
+ union {
+ ULONG LongValue;
+ HARDWARE_ADDRESS HardwareAddressValue;
+ STRING StringValue; // allocated string value, if of that type.
+ } Value;
+
+} TP_VARIABLE, *PTP_VARIABLE;
+
+
+//
+// This structure defines a TP_CONNECTION, or active transport connection,
+// maintained on a transport address.
+//
+
+#if DBG
+#define CONNECTION_HISTORY_LENGTH 50
+
+#define CREF_SPECIAL_CREATION 0
+#define CREF_SPECIAL_TEMP 1
+#define CREF_COMPLETE_SEND 2
+#define CREF_SEND_IRP 3
+#define CREF_ADM_SESS 4
+#define CREF_TRANSFER_DATA 5
+#define CREF_FRAME_SEND 6
+#define CREF_TIMER 7
+#define CREF_BY_ID 8
+#define CREF_LINK 9
+#define CREF_SESSION_END 10
+#define CREF_LISTENING 11
+#define CREF_P_LINK 12
+#define CREF_P_CONNECT 13
+#define CREF_PACKETIZE 14
+#define CREF_RECEIVE_IRP 15
+#define CREF_PROCESS_DATA 16
+#define CREF_REQUEST 17
+#define CREF_TEMP 18
+#define CREF_DATA_ACK_QUEUE 19
+#define CREF_ASSOCIATE 20
+#define CREF_STOP_ADDRESS 21
+#define CREF_PACKETIZE_QUEUE 22
+#define CREF_STALLED 23
+
+#define NUMBER_OF_CREFS 24
+#endif
+
+//
+// This structure holds our "complex send pointer" indicating
+// where we are in the packetization of a send.
+//
+
+typedef struct _TP_SEND_POINTER {
+ ULONG MessageBytesSent; // up count, bytes sent/this msg.
+ PIRP CurrentSendIrp; // ptr, current send request in chain.
+ PMDL CurrentSendMdl; // ptr, current MDL in send chain.
+ ULONG SendByteOffset; // current byte offset in current MDL.
+} TP_SEND_POINTER, *PTP_SEND_POINTER;
+
+typedef struct _TP_CONNECTION {
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_CREFS];
+#endif
+
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ ULONG Padding;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ LIST_ENTRY LinkList; // used for link thread or for free
+ // resource list
+ KSPIN_LOCK SpinLock; // spinlock for connection protection.
+ PKSPIN_LOCK LinkSpinLock; // pointer to link's spinlock
+
+ LONG ReferenceCount; // number of references to this object.
+ LONG SpecialRefCount; // controls freeing of connection.
+
+ //
+ // The following lists are used to associate this connection with a
+ // particular address.
+ //
+
+ LIST_ENTRY AddressList; // list of connections for given address
+ LIST_ENTRY AddressFileList; // list for connections bound to a
+ // given address reference
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketizeQueue
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device context's
+ // PacketWaitQueue.
+ //
+
+ LIST_ENTRY PacketWaitLinkage;
+
+ //
+ // The following field points to the TP_LINK object that describes the
+ // (active) data link connection for this transport connection. To be
+ // valid, this field is non-NULL.
+ //
+
+ struct _TP_LINK *Link; // pointer to transport link object.
+ struct _TP_ADDRESS_FILE *AddressFile; // pointer to owning Address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+
+ //
+ // The following field contains the actual ID we expose to the TDI client
+ // to represent this connection. A unique one is created from the address.
+ //
+
+ USHORT ConnectionId; // unique identifier.
+ UCHAR SessionNumber; // the session number used in the packet header
+
+ //
+ // This field is used to keep the reason for the connection disconnect
+ // around until connection deletion time.
+ //
+
+ BOOLEAN RemoteDisconnect; // was this connection remotely disonnected?
+
+ //
+ // The following field is specified by the user at connection open time.
+ // It is the context that the user associates with the connection so that
+ // indications to and from the client can be associated with a particular
+ // connection.
+ //
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ //
+ // The following two queues are used to associate TdiSend and TdiReceive
+ // IRPs with this connection. New arrivals are placed at the end of
+ // the queues (really a linked list) and IRPs are processed at the
+ // front of the queues. The first TdiSend IRP on the SendQueue is
+ // the current TdiSend being processed, and the first TdiReceive IRP
+ // on the ReceiveQueue is the first TdiReceive being processed, PROVIDED
+ // the CONNECTION_FLAGS_ACTIVE_RECEIVE flag is set. If this flag is not
+ // set, then the first TdiReceive IRP on the ReceiveQueue is not active.
+ // These queues are managed by the EXECUTIVE interlocked list manipuation
+ // routines.
+ //
+
+ LIST_ENTRY SendQueue; // FIFO of outstanding TdiSends.
+ LIST_ENTRY ReceiveQueue; // FIFO of outstanding TdiReceives.
+
+ //
+ // The following fields are used to maintain state for the current receive.
+ //
+
+ ULONG MessageBytesReceived; // up count, bytes recd/this msg.
+ ULONG MessageBytesAcked; // bytes acked (NR or RO) this msg.
+ ULONG MessageInitAccepted; // bytes accepted during indication.
+
+ //
+ // These fields are only valid if the CONNECTION_FLAGS_ACTIVE_RECEIVE
+ // flag is set.
+ //
+
+ PIRP SpecialReceiveIrp; // a "no-request" receive IRP exists.
+ PIRP CurrentReceiveIrp; // ptr, current receive IRP.
+ PMDL CurrentReceiveMdl; // ptr, current MDL in receive chain.
+ ULONG ReceiveByteOffset; // current byte offset in current MDL.
+ ULONG ReceiveLength; // current receive length, in bytes (total)
+ ULONG ReceiveBytesUnaccepted; // by client...only indicate when == 0
+
+ //
+ // The following fields are used to maintain state for the active send.
+ // They only have meaning if the connection's SendState is not IDLE.
+ // Because the TDI client may submit multiple TdiSend requests to comprise
+ // a full message, we have to keep a complex pointer to the first byte of
+ // unACKed data (hence the first three fields). We also have a complex
+ // pointer to the first byte of unsent data (hence the last three fields).
+ //
+
+ ULONG SendState; // send state machine variable.
+
+ PIRP FirstSendIrp; // ptr, 1st TdiSend's IRP.
+ PMDL FirstSendMdl; // ptr, 1st unacked MDL in chain/this msg.
+ ULONG FirstSendByteOffset; // pre-acked bytes in that MDL.
+
+ TP_SEND_POINTER sp; // current send loc, defined above.
+ ULONG CurrentSendLength; // how long is this send (total)
+ ULONG StallCount; // times in a row we looked stalled.
+ ULONG StallBytesSent; // bytes sent last time we checked.
+
+ //
+ // This is TRUE if we need don't need to reference the current
+ // receive IRP during transfers (because it is a special
+ // receive or the driver doesn't pend transfers).
+ //
+
+ BOOLEAN CurrentReceiveSynchronous;
+
+ //
+ // This field will be TRUE if the last DOL received allowed
+ // piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveAckQueueable;
+
+ //
+ //
+ // This field will be TRUE if the last DOL received was
+ // sent NO.ACK.
+ //
+
+ BOOLEAN CurrentReceiveNoAck;
+
+ //
+ // These fields handle asynchronous TransferData calls.
+ //
+
+ ULONG TransferBytesPending; // bytes pending in current transfers
+ ULONG TotalTransferBytesPending; // bytes since TransferBytesPending was 0;
+ // how much we back off if a transfer fails
+ PMDL SavedCurrentReceiveMdl; // used to back off by TotalTransferPending bytes
+ ULONG SavedReceiveByteOffset; // used to back off by TotalTransferPending bytes
+
+ //
+ // This field will be TRUE if we are in the middle of
+ // processing a receive indication on this connection and
+ // we are not yet in a state where another indication
+ // can be handled.
+ //
+ // It is stored as a INT since access to it is guarded
+ // by the connection's link spinlock, unlike the variables
+ // around it (BUGBUG: What about Alpha?)
+ //
+
+ UINT IndicationInProgress;
+
+ //
+ // The following field is used as a linkage when on the device
+ // context's DataAckQueue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if the connection is on the data ack queue.
+ // Also an INT so access can be non-guarded.
+ //
+
+ UINT OnDataAckQueue;
+
+ //
+ // These keep track of the number of consecutive sends or
+ // receives on this connection. This is used in determining when
+ // to queue a data ack.
+ //
+
+ ULONG ConsecutiveSends;
+ ULONG ConsecutiveReceives;
+
+ //
+ // The following list head is used as a pointer to a TdiListen/TdiConnect
+ // request which is in progress. Although manipulated
+ // with queue instructions, there will only be one request in the queue.
+ // This is done for consistency with respect to TpCreateRequest, which
+ // does a great job of creating a request and associating it atomically
+ // with a supervisory object.
+ //
+
+ LIST_ENTRY InProgressRequest; // TdiListen/TdiConnect
+
+ //
+ // If the connection is being disconnected as a result of
+ // a TdiDisconnect call (RemoteDisconnect is FALSE) then this
+ // will hold the IRP passed to TdiDisconnect. It is needed
+ // when the TdiDisconnect request is completed.
+ //
+
+ PIRP DisconnectIrp;
+
+ //
+ // If the connection is being closed, this will hold
+ // the IRP passed to TdiCloseConnection. It is needed
+ // when the request is completed.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // These fields are used for deferred operations on connections; the only
+ // deferred operation currently supported is piggyback ACK
+ //
+
+ ULONG DeferredFlags;
+#if DBG
+ ULONG DeferredPasses;
+#endif
+ LIST_ENTRY DeferredQueue;
+
+ //
+ // The following fields are used for connection housekeeping.
+ //
+
+ ULONG Flags; // attributes guarded by LinkSpinLock
+ ULONG Flags2; // attributes guarded by SpinLock
+ UINT OnPacketWaitQueue; // TRUE if on PacketWaitQueue
+ UCHAR Lsn; // local session number (1-254).
+ UCHAR Rsn; // remote session number (1-254).
+ USHORT Retries; // retry limit for NAME_QUERY shipments.
+ KTIMER Timer; // kernel timer for timeouts on NQ/NR.
+ LARGE_INTEGER ConnectStartTime; // when we sent the committed NQ.
+ KDPC Dpc; // DPC object for timeouts.
+ NTSTATUS Status; // status code for connection rundown.
+ ULONG LastPacketsSent; // The value that was in Link->XXX the
+ ULONG LastPacketsResent; // last time we calculated the throughput.
+ NBF_NETBIOS_ADDRESS CalledAddress; // TdiConnect request's T.A.
+ USHORT MaximumDataSize; // maximum I-frame data size for NBF.
+
+ NBF_HDR_CONNECTION NetbiosHeader; // pre-built Netbios header; we store
+ // the current send and reply correlators
+ // in the appropriate spots in this.
+
+ //
+ // These are for CONNECTION_INFO queries.
+ //
+
+ ULONG TransmittedTsdus; // TSDUs sent on this connection.
+ ULONG ReceivedTsdus; // TSDUs received on this connection.
+ ULONG TransmissionErrors; // TSDUs transmitted in error/this connection.
+ ULONG ReceiveErrors; // TSDUs received in error/this connection.
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ // TDI_CONNECTION_INFO Information; // information about this connection.
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[CONNECTION_HISTORY_LENGTH];
+ BOOLEAN Destroyed;
+#endif
+ CHAR RemoteName[16];
+
+} TP_CONNECTION, *PTP_CONNECTION;
+
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalConnectionList;
+#define StoreConnectionHistory(_conn,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_conn)->Destroyed) { \
+ DbgPrint ("connection touched after being destroyed 0x%lx\n", \
+ (_conn)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_conn)->History[(_conn)->NextRefLoc].Caller, \
+ &(_conn)->History[(_conn)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_conn)->TotalReferences++; \
+ } else { \
+ (_conn)->TotalDereferences++; \
+ (_conn)->History[(_conn)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_conn)->History[(_conn)->NextRefLoc].Caller | 1); \
+ } \
+ if (++(_conn)->NextRefLoc == CONNECTION_HISTORY_LENGTH) { \
+ (_conn)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define CONNECTION_FLAGS_VERSION2 0x00000001 // remote netbios is version 2.0.
+#define CONNECTION_FLAGS_RECEIVE_WAKEUP 0x00000002 // send a RECEIVE_OUTSTANDING when a receive arrives.
+#define CONNECTION_FLAGS_ACTIVE_RECEIVE 0x00000004 // a receive is active.
+#define CONNECTION_FLAGS_WAIT_SI 0x00000020 // waiting for a SESSION_INITIALIZE.
+#define CONNECTION_FLAGS_WAIT_SC 0x00000040 // waiting for a SESSION_CONFIRM.
+#define CONNECTION_FLAGS_WAIT_LINK_UP 0x00000080 // waiting for DDI to est. connection.
+#define CONNECTION_FLAGS_READY 0x00000200 // sends/rcvs/discons valid.
+#define CONNECTION_FLAGS_RC_PENDING 0x00001000 // a receive is pending completion
+#define CONNECTION_FLAGS_W_PACKETIZE 0x00002000 // w/for a packet to packetize.
+#define CONNECTION_FLAGS_PACKETIZE 0x00004000 // we're on the PacketizeQueue.
+#define CONNECTION_FLAGS_W_RESYNCH 0x00008000 // waiting for resynch indicator. (receive)
+#define CONNECTION_FLAGS_SEND_SI 0x00010000 // w/for a packet to send SI.
+#define CONNECTION_FLAGS_SEND_SC 0x00020000 // w/for a packet to send SC.
+#define CONNECTION_FLAGS_SEND_DA 0x00040000 // w/for a packet to send DA.
+#define CONNECTION_FLAGS_SEND_RO 0x00080000 // w/for a packet to send RO.
+#define CONNECTION_FLAGS_SEND_RC 0x00100000 // w/for a packet to send RC.
+#define CONNECTION_FLAGS_SEND_SE 0x00200000 // w/for a packet to send SE.
+#define CONNECTION_FLAGS_SEND_NR 0x00400000 // w/for a packet to send NR.
+#define CONNECTION_FLAGS_NO_INDICATE 0x00800000 // don't take packets at indication time
+#define CONNECTION_FLAGS_FAILING_TO_EOR 0x01000000 // wait for an EOF in an incoming request before sending
+#define CONNECTION_FLAGS_RESYNCHING 0x02000000 // engaged send side resynch
+#define CONNECTION_FLAGS_RCV_CANCELLED 0x10000000 // current receive was cancelled
+#define CONNECTION_FLAGS_PEND_INDICATE 0x20000000 // new data received during RC_PENDING
+#define CONNECTION_FLAGS_TRANSFER_FAIL 0x40000000 // a transfer data call failed
+
+#define CONNECTION_FLAGS2_STOPPING 0x00000001 // connection is running down.
+#define CONNECTION_FLAGS2_WAIT_NR 0x00000002 // waiting for NAME_RECOGNIZED.
+#define CONNECTION_FLAGS2_WAIT_NQ 0x00000004 // waiting for NAME_QUERY.
+#define CONNECTION_FLAGS2_WAIT_NR_FN 0x00000008 // waiting for FIND NAME response.
+#define CONNECTION_FLAGS2_CLOSING 0x00000010 // connection is closing
+#define CONNECTION_FLAGS2_ASSOCIATED 0x00000020 // associated with address
+#define CONNECTION_FLAGS2_DISCONNECT 0x00000040 // disconnect done on connection
+#define CONNECTION_FLAGS2_ACCEPTED 0x00000080 // accept done on connection
+#define CONNECTION_FLAGS2_REQ_COMPLETED 0x00000100 // Listen/Connect request completed.
+#define CONNECTION_FLAGS2_DISASSOCIATED 0x00000200 // associate CRef has been removed
+#define CONNECTION_FLAGS2_DISCONNECTED 0x00000400 // disconnect has been indicated
+#define CONNECTION_FLAGS2_NO_LISTEN 0x00000800 // no_listen received during setup
+#define CONNECTION_FLAGS2_REMOTE_VALID 0x00001000 // Connection->RemoteName is valid
+#define CONNECTION_FLAGS2_GROUP_LSN 0x00002000 // connection LSN is globally assigned
+#define CONNECTION_FLAGS2_W_ADDRESS 0x00004000 // waiting for address reregistration.
+#define CONNECTION_FLAGS2_PRE_ACCEPT 0x00008000 // no TdiAccept after listen completes
+#define CONNECTION_FLAGS2_ABORT 0x00010000 // abort this connection.
+#define CONNECTION_FLAGS2_ORDREL 0x00020000 // we're in orderly release.
+#define CONNECTION_FLAGS2_DESTROY 0x00040000 // destroy this connection.
+#define CONNECTION_FLAGS2_LISTENER 0x00100000 // we were the passive listener.
+#define CONNECTION_FLAGS2_CONNECTOR 0x00200000 // we were the active connector.
+#define CONNECTION_FLAGS2_WAITING_SC 0x00400000 // the connection is waiting for
+ // and accept to send the
+ // session confirm
+#define CONNECTION_FLAGS2_INDICATING 0x00800000 // connection was manipulated while
+ // indication was in progress
+
+#define CONNECTION_FLAGS2_LDISC 0x01000000 // Local disconnect req.
+#ifdef RASAUTODIAL
+#define CONNECTION_FLAGS2_AUTOCONNECTING 0x02000000 // RAS autodial in progress
+#define CONNECTION_FLAGS2_AUTOCONNECTED 0x04000000 // RAS autodial done
+#endif // RASAUTODIAL
+
+#define CONNECTION_FLAGS_STARVED ( \
+ CONNECTION_FLAGS_SEND_SI | \
+ CONNECTION_FLAGS_SEND_SC | \
+ CONNECTION_FLAGS_SEND_DA | \
+ CONNECTION_FLAGS_SEND_RO | \
+ CONNECTION_FLAGS_SEND_RC | \
+ CONNECTION_FLAGS_SEND_NR | \
+ CONNECTION_FLAGS_SEND_SE \
+ )
+
+#define CONNECTION_FLAGS_DEFERRED_ACK 0x00000001 // send piggyback ack first opportunity
+#define CONNECTION_FLAGS_DEFERRED_ACK_2 0x00000002 // deferred ack wasn't sent
+#define CONNECTION_FLAGS_DEFERRED_NOT_Q 0x00000004 // DEFERRED_ACK set, but not on DataAckQueue
+#define CONNECTION_FLAGS_DEFERRED_SENDS 0x80000000 // print completed sends
+
+#define CONNECTION_SENDSTATE_IDLE 0 // no sends being processed.
+#define CONNECTION_SENDSTATE_PACKETIZE 1 // send being packetized.
+#define CONNECTION_SENDSTATE_W_PACKET 2 // waiting for free packet.
+#define CONNECTION_SENDSTATE_W_LINK 3 // waiting for good link conditions.
+#define CONNECTION_SENDSTATE_W_EOR 4 // waiting for TdiSend(EOR).
+#define CONNECTION_SENDSTATE_W_ACK 5 // waiting for DATA_ACK.
+#define CONNECTION_SENDSTATE_W_RCVCONT 6 // waiting for RECEIVE_CONTINUE.
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to a TP_ADDRESS
+// structure, which describes the address that it is bound to. Thus, a
+// connection will point to this structure, which describes the address the
+// connection was associated with. When the address file closes, all connections
+// opened on this address file get closed, too. Note that this may leave an
+// address hanging around, with other references.
+//
+
+typedef struct _TP_ADDRESS_FILE {
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // This structure is edited after taking the Address spinlock for the
+ // owning address. This ensures that the address and this structure
+ // will never get out of syncronization with each other.
+ //
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per connection open on this address. This list of connections
+ // is used to help the cleanup process if a process closes an address
+ // before disassociating all connections on it. By design, connections
+ // will stay around until they are explicitly
+ // closed; we use this database to ensure that we clean up properly.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PIRP Irp; // the irp used for open or close
+ struct _TP_ADDRESS *Address; // address to which we are bound.
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the Irp used to close this address file,
+ // for pended completion.
+ //
+
+ PIRP CloseIrp;
+
+ //
+ // is this address file currently indicating a connection request? if yes, we
+ // need to mark connections that are manipulated during this time.
+ //
+
+ BOOLEAN ConnectIndicationInProgress;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredConnectionHandler;
+ BOOLEAN RegisteredDisconnectHandler;
+ BOOLEAN RegisteredReceiveHandler;
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredExpeditedDataHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ //
+ //
+
+ PTDI_IND_CONNECT ConnectionHandler;
+ PVOID ConnectionHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PVOID DisconnectHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address. If the NULL handler
+ // is specified in a TdiSetEventHandler, then this points to an internal
+ // routine which does not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PVOID ReceiveHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+
+ //
+ // An expedited data handler. This handler is used if expedited data is
+ // expected; it never is in NBF, thus this handler should always point to
+ // the default handler.
+ //
+
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ PVOID ExpeditedDataHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+ PVOID ErrorHandlerOwner;
+
+
+} TP_ADDRESS_FILE, *PTP_ADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a TP_ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#if DBG
+#define AREF_TIMER 0
+#define AREF_TEMP_CREATE 1
+#define AREF_OPEN 2
+#define AREF_VERIFY 3
+#define AREF_LOOKUP 4
+#define AREF_FRAME_SEND 5
+#define AREF_CONNECTION 6
+#define AREF_TEMP_STOP 7
+#define AREF_REQUEST 8
+#define AREF_PROCESS_UI 9
+#define AREF_PROCESS_DATAGRAM 10
+#define AREF_TIMER_SCAN 11
+
+#define NUMBER_OF_AREFS 12
+#endif
+
+typedef struct _TP_ADDRESS {
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_AREFS];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ LONG ReferenceCount; // number of references to this object.
+
+ //
+ // The following spin lock is acquired to edit this TP_ADDRESS structure
+ // or to scan down or edit the list of address files.
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this structure.
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PIRP Irp; // pointer to address creation IRP.
+ PNBF_NETBIOS_ADDRESS NetworkName; // this address
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE_CONTEXT *Provider; // device context to which we are attached.
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY SendDatagramQueue; // FIFO of outstanding TdiSendDatagrams.
+
+ //
+ // The following field points to a list of TP_CONNECTION structures,
+ // one per active, connecting, or disconnecting connections on this
+ // address. By definition, if a connection is on this list, then
+ // it is visible to the client in terms of receiving events and being
+ // able to post requests by naming the ConnectionId. If the connection
+ // is not on this list, then it is not valid, and it is guaranteed that
+ // no indications to the client will be made with reference to it, and
+ // no requests specifying its ConnectionId will be accepted by the transport.
+ //
+
+ LIST_ENTRY ConnectionDatabase; // list of defined transport connections.
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // The packet pool of size 1 that holds the UI frame, and the
+ // frame that is allocated out of it.
+ //
+
+ NDIS_HANDLE UIFramePoolHandle;
+ PTP_UI_FRAME UIFrame; // DLC-UI/NBF header for datagram sends.
+
+ //
+ // The following fields are used to register this address on the network.
+ //
+
+ ULONG Retries; // retries of ADD_NAME_QUERY left to go.
+ KTIMER Timer; // kernel timer for timeouts on ANQ/ANR.
+ KDPC Dpc; // DPC object for timeout.
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbfDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ //
+ // If we get an ADD_NAME_RESPONSE frame, this holds the address
+ // of the remote we got it from (used to check for duplicate names).
+ //
+
+ UCHAR UniqueResponseAddress[6];
+
+ //
+ // Set to TRUE once we send a name in conflict frame, so that
+ // we don't flood the network with them on every response.
+ //
+
+ BOOLEAN NameInConflictSent;
+
+} TP_ADDRESS, *PTP_ADDRESS;
+
+#define ADDRESS_FLAGS_GROUP 0x00000001 // set if group, otherwise unique.
+#define ADDRESS_FLAGS_CONFLICT 0x00000002 // address in conflict detected.
+#define ADDRESS_FLAGS_REGISTERING 0x00000004 // registration in progress.
+#define ADDRESS_FLAGS_DEREGISTERING 0x00000008 // deregistration in progress.
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000010 // duplicate name was found on net.
+#define ADDRESS_FLAGS_NEEDS_REG 0x00000020 // address must be registered.
+#define ADDRESS_FLAGS_STOPPING 0x00000040 // TpStopAddress is in progress.
+#define ADDRESS_FLAGS_BAD_ADDRESS 0x00000080 // name in conflict on associated address.
+#define ADDRESS_FLAGS_SEND_IN_PROGRESS 0x00000100 // send datagram process active.
+#define ADDRESS_FLAGS_CLOSED 0x00000200 // address has been closed;
+ // existing activity can
+ // complete, nothing new can start
+#define ADDRESS_FLAGS_NEED_REREGISTER 0x00000400 // quick-reregister on next connect.
+#define ADDRESS_FLAGS_QUICK_REREGISTER 0x00000800 // address is quick-reregistering.
+
+
+//
+// This structure defines a TP_LINK, or established data link object,
+// maintained by the transport provider. Each data link connection with
+// a remote machine is represented by this object. Zero, one, or several
+// transport connections can be multiplexed over the same data link connection.
+// This object is managed by routines in LINK.C.
+//
+
+#if DBG
+#define LREF_SPECIAL_CONN 0
+#define LREF_SPECIAL_TEMP 1
+#define LREF_CONNECTION 2
+#define LREF_STOPPING 3
+#define LREF_START_T1 4
+#define LREF_TREE 5
+#define LREF_NOT_ADM 6
+#define LREF_NDIS_SEND 7
+
+#define NUMBER_OF_LREFS 8
+#endif
+
+#if DBG
+#define LINK_HISTORY_LENGTH 20
+#endif
+
+typedef struct _TP_LINK {
+
+ RTL_SPLAY_LINKS SplayLinks; // for the link splay tree
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_LREFS];
+#endif
+
+ LIST_ENTRY Linkage; // for list of free links or deferred
+ // operation queue
+ KSPIN_LOCK SpinLock; // lock to manipulate this structure.
+
+ LONG ReferenceCount; // number of references to this object.
+ LONG SpecialRefCount; // controls freeing of the link.
+
+ //
+ // information about the remote hardware this link is talking to.
+ //
+
+ BOOLEAN Loopback; // TRUE if this is a loopback link.
+ UCHAR LoopbackDestinationIndex; // if Loopback, the index.
+
+ HARDWARE_ADDRESS HardwareAddress; // hardware address of remote.
+ ULARGE_INTEGER MagicAddress; // numerical representation of the
+ // hardware address used for quick
+ // comparisons
+ UCHAR Header[MAX_MAC_HEADER_LENGTH]; // a place to stick a prebuilt packet
+ // header.
+ ULONG HeaderLength; // length of Header for this link
+
+ //
+ // Vital conditions surrounding the data link connnection.
+ //
+
+ ULONG MaxFrameSize; // maximum size of NetBIOS frame, MAC
+ // dependent.
+
+ //
+ // Connections associated with this link. We keep a simple list of
+ // connections because it's unlikely we'll get more than a few connections
+ // on a given link (we're assuming that the server or redir will be the
+ // biggest user of the net in the vast majority of environments). We've
+ // made the link lookup be via a splay tree, which vastly speeds the
+ // process of getting to the proper link; as long as there are only a few
+ // connections, the connection lookup will be fast. If this becomes a
+ // problem down the road, we can make this connection list be a splay tree
+ // also.
+ //
+
+ LIST_ENTRY ConnectionDatabase;
+ ULONG ActiveConnectionCount; // # connections in above list.
+
+ //
+ // The following fields are used to maintain state about this link.
+ // One other field is implicit-- the address of this object is the
+ // ConnectionContext value as described in the PDI spec.
+ //
+
+ ULONG Flags; // attributes of the link.
+ ULONG DeferredFlags; // when on the deferred queue.
+ ULONG State; // link state variable.
+
+ //
+ // Send-side state.
+ //
+
+ ULONG PacketsSent; // number of packets sent.
+ ULONG PacketsResent; // number of packets resent.
+ UCHAR SendState; // send-side state variable.
+ UCHAR NextSend; // next N(S) we should send.
+ UCHAR LastAckReceived; // last N(R) we received.
+ UCHAR SendWindowSize; // current send window size.
+ UCHAR PrevWindowSize; // size last time we dropped a frame.
+ UCHAR WindowsUntilIncrease; // how many windows until size increases.
+ UCHAR SendRetries; // number of retries left/this checkpoint.
+ UCHAR ConsecutiveLastPacketLost; // consecutive windows with last packet dropped.
+ ULONG NdisSendsInProgress; // >0 if sends queued to NdisSendQueue.
+ LIST_ENTRY NdisSendQueue; // queue of sends to pass to NdisSend.
+ LIST_ENTRY WackQ; // sent packets waiting LLC acks.
+
+ BOOLEAN OnDeferredRrQueue;
+ LIST_ENTRY DeferredRrLinkage;
+
+ //
+ // Receive-side state.
+ //
+
+ ULONG PacketsReceived; // number of packets received.
+ UCHAR ReceiveState; // receive-side state variable.
+ UCHAR NextReceive; // next expected N(S) we should receive.
+ UCHAR LastAckSent; // last N(R) we sent.
+ UCHAR ReceiveWindowSize; // current receive window size.
+ BOOLEAN RespondToPoll; // remote guy is polling-- we must final.
+ BOOLEAN ResendingPackets; // ResendLlcPackets in progress
+ BOOLEAN LinkBusy; // received RNR (really send-side state).
+
+ //
+ // Timer, used to determine delay and throughput.
+ //
+
+ ULONG Delay; // an NT time, but only LowPart is saved.
+ LARGE_INTEGER Throughput;
+
+ //
+ // These are counters needed by ADAPTER_STATUS queries.
+ //
+
+ USHORT FrmrsReceived;
+ USHORT FrmrsTransmitted;
+ USHORT ErrorIFramesReceived;
+ USHORT ErrorIFramesTransmitted;
+ USHORT AbortedTransmissions;
+ USHORT BuffersNotAvailable;
+ ULONG SuccessfulTransmits;
+ ULONG SuccessfulReceives;
+ USHORT T1Expirations;
+ USHORT TiExpirations;
+
+ //
+ // Timeout state. There is one kernel timer for this transport that is set
+ // to go off at regular intervals. This timer increments the current time,
+ // which is then used to compare against the timer queues. The timer queues
+ // are ordered, so whenever the first element is not expired, the rest of
+ // the queue is not expired. This allows us to have hundreds of timers
+ // running with very little system overhead.
+ // A value of 0 indicates that the timer is not active.
+ //
+
+ ULONG T1; // retry timer.
+ ULONG T2; // delayed ack timer.
+ ULONG Ti; // inactivity timer.
+ BOOLEAN OnShortList; // TRUE if link is in ShortList
+ BOOLEAN OnLongList; // TRUE if link is in LongList
+ LIST_ENTRY ShortList; // list of links waiting t1 or t2
+ LIST_ENTRY LongList; // list of links waiting ti
+
+ LIST_ENTRY PurgeList;
+
+ //
+ // This counter is used to keep track of whether there are
+ // any "connectors" (connections initiated by this side) on
+ // this link. If there are none, and we are on an easily
+ // disconnected link, then we handle the inactivity timeout
+ // differently.
+ //
+
+ LONG NumberOfConnectors;
+
+ //
+ // BaseT1Timeout is the current T1 timeout computed based on
+ // the response to previous poll frames. T1Timeout is the
+ // value to be used for the next T1, and will generally be
+ // based on BaseT1Timeout but may be more if T1 is backing
+ // off. T2Timeout and TiTimeout are independent of these.
+ //
+
+ ULONG BaseT1Timeout; // Timeout value for T1, << 16.
+ ULONG CurrentT1Timeout; // Current backed-off T1 timeout.
+ ULONG MinimumBaseT1Timeout; // Minimum value, based on link speed.
+ ULONG BaseT1RecalcThreshhold; // Only recalc BaseT1 on frames > this.
+ ULONG CurrentPollRetransmits; // Current retransmits waiting for final.
+ BOOLEAN ThroughputAccurate; // Is the throughput on this link accurate?
+ BOOLEAN CurrentT1Backoff; // the last poll frame had retransmits
+ BOOLEAN CurrentPollOutstanding; // Check that we have a poll outstanding.
+ LARGE_INTEGER CurrentTimerStart; // Time that current timing was begun.
+ ULONG CurrentPollSize; // Size of current poll packet.
+ ULONG T2Timeout; // Timeout value for T2.
+ ULONG TiTimeout; // Timeout value for Ti.
+ ULONG LlcRetries; // total retry count for this link.
+ ULONG MaxWindowSize; // maximum send window size.
+ ULONG TiStartPacketsReceived; // PacketsReceived when Ti was started.
+
+ //
+ // Adaptive window algorithm state.
+ //
+
+ ULONG WindowErrors; // # retransmissions/this adaptive run.
+ UCHAR BestWindowSize; // our best window from experience.
+ UCHAR WorstWindowSize; // our worst window from experience.
+
+ //
+ // Keep track of remotes that never poll so we can send
+ // an RR every two frames.
+ //
+
+ BOOLEAN RemoteNoPoll; // We think remote doesn't poll
+ UCHAR ConsecutiveIFrames; // number received since polling
+
+#if DBG
+ UCHAR CreatePacketFailures; // consecutive failures
+#endif
+
+ LIST_ENTRY DeferredList; // for threading on deferred list
+
+ struct _DEVICE_CONTEXT *Provider;
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock
+
+#if DBG
+ LIST_ENTRY GlobalLinkage;
+ ULONG TotalReferences;
+ ULONG TotalDereferences;
+ ULONG NextRefLoc;
+ struct {
+ PVOID Caller;
+ PVOID CallersCaller;
+ } History[LINK_HISTORY_LENGTH];
+ BOOLEAN Destroyed;
+#endif
+
+} TP_LINK, *PTP_LINK;
+
+#if DBG
+extern KSPIN_LOCK NbfGlobalHistoryLock;
+extern LIST_ENTRY NbfGlobalLinkList;
+#define StoreLinkHistory(_link,_ref) { \
+ KIRQL oldIrql; \
+ KeAcquireSpinLock (&NbfGlobalHistoryLock, &oldIrql); \
+ if ((_link)->Destroyed) { \
+ DbgPrint ("link touched after being destroyed 0x%lx\n", (_link)); \
+ DbgBreakPoint(); \
+ } \
+ RtlGetCallersAddress( \
+ &(_link)->History[(_link)->NextRefLoc].Caller, \
+ &(_link)->History[(_link)->NextRefLoc].CallersCaller \
+ ); \
+ if ((_ref)) { \
+ (_link)->TotalReferences++; \
+ } else { \
+ (_link)->TotalDereferences++; \
+ (_link)->History[(_link)->NextRefLoc].Caller = \
+ (PVOID)((ULONG)(_link)->History[(_link)->NextRefLoc].Caller & \
+ ~0x80000000); \
+ } \
+ if (++(_link)->NextRefLoc == LINK_HISTORY_LENGTH) { \
+ (_link)->NextRefLoc = 0; \
+ } \
+ KeReleaseSpinLock (&NbfGlobalHistoryLock, oldIrql); \
+}
+#endif
+
+#define LINK_FLAGS_JUMP_START 0x00000040 // run adaptive alg/every sent window.
+#define LINK_FLAGS_LOCAL_DISC 0x00000080 // link was stopped locally.
+
+//
+// deferred flags, used for processing at timer tick if needed
+//
+
+#define LINK_FLAGS_DEFERRED_DELETE 0x00010000 // delete at next opportunity
+#define LINK_FLAGS_DEFERRED_ADD 0x00020000 // add to splay tree, next opportunity
+#define LINK_FLAGS_DEFERRED_MASK 0x00030000 // (LINK_FLAGS_DEFERRED_DELETE | LINK_FLAGS_DEFERRED_ADD)
+
+#define LINK_STATE_ADM 1 // asynchronous disconnected mode.
+#define LINK_STATE_READY 2 // asynchronous balanced mode extended.
+#define LINK_STATE_BUSY 3 // all link buffers are busy, sent RNR
+#define LINK_STATE_CONNECTING 4 // waiting SABME response (UA-r/f).
+#define LINK_STATE_W_POLL 5 // waiting initial checkpoint.
+#define LINK_STATE_W_FINAL 6 // waiting final from initial checkpoint.
+#define LINK_STATE_W_DISC_RSP 7 // waiting disconnect response.
+
+#define SEND_STATE_DOWN 0 // asynchronous disconnected mode.
+#define SEND_STATE_READY 1 // completely ready to send.
+#define SEND_STATE_REJECTING 2 // other guy is rejecting.
+#define SEND_STATE_CHECKPOINTING 3 // we're checkpointing (can't send data).
+
+#define RECEIVE_STATE_DOWN 0 // asynchronous disconnected mode.
+#define RECEIVE_STATE_READY 1 // we're ready to receive.
+#define RECEIVE_STATE_REJECTING 2 // we're rejecting.
+
+
+//
+// This structure defines the DEVICE_OBJECT and its extension allocated at
+// the time the transport provider creates its device object.
+//
+
+#if DBG
+#define DCREF_CREATION 0
+#define DCREF_ADDRESS 1
+#define DCREF_CONNECTION 2
+#define DCREF_LINK 3
+#define DCREF_QUERY_INFO 4
+#define DCREF_SCAN_TIMER 5
+#define DCREF_REQUEST 6
+
+#define NUMBER_OF_DCREFS 8
+#endif
+
+
+typedef struct _NBF_POOL_LIST_DESC {
+ NDIS_HANDLE PoolHandle;
+ USHORT NumElements;
+ USHORT TotalElements;
+ struct _NBF_POOL_LIST_DESC *Next;
+} NBF_POOL_LIST_DESC, *PNBF_POOL_LIST_DESC;
+
+typedef struct _DEVICE_CONTEXT {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[NUMBER_OF_DCREFS];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+ LIST_ENTRY Linkage; // links them on NbfDeviceList;
+
+ KSPIN_LOCK Interlock; // GLOBAL spinlock for reference count.
+ // (used in ExInterlockedXxx calls)
+ LONG ReferenceCount; // activity count/this provider.
+
+
+ //
+ // This protects the LoopbackQueue.
+ //
+
+ KSPIN_LOCK LoopbackSpinLock;
+
+ //
+ // The queue of packets waiting to be looped back.
+ //
+
+ LIST_ENTRY LoopbackQueue;
+
+ //
+ // These two links are used for loopback.
+ //
+
+ PTP_LINK LoopbackLinks[2];
+
+ //
+ // This buffer is used for loopback indications; a
+ // contiguous piece is copied into it. It is allocated
+ // (of size NBF_MAX_LOOPBACK_LOOKAHEAD) when one of
+ // the LoopbackLinks become non-NULL.
+ //
+
+ PUCHAR LookaheadContiguous;
+
+ //
+ // This holds the length of the header in the currently
+ // indicating loopback packet.
+ //
+
+ ULONG LoopbackHeaderLength;
+
+ //
+ // Used for processing the loopback queue.
+ //
+
+ KDPC LoopbackDpc;
+
+ //
+ // Determines if a LoopbackDpc is in progress.
+ //
+
+ BOOLEAN LoopbackInProgress;
+
+ //
+ // Determines if a WanDelayedDpc is in progress.
+ //
+
+ BOOLEAN WanThreadQueued;
+
+ //
+ // Used for momentarily delaying WAN packetizing to
+ // allow RR's to be received.
+ //
+
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+
+ //
+ // The queue of FIND.NAME requests waiting to be processed.
+ //
+
+ LIST_ENTRY FindNameQueue;
+
+ //
+ // The queue of STATUS.QUERY requests waiting to be processed.
+ //
+
+ LIST_ENTRY StatusQueryQueue;
+
+ //
+ // The queue of QUERY.INDICATION requests waiting to be completed.
+ //
+
+ LIST_ENTRY QueryIndicationQueue;
+
+ //
+ // The queue of DATAGRAM.INDICATION requests waiting to be completed.
+ //
+
+ LIST_ENTRY DatagramIndicationQueue;
+
+ //
+ // The queue of (currently receive only) IRPs waiting to complete.
+ //
+
+ LIST_ENTRY IrpCompletionQueue;
+
+ //
+ // This boolean is TRUE if either of the above two have ever
+ // had anything on them.
+ //
+
+ BOOLEAN IndicationQueuesInUse;
+
+ //
+ // Following are protected by Global Device Context SpinLock
+ //
+
+ KSPIN_LOCK SpinLock; // lock to manipulate this object.
+ // (used in KeAcquireSpinLock calls)
+
+ //
+ // the device context state, among open, closing
+ //
+
+ UCHAR State;
+
+ //
+ // Used when processing a STATUS_CLOSING indication.
+ //
+
+ WORK_QUEUE_ITEM StatusClosingQueueItem;
+
+ //
+ // The following queue holds free TP_LINK objects available for allocation.
+ //
+
+ LIST_ENTRY LinkPool;
+
+ //
+ // These counters keep track of resources uses by TP_LINK objects.
+ //
+
+ ULONG LinkAllocated;
+ ULONG LinkInitAllocated;
+ ULONG LinkMaxAllocated;
+ ULONG LinkInUse;
+ ULONG LinkMaxInUse;
+ ULONG LinkExhausted;
+ ULONG LinkTotal;
+ ULONG LinkSamples;
+
+
+ //
+ // The following queue holds free TP_ADDRESS objects available for allocation.
+ //
+
+ LIST_ENTRY AddressPool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS objects.
+ //
+
+ ULONG AddressAllocated;
+ ULONG AddressInitAllocated;
+ ULONG AddressMaxAllocated;
+ ULONG AddressInUse;
+ ULONG AddressMaxInUse;
+ ULONG AddressExhausted;
+ ULONG AddressTotal;
+ ULONG AddressSamples;
+
+
+ //
+ // The following queue holds free TP_ADDRESS_FILE objects available for allocation.
+ //
+
+ LIST_ENTRY AddressFilePool;
+
+ //
+ // These counters keep track of resources uses by TP_ADDRESS_FILE objects.
+ //
+
+ ULONG AddressFileAllocated;
+ ULONG AddressFileInitAllocated;
+ ULONG AddressFileMaxAllocated;
+ ULONG AddressFileInUse;
+ ULONG AddressFileMaxInUse;
+ ULONG AddressFileExhausted;
+ ULONG AddressFileTotal;
+ ULONG AddressFileSamples;
+
+
+ //
+ // The following queue holds free TP_CONNECTION objects available for allocation.
+ //
+
+ LIST_ENTRY ConnectionPool;
+
+ //
+ // These counters keep track of resources uses by TP_CONNECTION objects.
+ //
+
+ ULONG ConnectionAllocated;
+ ULONG ConnectionInitAllocated;
+ ULONG ConnectionMaxAllocated;
+ ULONG ConnectionInUse;
+ ULONG ConnectionMaxInUse;
+ ULONG ConnectionExhausted;
+ ULONG ConnectionTotal;
+ ULONG ConnectionSamples;
+
+
+ //
+ // The following is a free list of TP_REQUEST blocks which have been
+ // previously allocated and are available for use.
+ //
+
+ LIST_ENTRY RequestPool; // free request block pool.
+
+ //
+ // These counters keep track of resources uses by TP_REQUEST objects.
+ //
+
+ ULONG RequestAllocated;
+ ULONG RequestInitAllocated;
+ ULONG RequestMaxAllocated;
+ ULONG RequestInUse;
+ ULONG RequestMaxInUse;
+ ULONG RequestExhausted;
+ ULONG RequestTotal;
+ ULONG RequestSamples;
+
+
+ //
+ // The following list comprises a pool of UI NetBIOS frame headers
+ // that are manipulated by the routines in FRAMESND.C.
+ //
+
+ LIST_ENTRY UIFramePool; // free UI frames (TP_UI_FRAME objects).
+
+ //
+ // These counters keep track of resources uses by TP_UI_FRAME objects.
+ //
+
+ ULONG UIFrameLength;
+ ULONG UIFrameHeaderLength;
+ ULONG UIFrameAllocated;
+ ULONG UIFrameInitAllocated;
+ ULONG UIFrameExhausted;
+
+
+ //
+ // The following queue holds I-frame Send packets managed by PACKET.C.
+ //
+
+ SINGLE_LIST_ENTRY PacketPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG PacketLength;
+ ULONG PacketHeaderLength;
+ ULONG PacketAllocated;
+ ULONG PacketInitAllocated;
+ ULONG PacketExhausted;
+
+
+ //
+ // The following queue holds RR-frame Send packets managed by PACKET.C.
+ //
+
+ SINGLE_LIST_ENTRY RrPacketPool;
+
+
+ //
+ // The following queue contains Receive packets
+ //
+
+ SINGLE_LIST_ENTRY ReceivePacketPool;
+
+ //
+ // These counters keep track of resources uses by NDIS_PACKET objects.
+ //
+
+ ULONG ReceivePacketAllocated;
+ ULONG ReceivePacketInitAllocated;
+ ULONG ReceivePacketExhausted;
+
+
+ //
+ // This queue contains pre-allocated receive buffers
+ //
+
+ SINGLE_LIST_ENTRY ReceiveBufferPool;
+
+ //
+ // These counters keep track of resources uses by TP_PACKET objects.
+ //
+
+ ULONG ReceiveBufferLength;
+ ULONG ReceiveBufferAllocated;
+ ULONG ReceiveBufferInitAllocated;
+ ULONG ReceiveBufferExhausted;
+
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ ULONG MemoryUsage;
+ ULONG MemoryLimit;
+
+
+ //
+ // The following field is a head of a list of TP_ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+
+ //
+ // The following field is the pointer to the root of the splay tree of
+ // links that are associated with this Device Context. You must hold the
+ // LinkSpinLock to modify this list. You must set the LinkTreeSemaphore
+ // to traverse this list without modifying it. Note that all modify
+ // operations are deferred to timer(DPC)-time operations.
+ //
+
+ KSPIN_LOCK LinkSpinLock; // protects these values
+ PTP_LINK LastLink; // the last link found in the tree.
+ PRTL_SPLAY_LINKS LinkTreeRoot; // pointer to root of the tree.
+ ULONG LinkTreeElements; // how many elements in the tree
+ LIST_ENTRY LinkDeferred; // Deferred operations on links.
+ ULONG DeferredNotSatisfied; // how many times we've come to the
+ // deferred well and not gotten it clear.
+
+ //
+ // The following queue holds connections which are waiting on available
+ // packets. As each new packet becomes available, a connection is removed
+ // from this queue and placed on the PacketizeQueue.
+ //
+
+ LIST_ENTRY PacketWaitQueue; // queue of packet-starved connections.
+ LIST_ENTRY PacketizeQueue; // queue of ready-to-packetize connections.
+
+ //
+ // The following queue holds connections which are waiting to send
+ // a piggyback ack. In that case the CONNECTION_FLAGS_DEFERRED_ACK
+ // bit in DeferredFlags will be set.
+ //
+
+ LIST_ENTRY DataAckQueue;
+
+ //
+ // The following queue holds links which are waiting to send an
+ // RR frame because the remote they are talking to never polls.
+ //
+
+ LIST_ENTRY DeferredRrQueue;
+
+ //
+ // Used to track when the queue has changed.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // When this hits thirty seconds we checked for stalled connections.
+ //
+
+ USHORT StalledConnectionCount;
+
+ //
+ // This queue contains receives that are in progress
+ //
+
+ LIST_ENTRY ReceiveInProgress;
+
+ //
+ // NDIS fields
+ //
+
+ //
+ // following is used to keep adapter information.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The following fields are used for talking to NDIS. They keep information
+ // for the NDIS wrapper to use when determining what pool to use for
+ // allocating storage.
+ //
+
+ KSPIN_LOCK SendPoolListLock; // protects these values
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ KSPIN_LOCK RcvPoolListLock; // protects these values
+ PNBF_POOL_LIST_DESC ReceivePacketPoolDesc;
+ NDIS_HANDLE NdisBufferPool;
+
+ //
+ // These are kept around for error logging.
+ //
+
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxRequests;
+ ULONG MaxLinks;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NBF_NDIS_IDENTIFICATION MacInfo; // MAC type and other info
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG CurSendPacketSize; // may be smaller for async
+ USHORT RecommendedSendWindow; // used for Async lines
+ BOOLEAN EasilyDisconnected; // TRUE over wireless nets.
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalAddress; // our local hardware address.
+ HARDWARE_ADDRESS NetBIOSAddress; // NetBIOS functional address, used for TR
+
+ //
+ // The reserved Netbios address; consists of 10 zeroes
+ // followed by LocalAddress;
+ //
+
+ UCHAR ReservedNetBIOSAddress[NETBIOS_NAME_LENGTH];
+#ifdef _PNP_POWER
+ HANDLE TdiDeviceHandle;
+ HANDLE ReservedAddressHandle;
+#endif
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+
+ //
+ // This next field maintains a unique number which can next be assigned
+ // as a connection identifier. It is incremented by one each time a
+ // value is allocated.
+ //
+
+ USHORT UniqueIdentifier; // starts at 0, wraps around 2^16-1.
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // The following fields are used to implement the lightweight timer
+ // system in the protocol provider. Each TP_LINK object in the device
+ // context's LinkDatabase contains three lightweight timers that are
+ // serviced by a DPC routine, which receives control by kernel functions.
+ // There is one kernel timer for this transport that is set
+ // to go off at regular intervals. This timer increments the Absolute time,
+ // which is then used to compare against the timer queues. The timer queues
+ // are ordered, so whenever the first element is not expired, the rest of
+ // the queue is not expired. This allows us to have hundreds of timers
+ // running with very low system overhead.
+ // A value of -1 indicates that the timer is not active.
+ //
+
+ LARGE_INTEGER ShortTimerStart; // when the short timer was set.
+ KDPC ShortTimerSystemDpc; // kernel DPC object, short timer.
+ KTIMER ShortSystemTimer; // kernel timer object, short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ ULONG AdaptivePurge; // absolute time of next purge (short timer).
+ KDPC LongTimerSystemDpc; // kernel DPC object, long timer.
+ KTIMER LongSystemTimer; // kernel timer object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ union _DC_ACTIVE {
+ struct _DC_INDIVIDUAL {
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckQueueActive; // DataAckQueue is not empty.
+ BOOLEAN LinkDeferredActive; // LinkDeferred is not empty.
+ } i;
+ ULONG AnyActive; // used to check all four at once.
+ } a;
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+ KSPIN_LOCK TimerSpinLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of links waiting T1 or T2
+ LIST_ENTRY LongList; // list of links waiting Ti expire
+ LIST_ENTRY PurgeList; // list of links waiting LAT expire
+
+ //
+ // These fields are used on "easily disconnected" adapters.
+ // Every time the long timer expires, it notes if there has
+ // been any multicast traffic received. If there has not been,
+ // it increments LongTimeoutsWithoutMulticast. Activity is
+ // recorded by incrementing MulticastPacket when MC
+ // packets are received, and zeroing it when the long timer
+ // expires.
+ //
+
+ ULONG LongTimeoutsWithoutMulticast; // LongTimer timeouts since traffic.
+ ULONG MulticastPacketCount; // How many MC packets rcved, this timeout.
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ BOOLEAN MediumSpeedAccurate; // if FALSE, can't use the link.
+
+ //
+ // This is TRUE if we are on a UP system.
+ //
+
+ BOOLEAN UniProcessor;
+
+ //
+ // Configuration information on how soon we should send
+ // an unasked for RR with a non-polling remote.
+ //
+
+ UCHAR MaxConsecutiveIFrames;
+
+ //
+ // This is configuration information controlling the default
+ // value of timers and retry counts.
+ //
+
+ ULONG DefaultT1Timeout;
+ ULONG MinimumT1Timeout;
+ ULONG DefaultT2Timeout;
+ ULONG DefaultTiTimeout;
+ ULONG LlcRetries;
+ ULONG LlcMaxWindowSize;
+ ULONG NameQueryRetries;
+ ULONG NameQueryTimeout;
+ ULONG AddNameQueryRetries;
+ ULONG AddNameQueryTimeout;
+ ULONG GeneralRetries;
+ ULONG GeneralTimeout;
+ ULONG MinimumSendWindowLimit; // how low we can lock a connection's window
+
+ //
+ // Counters for most of the statistics that NBF maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempIFrameBytesSent;
+ ULONG TempIFramesSent;
+ ULONG TempIFrameBytesReceived;
+ ULONG TempIFramesReceived;
+
+ //
+ // Some counters needed for Netbios adapter status.
+ //
+
+ ULONG TiExpirations;
+ ULONG FrmrReceived;
+ ULONG FrmrTransmitted;
+
+ //
+ // These are used to compute AverageSendWindow.
+ //
+
+ ULONG SendWindowTotal;
+ ULONG SendWindowSamples;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbfStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // This array is used to keep track of which LSNs are
+ // available for use by Netbios sessions. LSNs can be
+ // re-used for sessions to unique names if they are on
+ // different links, but must be committed beforehand
+ // for group names. The maximum value that can fit in
+ // an array element is defined by LSN_TABLE_MAX.
+ //
+
+ UCHAR LsnTable[NETBIOS_SESSION_LIMIT+1];
+
+ //
+ // This is where we start looking in LsnTable for an
+ // unused LSN. We cycle from 0-63 to prevent quick
+ // down-and-up connections from getting funny data.
+ //
+
+ ULONG NextLsnStart;
+
+ //
+ // This array is used to quickly dismiss UI frames that
+ // are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ PTP_VARIABLE NetmanVariables; // list of network managable variables.
+
+ //
+ // The magic bullet is a packet that is sent under certain debugging
+ // conditions. This allows the transport to signal packet capture devices
+ // that a particular condiion has been met. This packet has the current
+ // devicecontext as the source, and 0x04 in every other byte of the packet.
+ //
+
+ UCHAR MagicBullet[32]; //
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// device context state definitions
+//
+
+#define DEVICECONTEXT_STATE_OPENING 0x00
+#define DEVICECONTEXT_STATE_OPEN 0x01
+#define DEVICECONTEXT_STATE_DOWN 0x02
+#define DEVICECONTEXT_STATE_STOPPING 0x03
+
+//
+// This is the maximum value that can go in an element
+// of LsnTable (should be 0xff if they are UCHARs,
+// 0xffff for USHORTs, etc.).
+//
+
+#define LSN_TABLE_MAX 0xff
+
+
+#define MAGIC_BULLET_FOOD 0x04
+
+
+//
+// These are constants for the LoopbackLinks elements.
+// The distinctions are arbitrary; the listener link
+// is the one established from ProcessNameQuery, and
+// the connector link is the one established from
+// ProcessNameRecognized.
+//
+
+#define LISTENER_LINK 0
+#define CONNECTOR_LINK 1
+
+
+//
+// This structure defines the packet object, used to represent a DLC I-frame
+// in some portion of its lifetime. The PACKET.C module contains routines
+// to manage this object.
+//
+
+typedef struct _TP_PACKET {
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+ PNDIS_PACKET NdisPacket; // ptr to owning Ndis Packet
+ ULONG NdisIFrameLength; // Length of NdisPacket
+
+ LIST_ENTRY Linkage; // used to chain packets together.
+ LONG ReferenceCount; // activity count/this packet.
+ BOOLEAN PacketSent; // packet completed by NDIS.
+ BOOLEAN PacketNoNdisBuffer; // chain on this packet was not allocated.
+
+ UCHAR Action; // what to do when we're acked.
+ BOOLEAN PacketizeConnection; // restart packetizing when completed.
+
+ PVOID Owner; // ptr to owning connection or IrpSp.
+ PTP_LINK Link; // ptr to link it was sent on.
+ PDEVICE_CONTEXT Provider; // The owner of this packet.
+ PKSPIN_LOCK ProviderInterlock; // &Provider->Interlock.
+
+ UCHAR Header[1]; // the MAC, DLC, and NBF headers
+
+} TP_PACKET, *PTP_PACKET;
+
+
+//
+// The following values are placed in the Action field in the TP_PACKET
+// object to indicate what action, if any, should be taken when the packet
+// is destroyed.
+//
+
+#define PACKET_ACTION_NULL 0 // no special action should be taken.
+#define PACKET_ACTION_IRP_SP 1 // Owner is an IRP_SP, deref when done.
+#define PACKET_ACTION_CONNECTION 2 // Owner is a TP_CONNECTION, deref when done.
+#define PACKET_ACTION_END 3 // shutdown session (sent SESSION_END).
+#define PACKET_ACTION_RR 5 // packet is an RR, put back in RR pool.
+
+//
+// Types used to hold information in the send and receive NDIS packets
+//
+
+typedef struct _SEND_PACKET_TAG {
+ LIST_ENTRY Linkage; // used for threading on loopback queue
+ BOOLEAN OnLoopbackQueue; // TRUE if the packet is on a loopback queue
+ UCHAR LoopbackLinkIndex; // index of other link for loopback packets
+ USHORT Type; // identifier for packet type
+ PVOID Frame; // backpointer to owning NBF structure
+ PVOID Owner; // backpointer for owning nbf construct
+ // (like address, devicecontext, etc)
+ } SEND_PACKET_TAG, *PSEND_PACKET_TAG;
+
+//
+// Packet types used in send completion
+//
+
+#define TYPE_I_FRAME 1
+#define TYPE_UI_FRAME 2
+#define TYPE_ADDRESS_FRAME 3
+
+//
+// LoopbackLinkIndex values.
+//
+
+#define LOOPBACK_TO_LISTENER 0
+#define LOOPBACK_TO_CONNECTOR 1
+#define LOOPBACK_UI_FRAME 2
+
+//
+// receive packet used to hold information about this receive
+//
+
+typedef struct _RECEIVE_PACKET_TAG {
+ SINGLE_LIST_ENTRY Linkage; // used for threading in pool
+ PTP_CONNECTION Connection; // connection this receive is occuring on
+ ULONG BytesToTransfer; // for I-frame, bytes in this transfer
+ UCHAR PacketType; // the type of packet we're processing
+ BOOLEAN AllocatedNdisBuffer; // did we allocate our own NDIS_BUFFERs
+ BOOLEAN EndOfMessage; // does this receive complete the message
+ BOOLEAN CompleteReceive; // complete the receive after TransferData?
+ BOOLEAN TransferDataPended; // TRUE if TransferData returned PENDING
+ } RECEIVE_PACKET_TAG, *PRECEIVE_PACKET_TAG;
+
+#define TYPE_AT_INDICATE 1
+#define TYPE_AT_COMPLETE 2
+#define TYPE_STATUS_RESPONSE 3
+
+//
+// receive buffer descriptor (built in memory at the beginning of the buffer)
+//
+
+typedef struct _BUFFER_TAG {
+ LIST_ENTRY Linkage; // thread in pool and on receive queue
+ NDIS_STATUS NdisStatus; // completion status for send
+ PTP_ADDRESS Address; // the address this datagram is for.
+ PNDIS_BUFFER NdisBuffer; // describes the rest of the buffer
+ ULONG Length; // the length of the buffer
+ UCHAR Buffer[1]; // the actual storage (accessed through the NDIS_BUFFER)
+ } BUFFER_TAG, *PBUFFER_TAG;
+
+#endif // def _NBFTYPES_
+
diff --git a/private/ntos/tdi/nbf/packet.c b/private/ntos/tdi/nbf/packet.c
new file mode 100644
index 000000000..2b6de5b25
--- /dev/null
+++ b/private/ntos/tdi/nbf/packet.c
@@ -0,0 +1,1808 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the TP_PACKET object, which
+ describes a DLC I-frame at some point in its lifetime. Routines are
+ provided to allocate packets for shipment, to ship packets, to reference
+ packets, to dereference packets, to mark a connection as waiting for a
+ packet to become available, to satisfy the next waiting connection for
+ a packet, and to destroy packets (return them to the pool).
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// This is temporary; this is the quota that we charge for a receive
+// packet for now, until we fix the problem with token-ring needing
+// big packets and using all the memory. The number is the actual
+// value for Ethernet.
+//
+
+#if 1
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) 1533
+#else
+#define RECEIVE_BUFFER_QUOTA(_DeviceContext) (_DeviceContext)->ReceiveBufferLength
+#endif
+
+#define PACKET_POOL_GROW_COUNT 32
+
+#if DBG
+ULONG NbfCreatePacketThreshold = 5;
+extern ULONG NbfPacketPanic;
+#endif
+
+NDIS_STATUS
+NbfAllocateNdisSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *NdisPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a recieve packet from the receive packet pool.
+ It Grows the packet pool if necessary.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ NDIS_STATUS NdisStatus;
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SendPoolListLock, &oldirql);
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage +
+ PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG))) >
+ DeviceContext->MemoryLimit)) {
+
+ PANIC("NBF: Could not grow packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ DeviceContext->MemoryUsage +=
+ (PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG)));
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ SendPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (DeviceContext->SendPacketPoolDesc == NULL) {
+ return(NdisStatus);
+ }
+
+ RtlZeroMemory(SendPacketPoolDesc, sizeof(NBF_POOL_LIST_DESC));
+
+ SendPacketPoolDesc->NumElements =
+ SendPacketPoolDesc->TotalElements = PACKET_POOL_GROW_COUNT;
+
+ NdisAllocatePacketPool ( &NdisStatus, &SendPacketPoolDesc->PoolHandle,
+ PACKET_POOL_GROW_COUNT, sizeof (SEND_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 ("NbfGrowSendPacketPool: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ ExFreePool (SendPacketPoolDesc);
+ return(NdisStatus);
+ }
+ SendPacketPoolDesc->Next = DeviceContext->SendPacketPoolDesc;
+ DeviceContext->SendPacketPoolDesc = SendPacketPoolDesc;
+ RELEASE_SPIN_LOCK (&DeviceContext->SendPoolListLock, oldirql);
+ NdisAllocatePacket ( &NdisStatus, NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+ return(NdisStatus);
+}
+
+NDIS_STATUS
+NbfAllocateNdisRcvPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *NdisPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a recieve packet from the receive packet pool.
+ It Grows the packet pool if necessary.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNBF_POOL_LIST_DESC RcvPacketPoolDesc;
+ NDIS_STATUS NdisStatus;
+ KIRQL oldirql;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, &oldirql);
+ for (RcvPacketPoolDesc = DeviceContext->ReceivePacketPoolDesc;
+ RcvPacketPoolDesc != NULL;
+ RcvPacketPoolDesc = RcvPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ NdisPacket,
+ RcvPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage +
+ PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG))) >
+ DeviceContext->MemoryLimit)) {
+
+ PANIC("NBF: Could not grow packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+ }
+
+ DeviceContext->MemoryUsage +=
+ (PACKET_POOL_GROW_COUNT *
+ (sizeof(NDIS_PACKET) + sizeof(SEND_PACKET_TAG)));
+
+ // Allocate Packet pool descriptors for dynamic packet allocation.
+
+ RcvPacketPoolDesc = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(NBF_POOL_LIST_DESC),
+ ' FBN');
+
+ if (RcvPacketPoolDesc == NULL) {
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ return(NdisStatus);
+ }
+
+ RtlZeroMemory(RcvPacketPoolDesc, sizeof(NBF_POOL_LIST_DESC));
+
+ RcvPacketPoolDesc->NumElements =
+ RcvPacketPoolDesc->TotalElements = PACKET_POOL_GROW_COUNT;
+
+ NdisAllocatePacketPool ( &NdisStatus, &RcvPacketPoolDesc->PoolHandle,
+ PACKET_POOL_GROW_COUNT, sizeof (RECEIVE_PACKET_TAG));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if DBG
+ NbfPrint1 ("NbfGrowSendPacketPool: NdisInitializePacketPool failed, reason: %s.\n",
+ NbfGetNdisStatus (NdisStatus));
+#endif
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ ExFreePool (RcvPacketPoolDesc);
+ return(NdisStatus);
+ }
+ RcvPacketPoolDesc->Next = DeviceContext->ReceivePacketPoolDesc;
+ DeviceContext->ReceivePacketPoolDesc = RcvPacketPoolDesc;
+ RELEASE_SPIN_LOCK (&DeviceContext->RcvPoolListLock, oldirql);
+ NdisAllocatePacket ( &NdisStatus, NdisPacket,
+ RcvPacketPoolDesc->PoolHandle);
+
+ return(NdisStatus);
+}
+
+
+VOID
+NbfAllocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_UI_FRAME *TransportUIFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a UI frame. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - Returns a pointer to the frame, or NULL if no storage
+ can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PSEND_PACKET_TAG SendTag;
+ PTP_UI_FRAME UIFrame;
+ PNDIS_BUFFER NdisBuffer;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->UIFrameLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate UI frame: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 106,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+ UIFrame = (PTP_UI_FRAME) ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->UIFrameLength,
+ 'uFBN');
+ if (UIFrame == NULL) {
+ PANIC("NBF: Could not allocate UI frame: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 206,
+ DeviceContext->UIFrameLength,
+ UI_FRAME_RESOURCE_ID);
+ *TransportUIFrame = NULL;
+ return;
+ }
+ RtlZeroMemory (UIFrame, DeviceContext->UIFrameLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->UIFrameLength;
+ NdisStatus = NbfAllocateNdisSendPacket(DeviceContext, &NdisPacket);
+#if 0
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ break;
+ }
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (UIFrame);
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 306,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+#endif
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+
+ UIFrame->NdisPacket = NdisPacket;
+ UIFrame->DataBuffer = NULL;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_UI_FRAME;
+ SendTag->Frame = UIFrame;
+ SendTag->Owner = DeviceContext;
+
+ //
+ // Make the packet header known to the packet descriptor
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ UIFrame->Header,
+ DeviceContext->UIFrameHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 406,
+ 0,
+ UI_FRAME_RESOURCE_ID);
+ NdisFreePacket (NdisPacket);
+ ExFreePool (UIFrame);
+ *TransportUIFrame = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ ++DeviceContext->UIFrameAllocated;
+
+ *TransportUIFrame = UIFrame;
+
+} /* NbfAllocateUIFrame */
+
+
+VOID
+NbfDeallocateUIFrame(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_UI_FRAME TransportUIFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a UI frame.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ UIFrame - A pointer to the frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisPacket = TransportUIFrame->NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+
+ NdisFreePacket (NdisPacket);
+ ExFreePool (TransportUIFrame);
+ --DeviceContext->UIFrameAllocated;
+
+ DeviceContext->MemoryUsage -= DeviceContext->UIFrameLength;
+
+} /* NbfDeallocateUIFrame */
+
+
+VOID
+NbfAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a send packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PTP_PACKET Packet;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PSEND_PACKET_TAG SendTag;
+ PNDIS_BUFFER NdisBuffer;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate send packet: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 107,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ Packet = (PTP_PACKET)ExAllocatePoolWithTag (
+ NonPagedPool,
+ DeviceContext->PacketLength,
+ 'pFBN');
+ if (Packet == NULL) {
+ PANIC("NBF: Could not allocate send packet: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 207,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ *TransportSendPacket = NULL;
+ return;
+ }
+ RtlZeroMemory (Packet, DeviceContext->PacketLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->PacketLength;
+
+ NdisStatus = NbfAllocateNdisSendPacket(DeviceContext, &NdisPacket);
+#if 0
+ for (SendPacketPoolDesc = DeviceContext->SendPacketPoolDesc;
+ SendPacketPoolDesc != NULL;
+ SendPacketPoolDesc = SendPacketPoolDesc->Next) {
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ SendPacketPoolDesc->PoolHandle);
+
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ break;
+ }
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (Packet);
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 307,
+ 0,
+ PACKET_RESOURCE_ID);
+#endif
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ Packet->Header,
+ DeviceContext->PacketHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 407,
+ 0,
+ PACKET_RESOURCE_ID);
+ NdisFreePacket (NdisPacket);
+ ExFreePool (Packet);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisChainBufferAtFront (NdisPacket, NdisBuffer);
+
+ Packet->NdisPacket = NdisPacket;
+ SendTag = (PSEND_PACKET_TAG)NdisPacket->ProtocolReserved;
+ SendTag->Type = TYPE_I_FRAME;
+ SendTag->Frame = Packet;
+ SendTag->Owner = DeviceContext;
+
+ Packet->Type = NBF_PACKET_SIGNATURE;
+ Packet->Size = sizeof (TP_PACKET);
+ Packet->Provider = DeviceContext;
+ Packet->Owner = NULL; // no connection/irpsp yet.
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ Packet->PacketizeConnection = FALSE;
+ Packet->PacketNoNdisBuffer = FALSE;
+ Packet->ProviderInterlock = &DeviceContext->Interlock;
+// KeInitializeSpinLock (&Packet->Interlock);
+
+ ++DeviceContext->PacketAllocated;
+
+ *TransportSendPacket = Packet;
+
+} /* NbfAllocateSendPacket */
+
+
+VOID
+NbfDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a send packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportSendPacket - A pointer to the send packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisPacket = TransportSendPacket->NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ if (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ }
+
+ NdisFreePacket (NdisPacket);
+ ExFreePool (TransportSendPacket);
+
+ --DeviceContext->PacketAllocated;
+ DeviceContext->MemoryUsage -= DeviceContext->PacketLength;
+
+} /* NbfDeallocateSendPacket */
+
+
+VOID
+NbfAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive packet. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - Returns a pointer to the packet, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+
+ //
+ // This does not count in DeviceContext->MemoryUsage because
+ // the storage is allocated when we allocate the packet pool.
+ //
+
+ NdisStatus = NbfAllocateNdisRcvPacket(DeviceContext, &NdisPacket);
+#if 0
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->ReceivePacketPoolDesc->PoolHandle);
+#endif
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+#if 0
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 309,
+ 0,
+ RECEIVE_PACKET_RESOURCE_ID);
+#endif
+ *TransportReceivePacket = NULL;
+ return;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ++DeviceContext->ReceivePacketAllocated;
+
+ *TransportReceivePacket = NdisPacket;
+
+} /* NbfAllocateReceivePacket */
+
+
+VOID
+NbfDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceivePacket - A pointer to the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreePacket (TransportReceivePacket);
+
+ --DeviceContext->ReceivePacketAllocated;
+
+} /* NbfDeallocateReceivePacket */
+
+
+VOID
+NbfAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates storage for a receive buffer. Some initialization
+ is done here.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - Returns a pointer to the buffer, or NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBUFFER_TAG BufferTag;
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + RECEIVE_BUFFER_QUOTA(DeviceContext)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate receive buffer: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 108,
+ RECEIVE_BUFFER_QUOTA(DeviceContext),
+ RECEIVE_BUFFER_RESOURCE_ID);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ //
+ // BUGBUG: The Aligned doesn't help since the header makes it unaligned.
+ //
+
+ BufferTag = (PBUFFER_TAG)ExAllocatePoolWithTag (
+ NonPagedPoolCacheAligned,
+ DeviceContext->ReceiveBufferLength,
+ 'tFBN');
+
+ if (BufferTag == NULL) {
+ PANIC("NBF: Could not allocate receive buffer: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 208,
+ DeviceContext->ReceiveBufferLength,
+ RECEIVE_BUFFER_RESOURCE_ID);
+
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ DeviceContext->MemoryUsage += RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+ //
+ // point to the buffer for NDIS
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ BufferTag->Buffer,
+ DeviceContext->MaxReceivePacketSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ PANIC("NBF: Could not allocate receive buffer: no buffer\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 308,
+ 0,
+ RECEIVE_BUFFER_RESOURCE_ID);
+ ExFreePool (BufferTag);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag->Length = DeviceContext->MaxReceivePacketSize;
+ BufferTag->NdisBuffer = NdisBuffer;
+
+ ++DeviceContext->ReceiveBufferAllocated;
+
+ *TransportReceiveBuffer = BufferTag;
+
+} /* NbfAllocateReceiveBuffer */
+
+
+VOID
+NbfDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees storage for a receive buffer.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ TransportReceiveBuffer - A pointer to the buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisFreeBuffer (TransportReceiveBuffer->NdisBuffer);
+ ExFreePool (TransportReceiveBuffer);
+
+ --DeviceContext->ReceiveBufferAllocated;
+ DeviceContext->MemoryUsage -= RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+} /* NbfDeallocateReceiveBuffer */
+
+
+NTSTATUS
+NbfCreatePacket(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_LINK Link,
+ PTP_PACKET *Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool,
+ and prepares the MAC and DLC headers for use by the connection.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ Link - The link the packet will be sent over.
+
+ Packet - Pointer to a place where we will return a pointer to the
+ allocated packet.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET ThePacket;
+ PDLC_I_FRAME DlcHdr;
+#if DBG
+ PNBF_HDR_CONNECTION NbfHdr;
+#endif
+ typedef struct _SIXTEEN_BYTES {
+ ULONG Data[4];
+ } SIXTEEN_BYTES, *PSIXTEEN_BYTES;
+
+ ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NbfCreatePacket: Entered.\n");
+ }
+
+ //
+ // Make sure that structure packing hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTION) == 14);
+
+#if defined(NBF_UP)
+ s = DeviceContext->PacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->PacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+#endif
+
+ if (s == NULL) {
+ NbfGrowSendPacketPool(DeviceContext);
+
+#if defined(NBF_UP)
+ s = DeviceContext->PacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->PacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+#endif
+ if (s == NULL) {
+#if DBG
+ ++Link->CreatePacketFailures;
+ if ((ULONG)Link->CreatePacketFailures >= NbfCreatePacketThreshold) {
+ if (NbfPacketPanic) {
+ NbfPrint1 ("NbfCreatePacket: PANIC! no more packets in provider's pool (%d times).\n",
+ Link->CreatePacketFailures);
+ }
+ Link->CreatePacketFailures = 0;
+ }
+#endif
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->PacketExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ //
+ // NOTE: ThePacket->Action and ThePacket->Owner are filled
+ // in by the caller of this function.
+ //
+
+ ThePacket->ReferenceCount = 1; // automatic ref count of 1.
+ ThePacket->Link = NULL; // no link yet.
+ ThePacket->PacketSent = FALSE;
+ ASSERT (ThePacket->Action == PACKET_ACTION_IRP_SP);
+ ASSERT (ThePacket->PacketNoNdisBuffer == FALSE);
+ ASSERT (ThePacket->PacketizeConnection == FALSE);
+
+ //
+ // Initialize the MAC header for this packet, using the connection's
+ // link pre-built header.
+ //
+
+ if (Link->HeaderLength <= 14) {
+
+ *(PSIXTEEN_BYTES)ThePacket->Header = *(PSIXTEEN_BYTES)Link->Header;
+
+ } else {
+
+ RtlCopyMemory(
+ ThePacket->Header,
+ Link->Header,
+ Link->HeaderLength);
+
+ //
+ // Initialize the TP_FRAME_CONNECTION header for this packet.
+ //
+
+ DlcHdr = (PDLC_I_FRAME)&(ThePacket->Header[Link->HeaderLength]);
+ DlcHdr->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHdr->Ssap = DSAP_NETBIOS_OVER_LLC;
+#if DBG
+ DlcHdr->SendSeq = 0; // known values, will assist debugging.
+ DlcHdr->RcvSeq = 0; // these are assigned at shipment time.
+#endif
+
+ }
+
+
+#if DBG
+ NbfHdr = (PNBF_HDR_CONNECTION)&(ThePacket->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ NbfHdr->Command = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data1 = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2Low = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2High = 0xff; // to assist debugging-- assigned later.
+ TRANSMIT_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ RESPONSE_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ NbfHdr->DestinationSessionNumber = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->SourceSessionNumber = 0xff; // to assist debugging-- assigned later.
+#endif
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* NbfCreatePacket */
+
+
+NTSTATUS
+NbfCreateRrPacket(
+ PDEVICE_CONTEXT DeviceContext,
+ PTP_LINK Link,
+ PTP_PACKET *Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an RR packet from the device context's pool,
+ and prepares the MAC and DLC headers for use by the connection.
+ It first looks in the special RR packet pool, then in the regular
+ packet pool.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context to charge the packet to.
+
+ Link - The link the packet will be sent over.
+
+ Packet - Pointer to a place where we will return a pointer to the
+ allocated packet.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET ThePacket;
+ PDLC_I_FRAME DlcHdr;
+ NTSTATUS Status;
+#if DBG
+ PNBF_HDR_CONNECTION NbfHdr;
+#endif
+ typedef struct _SIXTEEN_BYTES {
+ ULONG Data[4];
+ } SIXTEEN_BYTES, *PSIXTEEN_BYTES;
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint0 ("NbfCreateRrPacket: Entered.\n");
+ }
+
+ //
+ // Make sure that structure packing hasn't happened.
+ //
+
+ ASSERT (sizeof(NBF_HDR_CONNECTION) == 14);
+
+#if defined(NBF_UP)
+ s = DeviceContext->RrPacketPool.Next;
+ if (s != NULL) {
+ DeviceContext->RrPacketPool.Next = s->Next;
+ }
+#else
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->RrPacketPool,
+ &DeviceContext->Interlock);
+#endif
+
+ if (s == NULL) {
+#if DBG
+ ++Link->CreatePacketFailures;
+ if ((ULONG)Link->CreatePacketFailures >= NbfCreatePacketThreshold) {
+ if (NbfPacketPanic) {
+ NbfPrint1 ("NbfCreateRrPacket: PANIC! no more packets in provider's pool (%d times).\n",
+ Link->CreatePacketFailures);
+ }
+ Link->CreatePacketFailures = 0;
+ }
+#endif
+ //
+ // Try to get one from the regular pool, and mark it so
+ // it goes back there.
+ //
+
+ Status = NbfCreatePacket(
+ DeviceContext,
+ Link,
+ Packet);
+
+ if (Status == STATUS_SUCCESS) {
+ (*Packet)->Action = PACKET_ACTION_NULL;
+ }
+ return Status;
+ }
+#if DBG
+ Link->CreatePacketFailures = 0;
+#endif
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ //
+ // NOTE: ThePacket->Owner is filled in by the caller of this
+ // function.
+ //
+
+ ThePacket->ReferenceCount = 1; // automatic ref count of 1.
+ ThePacket->Link = NULL; // no link yet.
+ ThePacket->PacketSent = FALSE;
+ ASSERT (ThePacket->Action == PACKET_ACTION_RR);
+ ASSERT (ThePacket->PacketNoNdisBuffer == FALSE);
+
+ //
+ // Initialize the MAC header for this packet, using the connection's
+ // link pre-built header.
+ //
+
+ if (Link->HeaderLength <= 14) {
+
+ *(PSIXTEEN_BYTES)ThePacket->Header = *(PSIXTEEN_BYTES)Link->Header;
+
+ } else {
+
+ RtlCopyMemory(
+ ThePacket->Header,
+ Link->Header,
+ Link->HeaderLength);
+
+ //
+ // Initialize the TP_FRAME_CONNECTION header for this packet.
+ //
+
+ DlcHdr = (PDLC_I_FRAME)&(ThePacket->Header[Link->HeaderLength]);
+ DlcHdr->Dsap = DSAP_NETBIOS_OVER_LLC;
+ DlcHdr->Ssap = DSAP_NETBIOS_OVER_LLC;
+#if DBG
+ DlcHdr->SendSeq = 0; // known values, will assist debugging.
+ DlcHdr->RcvSeq = 0; // these are assigned at shipment time.
+#endif
+
+ }
+
+
+#if DBG
+ NbfHdr = (PNBF_HDR_CONNECTION)&(ThePacket->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ NbfHdr->Command = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data1 = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2Low = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->Data2High = 0xff; // to assist debugging-- assigned later.
+ TRANSMIT_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ RESPONSE_CORR(NbfHdr) = 0xffff; // to assist debugging-- assigned later.
+ NbfHdr->DestinationSessionNumber = 0xff; // to assist debugging-- assigned later.
+ NbfHdr->SourceSessionNumber = 0xff; // to assist debugging-- assigned later.
+#endif
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* NbfCreateRrPacket */
+
+
+VOID
+NbfDestroyPacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a packet, thereby returning it to the pool. If
+ it is determined that there is at least one connection waiting for a
+ packet to become available (and it just has), then the connection is
+ removed from the device context's list and AdvanceSend is called to
+ prep the connection further.
+
+Arguments:
+
+ Packet - Pointer to a packet to be returned to the pool.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+ ULONG Flags;
+
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint2 ("NbfDestroyPacket: Entered, Packet: %lx, NdisPacket: %lx\n",
+ Packet, Packet->NdisPacket);
+ }
+
+ DeviceContext = Packet->Provider;
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ if (Packet->PacketNoNdisBuffer) {
+
+ //
+ // If the NDIS_BUFFER chain is not ours, then we can't
+ // start unchaining since that would mess up the queue;
+ // instead we just drop the rest of the chain after the
+ // header.
+ //
+
+ NdisQueryPacket (Packet->NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ ASSERT (HeaderBuffer != NULL);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisRecalculatePacketCounts (Packet->NdisPacket);
+
+ Packet->PacketNoNdisBuffer = FALSE;
+
+ } else {
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &HeaderBuffer);
+ ASSERT (HeaderBuffer != NULL);
+
+ //
+ // Return all the NDIS_BUFFERs to the system.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ }
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Packet->NdisPacket, HeaderBuffer);
+
+ }
+
+
+ //
+ // invoke the packet deallocate action specified in this packet.
+ //
+
+ switch (Packet->Action) {
+
+ case PACKET_ACTION_NULL:
+ // PANIC ("NbfDestroyPacket: no action.\n");
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_IRP_SP:
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfDestroyPacket: Packet %x deref IrpSp %x.\n", Packet, Packet->Owner);
+ }
+ NbfDereferenceSendIrp("Destroy packet", (PIO_STACK_LOCATION)(Packet->Owner), RREF_PACKET);
+ break;
+
+ case PACKET_ACTION_CONNECTION:
+ NbfDereferenceConnection ("Destroy packet", (PTP_CONNECTION)(Packet->Owner), CREF_FRAME_SEND);
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_END:
+ NbfDereferenceConnection ("SessionEnd destroyed", (PTP_CONNECTION)(Packet->Owner), CREF_FRAME_SEND);
+ NbfDereferenceConnection ("SessionEnd destroyed", (PTP_CONNECTION)(Packet->Owner), CREF_LINK);
+ Packet->Action = PACKET_ACTION_IRP_SP;
+ break;
+
+ case PACKET_ACTION_RR:
+#if defined(NBF_UP)
+ ((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next =
+ DeviceContext->RrPacketPool.Next;
+ DeviceContext->RrPacketPool.Next =
+ &((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next;
+#else
+ ExInterlockedPushEntryList (
+ &DeviceContext->RrPacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+#endif
+ return;
+
+ default:
+ IF_NBFDBG (NBF_DEBUG_RESOURCE) {
+ NbfPrint1 ("NbfDestroyPacket: invalid action (%ld).\n", Packet->Action);
+ }
+ ASSERT (FALSE);
+ }
+
+
+ //
+ // Put the packet back for use again.
+ //
+
+#if defined(NBF_UP)
+ ((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next =
+ DeviceContext->PacketPool.Next;
+ DeviceContext->PacketPool.Next =
+ &((PSINGLE_LIST_ENTRY)&Packet->Linkage)->Next;
+#else
+ ExInterlockedPushEntryList (
+ &DeviceContext->PacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+#endif
+
+ //
+ // If there is a connection waiting to ship out more packets, then
+ // wake it up and start packetizing again.
+ //
+ // We do a quick check without the lock; there is a small
+ // window where we may not take someone off, but this
+ // window exists anyway and we assume that more packets
+ // will be freed in the future.
+ //
+
+ if (IsListEmpty (&DeviceContext->PacketWaitQueue)) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (!(IsListEmpty(&DeviceContext->PacketWaitQueue))) {
+
+ //
+ // Remove a connection from the "packet starved" queue.
+ //
+
+ p = RemoveHeadList (&DeviceContext->PacketWaitQueue);
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketWaitLinkage);
+ Connection->OnPacketWaitQueue = FALSE;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If this connection is starved because it couldn't send a
+ // control packet (SI, SC, RO, RC, or DA) then start that
+ // operation up again. Otherwise, just start packetizing.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_STARVED) {
+
+ Flags = Connection->Flags & CONNECTION_FLAGS_STARVED;
+
+ if ((Flags & (Flags-1)) != 0) {
+
+ //
+ // More than one bit is on, use only the low one
+ // (an arbitrary choice).
+ //
+
+#if DBG
+ DbgPrint ("NBF: Connection %lx has two flag bits on %lx\n", Connection, Connection->Flags);
+#endif
+ Flags &= ~(Flags-1);
+
+ }
+
+ Connection->Flags &= ~Flags;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_W_PACKETIZE) ||
+ (Connection->Flags & CONNECTION_FLAGS_STARVED)) {
+
+ //
+ // We are waiting for both a specific packet and
+ // to packetize, or for two specific packets, so
+ // put ourselves back on the queue.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ if (!Connection->OnPacketWaitQueue) {
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList(
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (Flags & CONNECTION_FLAGS_SEND_SI) {
+ NbfSendSessionInitialize (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_SC) {
+ NbfSendSessionConfirm (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_RO) {
+ NbfSendReceiveOutstanding (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_RC) {
+ NbfSendReceiveContinue (Connection);
+ } else if (Flags & CONNECTION_FLAGS_SEND_SE) {
+ NbfSendSessionEnd (
+ Connection,
+ FALSE);
+ } else if (Flags & CONNECTION_FLAGS_SEND_DA) {
+ NbfSendDataAck (Connection);
+ } else {
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint0 ("NbfDestroyPacket: connection flags mismanaged.\n");
+ }
+ }
+
+ } else {
+
+ //
+ // Place the connection on the packetize queue and start
+ // packetizing the next connection to be serviced. If he
+ // is already on the packetize queue for some reason, then
+ // don't do this.
+ //
+ // We shouldn't be packetizing in this case!! - adb (7/3/91).
+ // This used to be a check that did nothing if FLAGS_PACKETIZE
+ // was set, but if that happens something is wrong...
+ //
+
+ ASSERT (Connection->Flags & CONNECTION_FLAGS_W_PACKETIZE);
+ Connection->Flags &= ~CONNECTION_FLAGS_W_PACKETIZE;
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packet available", Connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ PacketizeConnections (DeviceContext);
+
+ }
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+} /* NbfDestroyPacket */
+
+VOID NbfGrowSendPacketPool(PDEVICE_CONTEXT DeviceContext)
+{
+
+ NDIS_STATUS NdisStatus;
+ PNBF_POOL_LIST_DESC SendPacketPoolDesc;
+ PTP_PACKET TransportSendPacket;
+ UINT i;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not grow send packet pool: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 107,
+ DeviceContext->PacketLength,
+ PACKET_RESOURCE_ID);
+ return;
+ }
+
+ for (i = 0; i < PACKET_POOL_GROW_COUNT; i += 1) {
+ NbfAllocateSendPacket(DeviceContext, &TransportSendPacket);
+
+ if (TransportSendPacket != NULL) {
+ ExInterlockedPushEntryList(&(DeviceContext)->PacketPool,
+ (PSINGLE_LIST_ENTRY)&TransportSendPacket->Linkage,
+ &(DeviceContext)->Interlock);
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i == PACKET_POOL_GROW_COUNT) {
+ return;
+ }
+
+#ifdef DBG
+ DbgBreakPoint();
+#endif // DBG
+
+}
+
+#if DBG
+VOID
+NbfReferencePacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increases the number of reasons why a packet cannot be
+ discarded.
+
+Arguments:
+
+ Packet - Pointer to a packet to be referenced.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("NbfReferencePacket: Entered, NdisPacket: %lx Packet: %lx Ref Count: %lx.\n",
+ Packet->NdisPacket, Packet, Packet->ReferenceCount);
+ }
+
+ result = InterlockedIncrement (&Packet->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+} /* NbfReferencePacket */
+
+
+VOID
+NbfDereferencePacket(
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport packet by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyPacket to remove it from the system.
+
+Arguments:
+
+ Packet - Pointer to a packet object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Packet->ReferenceCount);
+
+ //
+ // If we have deleted all references to this packet, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the packet any longer.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint1 ("NbfDereferencePacket: Entered, result: %lx\n", result);
+ }
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ NbfDestroyPacket (Packet);
+ }
+
+} /* NbfDereferencePacket */
+#endif
+
+
+VOID
+NbfWaitPacket(
+ PTP_CONNECTION Connection,
+ ULONG Flags
+ )
+
+/*++
+
+Routine Description:
+
+ This routine causes the specified connection to be put into a wait
+ state pending the availability of a packet to send the specified
+ frame.
+
+Arguments:
+
+ Connection - Pointer to the connection object to be paused.
+
+ Flags - Bitflag indicating which specific frame should be resent.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint0 ("NbfWaitPacket: Entered.\n");
+ }
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Now put this connection on the device context's PacketWaitQueue,
+ // but only if it isn't already queued there. This state is managed
+ // with the OnPacketWaitQueue variable.
+ //
+ // If the connection is stopping, don't queue him either.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) ||
+ (Flags == CONNECTION_FLAGS_SEND_SE)) {
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ //
+ // Turn on the bitflag that indicates which frame we couldn't send.
+ //
+
+#if DBG
+ if (Flags == CONNECTION_FLAGS_SEND_SE) {
+ DbgPrint ("NBF: Inserting connection %lx on PacketWait for SESSION_END\n", Connection);
+ }
+#endif
+ Connection->Flags |= Flags;
+
+ if (!Connection->OnPacketWaitQueue) {
+
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList (
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+} /* NbfWaitPacket */
+
+
+#if MAGIC
+VOID
+NbfSendMagicBullet (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a magic bullet on the net that can be used to trigger
+ sniffers or other such things.
+
+Arguments:
+
+ DeviceContext - pointer to the device context
+
+ Link - This is needed to call NbfCreatePacket
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PTP_UI_FRAME RawFrame;
+ PUCHAR Header;
+ PNDIS_BUFFER NdisBuffer;
+ UINT i;
+
+ UNREFERENCED_PARAMETER (Link); // no longer needed
+
+ Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+#if DBG
+ DbgPrint ("NbfSendMagicBullet: Couldn't allocate frame!\n");
+#endif
+ return;
+ }
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPool,
+ DeviceContext->MagicBullet,
+ 32);
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ Header = (PUCHAR)&RawFrame->Header;
+
+ for (i=0;i<6;i++) {
+ Header[i] = MAGIC_BULLET_FOOD;
+ Header[i+6] = DeviceContext->LocalAddress.Address[i];
+ }
+
+ Header[12] = 0;
+ Header[13] = (UCHAR)(DeviceContext->UIFrameHeaderLength + 18);
+
+ for (i=14;i<DeviceContext->UIFrameHeaderLength;i++) {
+ Header[i] = MAGIC_BULLET_FOOD;
+ }
+
+ NdisChainBufferAtBack (RawFrame->NdisPacket, NdisBuffer);
+
+ NbfSendUIFrame (
+ DeviceContext,
+ RawFrame,
+ FALSE); // no loopback
+
+ }
+
+ return;
+
+}
+#endif
+
diff --git a/private/ntos/tdi/nbf/precomp.h b/private/ntos/tdi/nbf/precomp.h
new file mode 100644
index 000000000..4b3c3c642
--- /dev/null
+++ b/private/ntos/tdi/nbf/precomp.h
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ nbf.h
+
+Abstract:
+
+ Private include file for the NBF (NetBIOS Frames Protocol) transport
+ provider subcomponent of the NTOS project.
+
+Author:
+
+ Stephen E. Jones (stevej) 25-Oct-1989
+
+Revision History:
+
+ David Beaver (dbeaver) 24-Sep-1990
+ Remove PDI and PC586-specific support; add NDIS support
+
+--*/
+
+#include <ntddk.h>
+
+#include <windef.h>
+#include <nb30.h>
+//#include <ntiologc.h>
+//#include <ctype.h>
+//#include <assert.h>
+//#include <stdio.h>
+//#include <stdlib.h>
+//#include <memory.h>
+//#include <nt.h>
+//#include <ntrtl.h>
+//#include <nturtl.h>
+//#include <string.h>
+//#include <windows.h>
+
+#ifdef BUILD_FOR_511
+#define ExAllocatePoolWithTag(a,b,c) ExAllocatePool(a,b)
+#endif
+
+typedef struct _RTL_SPLAY_LINKS {
+ struct _RTL_SPLAY_LINKS *Parent;
+ struct _RTL_SPLAY_LINKS *LeftChild;
+ struct _RTL_SPLAY_LINKS *RightChild;
+} RTL_SPLAY_LINKS;
+typedef RTL_SPLAY_LINKS *PRTL_SPLAY_LINKS;
+
+#define RtlInitializeSplayLinks(Links) { \
+ PRTL_SPLAY_LINKS _SplayLinks; \
+ _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \
+ _SplayLinks->Parent = _SplayLinks; \
+ _SplayLinks->LeftChild = NULL; \
+ _SplayLinks->RightChild = NULL; \
+ }
+
+#define RtlLeftChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->LeftChild \
+ )
+
+#define RtlRightChild(Links) ( \
+ (PRTL_SPLAY_LINKS)(Links)->RightChild \
+ )
+
+#define RtlInsertAsLeftChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->LeftChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+#define RtlInsertAsRightChild(ParentLinks,ChildLinks) { \
+ PRTL_SPLAY_LINKS _SplayParent; \
+ PRTL_SPLAY_LINKS _SplayChild; \
+ _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \
+ _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \
+ _SplayParent->RightChild = _SplayChild; \
+ _SplayChild->Parent = _SplayParent; \
+ }
+
+
+PRTL_SPLAY_LINKS
+NTAPI
+RtlDelete (
+ PRTL_SPLAY_LINKS Links
+ );
+
+
+#include <tdikrnl.h> // Transport Driver Interface.
+
+#include <ndis.h> // Physical Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "nbfconst.h" // private NETBEUI constants.
+#include "nbfmac.h" // mac-specific definitions
+#include "nbfhdrs.h" // private NETBEUI protocol headers.
+#include "nbftypes.h" // private NETBEUI types.
+#include "nbfcnfg.h" // configuration information.
+#include "nbfprocs.h" // private NETBEUI function prototypes.
+#ifdef MEMPRINT
+#include "memprint.h" // drt's memory debug print
+#endif
+
+#if defined(NT_UP) && defined(DRIVERS_UP)
+#define NBF_UP 1
+#endif
+
+#ifndef NBF_LOCKS
+
+#if !defined(NBF_UP)
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+#define ACQUIRE_DPC_SPIN_LOCK(lock) KeAcquireSpinLockAtDpcLevel(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock) KeReleaseSpinLockFromDpcLevel(lock)
+
+#else // NBF_UP
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) ExAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) ExReleaseSpinLock(lock,irql)
+#define ACQUIRE_DPC_SPIN_LOCK(lock)
+#define RELEASE_DPC_SPIN_LOCK(lock)
+
+#endif
+
+#if DBG
+
+#define ACQUIRE_C_SPIN_LOCK(lock,irql) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ KeAcquireSpinLock(lock,irql); \
+ _conn->LockAcquired = TRUE; \
+ strncpy(_conn->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastAcquireLine = __LINE__; \
+}
+#define RELEASE_C_SPIN_LOCK(lock,irql) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ _conn->LockAcquired = FALSE; \
+ strncpy(_conn->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastReleaseLine = __LINE__; \
+ KeReleaseSpinLock(lock,irql); \
+}
+
+#define ACQUIRE_DPC_C_SPIN_LOCK(lock) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ KeAcquireSpinLockAtDpcLevel(lock); \
+ _conn->LockAcquired = TRUE; \
+ strncpy(_conn->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastAcquireLine = __LINE__; \
+}
+#define RELEASE_DPC_C_SPIN_LOCK(lock) { \
+ PTP_CONNECTION _conn = CONTAINING_RECORD(lock,TP_CONNECTION,SpinLock); \
+ _conn->LockAcquired = FALSE; \
+ strncpy(_conn->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ _conn->LastReleaseLine = __LINE__; \
+ KeReleaseSpinLockFromDpcLevel(lock); \
+}
+
+#else // DBG
+
+#define ACQUIRE_C_SPIN_LOCK(lock,irql) ACQUIRE_SPIN_LOCK(lock,irql)
+#define RELEASE_C_SPIN_LOCK(lock,irql) RELEASE_SPIN_LOCK(lock,irql)
+#define ACQUIRE_DPC_C_SPIN_LOCK(lock) ACQUIRE_DPC_SPIN_LOCK(lock)
+#define RELEASE_DPC_C_SPIN_LOCK(lock) RELEASE_DPC_SPIN_LOCK(lock)
+
+#endif // DBG
+
+#define ENTER_NBF
+#define LEAVE_NBF
+
+#else
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ );
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) \
+ NbfAcquireSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+#define RELEASE_SPIN_LOCK(lock,irql) \
+ NbfReleaseSpinLock( lock, irql, #lock, __FILE__, __LINE__ )
+
+#define ACQUIRE_DPC_SPIN_LOCK(lock) \
+ { \
+ KIRQL OldIrql; \
+ NbfAcquireSpinLock( lock, &OldIrql, #lock, __FILE__, __LINE__ ); \
+ }
+#define RELEASE_DPC_SPIN_LOCK(lock) \
+ NbfReleaseSpinLock( lock, DISPATCH_LEVEL, #lock, __FILE__, __LINE__ )
+
+#define ENTER_NBF \
+ NbfAcquireSpinLock( (PKSPIN_LOCK)NULL, (PKIRQL)NULL, "(Global)", __FILE__, __LINE__ )
+#define LEAVE_NBF \
+ NbfReleaseSpinLock( (PKSPIN_LOCK)NULL, (KIRQL)-1, "(Global)", __FILE__, __LINE__ )
+
+#endif
+
diff --git a/private/ntos/tdi/nbf/rcv.c b/private/ntos/tdi/nbf/rcv.c
new file mode 100644
index 000000000..8fdc87af9
--- /dev/null
+++ b/private/ntos/tdi/nbf/rcv.c
@@ -0,0 +1,309 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ rcv.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceive
+ o TdiReceiveDatagram
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiReceive(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceive request for the transport provider.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+
+ //
+ // verify that the operation is taking place on a connection. At the same
+ // time we do this, we reference the connection. This ensures it does not
+ // get removed out from under us. Note also that we do the connection
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // Check that this is really a connection.
+ //
+
+ if ((connection->Size != sizeof (TP_CONNECTION)) ||
+ (connection->Type != NBF_CONNECTION_SIGNATURE)) {
+#if DBG
+ NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ //
+ // Initialize bytes transferred here.
+ //
+
+ Irp->IoStatus.Information = 0; // reset byte transfer count.
+
+ // This reference is removed by NbfDestroyRequest.
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ Irp->IoStatus.Status = connection->Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ status = STATUS_PENDING;
+
+ } else {
+ KIRQL cancelIrql;
+
+ //
+ // Once the reference is in, LinkSpinLock will be valid.
+ //
+
+ NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ IRP_RECEIVE_IRP(irpSp) = Irp;
+ IRP_RECEIVE_REFCOUNT(irpSp) = 1;
+
+#if DBG
+ NbfReceives[NbfReceivesNext].Irp = Irp;
+ NbfReceives[NbfReceivesNext].Request = NULL;
+ NbfReceives[NbfReceivesNext].Connection = (PVOID)connection;
+ NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // If this IRP has been cancelled, complete it now.
+ //
+
+ if (Irp->Cancel) {
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0;
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // It is safe to do this with locks held.
+ //
+ NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0);
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ } else {
+
+ //
+ // Insert onto the receive queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NbfCancelReceive);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at dpc level when it was acquired, we don't
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // This call releases the link spinlock, and references the
+ // connection first if it needs to access it after
+ // releasing the lock.
+ //
+
+ AwakenReceive (connection); // awaken if sleeping.
+
+ }
+
+ status = STATUS_PENDING;
+
+ }
+
+ KeLowerIrql (oldirql);
+
+ return status;
+} /* TdiReceive */
+
+
+NTSTATUS
+NbfTdiReceiveDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PIO_STACK_LOCATION irpSp;
+ KIRQL cancelIrql;
+
+ //
+ // verify that the operation is taking place on an address. At the same
+ // time we do this, we reference the address. This ensures it does not
+ // get removed out from under us. Note also that we do the address
+ // lookup within a try/except clause, thus protecting ourselves against
+ // really bogus handles
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject (addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+#if DBG
+ if (((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength > 0) {
+ ASSERT (Irp->MdlAddress != NULL);
+ }
+#endif
+
+ address = addressFile->Address;
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
+ STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ IoSetCancelRoutine(Irp, NbfCancelReceiveDatagram);
+ NbfReferenceAddress ("Receive datagram", address, AREF_REQUEST);
+ InsertTailList (&addressFile->ReceiveDatagramQueue,&Irp->Tail.Overlay.ListEntry);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelIrql);
+ }
+
+ }
+
+ NbfDereferenceAddress ("Temp rcv datagram", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* TdiReceiveDatagram */
+
diff --git a/private/ntos/tdi/nbf/rcveng.c b/private/ntos/tdi/nbf/rcveng.c
new file mode 100644
index 000000000..f3b3eab33
--- /dev/null
+++ b/private/ntos/tdi/nbf/rcveng.c
@@ -0,0 +1,823 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ rcveng.c
+
+Abstract:
+
+ This module contains code that implements the receive engine for the
+ Jetbeui transport provider. This code is responsible for the following
+ basic activities:
+
+ 1. Transitioning a TdiReceive request from an inactive state on the
+ connection's ReceiveQueue to the active state on that connection
+ (ActivateReceive).
+
+ 2. Advancing the status of the active receive request by copying 0 or
+ more bytes of data from an incoming DATA_FIRST_MIDDLE or DATA_ONLY_LAST
+ NBF frame.
+
+ 3. Completing receive requests.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+VOID
+ActivateReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine activates the next TdiReceive request on the specified
+ connection object if there is no active request on that connection
+ already. This allows the request to accept data on the connection.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ActivateReceive: Entered.\n");
+ }
+
+ //
+ // The ACTIVE_RECEIVE bitflag will be set on the connection if
+ // the receive-fields in the CONNECTION object are valid. If
+ // this flag is cleared, then we try to make the next TdiReceive
+ // request in the ReceiveQueue the active request.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (!(Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE)) {
+ if (!IsListEmpty (&Connection->ReceiveQueue)) {
+
+ //
+ // Found a receive, so make it the active one.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ Irp = CONTAINING_RECORD(
+ Connection->ReceiveQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->MessageInitAccepted = 0;
+ Connection->CurrentReceiveIrp = Irp;
+ Connection->CurrentReceiveSynchronous =
+ Connection->Provider->MacInfo.SingleReceive;
+ Connection->CurrentReceiveMdl = Irp->MdlAddress;
+ Connection->ReceiveLength = IRP_RECEIVE_LENGTH(IoGetCurrentIrpStackLocation(Irp));
+ Connection->ReceiveByteOffset = 0;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" ActivateReceive: Exiting.\n");
+ }
+} /* ActivateReceive */
+
+
+VOID
+AwakenReceive(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to reactivate a sleeping connection with the
+ RECEIVE_WAKEUP bitflag set because data arrived for which no receive
+ was available. The caller has made a receive available at the connection,
+ so here we activate the next receive, and send the appropriate protocol
+ to restart the message at the first byte offset past the one received
+ by the last receive.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL. IT IS CALLED
+ WITH CONNECTION->LINKSPINLOCK HELD.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" AwakenReceive: Entered.\n");
+ }
+
+ //
+ // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_RECEIVE_WAKEUP) {
+ if (Connection->ReceiveQueue.Flink != &Connection->ReceiveQueue) {
+ Connection->Flags &= ~CONNECTION_FLAGS_RECEIVE_WAKEUP;
+
+ //
+ // Found a receive, so turn off the wakeup flag, activate
+ // the next receive, and send the protocol.
+ //
+
+ //
+ // Quick fix: So there is no window where a receive
+ // is active but the bit is not on (otherwise we could
+ // accept whatever data happens to show up in the
+ // interim).
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH;
+
+ NbfReferenceConnection ("temp AwakenReceive", Connection, CREF_BY_ID); // release lookup hold.
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ActivateReceive (Connection);
+
+ //
+ // BUGBUG: What if this fails? The successful queueing
+ // of a RCV_O should cause ActivateReceive to be called.
+ //
+ // NOTE: Send this after ActivateReceive, since that
+ // is where the MessageBytesAcked/Received variables
+ // are initialized.
+ //
+
+ NbfSendReceiveOutstanding (Connection);
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" AwakenReceive: Returned from NbfSendReceive.\n");
+ }
+
+ NbfDereferenceConnection("temp AwakenReceive", Connection, CREF_BY_ID);
+ return;
+ }
+ }
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+} /* AwakenReceive */
+
+
+VOID
+CompleteReceive(
+ PTP_CONNECTION Connection,
+ BOOLEAN EndOfMessage,
+ IN ULONG BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ProcessIncomingData when the current receive
+ must be completed. Depending on whether the current frame being
+ processed is a DATA_FIRST_MIDDLE or DATA_ONLY_LAST, and also whether
+ all of the data was processed, the EndOfMessage flag will be set accordingly
+ by the caller to indicate that a message boundary was received.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ EndOfMessage - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
+
+ BytesTransferred - Number of bytes copied in this receive.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PIRP Irp;
+ ULONG BytesReceived;
+ PIO_STACK_LOCATION IrpSp;
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" CompleteReceive: Entered.\n");
+ }
+
+
+ if (Connection->SpecialReceiveIrp) {
+
+ PIRP Irp = Connection->SpecialReceiveIrp;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = BytesTransferred;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->SpecialReceiveIrp = FALSE;
+
+ ++Connection->ReceivedTsdus;
+
+ ExInterlockedInsertHeadList(
+ &Connection->Provider->IrpCompletionQueue,
+ &Irp->Tail.Overlay.ListEntry,
+ Connection->ProviderInterlock);
+
+ //
+ // NOTE: NbfAcknowledgeDataOnlyLast releases
+ // the connection spinlock.
+ //
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ } else {
+ KIRQL cancelIrql;
+
+ if (EndOfMessage) {
+
+ //
+ // The messages has been completely received, ack it.
+ //
+ // We set DEFERRED_ACK and DEFERRED_NOT_Q here, which
+ // will cause an ack to be piggybacked if any data is
+ // sent during the call to CompleteReceive. If this
+ // does not happen, then we will call AcknowledgeDataOnlyLast
+ // which will will send a DATA ACK or queue a request for
+ // a piggyback ack. We do this *after* calling CompleteReceive
+ // so we know that we will complete the receive back to
+ // the client before we ack the data, to prevent the
+ // next receive from being sent before this one is
+ // completed.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Connection->DeferredFlags |=
+ (CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+ Connection->Flags |= CONNECTION_FLAGS_RC_PENDING;
+
+ } else {
+
+ //
+ // Send a receive outstanding (even though we don't
+ // know that we have a receive) to get him to
+ // reframe his send. Pre-2.0 clients require a
+ // no receive before the receive outstanding.
+ //
+ // BUGBUG: what if this fails (due to no send packets)?
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_VERSION2) == 0) {
+ NbfSendNoReceive (Connection);
+ }
+ NbfSendReceiveOutstanding (Connection);
+
+ //
+ // If there is a receive posted, make it current and
+ // send a receive outstanding.
+ //
+ // BUGBUG: need general function for this, which sends
+ // NO_RECEIVE if appropriate.
+ //
+
+ ActivateReceive (Connection);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveBytesUnaccepted) {
+ if (Connection->MessageBytesReceived >= Connection->ReceiveBytesUnaccepted) {
+ Connection->ReceiveBytesUnaccepted = 0;
+ } else {
+ Connection->ReceiveBytesUnaccepted -= Connection->MessageBytesReceived;
+ }
+ }
+
+ //
+ // NOTE: The connection lock is held here.
+ //
+
+ if (IsListEmpty (&Connection->ReceiveQueue)) {
+
+ ASSERT ((Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) != 0);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at DPC level when it was acquired, there is no
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ } else {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ BytesReceived = Connection->MessageBytesReceived;
+
+
+ //
+ // Complete the TdiReceive request at the head of the
+ // connection's ReceiveQueue.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_RCVENG) {
+ NbfPrint0 (" CompleteReceive: Normal IRP is present.\n");
+ }
+
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ IoSetCancelRoutine(Irp, NULL);
+
+ //
+ // Release the cancel spinlock out of order. Since we were
+ // already at DPC level when it was acquired, there is no
+ // need to swap irqls.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // If this request should generate no back traffic, then
+ // disable piggyback acks for it.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ if (IRP_RECEIVE_FLAGS(IrpSp) & TDI_RECEIVE_NO_RESPONSE_EXP) {
+ Connection->CurrentReceiveAckQueueable = FALSE;
+ }
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status =
+ EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+ ++Connection->ReceivedTsdus;
+
+ //
+ // This can be called with locks held.
+ //
+ NbfCompleteReceiveIrp(
+ Irp,
+ EndOfMessage ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ BytesReceived);
+
+ }
+
+
+ //
+ // If NOT_Q is still set, that means that the deferred ack was
+ // not satisfied by anything resulting from the call to
+ // CompleteReceive, so we need to ack or queue an ack here.
+ //
+
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) != 0) {
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ //
+ // NOTE: NbfAcknowledgeDataOnlyLast releases
+ // the connection spinlock.
+ //
+
+ NbfAcknowledgeDataOnlyLast(
+ Connection,
+ Connection->MessageBytesReceived
+ );
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ }
+
+} /* CompleteReceive */
+
+
+VOID
+NbfCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The receive is found on the connection's receive queue; if it
+ is the current request it is cancelled and the connection
+ goes into "cancelled receive" mode, otherwise it is cancelled
+ silently.
+
+ In "cancelled receive" mode the connection makes it appear to
+ the remote the data is being received, but in fact it is not
+ indicated to the transport or buffered on our end
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PIRP ReceiveIrp;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ ULONG BytesReceived;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_RECEIVE));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+ //
+ // See if this is the IRP for the current receive request.
+ //
+
+ ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
+
+ BytesReceived = Connection->MessageBytesReceived;
+
+ p = Connection->ReceiveQueue.Flink;
+
+ //
+ // If there is a receive active and it is not a special
+ // IRP, then see if this is it.
+ //
+
+ if (((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) &&
+ (!Connection->SpecialReceiveIrp)) {
+
+ ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ if (ReceiveIrp == Irp) {
+
+ //
+ // yes, it is the active receive. Turn on the RCV_CANCELLED
+ // bit instructing the connection to drop the rest of the
+ // data received (until the DOL comes in).
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_RCV_CANCELLED;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ (VOID)RemoveHeadList (&Connection->ReceiveQueue);
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = ReceiveIrp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled in-progress receive %lx on %lx\n",
+ Irp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
+ return;
+
+ }
+
+ }
+
+
+ //
+ // If we fall through to here, the IRP was not the active receive.
+ // Scan through the list, looking for this IRP.
+ //
+
+ Found = FALSE;
+
+ while (p != &Connection->ReceiveQueue) {
+
+ ReceiveIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (ReceiveIrp == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+
+#if DBG
+ NbfCompletedReceives[NbfCompletedReceivesNext].Irp = ReceiveIrp;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
+ NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
+ {
+ ULONG i,j,k;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = ReceiveIrp->MdlAddress;
+
+ if (BytesReceived > TRACK_TDI_CAPTURE) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = 0xFF;
+ } else {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)BytesReceived;
+ }
+
+ i = 1;
+ while (i<TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ va = MmGetSystemAddressForMdl (mdl);
+ j = MmGetMdlByteCount (mdl);
+
+ for (i=i,k=0;i<TRACK_TDI_CAPTURE&k<j;i++,k++) {
+ NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled receive %lx on %lx\n",
+ ReceiveIrp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteReceiveIrp (ReceiveIrp, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel receive %lx on %lx, not found\n",
+ Irp, Connection);
+#endif
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+}
+
+
+VOID
+NbfCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The receive is looked for on the address file's
+ receive datagram queue; if it is found it is cancelled.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_RECEIVE_DATAGRAM));
+
+ AddressFile = IrpSp->FileObject->FsContext;
+ Address = AddressFile->Address;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the address file is still around (although it may be in
+ // the process of being torn down). See if the IRP is on the list.
+ //
+
+ Found = FALSE;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry) == Irp) {
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+#if DBG
+ DbgPrint("NBF: Canceled receive datagram %lx on %lx\n",
+ Irp, AddressFile);
+#endif
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ NbfDereferenceAddress ("Receive DG cancelled", Address, AREF_REQUEST);
+
+ } else {
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel receive datagram %lx on %lx, not found\n",
+ Irp, AddressFile);
+#endif
+
+ }
+
+} /* NbfCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/nbf/request.c b/private/ntos/tdi/nbf/request.c
new file mode 100644
index 000000000..5547e31ee
--- /dev/null
+++ b/private/ntos/tdi/nbf/request.c
@@ -0,0 +1,1376 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This module contains code which implements the TP_REQUEST object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport request objects.
+
+Author:
+
+ David Beaver (dbeaver) 1 July 1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+
+//
+// External variables
+//
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+//
+// Imported routines
+//
+VOID
+NbfNoteNewConnection(
+ PTP_CONNECTION Connection,
+ PDEVICE_CONTEXT DeviceContext
+ );
+#endif // RASAUTODIAL
+
+
+VOID
+NbfTdiRequestTimeoutHandler(
+ 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 a request
+ such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc.,
+ encounters a timeout. This routine cleans up the activity and cancels it.
+
+Arguments:
+
+ Dpc - Pointer to a system DPC object.
+
+ DeferredContext - Pointer to the TP_REQUEST block representing the
+ request that has timed out.
+
+ SystemArgument1 - Not used.
+
+ SystemArgument2 - Not used.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+ PTP_CONNECTION Connection;
+#if DBG
+ LARGE_INTEGER time, difference;
+#endif
+ PIO_STACK_LOCATION IrpSp;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PDEVICE_CONTEXT DeviceContext;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ Request = (PTP_REQUEST)DeferredContext;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("RequestTimeoutHandler: Entered, Request %lx\n", Request);
+ }
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+
+#if DBG
+ KeQuerySystemTime (&time);
+ difference.QuadPart = time.QuadPart - (Request->Time).QuadPart;
+ NbfPrint1 ("RequestTimeoutHandler: Request timed out, queued for %ld seconds\n",
+ difference.LowPart / SECONDS);
+#endif
+
+ //
+ // find reason for timeout
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) {
+ switch (IrpSp->MinorFunction) {
+
+ //
+ // none of these should time out.
+ //
+
+ case TDI_SEND:
+ case TDI_ACCEPT:
+ case TDI_SET_INFORMATION:
+ case TDI_SET_EVENT_HANDLER:
+ case TDI_SEND_DATAGRAM:
+ case TDI_RECEIVE_DATAGRAM:
+ case TDI_RECEIVE:
+
+#if DBG
+ NbfPrint1 ("RequestTimeoutHandler: Request: %lx Timed out, and shouldn't have!\n",
+ Request);
+#endif
+ ASSERT (FALSE);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
+ break;
+
+
+ case TDI_LISTEN:
+ case TDI_CONNECT:
+
+#if DBG
+ NbfPrint2 ("RequestTimeoutHandler: %s Failed, Request: %lx\n",
+ IrpSp->MinorFunction == TDI_LISTEN ?
+ "Listen" :
+ IrpSp->MinorFunction == TDI_CONNECT ?
+ "Connect" : "Disconnect",
+ Request);
+#endif
+ Connection = (PTP_CONNECTION)(Request->Context);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // Since these requests are part of the connection
+ // itself, we just stop the connection and the
+ // request will get torn down then. If we get the
+ // situation where the request times out before
+ // it is queued to the connection, then the code
+ // that is about to queue it will check the STOPPING
+ // flag and complete it then.
+ //
+ // Don't stop the connection if an automatic connection
+ // is in progress.
+ //
+
+#if DBG
+ DbgPrint("RequestTimeoutHandler: AUTOCONNECTING=0x%x\n", Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING);
+#endif
+ if (!(Connection->Flags2 & CONNECTION_FLAGS2_AUTOCONNECTING))
+ NbfStopConnection (Connection, STATUS_IO_TIMEOUT);
+ break;
+
+ case TDI_DISCONNECT:
+
+ //
+ // We don't create requests for TDI_DISCONNECT any more.
+ //
+
+ ASSERT(FALSE);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+
+ DeviceContext = (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject;
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
+
+ IF_NBFDBG (NBF_DEBUG_DEVCTX) {
+ NbfPrint1 ("RequestTimeout: %lx:\n", DeviceContext);
+ }
+
+ //
+ // Determine if the request is done, or if we should
+ // requeue it.
+ //
+
+ --Request->Retries;
+
+ if (Request->Retries > 0) {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // Send another packet out, and restart the timer.
+ //
+
+ if (query->QueryType == TDI_QUERY_FIND_NAME) {
+
+ NbfSendQueryFindName (
+ DeviceContext,
+ Request);
+
+ } else if (query->QueryType == TDI_QUERY_ADAPTER_STATUS) {
+
+ PUCHAR SingleSR;
+ UINT SingleSRLength;
+
+ //
+ // Send the STATUS_QUERY frames out as
+ // single-route source routing.
+ //
+ // BUGBUG: On a second status query this should
+ // really be sent directed, but currently we
+ // don't record the address anywhere.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SingleSR,
+ &SingleSRLength);
+
+ NbfSendStatusQuery (
+ DeviceContext,
+ Request,
+ &DeviceContext->NetBIOSAddress,
+ SingleSR,
+ SingleSRLength);
+
+ } else {
+
+ ASSERT (FALSE);
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ //
+ // That's it, we retried enough, complete it.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+ RemoveEntryList (&Request->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (Request->BytesWritten > 0) {
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, Request->BytesWritten);
+
+ } else {
+
+ NbfCompleteRequest (Request, STATUS_IO_TIMEOUT, Request->BytesWritten);
+
+ }
+
+
+ }
+
+ break;
+
+ default:
+#if DBG
+ NbfPrint2 ("RequestTimeoutHandler: Unknown Request Timed out, Request: %lx Type: %x\n",
+ Request, IrpSp->MinorFunction);
+#endif
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ break;
+
+ } // end of switch
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+ NbfDereferenceRequest ("Timeout", Request, RREF_TIMER); // for the timeout
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ NbfDereferenceRequest ("Timeout: stopping", Request, RREF_TIMER); // for the timeout
+
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* RequestTimeoutHandler */
+
+
+VOID
+NbfAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a request packet from nonpaged pool and initializes
+ it to a known state.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a place where this routine will return
+ a pointer to a transport request structure. It returns NULL if no
+ storage can be allocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PTP_REQUEST Request;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("NBF: Could not allocate request: limit\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_LIMIT,
+ 104,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ *TransportRequest = NULL;
+ return;
+ }
+
+ Request = (PTP_REQUEST)ExAllocatePoolWithTag (
+ NonPagedPool,
+ sizeof (TP_REQUEST),
+ 'rFBN');
+ if (Request == NULL) {
+ PANIC("NBF: Could not allocate request: no pool\n");
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 204,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ *TransportRequest = NULL;
+ return;
+ }
+ RtlZeroMemory (Request, sizeof(TP_REQUEST));
+
+ DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
+ ++DeviceContext->RequestAllocated;
+
+ Request->Type = NBF_REQUEST_SIGNATURE;
+ Request->Size = sizeof (TP_REQUEST);
+
+ Request->ResponseBuffer = NULL;
+
+ Request->Provider = DeviceContext;
+ Request->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Request->SpinLock);
+ KeInitializeDpc (&Request->Dpc, NbfTdiRequestTimeoutHandler, (PVOID)Request);
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+
+ *TransportRequest = Request;
+
+} /* NbfAllocateRequest */
+
+
+VOID
+NbfDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a request packet.
+
+ NOTE: This routine is called with the device context spinlock
+ held, or at such a time as synchronization is unnecessary.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ TransportRequest - Pointer to a transport request structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ExFreePool (TransportRequest);
+ --DeviceContext->RequestAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_REQUEST);
+
+} /* NbfDeallocateRequest */
+
+
+NTSTATUS
+NbfCreateRequest(
+ IN PIRP Irp,
+ IN PVOID Context,
+ IN ULONG Flags,
+ IN PMDL Buffer2,
+ IN ULONG Buffer2Length,
+ IN LARGE_INTEGER Timeout,
+ OUT PTP_REQUEST * TpRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport request and associates it with the
+ specified IRP, context, and queue. All major requests, including
+ TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests,
+ are composed in this manner.
+
+Arguments:
+
+ Irp - Pointer to an IRP which was received by the transport for this
+ request.
+
+ Context - Pointer to anything to associate this request with. This
+ value is not interpreted except at request cancelation time.
+
+ Flags - A set of bitflags indicating the disposition of this request.
+
+ Timeout - Timeout value (if non-zero) to start a timer for this request.
+ If zero, then no timer is activated for the request.
+
+ TpRequest - If the function returns STATUS_SUCCESS, this will return
+ pointer to the TP_REQUEST structure allocated.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PIO_STACK_LOCATION irpSp;
+#if DBG
+ LARGE_INTEGER Time;
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint0 ("NbfCreateRequest: Entered.\n");
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+ DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
+
+#if DBG
+ if (!MmIsNonPagedSystemAddressValid (DeviceContext->RequestPool.Flink)) {
+ NbfPrint2 ("NbfCreateRequest: RequestList hosed: %lx DeviceContext: %lx\n",
+ &DeviceContext->RequestPool, DeviceContext);
+ }
+#endif
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->RequestPool);
+ if (p == &DeviceContext->RequestPool) {
+
+ if ((DeviceContext->RequestMaxAllocated == 0) ||
+ (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
+
+ NbfAllocateRequest (DeviceContext, &Request);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Allocated request at %lx\n", Request);
+ }
+
+ } else {
+
+ NbfWriteResourceErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_RESOURCE_SPECIFIC,
+ 404,
+ sizeof(TP_REQUEST),
+ REQUEST_RESOURCE_ID);
+ Request = NULL;
+
+ }
+
+ if (Request == NULL) {
+ ++DeviceContext->RequestExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("NbfCreateConnection: Could not allocate request object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ }
+
+ ++DeviceContext->RequestInUse;
+ if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) {
+ ++DeviceContext->RequestMaxInUse;
+ }
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ //
+ // fill out the request.
+ //
+
+ // Request->Provider = DeviceContext;
+ Request->IoRequestPacket = Irp;
+ Request->Buffer2 = Buffer2;
+ Request->Buffer2Length = Buffer2Length;
+ Request->Flags = Flags;
+ Request->Context = Context;
+ Request->ReferenceCount = 1; // initialize reference count.
+
+#if DBG
+ {
+ UINT Counter;
+ for (Counter = 0; Counter < NUMBER_OF_RREFS; Counter++) {
+ Request->RefTypes[Counter] = 0;
+ }
+
+ // This reference is removed by NbfCompleteRequest
+
+ Request->RefTypes[RREF_CREATION] = 1;
+ }
+#endif
+
+#if DBG
+ Request->Completed = FALSE;
+ Request->Destroyed = FALSE;
+ Request->TotalReferences = 0;
+ Request->TotalDereferences = 0;
+ Request->NextRefLoc = 0;
+ ExInterlockedInsertHeadList (&NbfGlobalRequestList, &Request->GlobalLinkage, &NbfGlobalInterlock);
+ StoreRequestHistory (Request, TRUE);
+#endif
+
+#if DBG
+ KeQuerySystemTime (&Time); // ugly, but effective
+ Request->Time.LowPart = Time.LowPart;
+ Request->Time.HighPart = Time.HighPart;
+#endif
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ if (Irp->MdlAddress != NULL) {
+ PMDL mdl;
+ NbfPrint2 ("NbfCreateRequest: Map request %lx Irp %lx MdlChain \n",
+ Request, Request->IoRequestPacket);
+ mdl = Request->Buffer2;
+ while (mdl != NULL) {
+ NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
+ mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
+ mdl->MdlFlags);
+ mdl = mdl->Next;
+ }
+ }
+ }
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint3 ("NbfCreateRequest: Request %lx Buffer2: %lx Irp: %lx\n", Request,
+ Buffer2, Irp);
+ }
+
+ if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
+
+ // no timeout
+ } else {
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint3 ("NbfCreateRequest: Starting timer %lx%lx Flags %lx\n",
+ Timeout.HighPart, Timeout.LowPart, Request->Flags);
+ }
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ NbfReferenceRequest ("Create: timer", Request, RREF_TIMER); // one for the timer
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+ }
+
+ *TpRequest = Request;
+
+ return STATUS_SUCCESS;
+} /* NbfCreateRequest */
+
+
+VOID
+NbfDestroyRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a request block to the free pool.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block to return to the free pool.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint0 ("NbfDestroyRequest: Entered.\n");
+ }
+
+#if DBG
+ if (Request->Destroyed) {
+ NbfPrint1 ("attempt to destroy already-destroyed request 0x%lx\n", Request);
+ DbgBreakPoint ();
+ }
+ Request->Destroyed = TRUE;
+#if 1
+ ACQUIRE_SPIN_LOCK (&NbfGlobalInterlock, &oldirql);
+ RemoveEntryList (&Request->GlobalLinkage);
+ RELEASE_SPIN_LOCK (&NbfGlobalInterlock, oldirql);
+#else
+ ExInterlockedRemoveHeadList (Request->GlobalLinkage.Blink, &NbfGlobalInterlock);
+#endif
+#endif
+ ASSERT(Request->Completed);
+
+ //
+ // Return the request to the caller with whatever status is in the IRP.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ NbfPrint1 ("NbfCompleteRequest: Completing IRP: %lx\n",
+ Request->IoRequestPacket);
+ }
+
+ //
+ // Now dereference the owner of this request so that we are safe when
+ // we finally tear down the {connection, address}. The problem we're
+ // facing here is that we can't allow the user to assume semantics;
+ // the end of life for a connection must truly be the real end of life.
+ // for that to occur, we reference the owning object when the request is
+ // created and we dereference it just before we return it to the pool.
+ //
+
+ switch (Request->Owner) {
+ case ConnectionType:
+ NbfDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context), CREF_REQUEST);
+ break;
+
+#if DBG
+ case AddressType:
+ ASSERT (FALSE);
+ NbfDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context), AREF_REQUEST);
+ break;
+#endif
+
+ case DeviceContextType:
+ NbfDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context), DCREF_REQUEST);
+ break;
+ }
+
+ //
+ // Unmap a possibly mapped buffer. We've only mapped the buffer if the
+ // Irp Major function is not method 0. (of 0, 1, 2, and 3.)
+ //
+
+ IF_NBFDBG (NBF_DEBUG_IRP) {
+ {
+ PMDL mdl;
+ NbfPrint2 ("NbfDestroyRequest: Unmap request %lx Irp %lx MdlChain \n",
+ Request, Request->IoRequestPacket);
+ mdl = Request->Buffer2;
+ while (mdl != NULL) {
+ NbfPrint4 ("Mdl %lx Va %lx StartVa %lx Flags %x\n",
+ mdl, MmGetSystemAddressForMdl(mdl), MmGetMdlVirtualAddress(mdl),
+ mdl->MdlFlags);
+ mdl = mdl->Next;
+ }
+ }
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ DeviceContext = Request->Provider;
+
+ LEAVE_NBF;
+ IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
+ ENTER_NBF;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ //
+ // Put the request back on the free list. NOTE: we have the
+ // lock held here.
+ //
+
+
+ DeviceContext->RequestTotal += DeviceContext->RequestInUse;
+ ++DeviceContext->RequestSamples;
+ --DeviceContext->RequestInUse;
+
+ if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) >
+ DeviceContext->RequestInitAllocated) {
+ NbfDeallocateRequest (DeviceContext, Request);
+ IF_NBFDBG (NBF_DEBUG_DYNAMIC) {
+ NbfPrint1 ("NBF: Deallocated request at %lx\n", Request);
+ }
+ } else {
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+} /* NbfDestroyRequest */
+
+
+#if DBG
+VOID
+NbfRefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport request.
+
+Arguments:
+
+ Request - Pointer to a TP_REQUEST block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefRequest: Entered, ReferenceCount: %x\n",
+ Request->ReferenceCount);
+ }
+
+#if DBG
+ StoreRequestHistory( Request, TRUE );
+#endif
+
+ ASSERT (Request->ReferenceCount > 0);
+
+ result = InterlockedIncrement (&Request->ReferenceCount);
+
+} /* NbfRefRequest */
+#endif
+
+
+VOID
+NbfDerefRequest(
+ IN PTP_REQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport request by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbfDestroyRequest to remove it from the system.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefRequest: Entered, ReferenceCount: %x\n",
+ Request->ReferenceCount);
+ }
+
+#if DBG
+ StoreRequestHistory( Request, FALSE );
+#endif
+
+ result = InterlockedDecrement (&Request->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+ NbfDestroyRequest (Request);
+ }
+
+} /* NbfDerefRequest */
+
+
+VOID
+NbfCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport request object, completing the I/O,
+ stopping the timeout, and freeing up the request object itself.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ NTSTATUS FinalStatus = Status;
+ NTSTATUS CopyStatus;
+ BOOLEAN TimerWasSet;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteRequest: Entered Request %lx, Request->Flags %lx\n",
+ Request, Request->Flags);
+ }
+
+#if DBG
+ if (Request->Completed) {
+ NbfPrint1 ("attempt to completed already-completed request 0x%lx\n", Request);
+ DbgBreakPoint ();
+ }
+ Request->Completed = TRUE;
+#endif
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+ Request->Flags |= REQUEST_FLAGS_STOPPING;
+
+ //
+ // Cancel the pending timeout on this request. Not all requests
+ // have their timer set. If this request has the TIMER bit set,
+ // then the timer needs to be cancelled. If it cannot be cancelled,
+ // then the timer routine will be run, so we just return and let
+ // the timer routine worry about cleaning up this request.
+ //
+
+ if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) {
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ TimerWasSet = KeCancelTimer (&Request->Timer);
+
+ if (TimerWasSet) {
+ NbfDereferenceRequest ("Complete: stop timer", Request, RREF_TIMER);
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfCompleteRequest: Canceled timer: %lx.\n", &Request->Timer);
+ }
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Irp = Request->IoRequestPacket;
+
+#ifdef RASAUTODIAL
+ //
+ // If this is a connect operation that has
+ // returned with either STATUS_SUCCESS or
+ // STATUS_BAD_NETWORK_PATH, then
+ // inform the automatic connection driver.
+ //
+ if (fAcdLoadedG) {
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ if (IrpSp->MinorFunction == TDI_CONNECT &&
+ FinalStatus == STATUS_SUCCESS)
+ {
+ KIRQL adirql;
+ BOOLEAN fEnabled;
+
+ ACQUIRE_SPIN_LOCK(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ RELEASE_SPIN_LOCK(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled) {
+ NbfNoteNewConnection(
+ IrpSp->FileObject->FsContext,
+ (PDEVICE_CONTEXT)IrpSp->FileObject->DeviceObject);
+ }
+ }
+ }
+#endif // RASAUTODIAL
+
+ //
+ // For requests associated with a device context, we need
+ // to copy the data from the temp buffer to the MDL and
+ // free the temp buffer.
+ //
+
+ if (Request->ResponseBuffer != NULL) {
+
+ if ((FinalStatus == STATUS_SUCCESS) ||
+ (FinalStatus == STATUS_BUFFER_OVERFLOW)) {
+
+ CopyStatus = TdiCopyBufferToMdl (
+ Request->ResponseBuffer,
+ 0L,
+ Information,
+ Irp->MdlAddress,
+ 0,
+ &Information);
+
+ if (CopyStatus != STATUS_SUCCESS) {
+ FinalStatus = CopyStatus;
+ }
+
+ }
+
+ ExFreePool (Request->ResponseBuffer);
+ Request->ResponseBuffer = NULL;
+
+ }
+
+ //
+ // Install the return code in the IRP so that when we call NbfDestroyRequest,
+ // it will get completed with the proper return status.
+ //
+
+ Irp->IoStatus.Status = FinalStatus;
+ Irp->IoStatus.Information = Information;
+
+ //
+ // The entire transport is done with this request.
+ //
+
+ NbfDereferenceRequest ("Complete", Request, RREF_CREATION); // remove creation reference.
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+} /* NbfCompleteRequest */
+
+
+#if DBG
+VOID
+NbfRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a send IRP.
+
+Arguments:
+
+ IrpSp - Pointer to the IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefSendIrp: Entered, ReferenceCount: %x\n",
+ IRP_SEND_REFCOUNT(IrpSp));
+ }
+
+ ASSERT (IRP_SEND_REFCOUNT(IrpSp) > 0);
+
+ InterlockedIncrement (&IRP_SEND_REFCOUNT(IrpSp));
+
+} /* NbfRefSendIrp */
+
+
+VOID
+NbfDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport send IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport send IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefSendIrp: Entered, ReferenceCount: %x\n",
+ IRP_SEND_REFCOUNT(IrpSp));
+ }
+
+ result = InterlockedDecrement (&IRP_SEND_REFCOUNT(IrpSp));
+
+ ASSERT (result >= 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 0) {
+
+ PIRP Irp = IRP_SEND_IRP(IrpSp);
+
+ IRP_SEND_REFCOUNT(IrpSp) = 0;
+ IRP_SEND_IRP (IrpSp) = NULL;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+} /* NbfDerefSendIrp */
+#endif
+
+
+VOID
+NbfCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport send IRP.
+
+Arguments:
+
+ Irp - Pointer to a send IRP.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PTP_CONNECTION Connection;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ Connection = IRP_SEND_CONNECTION(IrpSp);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteSendIrp: Entered IRP %lx, connection %lx\n",
+ Irp, Connection);
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ NbfDereferenceSendIrp ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
+
+ NbfDereferenceConnectionMacro ("Removing Connection", Connection, CREF_SEND_IRP);
+
+} /* NbfCompleteSendIrp */
+
+
+#if DBG
+VOID
+NbfRefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a receive IRP.
+
+Arguments:
+
+ IrpSp - Pointer to the IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfRefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ ASSERT (IRP_RECEIVE_REFCOUNT(IrpSp) > 0);
+
+ IRP_RECEIVE_REFCOUNT(IrpSp)++;
+
+} /* NbfRefReceiveIrpLocked */
+#endif
+
+
+VOID
+NbfDerefReceiveIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport receive IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport receive IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefReceiveIrp: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ result = ExInterlockedAddUlong (
+ (PULONG)&IRP_RECEIVE_REFCOUNT(IrpSp),
+ (ULONG)-1,
+ (IRP_RECEIVE_CONNECTION(IrpSp)->LinkSpinLock));
+
+ ASSERT (result > 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 1) {
+
+ PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
+
+ ExInterlockedInsertTailList(
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
+ &Irp->Tail.Overlay.ListEntry,
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
+
+ }
+
+} /* NbfDerefReceiveIrp */
+
+
+#if DBG
+VOID
+NbfDerefReceiveIrpLocked(
+ IN PIO_STACK_LOCATION IrpSp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport receive IRP by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IoCompleteRequest to actually complete the IRP.
+
+Arguments:
+
+ Request - Pointer to a transport receive IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG result;
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint1 ("NbfDerefReceiveIrpLocked: Entered, ReferenceCount: %x\n",
+ IRP_RECEIVE_REFCOUNT(IrpSp));
+ }
+
+ result = IRP_RECEIVE_REFCOUNT(IrpSp)--;
+
+ ASSERT (result > 0);
+
+ //
+ // If we have deleted all references to this request, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the request any longer.
+ //
+
+ if (result == 1) {
+
+ PIRP Irp = IRP_RECEIVE_IRP(IrpSp);
+
+ ExInterlockedInsertTailList(
+ &(IRP_DEVICE_CONTEXT(IrpSp)->IrpCompletionQueue),
+ &Irp->Tail.Overlay.ListEntry,
+ &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock));
+
+ }
+
+} /* NbfDerefReceiveIrpLocked */
+#endif
+
+
+VOID
+NbfCompleteReceiveIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ )
+
+/*++
+
+Routine Description:
+
+ This routine completes a transport receive IRP.
+
+ NOTE: THIS ROUTINE MUST BE CALLED WITH THE CONNECTION SPINLOCK
+ HELD.
+
+Arguments:
+
+ Irp - Pointer to a receive IRP.
+
+ Status - Actual return status to be assigned to the request. This
+ value may be overridden if the timed-out bitflag is set in the request.
+
+ Information - the information field for the I/O Status Block.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PTP_CONNECTION Connection;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ Connection = IRP_RECEIVE_CONNECTION(IrpSp);
+
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("NbfCompleteReceiveIrp: Entered IRP %lx, connection %lx\n",
+ Irp, Connection);
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ NbfDereferenceReceiveIrpLocked ("Complete", IrpSp, RREF_CREATION); // remove creation reference.
+
+} /* NbfCompleteReceiveIrp */
diff --git a/private/ntos/tdi/nbf/send.c b/private/ntos/tdi/nbf/send.c
new file mode 100644
index 000000000..a8a6cc7f3
--- /dev/null
+++ b/private/ntos/tdi/nbf/send.c
@@ -0,0 +1,503 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSend
+ o TdiSendDatagram
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+NbfTdiSend(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSend request for the transport provider.
+
+ NOTE: THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, cancelIrql;
+ PTP_CONNECTION connection;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SEND parameters;
+ PIRP TempIrp;
+
+ //
+ // Determine which connection this send belongs on.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // Check that this is really a connection.
+ //
+
+ if ((connection->Size != sizeof (TP_CONNECTION)) ||
+ (connection->Type != NBF_CONNECTION_SIGNATURE)) {
+#if DBG
+ NbfPrint2 ("TdiSend: Invalid Connection %lx Irp %lx\n", connection, Irp);
+#endif
+ return STATUS_INVALID_CONNECTION;
+ }
+
+#if DBG
+ Irp->IoStatus.Information = 0; // initialize it.
+ Irp->IoStatus.Status = 0x01010101; // initialize it.
+#endif
+
+ //
+ // Interpret send options.
+ //
+
+#if DBG
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ if ((parameters->SendFlags & TDI_SEND_PARTIAL) != 0) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("NbfTdiSend: TDI_END_OF_RECORD not found.\n");
+ }
+ }
+#endif
+
+ //
+ // Now we have a reference on the connection object. Queue up this
+ // send to the connection object.
+ //
+
+ //
+ // We would normally add a connection reference of type
+ // CREF_SEND_IRP, however we delay doing this until we
+ // know we are not going to call PacketizeSend with the
+ // second parameter TRUE. If we do call that it assumes
+ // we have not added the reference.
+ //
+
+ IRP_SEND_IRP(irpSp) = Irp;
+ IRP_SEND_REFCOUNT(irpSp) = 1;
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ Irp->IoStatus.Status = connection->Status;
+ Irp->IoStatus.Information = 0;
+
+ NbfDereferenceSendIrp ("Complete", irpSp, RREF_CREATION); // remove creation reference.
+
+ } else {
+
+ //
+ // Once the reference is in, LinkSpinLock will stay valid.
+ //
+
+ NbfReferenceConnection ("Verify Temp Use", connection, CREF_BY_ID);
+ RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+#if DBG
+ NbfSends[NbfSendsNext].Irp = Irp;
+ NbfSends[NbfSendsNext].Request = NULL;
+ NbfSends[NbfSendsNext].Connection = (PVOID)connection;
+ {
+ ULONG i,j;
+ PUCHAR va;
+ PMDL mdl;
+
+ mdl = Irp->MdlAddress;
+ if (parameters->SendLength > TRACK_TDI_CAPTURE) {
+ NbfSends[NbfSendsNext].Contents[0] = 0xFF;
+ } else {
+ NbfSends[NbfSendsNext].Contents[0] = (UCHAR)parameters->SendLength;
+ }
+
+ i = 1;
+ while (i < TRACK_TDI_CAPTURE) {
+ if (mdl == NULL) break;
+ for ( va = MmGetSystemAddressForMdl (mdl),
+ j = MmGetMdlByteCount (mdl);
+ (i < TRACK_TDI_CAPTURE) && (j > 0);
+ i++, j-- ) {
+ NbfSends[NbfSendsNext].Contents[i] = *va++;
+ }
+ mdl = mdl->Next;
+ }
+ }
+
+ NbfSendsNext++;
+ if (NbfSendsNext >= TRACK_TDI_LIMIT) NbfSendsNext = 0;
+#endif
+
+ //
+ // If this IRP has been cancelled already, complete it now.
+ //
+
+ if (Irp->Cancel) {
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ NbfReferenceConnection("TdiSend cancelled", connection, CREF_SEND_IRP);
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (Irp, STATUS_CANCELLED, 0);
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("IRP cancelled", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ //
+ // Insert onto the send queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
+ IoSetCancelRoutine(Irp, NbfCancelSend);
+
+ //
+ // Release the cancel spinlock out of order. We were at DPC level
+ // when we acquired both the cancel and link spinlocks, so the irqls
+ // don't need to be swapped.
+ //
+ ASSERT(cancelIrql == DISPATCH_LEVEL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // If this connection is waiting for an EOR to appear because a non-EOR
+ // send failed at some point in the past, fail this send. Clear the
+ // flag that causes this if this request has the EOR set.
+ //
+ // BUGBUG: Should the FailSend status be clearer here?
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_FAILING_TO_EOR) != 0) {
+
+ NbfReferenceConnection("TdiSend failing to EOR", connection, CREF_SEND_IRP);
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ //
+ // BUGBUG: Should we save status from real failure?
+ //
+
+ FailSend (connection, STATUS_LINK_FAILED, TRUE);
+
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+ connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
+ }
+
+ KeLowerIrql (oldirql);
+
+ NbfDereferenceConnection ("Failing to EOR", connection, CREF_BY_ID); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+
+ //
+ // If the send state is either IDLE or W_EOR, then we should
+ // begin packetizing this send. Otherwise, some other event
+ // will cause it to be packetized.
+ //
+
+ //
+ // NOTE: If we call StartPacketizingConnection, we make
+ // sure that it is the last operation we do on this
+ // connection. This allows us to "hand off" the reference
+ // we have to that function, which converts it into
+ // a reference for being on the packetize queue.
+ //
+
+// NbfPrint2 ("TdiSend: Sending, connection %lx send state %lx\n",
+// connection, connection->SendState);
+
+ switch (connection->SendState) {
+
+ case CONNECTION_SENDSTATE_IDLE:
+
+ InitializeSend (connection); // sets state to PACKETIZE
+
+ //
+ // If we can, packetize right now.
+ //
+
+ if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+#if DBG
+ NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
+ NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
+#endif
+
+ //
+ // This releases the spinlock. Note that PacketizeSend
+ // assumes that the current SendIrp has a reference
+ // of type RREF_PACKET;
+ //
+
+#if DBG
+ NbfReferenceSendIrp ("Packetize", irpSp, RREF_PACKET);
+#else
+ ++IRP_SEND_REFCOUNT(irpSp); // OK since it was just queued.
+#endif
+ PacketizeSend (connection, TRUE);
+
+ } else {
+
+#if DBG
+ NbfReferenceConnection("TdiSend packetizing", connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Stopping or already packetizing", connection, CREF_BY_ID); // release lookup hold.
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ }
+
+ break;
+
+ case CONNECTION_SENDSTATE_W_EOR:
+ connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ //
+ // Adjust the send variables on the connection so that
+ // they correctly point to this new send. We can't call
+ // InitializeSend to do that, because we need to keep
+ // track of the other outstanding sends on this connection
+ // which have been sent but are a part of this message.
+ //
+
+ TempIrp = CONTAINING_RECORD(
+ connection->SendQueue.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+
+ connection->sp.CurrentSendIrp = TempIrp;
+ connection->sp.CurrentSendMdl = TempIrp->MdlAddress;
+ connection->sp.SendByteOffset = 0;
+ connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(TempIrp));
+
+ //
+ // StartPacketizingConnection removes the CREF_BY_ID
+ // reference.
+ //
+
+ NbfReferenceConnection("TdiSend W_EOR", connection, CREF_SEND_IRP);
+
+ StartPacketizingConnection (connection, TRUE);
+ break;
+
+ default:
+// NbfPrint2 ("TdiSend: Sending, unknown state! connection %lx send state %lx\n",
+// connection, connection->SendState);
+ //
+ // The connection is in another state (such as
+ // W_ACK or W_LINK), we just need to make sure
+ // to call InitializeSend if the new one is
+ // the first one on the list.
+ //
+
+ //
+ // BUGBUG: Currently InitializeSend sets SendState,
+ // we should fix this.
+ //
+
+ if (connection->SendQueue.Flink == &Irp->Tail.Overlay.ListEntry) {
+ ULONG SavedSendState;
+ SavedSendState = connection->SendState;
+ InitializeSend (connection);
+ connection->SendState = SavedSendState;
+ }
+
+#if DBG
+ NbfReferenceConnection("TdiSend other", connection, CREF_SEND_IRP);
+ NbfDereferenceConnection("temp TdiSend", connection, CREF_BY_ID);
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
+
+ }
+
+ }
+
+ KeLowerIrql (oldirql);
+ return STATUS_PENDING;
+
+} /* TdiSend */
+
+
+NTSTATUS
+NbfTdiSendDatagram(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ KIRQL oldirql;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SENDDG parameters;
+ UINT MaxUserData;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = NbfVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("TdiSendDG: Invalid address %lx Irp %lx\n",
+ addressFile, Irp);
+ }
+ return status;
+ }
+
+ address = addressFile->Address;
+ parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
+
+ //
+ // Check that the length is short enough.
+ //
+
+ MacReturnMaxDataSize(
+ &address->Provider->MacInfo,
+ NULL,
+ 0,
+ address->Provider->MaxSendPacketSize,
+ FALSE,
+ &MaxUserData);
+
+ if (parameters->SendLength >
+ (MaxUserData - sizeof(DLC_FRAME) - sizeof(NBF_HDR_CONNECTIONLESS))) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // If we are on a disconnected RAS link, then fail the datagram
+ // immediately.
+ //
+
+ if ((address->Provider->MacInfo.MediumAsync) &&
+ (!address->Provider->MediumSpeedAccurate)) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_DEVICE_NOT_READY;
+ }
+
+ //
+ // Check that the target address includes a Netbios component.
+ //
+
+ if (!(NbfValidateTdiAddress(
+ parameters->SendDatagramInformation->RemoteAddress,
+ parameters->SendDatagramInformation->RemoteAddressLength)) ||
+ (NbfParseTdiAddress(parameters->SendDatagramInformation->RemoteAddress, TRUE) == NULL)) {
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
+ STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ NbfReferenceAddress ("Send datagram", address, AREF_REQUEST);
+ Irp->IoStatus.Information = parameters->SendLength;
+ InsertTailList (
+ &address->SendDatagramQueue,
+ &Irp->Tail.Overlay.ListEntry);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+
+ //
+ // The request is queued. Ship the next request at the head of the queue,
+ // provided the completion handler is not active. We serialize this so
+ // that only one MDL and NBF datagram header needs to be statically
+ // allocated for reuse by all send datagram requests.
+ //
+
+ (VOID)NbfSendDatagramsOnAddress (address);
+
+ }
+
+ NbfDereferenceAddress("tmp send datagram", address, AREF_VERIFY);
+
+ return STATUS_PENDING;
+
+} /* NbfTdiSendDatagram */
diff --git a/private/ntos/tdi/nbf/sendeng.c b/private/ntos/tdi/nbf/sendeng.c
new file mode 100644
index 000000000..1b6556581
--- /dev/null
+++ b/private/ntos/tdi/nbf/sendeng.c
@@ -0,0 +1,3657 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ sendeng.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ Jetbeui transport provider. This code is responsible for the following
+ basic activities, including some subordinate glue.
+
+ 1. Packetizing TdiSend requests already queued up on a TP_CONNECTION
+ object, using I-frame packets acquired from the PACKET.C module,
+ and turning them into shippable packets and placing them on the
+ TP_LINK's WackQ. In the process of doing this, the packets are
+ actually submitted as I/O requests to the Physical Provider, in
+ the form of PdiSend requests.
+
+ 2. Retiring packets queued to a TP_LINK's WackQ and returning them to
+ the device context's pool for use by other links. In the process
+ of retiring acked packets, step 1 may be reactivated.
+
+ 3. Resending packets queued to a TP_LINK's WackQ because of a reject
+ condition on the link. This involves no state update in the
+ TP_CONNECTION object.
+
+ 4. Handling of Send completion events from the Physical Provider,
+ to allow proper synchronization of the reuse of packets.
+
+ 5. Completion of TdiSend requests. This is triggered by the receipt
+ (in IFRAMES.C) of a DataAck frame, or by a combination of other
+ frames when the proper protocol has been negotiated. One routine
+ in this routine is responsible for the actual mechanics of TdiSend
+ request completion.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if DBG
+extern ULONG NbfSendsIssued;
+extern ULONG NbfSendsCompletedInline;
+extern ULONG NbfSendsCompletedOk;
+extern ULONG NbfSendsCompletedFail;
+extern ULONG NbfSendsPended;
+extern ULONG NbfSendsCompletedAfterPendOk;
+extern ULONG NbfSendsCompletedAfterPendFail;
+#endif
+
+
+//
+// Temporary variables to control piggyback ack usage.
+//
+#define NbfUsePiggybackAcks 1
+#if DBG
+ULONG NbfDebugPiggybackAcks = 0;
+#endif
+
+
+#if DBG
+//
+// *** This is the original version of StartPacketizingConnection, which
+// is now a macro on the free build. It has been left here as the
+// fully-commented version of the code.
+//
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to place a connection on the PacketizeQueue
+ of its device context object. Then this routine starts packetizing
+ the first connection on that queue.
+
+ *** The Connection LinkSpinLock must be held on entry to this routine.
+
+ *** THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Immediate - TRUE if the connection should be packetized
+ immediately; FALSE if the connection should be queued
+ up for later packetizing (implies that ReceiveComplete
+ will be called in the future, which packetizes always).
+
+ NOTE: If this is TRUE, it also implies that we have
+ a connection reference of type CREF_BY_ID which we
+ will "convert" into the CREF_PACKETIZE_QUEUE one.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("StartPacketizingConnection: Entered for connection %lx.\n",
+ Connection);
+ }
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // If this connection's SendState is set to PACKETIZE and if
+ // we are not already on the PacketizeQueue, then go ahead and
+ // append us to the end of that queue, and remember that we're
+ // on it by setting the CONNECTION_FLAGS_PACKETIZE bitflag.
+ //
+ // Also don't queue it if the connection is stopping.
+ //
+
+ if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (!(Connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ if (!Immediate) {
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+#if DBG
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+ NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
+#endif
+ }
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Immediate) {
+ NbfDereferenceConnection("temp TdiSend", Connection, CREF_BY_ID);
+ }
+ }
+
+ if (Immediate) {
+ PacketizeConnections (DeviceContext);
+ }
+
+} /* StartPacketizingConnection */
+#endif
+
+
+VOID
+PacketizeConnections(
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to packetize all connections waiting on the
+ PacketizeQueue of the DeviceContext.
+
+
+Arguments:
+
+ DeviceContext - Pointer to a DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeConnections: Entered for device context %lx.\n",
+ DeviceContext);
+ }
+
+ //
+ // Pick connections off of the device context's packetization queue
+ // until there are no more left to pick off. For each one, we call
+ // PacketizeSend. Note this routine can be executed concurrently
+ // on multiple processors and it doesn't matter; multiple connections
+ // may be packetized concurrently.
+ //
+
+ while (TRUE) {
+
+ p = ExInterlockedRemoveHeadList(
+ &DeviceContext->PacketizeQueue,
+ &DeviceContext->SpinLock);
+
+ if (p == NULL) {
+ break;
+ }
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+ NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ PacketizeSend (Connection, FALSE); // releases the lock.
+ }
+ }
+
+} /* PacketizeConnections */
+
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection,
+ IN BOOLEAN Direct
+ )
+
+/*++
+
+Routine Description:
+
+ This routine packetizes the current TdiSend request on the specified
+ connection as much as limits will permit. A given here is that there
+ is an active send on the connection that needs further packetization.
+
+ NOTE: This routine is called with the connection spinlock held and
+ returns with it released. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Direct - TRUE if we are called from TdiSend. This implies that
+ the connection does not have a reference of type CREF_SEND_IRP,
+ which we need to add before we leave.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG MaxFrameSize, FrameSize;
+ ULONG PacketBytes;
+ PNDIS_BUFFER PacketDescriptor;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_PACKET Packet;
+ NTSTATUS Status;
+ PNBF_HDR_CONNECTION NbfHeader;
+ BOOLEAN LinkCheckpoint;
+ BOOLEAN SentPacket = FALSE;
+ BOOLEAN ExitAfterSendOnePacket = FALSE;
+ PIO_STACK_LOCATION IrpSp;
+ ULONG LastPacketLength;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeSend: Entered for connection %lx.\n", Connection);
+ }
+
+ DeviceContext = Connection->Provider;
+
+ ASSERT (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
+
+ //
+ // Just loop until one of three events happens: (1) we run out of
+ // packets from NbfCreatePacket, (2) we completely packetize the send,
+ // or (3) we can't send any more packets because SendOnePacket failed.
+ //
+
+#if DBG
+
+ //
+ // Convert the queue reference into a packetize one. It is OK
+ // to do this with the lock held because we know that the refcount
+ // must already be at least one, so we don't drop to zero.
+ //
+
+ NbfReferenceConnection ("PacketizeSend", Connection, CREF_PACKETIZE);
+ NbfDereferenceConnection ("Off packetize queue", Connection, CREF_PACKETIZE_QUEUE);
+#endif
+
+ MaxFrameSize = Connection->MaximumDataSize;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("PacketizeSend: MaxFrameSize for user data=%ld.\n", MaxFrameSize);
+ }
+
+
+ //
+ // It is possible for a frame to arrive during the middle of this loop
+ // (such as a NO_RECEIVE) that will put us into a new state (such as
+ // W_RCVCONT). For this reason, we have to check the state every time
+ // (at the end of the loop).
+ //
+
+ do {
+
+ if (!NT_SUCCESS (NbfCreatePacket (DeviceContext, Connection->Link, &Packet))) {
+
+ //
+ // We need a packet to finish packetizing the current send, but
+ // there are no more packets available in the pool right now.
+ // Set our send state to W_PACKET, and put this connection on
+ // the PacketWaitQueue of the device context object. Then,
+ // when NbfDestroyPacket frees up a packet, it will check this
+ // queue for starved connections, and if it finds one, it will
+ // take a connection off the list and set its send state to
+ // SENDSTATE_PACKETIZE and put it on the PacketizeQueue.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: NbfCreatePacket failed.\n");
+ }
+ Connection->SendState = CONNECTION_SENDSTATE_W_PACKET;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+ // Don't queue him if the connection is stopping.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+#if DBG
+ if (Connection->Flags2 & CONNECTION_FLAGS2_STOPPING) {
+ DbgPrint ("NBF: BUGBUG! Trying to PacketWait stopping connection %lx\n", Connection);
+ DbgBreakPoint();
+ }
+#endif
+ Connection->Flags |= CONNECTION_FLAGS_W_PACKETIZE;
+ if (!Connection->OnPacketWaitQueue) {
+ Connection->OnPacketWaitQueue = TRUE;
+ InsertTailList(
+ &DeviceContext->PacketWaitQueue,
+ &Connection->PacketWaitLinkage);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (!SentPacket) {
+ NbfDereferenceSendIrp ("No packet", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ }
+ if (Direct) {
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ }
+
+ NbfDereferenceConnection ("No packet", Connection, CREF_PACKETIZE);
+ return;
+
+ }
+
+ //
+ // Set the length of the packet now, while only the
+ // header is attached.
+ //
+
+ NbfSetNdisPacketLength(
+ Packet->NdisPacket,
+ Connection->Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION));
+
+ // Add a reference count to the request, and keep track of
+ // which request it is. We rely on NbfDestroyPacket to
+ // remove the reference.
+
+ IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
+
+ Packet->Owner = IrpSp;
+ // Packet->Action = PACKET_ACTION_IRP_SP;
+ IF_NBFDBG (NBF_DEBUG_REQUEST) {
+ NbfPrint2 ("PacketizeSend: Packet %x ref IrpSp %x.\n", Packet, Packet->Owner);
+ }
+
+ //
+ // For performance reasons, the first time through here on
+ // a direct call, we have a IrpSp reference already.
+ //
+
+ if (SentPacket) {
+ NbfReferenceSendIrp ("Packetize", IrpSp, RREF_PACKET);
+ }
+
+ //
+ // Now build a DATA_ONLY_LAST header in this frame. If it
+ // turns out we need a DFM, we change it. The header we copy
+ // already has ResponseCorrelator set to our current correlator
+ // and TransmitCorrelator set to the last one we received from
+ // him (if we do not piggyback an ack, then we zero out
+ // TransmitCorrelator).
+ //
+
+ NbfHeader = (PNBF_HDR_CONNECTION)&(Packet->Header[Connection->Link->HeaderLength + sizeof(DLC_I_FRAME)]);
+ *(NBF_HDR_CONNECTION UNALIGNED *)NbfHeader = Connection->NetbiosHeader;
+
+ ASSERT (RESPONSE_CORR(NbfHeader) != 0);
+
+ //
+ // Determine if we need the resynch bit here.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_RESYNCHING) {
+
+ NbfHeader->Data2Low = 1;
+ Connection->Flags &= ~CONNECTION_FLAGS_RESYNCHING;
+
+ } else {
+
+ NbfHeader->Data2Low = 0;
+
+ }
+
+
+ //
+ // build an NDIS_BUFFER chain that describes the buffer we're using, and
+ // thread it off the NdisBuffer. This chain may not complete the
+ // packet, as the remaining part of the MDL chain may be shorter than
+ // the packet.
+ //
+
+ FrameSize = MaxFrameSize;
+
+ //
+ // Check if we have less than FrameSize left to send.
+ //
+
+ if (Connection->sp.MessageBytesSent + FrameSize > Connection->CurrentSendLength) {
+
+ FrameSize = Connection->CurrentSendLength - Connection->sp.MessageBytesSent;
+
+ }
+
+
+ //
+ // Make a copy of the MDL chain for this send, unless
+ // there are zero bytes left.
+ //
+
+ if (FrameSize != 0) {
+
+ //
+ // If the whole send will fit inside one packet,
+ // then there is no need to duplicate the MDL
+ // (note that this may include multi-MDL sends).
+ //
+
+ if ((Connection->sp.SendByteOffset == 0) &&
+ (Connection->CurrentSendLength == FrameSize)) {
+
+ PacketDescriptor = (PNDIS_BUFFER)Connection->sp.CurrentSendMdl;
+ PacketBytes = FrameSize;
+ Connection->sp.CurrentSendMdl = NULL;
+ Connection->sp.SendByteOffset = FrameSize;
+ Packet->PacketNoNdisBuffer = TRUE;
+
+ } else {
+
+ Status = BuildBufferChainFromMdlChain (
+ DeviceContext,
+ Connection->sp.CurrentSendMdl,
+ Connection->sp.SendByteOffset,
+ FrameSize,
+ &PacketDescriptor,
+ &Connection->sp.CurrentSendMdl,
+ &Connection->sp.SendByteOffset,
+ &PacketBytes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (NbfHeader->Data2Low) {
+ Connection->Flags |= CONNECTION_FLAGS_RESYNCHING;
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferencePacket (Packet); // remove creation hold.
+ goto BufferChainFailure;
+ }
+
+ }
+
+ //
+ // Chain the buffers to the packet, unless there
+ // are zero bytes of data.
+ //
+
+ Connection->sp.MessageBytesSent += PacketBytes;
+ NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
+
+ } else {
+
+ PacketBytes = 0;
+ Connection->sp.CurrentSendMdl = NULL;
+
+ }
+
+ {
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ {PNDIS_BUFFER NdisBuffer;
+ NdisQueryPacket(Packet->NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+ NbfPrint1 ("PacketizeSend: NDIS_BUFFER Built, chain is: %lx is Packet->Head\n", NdisBuffer);
+ NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NbfPrint1 (" %lx is Next\n",
+ NdisBuffer);
+ NdisGetNextBuffer (NdisBuffer, &NdisBuffer);
+ }}
+ }
+
+ //
+ // Have we run out of Mdl Chain in this request?
+ //
+
+#if DBG
+ if (PacketBytes < FrameSize) {
+ ASSERT (Connection->sp.CurrentSendMdl == NULL);
+ }
+#endif
+
+ if ((Connection->sp.CurrentSendMdl == NULL) ||
+ (Connection->CurrentSendLength <= Connection->sp.MessageBytesSent)) {
+
+ //
+ // Yep. We know that we've exhausted the current request's buffer
+ // here, so see if there's another request without EOF set that we
+ // can build start throwing into this packet.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Used up entire request.\n");
+ }
+
+ if (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
+
+ //
+ // We are sending the last packet in a message. Change
+ // the packet type and indicate in the connection object's
+ // send state that we are waiting for a DATA_ACK NetBIOS-
+ // level acknowlegement.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Request has EOR, making pkt a DOL.\n");
+ }
+
+ //
+ // Keep track of how many consecutive sends we have done.
+ //
+
+ Connection->ConsecutiveSends++;
+ Connection->ConsecutiveReceives = 0;
+
+ //
+ // Change it to a DOL with piggyback ack allowed if wanted.
+ //
+
+ ASSERT (NbfHeader->Command == NBF_CMD_DATA_ONLY_LAST);
+ if (!(IRP_SEND_FLAGS(IrpSp) &
+ TDI_SEND_NO_RESPONSE_EXPECTED) &&
+ (Connection->ConsecutiveSends < 2)) {
+ if (NbfUsePiggybackAcks) {
+ NbfHeader->Data1 |= DOL_OPTIONS_ACK_W_DATA_ALLOWED;
+ }
+ }
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_ACK;
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ ExitAfterSendOnePacket = TRUE;
+
+ } else {
+
+ //
+ // We are sending the last packet in this request. If there
+ // are more requests in the connection's SendQueue, then
+ // advance complex send pointer to point to the next one
+ // in line. Otherwise, if there aren't any more requests
+ // ready to packetize, then we enter the W_EOR state and
+ // stop packetizing. Note that we're waiting here for the TDI
+ // client to come up with data to send; we're just hanging out
+ // until then.
+ //
+ // DGB: Note that this will allow the last packet in the
+ // request to be smaller than the max packet length. This
+ // is not addressed anywhere that I can find in the NBF
+ // spec, and will be interesting to test against a non-NT
+ // NBF protocol.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: Request doesn't have EOR.\n");
+ }
+
+ NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
+
+ if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ ExitAfterSendOnePacket = TRUE;
+
+ } else {
+
+ Connection->sp.CurrentSendIrp =
+ CONTAINING_RECORD (
+ Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink,
+ IRP,
+ Tail.Overlay.ListEntry);
+ Connection->sp.CurrentSendMdl =
+ Connection->sp.CurrentSendIrp->MdlAddress;
+ Connection->sp.SendByteOffset = 0;
+ Connection->CurrentSendLength +=
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+ }
+ }
+
+ } else {
+
+ NbfHeader->Command = NBF_CMD_DATA_FIRST_MIDDLE;
+
+ }
+
+ //
+ // Before we release the spinlock, see if we want to
+ // piggyback an ack on here.
+ //
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+
+ //
+ // Turn off the flags. We don't take it off the queue,
+ // that will be handled by the timer function.
+ //
+
+ Connection->DeferredFlags &=
+ ~(CONNECTION_FLAGS_DEFERRED_ACK | CONNECTION_FLAGS_DEFERRED_NOT_Q);
+
+ ASSERT (DOL_OPTIONS_ACK_INCLUDED == DFM_OPTIONS_ACK_INCLUDED);
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("A");
+ }
+#endif
+
+ //
+ // TRANSMIT_CORR(NbfHeader) is already set correctly.
+ //
+
+ NbfHeader->Data1 |= DOL_OPTIONS_ACK_INCLUDED;
+
+ } else {
+
+ TRANSMIT_CORR(NbfHeader) = (USHORT)0;
+
+ }
+
+ //
+ // To prevent a send "crossing" the receive and
+ // causing a bogus piggyback ack timeout (this
+ // only matters if a receive indication is in
+ // progress).
+ //
+
+ Connection->CurrentReceiveAckQueueable = FALSE;
+
+ SentPacket = TRUE;
+ LastPacketLength =
+ sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION) + PacketBytes;
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ LastPacketLength);
+
+ Packet->NdisIFrameLength = LastPacketLength;
+
+ ASSERT (Connection->LinkSpinLock == &Connection->Link->SpinLock);
+
+ Status = SendOnePacket (Connection, Packet, FALSE, &LinkCheckpoint);
+
+ if (Status == STATUS_LINK_FAILED) {
+
+ //
+ // If SendOnePacket failed due to the link being
+ // dead, then we tear down the link.
+ //
+
+ FailSend (Connection, STATUS_LINK_FAILED, TRUE); // fail the send
+ NbfDereferencePacket (Packet); // remove creation hold.
+ if (Direct) {
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ }
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+
+ return;
+
+ } else {
+
+ //
+ // SendOnePacket returned success, so update our counters;
+ //
+
+ DeviceContext->TempIFrameBytesSent += PacketBytes;
+ ++DeviceContext->TempIFramesSent;
+
+ if ((Status == STATUS_SUCCESS) && LinkCheckpoint) {
+
+ //
+ // We are checkpointing; this means that SendOnePacket
+ // will already have set the state to W_LINK and turned
+ // off the PACKETIZE flag, so we should leave. When
+ // the checkpoint response is received, we will
+ // resume packetizing. We don't have to worry about
+ // doing all the other recovery stuff (resetting
+ // the piggyback ack flag, complex send pointer, etc.)
+ // because the send did in fact succeed.
+ //
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Link checkpoint", Connection, CREF_PACKETIZE);
+ }
+ return;
+
+ } else if (ExitAfterSendOnePacket ||
+ (Status == STATUS_MORE_PROCESSING_REQUIRED)) {
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Packetize done", Connection, CREF_PACKETIZE);
+ }
+ return;
+
+ }
+ }
+ }
+
+BufferChainFailure:;
+
+ //
+ // Note that we may have fallen out of the BuildBuffer... if above with
+ // Status set to STATUS_INSUFFICIENT_RESOURCES. if we have, we'll just
+ // stick this connection back onto the packetize queue and hope the
+ // system gets more resources later.
+ //
+
+
+ if (!NT_SUCCESS (Status)) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint0 ("PacketizeSend: SendOnePacket failed.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Indicate we're waiting on favorable link conditions.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer
+ // on the PacketizeQueue or actively packetizing. The flag
+ // was set by StartPacketizingConnection to indicate that
+ // the connection was already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // If we are exiting and we sent a packet without
+ // polling, we need to start T1.
+ //
+
+ if (Direct) {
+
+ //
+ // We have to do the CREF_SEND_IRP reference that is missing.
+ //
+
+#if DBG
+ NbfReferenceConnection("TdiSend", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("Send failed", Connection, CREF_PACKETIZE);
+ }
+
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // It is probable that a NetBIOS frame arrived while we released
+ // the connection's spin lock, so our state has probably changed.
+ // When we cycle around this loop again, we will have the lock
+ // again, so we can test the connection's send state.
+ //
+
+ } while (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE);
+
+ //
+ // Clear the PACKETIZE flag, indicating that we're no longer on the
+ // PacketizeQueue or actively packetizing. The flag was set by
+ // StartPacketizingConnection to indicate that the connection was
+ // already on the PacketizeQueue.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+
+ if (Direct) {
+#if DBG
+ NbfReferenceConnection ("Delayed request ref", Connection, CREF_SEND_IRP);
+ NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
+#endif
+ } else {
+ NbfDereferenceConnection ("PacketizeSend done", Connection, CREF_PACKETIZE);
+ }
+
+} /* PacketizeSend */
+
+
+VOID
+CompleteSend(
+ PTP_CONNECTION Connection,
+ IN USHORT Correlator
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called because the connection partner acknowleged
+ an entire message at the NetBIOS Frames Protocol level, either through
+ a DATA_ACK response, or a RECEIVE_OUTSTANDING, or RECEIVE_CONTINUE,
+ or NO_RECEIVE response where the number of bytes specified exactly
+ matches the number of bytes sent in the message. Here we retire all
+ of the TdiSends on the connection's SendQueue up to and including the
+ one with the TDI_END_OF_RECORD bitflag set. For each request, we
+ complete the I/O.
+
+ NOTE: This function is called with the connection spinlock
+ held and returns with it held, but it may release it in the
+ middle. THIS FUNCTION MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Correlator - The correlator in the DATA_ACK or piggybacked ack.
+
+ OldIrqlP - Returns the IRQL at which the connection spinlock
+ was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ KIRQL cancelIrql;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("CompleteSend: Entered for connection %lx.\n", Connection);
+ }
+
+
+ //
+ // Make sure that the correlator is the expect one, and
+ // that we are in a good state (don't worry about locking
+ // since this is an unusual case anyway).
+ //
+
+ if (Correlator != Connection->NetbiosHeader.ResponseCorrelator) {
+ NbfPrint0 ("NbfCompleteSend: ack ignored, wrong correlator\n");
+ return;
+ }
+
+ if (Connection->SendState != CONNECTION_SENDSTATE_W_ACK) {
+ NbfPrint0 ("NbfCompleteSend: ack not expected\n");
+ return;
+ }
+
+ //
+ // Pick off TP_REQUEST objects from the connection's SendQueue until
+ // we find one with an END_OF_RECORD mark embedded in it.
+ //
+
+ while (!(IsListEmpty(&Connection->SendQueue))) {
+
+ //
+ // We know for a fact that we wouldn't be calling this routine if
+ // we hadn't received an acknowlegement for an entire message,
+ // since NBF doesn't provide stream mode sends. Therefore, we
+ // know that we will run into a request with the END_OF_RECORD
+ // mark set BEFORE we will run out of requests on that queue,
+ // so there is no reason to check to see if we ran off the end.
+ // Note that it's possible that the send has been failed and the
+ // connection not yet torn down; if this has happened, we could be
+ // removing from an empty queue here. Make sure that doesn't happen.
+ //
+
+ p = RemoveHeadList(&Connection->SendQueue);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Request = NULL;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_SUCCESS;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_SENDS) != 0){
+ NbfPrint1 ("CompleteSend: Completing send request %lx\n", Irp);
+ if (++Connection->DeferredPasses >= 4) {
+ Connection->DeferredFlags &= ~CONNECTION_FLAGS_DEFERRED_SENDS;
+ Connection->DeferredPasses = 0;
+ }
+
+ }
+
+ }
+#endif
+
+
+ //
+ // Complete the send. Note that this may not actually call
+ // IoCompleteRequest for the Irp until sometime later, if the
+ // in-progress LLC resending going on below us needs to complete.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Since the irp is no longer on the send list, the cancel routine
+ // cannot find it and will just return. We must grab the cancel
+ // spinlock to lock out the cancel function while we null out
+ // the Irp->CancelRoutine field.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (
+ Irp,
+ STATUS_SUCCESS,
+ IRP_SEND_LENGTH(IrpSp));
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ++Connection->TransmittedTsdus;
+
+ if (EndOfRecord) {
+ break;
+ }
+
+ }
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+ // Note: The connection spinlock is held here.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ //
+ // If there is another send pending on the connection, then initialize
+ // it and start packetizing it.
+ //
+
+ if (!(IsListEmpty (&Connection->SendQueue))) {
+
+ InitializeSend (Connection);
+
+ //
+ // This code is similar to calling StartPacketizingConnection
+ // with the second parameter FALSE.
+ //
+
+ if ((!(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packetize", Connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &Connection->Provider->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &Connection->Provider->SpinLock);
+
+ }
+
+ }
+
+ //
+ // NOTE: We return with the lock held.
+ //
+
+} /* CompleteSend */
+
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called because something on the link caused this send to be
+ unable to complete. There are a number of possible reasons for this to have
+ happened, but all will fail with the common error STATUS_LINK_FAILED.
+ or NO_RECEIVE response where the number of bytes specified exactly
+ Here we retire all of the TdiSends on the connection's SendQueue up to
+ and including the current one, which is the one that failed.
+
+ Later - Actually, a send failing is cause for the entire circuit to wave
+ goodbye to this life. We now simply tear down the connection completly.
+ Any future sends on this connection will be blown away.
+
+ NOTE: THIS FUNCTION MUST BE CALLED WITH THE SPINLOCK HELD.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ BOOLEAN GotCurrent = FALSE;
+ KIRQL cancelIrql;
+
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("FailSend: Entered for connection %lx.\n", Connection);
+ }
+
+
+ //
+ // Pick off IRP objects from the connection's SendQueue until
+ // we get to this one. If this one does NOT have an EOF mark set, we'll
+ // need to keep going until we hit one that does have EOF set. Note that
+ // this may cause us to continue failing sends that have not yet been
+ // queued. (We do all this because NBF does not provide stream mode sends.)
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfReferenceConnection ("Failing Send", Connection, CREF_COMPLETE_SEND);
+
+ do {
+ if (IsListEmpty (&Connection->SendQueue)) {
+
+ //
+ // got an empty list, so we've run out of send requests to fail
+ // without running into an EOR. Set the connection flag that will
+ // cause all further sends to be failed up to an EOR and get out
+ // of here.
+ //
+
+ Connection->Flags |= CONNECTION_FLAGS_FAILING_TO_EOR;
+ break;
+ }
+ p = RemoveHeadList (&Connection->SendQueue);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ if (Irp == Connection->sp.CurrentSendIrp) {
+ GotCurrent = TRUE;
+ }
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = Irp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = RequestStatus;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ NbfCompleteSendIrp (Irp, RequestStatus, 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ ++Connection->TransmissionErrors;
+
+ } while (!EndOfRecord & !GotCurrent);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->sp.CurrentSendIrp = NULL;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // Blow away this connection; a failed send is a terrible thing to waste.
+ // Note that we are not on any packetizing queues or similar things at this
+ // point; we'll just disappear into the night.
+ //
+
+#if MAGIC
+ if (NbfEnableMagic) {
+ extern VOID NbfSendMagicBullet (PDEVICE_CONTEXT, PTP_LINK);
+ NbfSendMagicBullet (Connection->Provider, Connection->Link);
+ }
+#endif
+
+ if (StopConnection) {
+#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( "FailSend stopping connection to %S from %S\n",
+ &remoteName, &localName );
+ }
+#endif
+ NbfStopConnection (Connection, STATUS_LINK_FAILED);
+ }
+
+#if DBG
+ //DbgBreakPoint ();
+#endif
+
+ NbfDereferenceConnection ("FailSend", Connection, CREF_COMPLETE_SEND);
+
+} /* FailSend */
+
+#if DBG
+//
+// *** This is the original version of InitializeSend, which is now a macro.
+// It has been left here as the fully-commented version of the code.
+//
+
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever the next send on a connection should
+ be initialized; that is, all of the fields associated with the state
+ of the current send are set to refer to the first send on the SendQueue.
+
+ WARNING: This routine is executed with the Connection lock acquired
+ since it must be atomically executed with the caller's setup.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("InitializeSend: Entered for connection %lx.\n", Connection);
+ }
+
+ ASSERT (!IsListEmpty (&Connection->SendQueue));
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+ Connection->FirstSendIrp =
+ CONTAINING_RECORD (Connection->SendQueue.Flink, IRP, Tail.Overlay.ListEntry);
+ Connection->FirstSendMdl = Connection->FirstSendIrp->MdlAddress;
+ Connection->FirstSendByteOffset = 0;
+ Connection->sp.MessageBytesSent = 0;
+ Connection->sp.CurrentSendIrp = Connection->FirstSendIrp;
+ Connection->sp.CurrentSendMdl = Connection->FirstSendMdl;
+ Connection->sp.SendByteOffset = Connection->FirstSendByteOffset;
+ Connection->CurrentSendLength =
+ IRP_SEND_LENGTH(IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp));
+ Connection->StallCount = 0;
+ Connection->StallBytesSent = 0;
+
+ //
+ // The send correlator isn't used for much; it is used so we
+ // can distinguish which send a piggyback ack is acking.
+ //
+
+ if (Connection->NetbiosHeader.ResponseCorrelator == 0xffff) {
+ Connection->NetbiosHeader.ResponseCorrelator = 1;
+ } else {
+ ++Connection->NetbiosHeader.ResponseCorrelator;
+ }
+
+} /* InitializeSend */
+#endif
+
+
+VOID
+ReframeSend(
+ PTP_CONNECTION Connection,
+ ULONG BytesReceived
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to reset the send state variables in the connection
+ object to correctly point to the first byte of data to be transmitted.
+ In essence, this is the byte-level acknowlegement processor at the NetBIOS
+ level for this transport.
+
+ This is not straightforward because potentially multiple send requests
+ may be posted to the connection to comprise a single message. When a
+ send request has its TDI_END_OF_RECORD option bitflag set, then that
+ send is the last one to be sent in a logical message. Therefore, we
+ assume that the multiple-send scenario is the general case.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ BytesReceived - Number of bytes received thus far.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PIRP Irp;
+ PMDL Mdl;
+ ULONG Offset;
+ ULONG BytesLeft;
+ ULONG MdlBytes;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ReframeSend: Entered for connection %lx, Flags: %lx Current Mdl: %lx\n",
+ Connection, Connection->Flags, Connection->sp.CurrentSendMdl);
+ }
+
+ //
+ // The caller is responsible for restarting the packetization process
+ // on this connection. In some cases (i.e., NO_RECEIVE handler) we
+ // don't want to start packetizing, so that's why we do it elsewhere.
+ //
+
+ //
+ // Examine all of the send requests and associated MDL chains starting
+ // with the first one at the head of the connection's SendQueue, advancing
+ // our complex current send pointer through the requests and MDL chains
+ // until we reach the byte count he's specified.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ //
+ // In the case where a local disconnect has been issued, and we get a frame
+ // that causes us to reframe the send our FirstSendIrp and FirstMdl
+ // pointers are stale. Catch this condition and prevent faults caused by
+ // this. A better fix would be to change the logic that switches the
+ // connection sendstate from idle to W_LINK to not do that. However, this
+ // is a broader change than fixing it right here.
+ //
+
+ if (IsListEmpty(&Connection->SendQueue)) {
+ RELEASE_DPC_SPIN_LOCK(Connection->LinkSpinLock);
+ return;
+ }
+
+ BytesLeft = BytesReceived;
+ Irp = Connection->FirstSendIrp;
+ Mdl = Connection->FirstSendMdl;
+ if (Mdl) {
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ } else {
+ MdlBytes = 0; // zero-length send
+ }
+ Offset = Connection->FirstSendByteOffset;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+ NbfPrint3 ("ReFrameSend: Called with Connection %lx FirstSend %lx CurrentSend %lx\n",
+ Connection, Connection->FirstSendIrp, Connection->sp.CurrentSendIrp);
+ Connection->DeferredFlags |= CONNECTION_FLAGS_DEFERRED_SENDS;
+ Connection->DeferredPasses = 0;
+ }
+#endif
+
+ //
+ // We loop through while we have acked bytes left to account for,
+ // advancing our pointers and completing any sends that have been
+ // completely acked.
+ //
+
+ while (BytesLeft != 0) {
+
+ if (Mdl == NULL) {
+ KIRQL cancelIrql;
+
+ //
+ // We have exhausted the MDL chain on this request, so it has
+ // been implicitly acked. That means we must complete the I/O
+ // by dereferencing the request before we reframe further.
+ //
+
+ p = RemoveHeadList (&Connection->SendQueue);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // Since the irp is no longer on the list, the cancel routine
+ // won't find it. Grab the cancel spinlock to synchronize
+ // and complete the irp.
+ //
+
+ IoAcquireCancelSpinLock(&cancelIrql);
+ IoSetCancelRoutine(Irp, NULL);
+ IoReleaseCancelSpinLock(cancelIrql);
+
+ NbfCompleteSendIrp (Irp, STATUS_SUCCESS, Offset);
+
+ //
+ // Now continue with the next request in the list.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ p = Connection->SendQueue.Flink;
+ if (p == &Connection->SendQueue) {
+
+ ULONG DumpData[2];
+
+ //
+ // The byte acknowledgement was for more than the
+ // total length of sends we have outstanding; to
+ // avoid problems we tear down the connection.
+ //
+#if DBG
+ NbfPrint2 ("NbfReframeSend: Got %d extra bytes acked on %lx\n",
+ BytesLeft, Connection);
+ ASSERT (FALSE);
+#endif
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ DumpData[0] = Offset;
+ DumpData[1] = BytesLeft;
+
+ NbfWriteGeneralErrorLog(
+ Connection->Provider,
+ EVENT_TRANSPORT_BAD_PROTOCOL,
+ 1,
+ STATUS_INVALID_NETWORK_RESPONSE,
+ L"REFRAME",
+ 2,
+ DumpData);
+
+ NbfStopConnection (Connection, STATUS_INVALID_NETWORK_RESPONSE);
+
+ return;
+
+ }
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ Mdl = Irp->MdlAddress;
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ Offset = 0;
+
+ } else if (MdlBytes > (Offset + BytesLeft)) {
+
+ //
+ // This MDL has more data than we really need. Just use
+ // part of it. Then get out, because we're done.
+ //
+
+ Offset += BytesLeft;
+ BytesLeft = 0;
+ break;
+
+ } else {
+
+ //
+ // This MDL does not have enough data to satisfy the ACK, so
+ // use as much data as it has, and cycle around again.
+ //
+
+ Offset = 0;
+ BytesLeft -= MdlBytes;
+ Mdl = Mdl->Next;
+
+ if (Mdl != NULL) {
+ MdlBytes = MmGetMdlByteCount (Mdl);
+ }
+
+ }
+ }
+
+ //
+ // Tmp debugging; we want to see if we got byte acked
+ // for the entire send. This will break if we have
+ // non-EOR sends.
+ //
+
+#if DBG
+ if (BytesReceived != 0) {
+ ASSERTMSG ("NbfReframeSend: Byte ack for entire send\n",
+ Mdl != NULL);
+ }
+#endif
+
+ //
+ // We've acked some data, possibly on a byte or message boundary.
+ // We must pretend we're sending a new message all over again,
+ // starting with the byte immediately after the last one he acked.
+ //
+
+ Connection->FirstSendIrp = Irp;
+ Connection->FirstSendMdl = Mdl;
+ Connection->FirstSendByteOffset = Offset;
+
+ //
+ // Since we haven't started sending this new reframed message yet,
+ // we set our idea of the current complex send pointer to the first
+ // complex send pointer.
+ //
+
+ Connection->sp.MessageBytesSent = 0;
+ Connection->sp.CurrentSendIrp = Irp;
+ Connection->sp.CurrentSendMdl = Mdl;
+ Connection->sp.SendByteOffset = Offset;
+ Connection->CurrentSendLength -= BytesReceived;
+ Connection->StallCount = 0;
+ Connection->StallBytesSent = 0;
+
+#if DBG
+ IF_NBFDBG (NBF_DEBUG_TRACKTDI) {
+
+ {
+ PLIST_ENTRY p;
+ NbfPrint0 ("ReFrameSend: Walking Send List:\n");
+
+ for (
+ p = Connection->SendQueue.Flink;
+ p != &Connection->SendQueue;
+ p=p->Flink ) {
+
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ NbfPrint1 (" Irp %lx\n", Irp);
+ }
+ }}
+#endif
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+} /* ReframeSend */
+
+
+VOID
+NbfCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send.
+ The send is found on the connection's send queue; if it is the
+ current request it is cancelled and the connection is torn down,
+ otherwise it is silently cancelled.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+ PIRP SendIrp;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+
+ UNREFERENCED_PARAMETER (DeviceObject);
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_SEND));
+
+ Connection = IrpSp->FileObject->FsContext;
+
+ //
+ // Since this IRP is still in the cancellable state, we know
+ // that the connection is still around (although it may be in
+ // the process of being torn down).
+ //
+
+
+ //
+ // See if this is the IRP for the current send request.
+ //
+
+ ACQUIRE_SPIN_LOCK (Connection->LinkSpinLock, &oldirql);
+ NbfReferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
+
+ p = Connection->SendQueue.Flink;
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+
+ if (SendIrp == Irp) {
+
+ //
+ // yes, it is the first one on the send queue, so
+ // trash the send/connection. The first send is a special case
+ // there are multiple pointers to the send request. Just stop the
+ // connection.
+ //
+
+ // p = RemoveHeadList (&Connection->SendQueue);
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ //
+ // Prevent anyone from getting in to packetize before we
+ // call NbfStopConnection.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled in-progress send %lx on %lxn",
+ SendIrp, Connection);
+#endif
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ // NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+
+ //
+ // Since we are cancelling the current send, blow away
+ // the connection.
+ //
+
+ NbfStopConnection (Connection, STATUS_CANCELLED);
+
+ KeLowerIrql (oldirql1);
+
+ } else {
+
+ //
+ // Scan through the list, looking for this IRP. If we
+ // cancel anything up to the first EOR on the list
+ // we still tear down the connection since this would
+ // mess up our packetizing otherwise. We set CancelledFirstEor
+ // to FALSE when we pass an IRP without SEND_PARTIAL.
+ //
+ // NO MATTER WHAT WE MUST SHUT DOWN THE CONNECTION!!!!
+
+#if 0
+ if (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL)) {
+ CancelledFirstEor = FALSE;
+ } else {
+ CancelledFirstEor = TRUE;
+ }
+#endif
+
+ Found = FALSE;
+ p = p->Flink;
+ while (p != &Connection->SendQueue) {
+
+ SendIrp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ if (SendIrp == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+
+#if DBG
+ NbfCompletedSends[NbfCompletedSendsNext].Irp = SendIrp;
+ NbfCompletedSends[NbfCompletedSendsNext].Status = STATUS_CANCELLED;
+ NbfCompletedSendsNext = (NbfCompletedSendsNext++) % TRACK_TDI_LIMIT;
+#endif
+
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+#if DBG
+ DbgPrint("NBF: Canceled queued send %lx on %lx\n",
+ SendIrp, Connection);
+#endif
+
+ //
+ // The following dereference will complete the I/O, provided removes
+ // the last reference on the request object. The I/O will complete
+ // with the status and information stored in the Irp. Therefore,
+ // we set those values here before the dereference.
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ NbfCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+ //
+ // STOP THE CONNECTION NO MATTER WHAT!!!
+ //
+ NbfStopConnection (Connection, STATUS_CANCELLED);
+
+ KeLowerIrql (oldirql1);
+ break;
+
+ }
+#if 0
+ else {
+
+ if (CancelledFirstEor && (!(IRP_SEND_FLAGS(IoGetCurrentIrpStackLocation(SendIrp)) & TDI_SEND_PARTIAL))) {
+ CancelledFirstEor = FALSE;
+ }
+ }
+#endif
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel send %lx on %lx, not found\n",
+ Irp, Connection);
+#endif
+ RELEASE_SPIN_LOCK (Connection->LinkSpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+ }
+
+ NbfDereferenceConnection ("Cancelling Send", Connection, CREF_COMPLETE_SEND);
+
+}
+
+
+BOOLEAN
+ResendPacket (
+ PTP_LINK Link,
+ PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resends a packet on the link. Since this is a resend, we
+ are careful to not reset the state unless all resends have completed.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - pointer to packet to be resent.
+
+Return Value:
+
+ True if resending should continue; FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN PollFinal;
+ PDLC_I_FRAME DlcHeader;
+ UINT DataLength;
+
+
+ //
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ReSendPacket: %lx NdisPacket: %lx # %x\n",
+ Packet, Packet->NdisPacket,
+ DlcHeader->RcvSeq >>1);
+ IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
+ {PUCHAR q;
+ USHORT i;
+ q = Packet->Header;
+ for (i=0;i<20;i++) {
+ NbfPrint1 (" %2x",q[i]);
+ }
+ NbfPrint0 ("\n");}
+ }
+ }
+
+ DataLength = Packet->NdisIFrameLength;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ Link->WindowErrors++;
+
+ PollFinal = (BOOLEAN)((DlcHeader->RcvSeq & DLC_I_PF) != 0);
+
+ StopT2 (Link); // since this is potentially acking some frames
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ if (PollFinal) {
+ ASSERT (Packet->Link != NULL);
+ NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, 0);
+ }
+ } else {
+ StartT1 (Link, PollFinal ? DataLength : 0); // restart transmission timer
+ }
+
+ //
+ // Update the expected next receive in case it's changed
+ //
+
+ if (PollFinal) {
+
+ DlcHeader->RcvSeq = DLC_I_PF; // set the poll bit.
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+
+ Link->ResendingPackets = FALSE;
+
+ } else {
+
+ DlcHeader->RcvSeq = 0;
+
+ }
+
+ //
+ // DlcHeader->RcvSeq has Link->NextReceive inserted by NbfNdisSend.
+ //
+
+ NbfReferencePacket (Packet); // so we don't remove it in send completion
+
+ NbfReferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
+
+ ASSERT (Packet->PacketSent == TRUE);
+ Packet->PacketSent = FALSE;
+
+ //
+ // Update our "bytes resent" counters.
+ //
+
+ DataLength -=
+ Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION);
+
+
+ ADD_TO_LARGE_INTEGER(
+ &Link->Provider->Statistics.DataFrameBytesResent,
+ DataLength);
+ ++Link->Provider->Statistics.DataFramesResent;
+
+
+ //
+ // Send the packet (this release the link spinlock).
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ ++Link->PacketsResent;
+
+ NbfDereferenceLink ("ResendPacket", Link, LREF_NDIS_SEND);
+
+ //
+ // if this packet has POLL set, stop the resending so the
+ // link doesn't get all twisted up.
+ //
+
+ if (PollFinal) {
+
+ //
+ // so we're in the state of having sent a poll and not
+ // sending anything else until we get a final. This avoids
+ // overrunning the remote. Note that we leave the routine
+ // with state LINK_SENDSTATE_REJECTING, which guarentees
+ // we won't start any new sends until we traverse through
+ // this routine again.
+ //
+ //
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ResendLlcPackets (
+ PTP_LINK Link,
+ UCHAR AckSequenceNumber,
+ BOOLEAN Resend
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the state of a data link connection by retiring
+ all of the packets on the link's WackQ that have send sequence numbers
+ logically less than that number specified as the AckSequenceNumber, and
+ resending those above that number. The packets are disposed of by
+ dereferencing them. We cannot simply destroy them because this
+ acknowlegement might arrive even before the Physical Provider has had a
+ chance to issue a completion event for the associated I/O.
+
+ NOTE: This function is called with the link spinlock held and
+ returns with it held, but it may release it in between. THIS
+ ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ AckSequenceNumber - An unsigned number specifing the sequence number of
+ the first packet within the window that is NOT acknowleged.
+
+ Resend - if TRUE, resend packets. If FALSE, just remove them from the
+ wackq and get out.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_PACKET packet;
+ PLIST_ENTRY p, p1;
+ UCHAR packetSeq;
+ BOOLEAN passedAck = FALSE;
+ PDLC_I_FRAME DlcHeader;
+ SCHAR Difference;
+ BOOLEAN ReturnValue = FALSE;
+// NDIS_STATUS ndisStatus;
+
+ //
+ // Move through the queue, releasing those we've been acked for and resending
+ // others above that.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("ResendLlcPackets: Link %lx, Ack: %x, LinkLastAck: %x.\n",
+ Link, AckSequenceNumber, Link->LastAckReceived);
+ NbfPrint0 ("RLP: Walking WackQ, Packets:\n");
+ p = Link->WackQ.Flink; // p = ptr, 1st pkt's linkage.
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+ NbfPrint4 ("RLP: Pkt: %lx # %x Flags: %d %d\n", packet,
+ (UCHAR)(DlcHeader->SendSeq >> 1), packet->PacketSent, packet->PacketNoNdisBuffer);
+ p = packet->Linkage.Flink;
+ }
+ }
+
+ //
+ // If somebody else is resending LLC packets (which means they
+ // are in this function with Resend == TRUE), then ignore
+ // this frame. This is because it may ack a frame that he
+ // is in the middle of resending, which will cause problems.
+ //
+ // BUGBUG: This isn't a great solution, we should keep track
+ // of where the other guy is and avoid stepping on him. This
+ // might mess up his walking of the queue however.
+ //
+
+ if (Link->ResendingPackets) {
+ NbfPrint1("ResendLlcPackets: Someone else resending on %lx\n", Link);
+ return TRUE;
+ }
+
+ //
+ // We have already checked that AckSequenceNumber is reasonable.
+ //
+
+ Link->LastAckReceived = AckSequenceNumber;
+
+ if (Resend) {
+
+ //
+ // Only one person can be resending or potentially resending
+ // at one time.
+ //
+
+ Link->ResendingPackets = TRUE;
+ }
+
+ //
+ // Resend as many packets as we have window to send. We spin through the
+ // queue and remove those packets that have been acked or that are
+ // sequence numbered logically below the current ack number. The flags
+ // PACKET_FLAGS_RESEND and PACKET_FLAGS_SENT correspond to the three states
+ // a packet on this queue can be in:
+ //
+ // 1) if _RESEND is set, the packet has not been acked
+ //
+ // 2) if _SENT is set, the packet send has completed (conversely, if NOT
+ // set, the packet has not yet been completely sent, thus it is
+ // unnecessary to resend it).
+ // 3) if _RESEND and _SENT are both set, the packet has been sent and not
+ // acked and is grist for our mills.
+ // 4) if neither is set, the world is coming to an end next Thursday.
+ //
+
+ p=Link->WackQ.Flink;
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+
+ //
+ // if both bits aren't set we can't do a thing with this packet, or,
+ // for that matter, with the rest of the packet list. We can't
+ // have reached the ack number yet, as these packets haven't even
+ // completed sending.
+ // (Later) actually, we can have reached passedAck, and if we did
+ // we're in a world of hurt. We can't send more regular packets,
+ // but we can't send any resend packets either. Force the link to
+ // checkpoint and things will clear themselves up later.
+ //
+
+ if (!(packet->PacketSent)) {
+ if (passedAck) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("ResendLLCPacket: Can't send WACKQ Packet RcvSeq %x %x \n",
+ DlcHeader->RcvSeq, DlcHeader->SendSeq);
+ }
+
+ if (Link->SendState != SEND_STATE_CHECKPOINTING) {
+
+ //
+ // Don't start checkpointing if we already are.
+ //
+
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ StopTi (Link);
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // start checkpoint timeout.
+ Link->ResendingPackets = FALSE;
+
+ //
+ // Try this...in this case don't actually send
+ // an RR, since his response might put us right
+ // back here. When T1 expires we will recover.
+ //
+ // NbfSendRr (Link, TRUE, TRUE);
+
+ } else {
+
+ Link->ResendingPackets = FALSE;
+
+ }
+
+ return TRUE;
+ }
+
+ //
+ // Don't break, since passedAck is FALSE all we will
+ // do in the next section is TpDereferencePacket, which
+ // is correct.
+ //
+ // break;
+ }
+
+ //
+ // This loop is somewhat schizo; at this point, if we've not yet reached
+ // the ack number, we'll be ditching the packet. If we've gone through
+ // the ack number, we'll be re-transmitting. Note that in the first
+ // personality, we are always looking at the beginning of the list.
+ //
+
+ //
+ // NOTE: Link spinlock is held here.
+ //
+
+ packetSeq = (UCHAR)(DlcHeader->SendSeq >> 1);
+ if (!passedAck){
+
+ //
+ // Compute the signed difference here; see if
+ // packetSeq is equal to or "greater than"
+ // LastAckReceived.
+ //
+
+ Difference = packetSeq - Link->LastAckReceived;
+
+ if (((Difference >= 0) && (Difference < 0x40)) ||
+ (Difference < -0x40)) {
+
+ //
+ // We have found a packet on the queue that was
+ // not acknowledged by LastAckReceived.
+ //
+
+ if (Link->SendState == SEND_STATE_CHECKPOINTING) {
+
+ //
+ // If we are checkpointing, we should not do any of
+ // the passedAck things (i.e. any of the things which
+ // potentially involve sending packets) - adb 7/30/91.
+ //
+
+ if (Resend) {
+ Link->ResendingPackets = FALSE;
+ }
+ return TRUE;
+ }
+
+ if (!Resend) {
+
+ //
+ // If we are not supposed to resend, then exit.
+ // Since there are still packets on the queue
+ // we restart T1.
+ //
+
+ StopTi (Link);
+ StartT1 (Link, 0); // start checkpoint timeout.
+ return TRUE;
+ }
+
+ //
+ // Lock out senders, so we maintain packet sequences properly
+ //
+
+ Link->SendState = SEND_STATE_REJECTING; // we're resending.
+
+ passedAck = TRUE;
+
+ //
+ // Note that we don't advance the pointer to the next packet;
+ // thus, we will resend this packet on the next pass through
+ // the while loop (taking the passedAck branch).
+ //
+
+ } else {
+ p1 = RemoveHeadList (&Link->WackQ);
+ ASSERTMSG (" ResendLLCPacket: Packet not at queue head!\n", (p == p1));
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ ReturnValue = TRUE;
+ NbfDereferencePacket (packet);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = Link->WackQ.Flink;
+ }
+
+ } else {
+// NbfPrint1 ("RLP: # %x\n",packetSeq);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ //
+ // If this call returns FALSE (because we checkpoint)
+ // it clears ResendingPacket before it returns.
+ //
+
+ if (!ResendPacket (Link, packet)) {
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return ReturnValue;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ p = p->Flink;
+ }
+ }
+
+ //
+ // NOTE: Link spinlock is held here.
+ //
+
+ if (passedAck) {
+
+ //
+ // If we exit through here with passedAck TRUE, it means that we
+ // successfully called ResendPacket on every packet in the
+ // WackQ, which means we did not resend a poll packet, so we
+ // can start sending normally again. We have to clear
+ // ResendingPackets here.
+ //
+
+ Link->SendState = SEND_STATE_READY;
+ Link->ResendingPackets = FALSE;
+ StartTi (Link);
+
+ } else if (!Resend) {
+
+ //
+ // If Resend is FALSE (in which case passedAck will also be FALSE,
+ // by the way), and the WackQ is empty, that means that we
+ // successfully acknowledged all the packets on a non-final
+ // frame. In this case T1 may be running, but in fact is not
+ // needed since there are no sends outstanding.
+ //
+
+ if (Link->WackQ.Flink == &Link->WackQ) {
+ StopT1 (Link); // BUGBUG: StartTi??
+ }
+ Link->SendState = SEND_STATE_READY;
+ StartTi (Link);
+
+ } else {
+
+ //
+ // Resend is TRUE, but passedAck is FALSE; we came in
+ // expecting to resend, but didn't. This means that
+ // we have emptied the queue after receiving an
+ // RR/f, i.e. this send window is done and we can
+ // update our send window size, etc.
+ //
+
+ Link->ResendingPackets = FALSE;
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ return ReturnValue;
+ }
+
+ if (Link->WindowErrors > 0) {
+
+ //
+ // We had transmit errors on this window.
+ //
+
+ Link->PrevWindowSize = Link->SendWindowSize;
+
+ //
+ // We use 100 ms delay as the cutoff for a LAN.
+ //
+
+ if (Link->Delay < (100*MILLISECONDS)) {
+
+ //
+ // On a LAN, if we have a special case
+ // if one packet was lost; this means the
+ // final packet was retransmitted once. In
+ // that case, we keep track of Consecutive
+ // LastPacketLost, and if it reaches 2, then
+ // we lock the send window at its current
+ // value minus one.
+ //
+
+ if (Link->WindowErrors == 1) {
+
+ ++Link->ConsecutiveLastPacketLost;
+
+ if (Link->ConsecutiveLastPacketLost >= 2) {
+
+ //
+ // Freeze the window wherever it was.
+ //
+
+ if (Link->SendWindowSize > Link->Provider->MinimumSendWindowLimit) {
+ Link->MaxWindowSize = Link->SendWindowSize - 1;
+ Link->SendWindowSize = (UCHAR)Link->MaxWindowSize;
+ }
+
+ }
+
+ //
+ // Otherwise, we leave the window where it is.
+ //
+
+ } else {
+
+ Link->ConsecutiveLastPacketLost = 0;
+ Link->SendWindowSize -= (UCHAR)Link->WindowErrors;
+
+ }
+
+ } else {
+
+ //
+ // On a WAN we cut the send window in half,
+ // regardless of how many frames were retransmitted.
+ //
+
+ Link->SendWindowSize /= 2;
+ Link->WindowsUntilIncrease = 1; // in case Prev is also 1.
+ Link->ConsecutiveLastPacketLost = 0;
+
+ }
+
+ if ((SCHAR)Link->SendWindowSize < 1) {
+ Link->SendWindowSize = 1;
+ }
+
+ //
+ // Reset our counters for the next window.
+ //
+
+ Link->WindowErrors = 0;
+
+ } else {
+
+ //
+ // We have successfully sent a window of data, increase
+ // the send window size unless we are at the limit.
+ // We use 100 ms delay as the WAN/LAN cutoff.
+ //
+
+ if ((ULONG)Link->SendWindowSize < Link->MaxWindowSize) {
+
+ if (Link->Delay < (100*MILLISECONDS)) {
+
+ //
+ // On a LAN, increase the send window by 1.
+ //
+ // BUGBUG: Need to determine optimal window
+ // size.
+ //
+
+ Link->SendWindowSize++;
+
+ } else {
+
+ //
+ // On a WAN, increase the send window by 1 until
+ // we hit PrevWindowSize, then do it more slowly.
+ //
+
+ if (Link->SendWindowSize < Link->PrevWindowSize) {
+
+ Link->SendWindowSize++;
+
+ //
+ // If we just increased it to the previous window
+ // size, prepare for the next time through here.
+ //
+
+ if (Link->SendWindowSize == Link->PrevWindowSize) {
+ Link->WindowsUntilIncrease = Link->SendWindowSize;
+ }
+
+ } else {
+
+ //
+ // We passed the previous size, so only update every
+ // WindowsUntilIncrease times.
+ //
+
+ if (--Link->WindowsUntilIncrease == 0) {
+
+ Link->SendWindowSize++;
+ Link->WindowsUntilIncrease = Link->SendWindowSize;
+
+ }
+ }
+ }
+
+ if ((ULONG)Link->SendWindowSize > Link->Provider->Statistics.MaximumSendWindow) {
+ Link->Provider->Statistics.MaximumSendWindow = Link->SendWindowSize;
+ }
+
+ }
+
+ //
+ // Clear this since we had no errors.
+ //
+
+ Link->ConsecutiveLastPacketLost = 0;
+
+ }
+
+ }
+
+ return ReturnValue;
+
+} /* ResendLlcPackets */
+
+
+VOID
+NbfSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ NdisContext - the value associated with the adapter binding at adapter
+ open time (which adapter we're talking on).
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSEND_PACKET_TAG SendContext;
+ PTP_PACKET Packet;
+ KIRQL oldirql1;
+ ProtocolBindingContext; // avoid compiler warnings
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbfSendsCompletedAfterPendFail++;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
+ NdisPacket, NbfGetNdisStatus (NdisStatus));
+ }
+ } else {
+ NbfSendsCompletedAfterPendOk++;
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint2 ("NbfSendComplete: Entered for packet %lx, Status %s\n",
+ NdisPacket, NbfGetNdisStatus (NdisStatus));
+ }
+ }
+#endif
+
+ SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
+
+ switch (SendContext->Type) {
+ case TYPE_I_FRAME:
+
+ //
+ // Just dereference the packet. There are a couple possibilities here.
+ // First, the I/O completion might happen before an ACK is received,
+ // in which case this will remove one of the references, but not both.
+ // Second, the LLC ACK for this packet may have already been processed,
+ // in which case this will destroy the packet. Third, this packet may
+ // be resent, either before or after this call, in which case the deref
+ // won't destroy the packet.
+ //
+ // NbfDereferencePacket will call PacketizeSend if it determines that
+ // there is at least one connection waiting to be packetized because
+ // of out-of-resource conditions or because its window has been opened.
+ //
+
+ Packet = ((PTP_PACKET)SendContext->Frame);
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql1);
+
+ if (Packet->Provider->MacInfo.MediumAsync) {
+
+ if (Packet->Link) {
+
+ ASSERT (Packet->NdisIFrameLength > 0);
+
+ ACQUIRE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
+ StartT1 (Packet->Link, Packet->NdisIFrameLength);
+ RELEASE_DPC_SPIN_LOCK (&Packet->Link->SpinLock);
+
+ NbfDereferenceLink ("Send completed", Packet->Link, LREF_START_T1);
+ }
+
+ if (Packet->PacketizeConnection) {
+
+ PTP_CONNECTION Connection = IRP_SEND_CONNECTION((PIO_STACK_LOCATION)(Packet->Owner));
+ PDEVICE_CONTEXT DeviceContext = Packet->Provider;
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if ((Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) &&
+ (Connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (Connection->Flags & CONNECTION_FLAGS_PACKETIZE);
+
+ ACQUIRE_DPC_SPIN_LOCK(&DeviceContext->SpinLock);
+
+ NbfReferenceConnection ("Delayed packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ InsertTailList(&DeviceContext->PacketizeQueue, &Connection->PacketizeLinkage);
+
+ if (!DeviceContext->WanThreadQueued) {
+
+ DeviceContext->WanThreadQueued = TRUE;
+ ExQueueWorkItem(&DeviceContext->WanDelayedQueueItem, DelayedWorkQueue);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ } else {
+
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("PacketizeConnection FALSE", Connection, CREF_TEMP);
+
+ Packet->PacketizeConnection = FALSE;
+
+ }
+ }
+#if DBG
+ if (Packet->PacketSent) {
+ DbgPrint ("NbfSendCompletionHandler: Packet %lx already completed\n", Packet);
+ DbgBreakPoint();
+ }
+#endif
+ Packet->PacketSent = TRUE;
+
+ NbfDereferencePacket (Packet);
+
+ KeLowerIrql (oldirql1);
+ break;
+
+ case TYPE_UI_FRAME:
+
+ //
+ // just destroy the frame; name stuff doesn't depend on having any
+ // of the sent message left around after the send completed.
+ //
+
+ NbfDestroyConnectionlessFrame ((PDEVICE_CONTEXT)SendContext->Owner,
+ (PTP_UI_FRAME)SendContext->Frame);
+ break;
+
+ case TYPE_ADDRESS_FRAME:
+
+ //
+ // Addresses get their own frames; let the address know it's ok to
+ // use the frame again.
+ //
+
+ NbfSendDatagramCompletion ((PTP_ADDRESS)SendContext->Owner,
+ NdisPacket,
+ NdisStatus );
+ break;
+ }
+
+ return;
+
+} /* NbfSendCompletionHandler */
+
+
+NTSTATUS
+SendOnePacket(
+ IN PTP_CONNECTION Connection,
+ IN PTP_PACKET Packet,
+ IN BOOLEAN ForceAck,
+ OUT PBOOLEAN LinkCheckpoint OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connection-oriented packet by calling the NDIS
+ Send service. At least one event will occur following
+ (or during) the Send request's processing. (1) The Send request
+ will complete through the I/O system, calling IoCompleteRequest.
+ (2) The sequenced packet will be acknowleged at the LLC level, or it
+ will be rejected and reset at the LLC level. If the packet is resent,
+ then it remains queued at the TP_LINK object. If the packet is ACKed,
+ then is removed from the link's WackQ and the Action field in the
+ TP_PACKET structure dictates what operation to perform next.
+
+ NOTE: This routine is called with the link spinlock held. THIS
+ ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+ NOTE: This routine will now accept all frames unless the link
+ is down. If the link cannot send, the packet will be queued and
+ sent when possible.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+ ForceAck - Boolean that, if true, indicates this packet should always have
+ the Poll bit set; this force the other side to ack immediately,
+ which is necessary for correct session teardown.
+
+ LinkCheckpoint - If specified, will return TRUE if the link has
+ just entered a checkpoint state. In this case the status
+ will be STATUS_SUCCESS, but the connection should stop
+ packetizing now (in fact, to close a window, the connection
+ is put into the W_LINK state if this status will be
+ returned, so he must stop because somebody else may
+ already be doing it).
+
+Return Value:
+
+ STATUS_LINK_FAILED - the link is dead or not ready.
+ STATUS_SUCCESS - the packet has been sent.
+ STATUS_INSUFFICIENT_RESOURCES - the packet has been queued.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PDLC_I_FRAME DlcHeader;
+ PNDIS_BUFFER ndisBuffer;
+ ULONG SendsOutstanding;
+ BOOLEAN Poll = FALSE;
+ NTSTATUS Status;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("SendOnePacket: Entered, connection %lx, packet %lx DnisPacket %lx.\n",
+ Connection, Packet, Packet->NdisPacket);
+ }
+
+ Link = Connection->Link;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ UINT PLength, PCount;
+ UINT BLength;
+ PVOID BAddr;
+ NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
+ NbfPrint3 ("Sending Data Packet: %lx, Length: %lx Pages: %lx\n",
+ Packet->NdisPacket, PLength, PCount);
+ while (ndisBuffer != NULL) {
+ NdisQueryBuffer(ndisBuffer, &BAddr, &BLength);
+ NbfPrint3 ("Sending Data Packet: Buffer %08lx Length %08lx Va %08lx\n",
+ ndisBuffer, BLength, BAddr);
+ NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
+ }
+ }
+
+ //
+ // If the general state of the link is not READY, then we can't ship.
+ // This failure can be expected under some conditions, and may not cause
+ // failure of the send.
+ //
+
+ if (Link->State != LINK_STATE_READY) {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("SendOnePacket: Link state is not READY (%ld).\n", Link->State);
+ }
+
+ //
+ // determine what to do with this problem. If we shouldn't be sending
+ // here, percolate an error upward.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("SendOnePacket: Link Bad state, link: %lx Link Flags %lx Link State %lx\n",
+ Link, Link->Flags, Link->State);
+ }
+ return STATUS_LINK_FAILED;
+ }
+
+
+ SendsOutstanding = (((ULONG)Link->NextSend+128L-(ULONG)Link->LastAckReceived)%128L);
+
+ //
+ // Format LLC header while we've got the spinlock to atomically update
+ // the link's state information.
+ //
+
+ DlcHeader = (PDLC_I_FRAME)&(Packet->Header[Link->HeaderLength]);
+ DlcHeader->SendSeq = (UCHAR)(Link->NextSend << 1);
+ Link->NextSend = (UCHAR)((Link->NextSend + 1) & 0x7f);
+ DlcHeader->RcvSeq = 0; // Link->NextReceive is inserted by NbfNdisSend
+
+ //
+ // Before we release the spinlock, we append the packet to the
+ // end of the link's WackQ, so that if an ACK arrives before the NdisSend
+ // completes, it will be on the queue already. Also, mark the packet as
+ // needing resend, which is canceled by AckLLCPackets, and used by
+ // ResendLLCPackets. Thus, all packets will need to be resent until they
+ // are acked.
+ //
+
+ ASSERT (Packet->PacketSent == FALSE);
+
+ InsertTailList (&Link->WackQ, &Packet->Linkage);
+ //SrvCheckListIntegrity( &Link->WackQ, 200 );
+
+
+ //
+ // If the send state is not READY, we can't ship.
+ // This failure is mostly caused by flow control or retransmit in progress,
+ // and is never cause for failure of the send.
+ //
+
+ if ((Link->SendState != SEND_STATE_READY) ||
+ (Link->LinkBusy) ||
+ (SendsOutstanding >= (ULONG)Link->SendWindowSize)) {
+
+ if ((Link->SendWindowSize == 1) || ForceAck) {
+ DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Packet->Link = Link;
+ }
+ }
+
+ Packet->PacketSent = TRUE; // allows it to be resent.
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ if (Link->SendState != SEND_STATE_READY) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("SendOnePacket: Link send state not READY (%ld).\n", Link->SendState);
+ }
+ } else if (Link->LinkBusy) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ PANIC ("SendOnePacket: Link is busy.\n");
+ }
+ } else if (SendsOutstanding >= (ULONG)Link->SendWindowSize) {
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint3 ("SendOnePacket: No link send window; N(S)=%ld,LAR=%ld,SW=%ld.\n",
+ Link->NextSend, Link->LastAckReceived, Link->SendWindowSize);
+ }
+ }
+#endif
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Reference the packet since it is given to the NDIS driver.
+ //
+
+#if DBG
+ NbfReferencePacket (Packet);
+#else
+ ++Packet->ReferenceCount; // OK since it is not queued anywhere.
+#endif
+
+ //
+ // If this is the last I-frame in the window, then indicate that we
+ // should checkpoint. Also checkpoint if the sender is requesting
+ // acknowledgement (currently on SendSessionEnd does this).
+ // By default, this will also be a command frame.
+ //
+
+ if (((SendsOutstanding+1) >= (ULONG)Link->SendWindowSize) ||
+ ForceAck) {
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ StopTi (Link);
+ DlcHeader->RcvSeq |= DLC_I_PF; // set the poll bit.
+ Poll = TRUE;
+
+ }
+
+
+ //
+ // If we are polling, and the caller cares about it, then
+ // we set LinkCheckpoint, and also set up the connection to
+ // be waiting for resources. We do this now, before the send,
+ // so that even if the ack is receive right away, we will
+ // be in a good state. When we return LinkCheckpoint TRUE
+ // the caller realizes that he no longer owns the right
+ // to "packetize" and exits immediately.
+ //
+ // We also want to start our retransmission timer so, if this
+ // packet gets dropped, we will know to retransmit it. The
+ // exception is if LinkCheckpoint was specified, then we
+ // only StartT1 of we are not polling (the caller will
+ // ensure it is started if he exits before we poll).
+ //
+
+ if (ARGUMENT_PRESENT(LinkCheckpoint)) {
+
+ if (Poll) {
+
+ //
+ // If the connection still has send state PACKETIZE,
+ // then change it to W_LINK. If it is something else
+ // (such as W_PACKET or W_ACK) then don't worry, when
+ // that condition clears he will repacketize and the
+ // link conditions will be re-examined. In all
+ // case we turn off the PACKETIZE flag, because when
+ // we return with LinkCheckpoint TRUE he will stop
+ // packetizing, and to close the window we turn it
+ // off now (before the NdisSend) rather than then.
+ //
+
+ ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
+ if (Connection->SendState == CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+ }
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ Packet->Link = Link;
+ NbfReferenceLink ("Send I-frame", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, Packet->NdisIFrameLength);
+ }
+ *LinkCheckpoint = TRUE;
+
+ } else {
+
+ StartT1 (Link, 0);
+ *LinkCheckpoint = FALSE;
+
+ }
+
+ } else {
+
+ //
+ // If LinkCheckpoint is not true, then we are sending
+ // an I-frame other than DFM/DOL. In this case, as
+ // an optimization, we'll set W_LINK if a) we are
+ // polling b) we are IDLE (to avoid messing up other
+ // states such as W_ACK). This will avoid a window
+ // where we don't go W_LINK until after the next
+ // send tries to packetize and fails.
+ //
+
+ if (Poll) {
+
+ ASSERT (Connection->LinkSpinLock == &Link->SpinLock);
+ if (Connection->SendState == CONNECTION_SENDSTATE_IDLE) {
+ Connection->SendState = CONNECTION_SENDSTATE_W_LINK;
+ }
+
+ }
+
+ //
+ // This is an optimization; we know that if LinkCheckpoint
+ // is present than we are being called from PacketizeSend;
+ // in this case the Link will have the LREF_CONNECTION
+ // reference and the connection will have the CREF_PACKETIZE
+ // reference, so we don't have to reference the link
+ // again.
+ //
+
+ NbfReferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
+
+
+ //
+ // Start the retransmission timer.
+ //
+
+ if (Link->Provider->MacInfo.MediumAsync) {
+ if (Poll) {
+ Packet->Link = Link;
+ NbfReferenceLink ("ResendPacket", Link, LREF_START_T1);
+ } else {
+ StartT1 (Link, 0);
+ }
+ } else {
+ StartT1 (Link, Poll ? Packet->NdisIFrameLength : 0);
+ }
+
+ }
+
+ //
+ // Since this I-frame contains an N(R), it is potentially ACKing some
+ // previously received I-frames as reverse traffic. So we stop our
+ // delayed acknowlegement timer.
+ //
+
+ StopT2 (Link);
+
+ if ((Link->Provider->MacInfo.MediumAsync) &&
+ (ARGUMENT_PRESENT(LinkCheckpoint)) &&
+ (Link->SendWindowSize >= 3) &&
+ (!Poll) && (SendsOutstanding == (ULONG)(Link->SendWindowSize-2))) {
+
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+ NbfReferenceConnection ("PacketizeConnection TRUE", Connection, CREF_TEMP);
+ Packet->PacketizeConnection = TRUE;
+
+ } else {
+
+ Status = STATUS_SUCCESS;
+ }
+
+ //
+ // Send the packet; no locks held. Note that if the send fails, we will
+ // NOT fail upward; we allow things to continue onward. This lets us retry
+ // the send multiple times before we crap out; additionally, it keeps us
+ // from failing obscurely when sending control Iframes.
+ //
+ // NOTE: NbfNdisSend releases the link spinlock.
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ Link->PacketsSent++;
+
+ //
+ // Remove the reference made above if needed.
+ //
+
+ if (!ARGUMENT_PRESENT(LinkCheckpoint)) {
+ NbfDereferenceLink ("SendOnePacket", Link, LREF_NDIS_SEND);
+ }
+
+ return Status;
+
+} /* SendOnePacket */
+
+
+VOID
+SendControlPacket(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a connection-oriented packet by calling the Physical
+ Provider's Send service. While SendOnePacket is used to send an I-
+ frame, this routine is used to send one of the following: RR, RNR, REJ,
+ SABME, UA, DISC, DM, FRMR, TEST, and XID.
+
+ NOTE: This function is called with the link spinlock held,
+ and returns with it released. IT MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT i;
+ PUCHAR p;
+ PNDIS_BUFFER ndisBuffer;
+
+ IF_NBFDBG (NBF_DEBUG_PACKET) {
+ NbfPrint3 ("SendControlPacket: Entered for link %lx, packet %lx, NdisPacket %lx\n 00:",
+ Link, Packet, Packet->NdisPacket);
+ IF_NBFDBG (NBF_DEBUG_PKTCONTENTS) {
+ UINT PLength, PCount;
+ UINT BLength;
+ PVOID BAddr;
+ p = Packet->Header;
+ for (i=0;i<20;i++) {
+ NbfPrint1 (" %2x",p[i]);
+ }
+ NbfPrint0 ("\n");
+ NdisQueryPacket(Packet->NdisPacket, &PCount, NULL, &ndisBuffer, &PLength);
+ NbfPrint3 ("Sending Control Packet: %lx, Length: %lx Pages: %lx\n",
+ Packet->NdisPacket, PLength, PCount);
+ while (ndisBuffer != NULL) {
+ NdisQueryBuffer (ndisBuffer, &BAddr, &BLength);
+ NbfPrint3 ("Sending Control Packet: Buffer %08lx Length %08lx Va %08lx\n",
+ ndisBuffer, BLength, BAddr);
+ NdisGetNextBuffer (ndisBuffer, &ndisBuffer);
+ }
+ }
+ }
+
+ ASSERT (Packet->PacketSent == FALSE);
+
+ NbfReferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
+
+ //
+ // Send the packet (we have the lock, NbfNdisSend released
+ // it.
+ //
+
+ NbfNdisSend (Link, Packet);
+
+ NbfDereferenceLink ("SendControlPacket", Link, LREF_NDIS_SEND);
+
+} /* SendControlPacket */
+
+
+VOID
+NbfNdisSend(
+ IN PTP_LINK Link,
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of NdisSend
+ and after assigning the receive sequence number it locks out other
+ sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: This routine is called with the link spinlock held,
+ and it returns with it released. THIS ROUTINE MUST BE CALLED
+ AT DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PLIST_ENTRY p;
+ PDLC_S_FRAME DlcHeader;
+ PNDIS_PACKET TmpNdisPacket;
+ ULONG result;
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ if (Link->Provider->UniProcessor) {
+
+ //
+ // On a uni-processor, we can send without fear of
+ // being interrupted by an incoming packet.
+ //
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
+
+ //
+ // It's not a U-frame, so we assign RcvSeq.
+ //
+
+ DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
+
+ }
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ INCREMENT_COUNTER (Link->Provider, PacketsSent);
+
+ if (Link->Loopback) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ Link->Provider,
+ Packet->NdisPacket,
+ Link->LoopbackDestinationIndex
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ }
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_PENDING:
+#if DBG
+ NbfSendsPended++;
+#endif
+ break;
+
+ case NDIS_STATUS_SUCCESS:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedOk++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+ break;
+
+ default:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedFail++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+ break;
+
+ }
+
+ } else {
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Link->NdisSendsInProgress > 0) {
+
+ p = (PLIST_ENTRY)(Packet->NdisPacket->MacReserved);
+ InsertTailList (&Link->NdisSendQueue, p);
+ ++Link->NdisSendsInProgress;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ return;
+
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence field in the packet (note that the RcvSeq
+ // field is in the same place for I- and S-frames.
+ //
+
+ Link->NdisSendsInProgress = 1;
+
+ while (TRUE) {
+
+ DlcHeader = (PDLC_S_FRAME)&(Packet->Header[Link->HeaderLength]);
+
+ if ((DlcHeader->Command & DLC_U_INDICATOR) != DLC_U_INDICATOR) {
+
+ //
+ // It's not a U-frame, so we assign RcvSeq.
+ //
+
+ DlcHeader->RcvSeq |= (UCHAR)(Link->NextReceive << 1);
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+#if DBG
+ NbfSendsIssued++;
+#endif
+
+ INCREMENT_COUNTER (Link->Provider, PacketsSent);
+
+ if (Link->Loopback) {
+
+ //
+ // This packet is sent to ourselves; we should loop it
+ // back.
+ //
+
+ NbfInsertInLoopbackQueue(
+ Link->Provider,
+ Packet->NdisPacket,
+ Link->LoopbackDestinationIndex
+ );
+
+ NdisStatus = NDIS_STATUS_PENDING;
+
+ } else {
+
+ NdisSend (
+ &NdisStatus,
+ Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = ExInterlockedAddUlong(
+ &Link->NdisSendsInProgress,
+ (ULONG)-1,
+ &Link->SpinLock);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend: NdisSend completed Status: %s.\n",
+ NbfGetNdisStatus(NdisStatus));
+ }
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_PENDING:
+#if DBG
+ NbfSendsPended++;
+#endif
+ break;
+
+ case NDIS_STATUS_SUCCESS:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedOk++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+ break;
+
+ default:
+#if DBG
+ NbfSendsCompletedInline++;
+ NbfSendsCompletedFail++;
+#endif
+ NbfSendCompletionHandler (Link->Provider->NdisBindingHandle,
+ Packet->NdisPacket,
+ NDIS_STATUS_SUCCESS);
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("NbfNdisSend failed, status not Pending or Complete: %lx.\n",
+ NbfGetNdisStatus (NdisStatus));
+ }
+ break;
+
+ }
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit.
+ //
+
+ if (result == 1) {
+ return;
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ p = RemoveHeadList(&Link->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Link->NdisSendQueue);
+
+ //
+ // Get back the TP_PACKET by using the Frame pointer in the
+ // ProtocolReserved field of the NDIS_PACKET.
+ //
+
+ TmpNdisPacket = CONTAINING_RECORD (p, NDIS_PACKET, MacReserved[0]);
+ Packet = (PTP_PACKET)(((PSEND_PACKET_TAG)(&TmpNdisPacket->ProtocolReserved[0]))->Frame);
+
+ } // while loop
+
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+} /* NbfNdisSend */
+
+
+VOID
+RestartLinkTraffic(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine continues the activities of the connections on a link.
+
+ NOTE: This function is called with the link spinlock held and
+ it returns with it released. THIS FUNCTION MUST BE CALLED AT
+ DPC LEVEL.
+
+Arguments:
+
+ Link - Pointer to a TP_LINK object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_CONNECTION connection;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_SENDENG) {
+ NbfPrint1 ("RestartLinkTraffic: Entered for link %lx.\n", Link);
+ }
+
+ //
+ // Link conditions may have cleared up. Make all connections on this
+ // link eligible for more packetization if they are in W_LINK state.
+ //
+
+ for (p = Link->ConnectionDatabase.Flink;
+ p != &Link->ConnectionDatabase;
+ p = p->Flink) {
+
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ ASSERT (connection->LinkSpinLock == &Link->SpinLock);
+
+ //
+ // If we tried to send a plain-ole data frame DFM/DOL, but
+ // link conditions were not satisfactory, then we changed
+ // send state to W_LINK. Check for that now, and possibly
+ // start repacketizing.
+ //
+
+ if (connection->SendState == CONNECTION_SENDSTATE_W_LINK) {
+ if (!(IsListEmpty (&connection->SendQueue))) {
+
+ connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ //
+ // This is similar to calling StartPacketizingConnection
+ // with the Immediate set to FALSE.
+ //
+
+ if (!(connection->Flags & CONNECTION_FLAGS_PACKETIZE) &&
+ (connection->Flags & CONNECTION_FLAGS_READY)) {
+
+ ASSERT (!(connection->Flags2 & CONNECTION_FLAGS2_STOPPING));
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ NbfReferenceConnection ("Packetize", connection, CREF_PACKETIZE_QUEUE);
+
+ ExInterlockedInsertTailList(
+ &connection->Provider->PacketizeQueue,
+ &connection->PacketizeLinkage,
+ &connection->Provider->SpinLock);
+
+ }
+
+ } else {
+ connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ }
+ }
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+} /* RestartLinkTraffic */
+
+
+VOID
+NbfProcessWanDelayedQueue(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the thread routine which restarts packetizing
+ that has been delayed on WAN to allow RRs to come in.
+ This is very similar to PacketizeConnections.
+
+Arguments:
+
+ Parameter - A pointer to the device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ PLIST_ENTRY p;
+ PTP_CONNECTION Connection;
+ KIRQL oldirql;
+
+ DeviceContext = (PDEVICE_CONTEXT)Parameter;
+
+ //
+ // Packetize all waiting connections
+ //
+
+ KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
+ ASSERT (DeviceContext->WanThreadQueued);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ while (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ p = RemoveHeadList(&DeviceContext->PacketizeQueue);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketizeLinkage);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ NbfDereferenceConnection ("No longer packetizing", Connection, CREF_PACKETIZE_QUEUE);
+ } else {
+ NbfReferenceSendIrp ("Packetize", IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp), RREF_PACKET);
+ PacketizeSend (Connection, FALSE); // releases the lock.
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ }
+
+ DeviceContext->WanThreadQueued = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ KeLowerIrql (oldirql);
+
+} /* NbfProcessWanDelayedQueue */
+
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PMDL CurrentMdl,
+ IN ULONG ByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *Destination,
+ OUT PMDL *NewCurrentMdl,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *TrueLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source Mdl chain and
+ offset into it. We assume we don't know the length of the source Mdl chain,
+ and we must allocate the NDIS_BUFFERs for the destination chain, which
+ we do from the NDIS buffer pool.
+
+ The NDIS_BUFFERs that are returned are mapped and locked. (Actually, the pages in
+ them are in the same state as those in the source MDLs.)
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset. TrueLength is set to 0.
+
+Environment:
+
+ Kernel Mode, Source Mdls locked. It is recommended, although not required,
+ that the source Mdls be mapped and locked prior to calling this routine.
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentMdl - Points to the start of the Mdl chain from which to draw the
+ packet.
+
+ ByteOffset - Offset within this MDL to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ Destination - returned pointer to the NDIS_BUFFER chain describing the packet.
+
+ NewCurrentMdl - returned pointer to the Mdl that would be used for the next
+ byte of packet. NULL if the source Mdl chain was exhausted.
+
+ NewByteOffset - returned offset into the NewCurrentMdl for the next byte of
+ packet. NULL if the source Mdl chain was exhausted.
+
+ TrueLength - The actual length of the returned NDIS_BUFFER Chain. If less than
+ DesiredLength, the source Mdl chain was exhausted.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded (even if
+ shorter than the desired chain).
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while building the
+ destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ PMDL OldMdl;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+ //
+
+ IF_NBFDBG (NBF_DEBUG_NDIS) {
+ NbfPrint3 ("BuildBufferChain: Mdl: %lx Offset: %ld Length: %ld\n",
+ CurrentMdl, ByteOffset, DesiredLength);
+ }
+
+ AvailableBytes = MmGetMdlByteCount (CurrentMdl) - ByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ OldMdl = CurrentMdl;
+ *NewCurrentMdl = OldMdl;
+ *NewByteOffset = ByteOffset + AvailableBytes;
+ *TrueLength = AvailableBytes;
+
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ DeviceContext->NdisBufferPool,
+ OldMdl,
+ ByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *Destination = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Destination = NewNdisBuffer;
+
+
+// IF_NBFDBG (NBF_DEBUG_SENDENG) {
+// PVOID PAddr, UINT PLen;
+// NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
+// NbfPrint4 ("BuildBufferChain: (start)Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
+// NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
+// }
+
+ //
+ // Was the first NDIS_BUFFER enough data, or are we out of Mdls?
+ //
+
+ if ((AvailableBytes == DesiredLength) || (OldMdl->Next == NULL)) {
+ if (*NewByteOffset >= MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ while (OldMdl != NULL) {
+ AvailableBytes = DesiredLength - *TrueLength;
+ if (AvailableBytes > MmGetMdlByteCount (OldMdl)) {
+ AvailableBytes = MmGetMdlByteCount (OldMdl);
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ DeviceContext->NdisBufferPool,
+ OldMdl,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*Destination != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*Destination);
+ NdisFreeBuffer (*Destination);
+ *Destination = NewNdisBuffer;
+ }
+
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *NewCurrentMdl = CurrentMdl;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ *TrueLength += AvailableBytes;
+ *NewByteOffset = AvailableBytes;
+
+// IF_NBFDBG (NBF_DEBUG_SENDENG) {
+// PVOID PAddr, UINT PLen;
+// NdisQueryBuffer (NewNdisBuffer, &PAddr, &PLen);
+// NbfPrint4 ("BuildBufferChain: (continue) Built Mdl: %lx Length: %lx, Next: %lx Va: %lx\n",
+// NewNdisBuffer, PLen, NDIS_BUFFER_LINKAGE(NewNdisBuffer), PAddr);
+// }
+
+ if (*TrueLength == DesiredLength) {
+ if (*NewByteOffset == MmGetMdlByteCount (OldMdl)) {
+ *NewCurrentMdl = OldMdl->Next;
+ *NewByteOffset = 0;
+ }
+ return STATUS_SUCCESS;
+ }
+ OldMdl = OldMdl->Next;
+ *NewCurrentMdl = OldMdl;
+
+ } // while (mdl chain exists)
+
+ *NewCurrentMdl = NULL;
+ *NewByteOffset = 0;
+ return STATUS_SUCCESS;
+
+} // BuildBufferChainFromMdlChain
+
diff --git a/private/ntos/tdi/nbf/sources b/private/ntos/tdi/nbf/sources
new file mode 100644
index 000000000..6d6ab7f87
--- /dev/null
+++ b/private/ntos/tdi/nbf/sources
@@ -0,0 +1,79 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nbf
+
+TARGETNAME=nbf
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+#C_DEFINES = -DRASAUTODIAL
+C_DEFINES = -DRASAUTODIAL -D_PNP_POWER
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=action.c \
+ address.c \
+ autodial.c \
+ connect.c \
+ connobj.c \
+ devctx.c \
+ dlc.c \
+ event.c \
+ framecon.c \
+ framesnd.c \
+ iframes.c \
+ info.c \
+ link.c \
+ linktree.c \
+ nbf.rc \
+ nbfcnfg.c \
+ nbfdrvr.c \
+ nbfdebug.c \
+ nbfmac.c \
+ nbfndis.c \
+ nbfpnp.c \
+ packet.c \
+ rcv.c \
+ rcveng.c \
+ request.c \
+ send.c \
+ sendeng.c \
+ spnlckdb.c \
+ timer.c \
+ uframes.c
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/ntos/tdi/nbf/spnlckdb.c b/private/ntos/tdi/nbf/spnlckdb.c
new file mode 100644
index 000000000..485431ad5
--- /dev/null
+++ b/private/ntos/tdi/nbf/spnlckdb.c
@@ -0,0 +1,156 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ spnlckdb.c
+
+Abstract:
+
+ This module contains code which allows debugging of spinlock related NBF
+ problems. Most of this code is conditional on the manifest constant
+ NBF_LOCKS.
+
+Author:
+
+ David Beaver 13-Feb-1991
+ (From Chuck Lenzmeier, Jan 1991)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef NBF_LOCKS
+
+KSPIN_LOCK NbfGlobalLock = NULL;
+PKTHREAD NbfGlobalLockOwner = NULL;
+ULONG NbfGlobalLockRecursionCount = 0;
+ULONG NbfGlobalLockMaxRecursionCount = 0;
+KIRQL NbfGlobalLockPreviousIrql = (KIRQL)-1;
+BOOLEAN NbfGlobalLockPrint = 1;
+
+#define PRINT_ERR if ( (NbfGlobalLockPrint & 1) != 0 ) DbgPrint
+#define PRINT_INFO if ( (NbfGlobalLockPrint & 2) != 0 ) DbgPrint
+
+VOID
+NbfAcquireSpinLock(
+ IN PKSPIN_LOCK Lock,
+ OUT PKIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ )
+{
+ KIRQL previousIrql;
+
+ PKTHREAD currentThread = KeGetCurrentThread( );
+
+ if ( NbfGlobalLockOwner == currentThread ) {
+
+ ASSERT( Lock != NULL ); // else entering NBF with lock held
+
+ ASSERT( NbfGlobalLockRecursionCount != 0 );
+ NbfGlobalLockRecursionCount++;
+ if ( NbfGlobalLockRecursionCount > NbfGlobalLockMaxRecursionCount ) {
+ NbfGlobalLockMaxRecursionCount = NbfGlobalLockRecursionCount;
+ }
+
+ PRINT_INFO( "NBF reentered from %s/%ld, new count %ld\n",
+ FileName, LineNumber, NbfGlobalLockRecursionCount );
+
+ } else {
+
+ ASSERT( Lock == NULL ); // else missing an ENTER_NBF call
+
+ KeAcquireSpinLock( &NbfGlobalLock, &previousIrql );
+
+ ASSERT( NbfGlobalLockRecursionCount == 0 );
+ NbfGlobalLockOwner = currentThread;
+ NbfGlobalLockPreviousIrql = previousIrql;
+ NbfGlobalLockRecursionCount = 1;
+
+ PRINT_INFO( "NBF entered from %s/%ld\n", FileName, LineNumber );
+
+ }
+
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
+ return;
+
+} // NbfAcquireSpinLock
+
+VOID
+NbfReleaseSpinLock(
+ IN PKSPIN_LOCK Lock,
+ IN KIRQL OldIrql,
+ IN PSZ LockName,
+ IN PSZ FileName,
+ IN ULONG LineNumber
+ )
+{
+ PKTHREAD currentThread = KeGetCurrentThread( );
+ KIRQL previousIrql;
+
+ ASSERT( NbfGlobalLockOwner == currentThread );
+ ASSERT( NbfGlobalLockRecursionCount != 0 );
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
+ if ( --NbfGlobalLockRecursionCount == 0 ) {
+
+ ASSERT( Lock == NULL ); // else not exiting NBF, but releasing lock
+
+ NbfGlobalLockOwner = NULL;
+ previousIrql = NbfGlobalLockPreviousIrql;
+ NbfGlobalLockPreviousIrql = (KIRQL)-1;
+
+ PRINT_INFO( "NBF exited from %s/%ld\n", FileName, LineNumber );
+
+ KeReleaseSpinLock( &NbfGlobalLock, previousIrql );
+
+ } else {
+
+ ASSERT( Lock != NULL ); // else exiting NBF with lock held
+
+ PRINT_INFO( "NBF semiexited from %s/%ld, new count %ld\n",
+ FileName, LineNumber, NbfGlobalLockRecursionCount );
+
+ }
+
+ return;
+
+} // NbfReleaseSpinLock
+
+VOID
+NbfFakeSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+{
+ ENTER_NBF;
+ NbfSendCompletionHandler (ProtocolBindingContext, NdisPacket, NdisStatus);
+ LEAVE_NBF;
+}
+
+VOID
+NbfFakeTransferDataComplete (
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+{
+ ENTER_NBF;
+ NbfTransferDataComplete (BindingContext, NdisPacket, NdisStatus, BytesTransferred);
+ LEAVE_NBF;
+}
+
+#endif // def NBF_LOCKS
diff --git a/private/ntos/tdi/nbf/testnbf.c b/private/ntos/tdi/nbf/testnbf.c
new file mode 100644
index 000000000..91a3ca645
--- /dev/null
+++ b/private/ntos/tdi/nbf/testnbf.c
@@ -0,0 +1,1466 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ testtdi.c
+
+Abstract:
+
+ Kernel Mode test program for any Tdi network provider. This routine is an
+ example of how to use the TDI interface at the kernel level.
+
+Author:
+
+ Dave Beaver (DBeaver) 5 June 1991
+
+Revision History:
+
+--*/
+
+#include "nbf.h"
+#include <ctype.h>
+
+#define TRANSPORT_NAME L"\\Device\\Nbf"
+
+PSZ ServerName = "DCTDISERVER ";
+PSZ ClientName = "DCTDICLIENT ";
+PSZ AnyName = "* ";
+
+static PUCHAR TextBuffer; // dynamically allocated non-paged buffer.
+ULONG c9_Xmt = 0xff;
+ULONG c9_Rcv = 0xff;
+ULONG c9_Iteration = 0xffffffff;
+
+static ULONG TextBufferLength; // size of the above in bytes.
+#define BUFFER_SIZE 0xffff
+PUCHAR RBuff;
+PUCHAR XBuff;
+UCHAR c9_ListBlock[512];
+UCHAR c9_ConnBlock[512];
+
+extern KEVENT TdiSendEvent;
+extern KEVENT TdiReceiveEvent;
+extern KEVENT TdiServerEvent;
+
+ULONG ApcContext;
+
+NTSTATUS
+TSTRCVCompletion(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ DbgPrint ("TSTRCVCompletion event: %lx\n" , Context);
+// KeSetEvent ((PKEVENT)Context, 0, TRUE);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+ UNREFERENCED_PARAMETER( DeviceObject );
+ UNREFERENCED_PARAMETER( Irp );
+}
+
+#define InitWaitObject(_event)\
+ KeInitializeEvent (\
+ _event,\
+ SynchronizationEvent,\
+ FALSE)
+
+VOID
+NbfTestTimer(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+NTSTATUS
+TtdiOpenAddress (
+ IN PHANDLE FileHandle,
+ IN PSZ Name
+ );
+
+NTSTATUS
+TtdiOpenConnection (
+ IN PHANDLE FileHandle,
+ IN ULONG ConnectionContext
+ );
+
+
+NTSTATUS
+TtdiOpenAddress (
+ IN PHANDLE FileHandle,
+ IN PSZ Name)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ UNICODE_STRING NameString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ PTDI_ADDRESS_NETBIOS AddressName;
+ PTRANSPORT_ADDRESS Address;
+ PTA_ADDRESS AddressType;
+ int i;
+
+ DbgPrint ("TtdiOpenAddress: Opening ");
+ DbgPrint (Name);
+ DbgPrint (".\n");
+ RtlInitUnicodeString (&NameString, TRANSPORT_NAME);
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &NameString,
+ 0,
+ NULL,
+ NULL);
+
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool (NonPagedPool, 100);
+ if (EaBuffer == NULL) {
+ DbgBreakPoint ();
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TDI_ADDRESS_NETBIOS);
+
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiTransportAddress[i];
+ }
+
+ Address = (PTRANSPORT_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+ Address->TAAddressCount = 1;
+
+ AddressType = (PTA_ADDRESS)((PUCHAR)Address + sizeof (Address->TAAddressCount));
+
+ AddressType->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ AddressType->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+
+ AddressName = (PTDI_ADDRESS_NETBIOS)((PUCHAR)AddressType +
+ sizeof (AddressType->AddressType) + sizeof (AddressType->AddressLength));
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ for (i=0;i<16;i++) {
+ AddressName->NetbiosName[i] = Name[i];
+ }
+
+ Status = IoCreateFile (
+ FileHandle,
+ 0, // desired access.
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ FO_SYNCHRONOUS_IO, // file attributes.
+ 0,
+ 0,
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ (PUCHAR)&AddressName->NetbiosName[i] - (PUCHAR)EaBuffer + 1, // ea length
+ CreateFileTypeNone,
+ (PVOID)NULL,
+ 0 ); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("TtdiOpenAddress: FAILURE, NtCreateFile returned status code=%lC.\n", Status);
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("TtdiOpenAddress: FAILURE, IoStatusBlock.Status contains status code=%lC.\n", Status);
+ }
+
+ DbgPrint ("TtdiOpenAddress: returning\n");
+
+ return Status;
+} /* TtdiOpenAddress */
+
+
+NTSTATUS
+TtdiOpenConnection (IN PHANDLE FileHandle, IN ULONG ConnectionContext)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ UNICODE_STRING NameString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ int i;
+
+ DbgPrint ("TtdiOpenConnection: Opening Context %lx...\n ",
+ ConnectionContext);
+ RtlInitUnicodeString (&NameString, TRANSPORT_NAME);
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &NameString,
+ 0,
+ NULL,
+ NULL);
+
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)ExAllocatePool (NonPagedPool, 100);
+ if (EaBuffer == NULL) {
+ DbgBreakPoint ();
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
+ EaBuffer->EaValueLength = sizeof (ULONG);
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiConnectionContext[i];
+ }
+
+ RtlMoveMemory (
+ &EaBuffer->EaName[EaBuffer->EaValueLength + 1],
+ &ConnectionContext,
+ sizeof (PVOID));
+
+ Status = NtCreateFile (
+ FileHandle,
+ 0,
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ FO_SYNCHRONOUS_IO, // file attributes.
+ 0,
+ 0,
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ 100); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ DbgPrint ("TtdiOpenConnection: FAILURE, NtCreateFile returned status code=%lC.\n", Status);
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("TtdiOpenConnection: FAILURE, IoStatusBlock.Status contains status code=%lC.\n", Status);
+ }
+
+ DbgPrint ("TtdiOpenConnection: returning\n");
+
+ return Status;
+} /* TtdiOpenEndpoint */
+
+NTSTATUS
+CloseAddress (IN HANDLE FileHandle)
+{
+ NTSTATUS Status;
+
+ Status = NtClose (FileHandle);
+
+ if (!(NT_SUCCESS( Status ))) {
+ DbgPrint ("CloseAddress: FAILURE, NtClose returned status code=%lC.\n", Status);
+ } else {
+ DbgPrint ("CloseAddress: NT_SUCCESS.\n");
+ }
+
+ return Status;
+} /* CloseAddress */
+
+
+BOOLEAN
+TtdiSend()
+{
+ USHORT i, Iteration, Increment;
+ HANDLE RdrHandle, RdrConnectionHandle;
+ KEVENT Event1;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL SendMdl, ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PUCHAR SendBuffer;
+ ULONG SendBufferLength;
+ PIRP Irp;
+
+ Status = KeWaitForSingleObject (&TdiSendEvent, Suspended, KernelMode, FALSE, NULL);
+
+ SendBufferLength = (ULONG)BUFFER_SIZE;
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Send Test ******\n" );
+
+ XBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (XBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for send buffer exiting\n");
+ return FALSE;
+ }
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ClientName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&RdrHandle, AnyName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of client: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ //
+ // Open the connection on the transport.
+ //
+
+ Status = TtdiOpenConnection (&RdrConnectionHandle, 1);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ TdiBuildAssociateAddress (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ RdrHandle);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success AssociateAddress\n");
+ }
+ }
+
+ //
+ // Post a TdiConnect to the client endpoint.
+ //
+
+ RequestInformation.RemoteAddress = ConnectBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_CONNECT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildConnect (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ &ReturnInformation);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Connect: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Iosb status Connect: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Connect Iosb\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: Connect FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Connect Immediate\n");
+ }
+ }
+
+ DbgPrint( "\n****** Send Test: SUCCESSFUL TdiConnect: ******\n");
+
+ //
+ // Send/receive 1 or 10 messages.
+ //
+
+ SendBuffer = (PUCHAR)ExAllocatePool (NonPagedPool, SendBufferLength);
+ if (SendBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ SendMdl = IoAllocateMdl (SendBuffer, SendBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (SendMdl);
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // Cycle the buffer length from 0 up through the maximum for Tdi. after a
+ // couple of shots at the full range in one byte steps, increment by ever
+ // increasing amounts to get to the max.
+ //
+
+ CurrentBufferLength = 0;
+ Increment = 1;
+ for (Iteration=1; Iteration<(USHORT)c9_Iteration; Iteration++) {
+ CurrentBufferLength += Increment;
+ if (CurrentBufferLength > MessageBufferLength) {
+ CurrentBufferLength = 0;
+ Increment = 1;
+ }
+ if (CurrentBufferLength > 7500) {
+ Increment++;
+ }
+ if ((USHORT)((Iteration / 100) * 100) == Iteration) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ }
+ for (i=0; i<(USHORT)CurrentBufferLength; i++) {
+ SendBuffer [i] = (UCHAR)(i + Iteration % 256 );
+ MessageBuffer [i] = 0; // zap this sucker with something.
+ }
+
+ //
+ // Now issue a send on the client side.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_SEND,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildSend (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ 0,
+ CurrentBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Event1 Wait Send: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Send Test: FAILED Iosb status Send: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success SendIosb\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Send Test: Send FAILED Status: %lC %d ******\n",
+ Status, Iteration );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Send Test: Success Send Immediate\n");
+ }
+ }
+
+ if (Iosb1.Information != CurrentBufferLength) {
+ DbgPrint ("SendTest: Bytes sent <> Send buffer size.\n");
+ DbgPrint ("SendTest: BytesToSend=%ld. BytesSent=%ld.\n",
+ CurrentBufferLength, Iosb1.Information);
+ }
+
+ }
+
+ //
+ // We're done with this endpoint. Close it and get out.
+ //
+
+ Status = CloseAddress (RdrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on 2nd Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Send Test ******\n" );
+ return TRUE;
+} /* Send */
+
+
+BOOLEAN
+TtdiReceive()
+{
+ USHORT i, Iteration, Increment;
+ SHORT j,k;
+ HANDLE SvrHandle, SvrConnectionHandle;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL SendMdl, ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PUCHAR SendBuffer;
+ ULONG SendBufferLength;
+ PIRP Irp;
+ KEVENT Event1;
+
+ Status = KeWaitForSingleObject (&TdiReceiveEvent, Suspended, KernelMode, FALSE, NULL);
+
+ SendBufferLength = (ULONG)BUFFER_SIZE;
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Receive Test ******\n" );
+
+ XBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (XBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for send buffer exiting\n");
+ return FALSE;
+ }
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ClientName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&SvrHandle, ServerName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Address: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SvrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Address: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = TtdiOpenConnection (&SvrConnectionHandle, 2);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SvrConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ DbgPrint ("Build Irp %lx, Handle %lx \n",
+ Irp, SvrHandle);
+
+ TdiBuildAssociateAddress (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ SvrHandle);
+ InitWaitObject (&Event1);
+
+ {
+ PULONG Temp=(PULONG)IoGetNextIrpStackLocation (Irp);
+ DbgPrint ("Built IrpSp %lx %lx %lx %lx %lx \n", *(Temp++), *(Temp++),
+ *(Temp++), *(Temp++), *(Temp++));
+ }
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success AssociateAddress\n");
+ }
+ }
+
+ RequestInformation.RemoteAddress = ConnectBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ //
+ // Post a TdiListen to the server endpoint.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_LISTEN,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildListen (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ &ReturnInformation);
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Listen: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Listen Iosb status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success Listen IOSB\n");
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+ DbgPrint ("********** Receive Test: Success Listen Immediate\n");
+ }
+ }
+
+
+ DbgPrint ("\n****** Receive Test: LISTEN just completed! ******\n");
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ACCEPT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAccept (Irp, DeviceObject, ConnectionObject, NULL, NULL, &RequestInformation, NULL, 0);
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Accept: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Accept Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Accept FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // We have the connection data now. Sanity check it.
+ //
+
+ DbgPrint ("\n****** Receive Test: LISTEN completed successfully! ******\n");
+
+ //
+ // Receive/receive 1 or 10 messages.
+ //
+
+ SendBuffer = (PUCHAR)ExAllocatePool (NonPagedPool, SendBufferLength);
+ if (SendBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ SendMdl = IoAllocateMdl (SendBuffer, SendBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (SendMdl);
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // Cycle the buffer length from 0 up through the maximum for Tdi. after a
+ // couple of shots at the full range in one byte steps, increment by ever
+ // increasing amounts to get to the max.
+ //
+
+ CurrentBufferLength = 0;
+ Increment = 1;
+ for (Iteration=1; Iteration<(USHORT)c9_Iteration; Iteration++) {
+ CurrentBufferLength += Increment;
+ if (CurrentBufferLength > MessageBufferLength) {
+ CurrentBufferLength = 0;
+ Increment = 1;
+ }
+ if (CurrentBufferLength > 7500) {
+ Increment++;
+ }
+ if ((USHORT)((Iteration / 100) * 100) == Iteration) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ }
+ for (i=0; i<(USHORT)CurrentBufferLength; i++) {
+ SendBuffer [i] = (UCHAR)(i + Iteration % 256 );
+ MessageBuffer [i] = 0; // zap this sucker with something.
+ }
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_RECEIVE,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildReceive (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ MessageBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+// IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Receive: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Receive Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // The receive completed. Make sure the data is correct.
+ //
+
+ if (Iosb1.Information != CurrentBufferLength) {
+ DbgPrint ("Iteration #%d Buffer Length: %lx Buffer Start: %x\n",
+ Iteration, CurrentBufferLength,Iteration % 256);
+ DbgPrint ("ReceiveTest: Bytes received <> bytes sent.\n");
+ DbgPrint ("ReceiveTest: BytesToSend=%ld. BytesReceived=%ld.\n",
+ CurrentBufferLength, Iosb1.Information);
+ }
+
+ if (i == (USHORT)CurrentBufferLength) {
+// DbgPrint ("ReceiveTest: Message contains correct data.\n");
+ } else {
+ DbgPrint ("ReceiveTest: Message data corrupted at offset %lx of %lx.\n", (ULONG)i, (ULONG)SendBufferLength);
+ DbgPrint ("ReceiveTest: Data around corrupted location:\n");
+ for (j=-4;j<=3;j++) {
+ DbgPrint ("%08lx ", (ULONG) i+j*16);
+ for (k=(SHORT)i+(j*(SHORT)16);k<(SHORT)i+((j+(SHORT)1)*(SHORT)16);k++) {
+ DbgPrint ("%02x",MessageBuffer [k]);
+ }
+ for (k=(SHORT)i+(j*(SHORT)16);k<(SHORT)i+((j+(SHORT)1)*(SHORT)16);k++) {
+ DbgPrint ("%c",MessageBuffer [k]);
+ }
+ DbgPrint ("\n");
+ }
+ DbgPrint ("ReceiveTest: End of Corrupt Data.\n");
+ }
+ }
+
+ //
+ // We're done with this endpoint. Close it and get out.
+ //
+
+ Status = CloseAddress (SvrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED on 1st Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Receive Test ******\n" );
+ return TRUE;
+} /* Receive */
+
+BOOLEAN
+TtdiServer()
+{
+ USHORT i;
+ HANDLE RdrHandle, SrvConnectionHandle;
+ KEVENT Event1;
+ PFILE_OBJECT AddressObject, ConnectionObject;
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status;
+ PMDL ReceiveMdl;
+ IO_STATUS_BLOCK Iosb1;
+ TDI_CONNECTION_INFORMATION RequestInformation;
+ TDI_CONNECTION_INFORMATION ReturnInformation;
+ PTRANSPORT_ADDRESS ListenBlock;
+ PTRANSPORT_ADDRESS ConnectBlock;
+ PTDI_ADDRESS_NETBIOS temp;
+ PUCHAR MessageBuffer;
+ ULONG MessageBufferLength;
+ ULONG CurrentBufferLength;
+ PIRP Irp;
+
+ Status = KeWaitForSingleObject (&TdiServerEvent, Suspended, KernelMode, FALSE, NULL);
+
+ MessageBufferLength = (ULONG)BUFFER_SIZE;
+
+
+ DbgPrint( "\n****** Start of Server Test ******\n" );
+
+ RBuff = ExAllocatePool (NonPagedPool, BUFFER_SIZE);
+ if (RBuff == (PVOID)NULL) {
+ DbgPrint ("Unable to allocate nonpaged pool for receive buffer exiting\n");
+ return FALSE;
+ }
+
+ ListenBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+ ConnectBlock = ExAllocatePool (NonPagedPool, sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS));
+
+ ListenBlock->TAAddressCount = 1;
+ ListenBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ListenBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ListenBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = AnyName[i];
+ }
+
+ ConnectBlock->TAAddressCount = 1;
+ ConnectBlock->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ ConnectBlock->Address[0].AddressLength = sizeof (TDI_ADDRESS_NETBIOS);
+ temp = (PTDI_ADDRESS_NETBIOS)ConnectBlock->Address[0].Address;
+
+ temp->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ for (i=0;i<16;i++) {
+ temp->NetbiosName[i] = ServerName[i];
+ }
+
+ //
+ // Create an event for the synchronous I/O requests that we'll be issuing.
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Status = TtdiOpenAddress (&RdrHandle, ServerName);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of client: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ RdrHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &AddressObject,
+ NULL);
+
+ //
+ // Now loop forever trying to get a connection from a remote client to
+ // this server. We will create connections until we run out of resources,
+ // and we will echo the data we are sent back along the same connection.
+ // Sends and Receives are always asynchronous, while listens are
+ // synchronous.
+ //
+
+ while (TRUE) {
+
+ //
+ // Open the connection on the transport.
+ //
+
+ Status = TtdiOpenConnection (&SrvConnectionHandle, 1);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ Status = ObReferenceObjectByHandle (
+ SrvConnectionHandle,
+ 0L,
+ NULL,
+ KernelMode,
+ (PVOID *) &ConnectionObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED on open of server Connection: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ //
+ // Get a pointer to the stack location for the first driver. This will be
+ // used to pass the original function codes and parameters.
+ //
+
+ DeviceObject = IoGetRelatedDeviceObject( ConnectionObject );
+
+ //
+ // Now register the device handler for receives
+ //
+
+// Irp = TdiBuildInternalDeviceControlIrp (
+// TDI_SET_EVENT_HANDLER,
+// DeviceObject,
+// ConnectionObject,
+// &Event1,
+// &Iosb1);
+
+// TdiBuildSetEventHandler (Irp,
+// DeviceObject,
+// ConnectionObject,
+// TSTRCVCompletion,
+// &Event1,
+// TDI_RECEIVE_HANDLER,
+// TdiTestReceiveHandler,
+// ConnectionObject);
+
+// Status = IoCallDriver (DeviceObject, Irp);
+
+// if (Status == STATUS_PENDING) {
+// Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+// if (!NT_SUCCESS(Status)) {
+// DbgPrint( "\n****** Server Test: FAILED Event1 Wait Register: %lC ******\n", Status );
+// return FALSE;
+// }
+// if (!NT_SUCCESS(Iosb1.Status)) {
+// DbgPrint( "\n****** Server Test: FAILED Register Iosb status: %lC ******\n", Status );
+// return FALSE;
+// }
+//
+// } else {
+// if (!NT_SUCCESS (Status)) {
+// DbgPrint( "\n****** Server Test: RegisterHandler FAILED Status: %lC ******\n", Status );
+// return FALSE;
+// }
+// }
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ASSOCIATE_ADDRESS,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAssociateAddress (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ RdrHandle);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ // IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Event1 Wait Associate: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Associate Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Server Test: AssociateAddress FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // Post a TdiListen to the server endpoint.
+ //
+
+ RequestInformation.RemoteAddress = ListenBlock;
+ RequestInformation.RemoteAddressLength = sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_LISTEN,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildListen (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ 0,
+ &RequestInformation,
+ NULL);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Event1 Wait Listen: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Server Test: FAILED Listen Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Server Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ DbgPrint ("\n****** Server Test: LISTEN just completed! ******\n");
+
+ //
+ // accept the connection from the remote
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_ACCEPT,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildAccept (
+ Irp,
+ DeviceObject,
+ ConnectionObject,
+ NULL,
+ NULL,
+ &RequestInformation,
+ NULL,
+ 0);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ // IoFreeIrp (Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Accept: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Accept Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+ DbgPrint( "\n****** Accept Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ }
+ }
+
+ //
+ // Get a buffer for the continued read/write loop.
+ //
+
+ MessageBuffer=(PUCHAR)ExAllocatePool (NonPagedPool, MessageBufferLength);
+ if (MessageBuffer == NULL) {
+ DbgPrint ("\n****** Send Test: ExAllocatePool failed! ******\n");
+ }
+ ReceiveMdl = IoAllocateMdl (MessageBuffer, MessageBufferLength, FALSE, FALSE, NULL);
+ MmBuildMdlForNonPagedPool (ReceiveMdl);
+
+ //
+ // have a receive buffer, and a connection; go ahead and read and write
+ // until the remote disconnects.
+ //
+
+ while (TRUE) {
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_RECEIVE,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildReceive (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ MessageBufferLength);
+
+ InitWaitObject (&Event1);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Receive: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Receive Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+
+ //
+ // Check to see if the remote has disconnected, which is
+ // the only reason for us shutting down/
+ //
+
+ if (Status == STATUS_REMOTE_DISCONNECT) {
+
+ //
+ // We've been disconnected from; get out
+ //
+
+ NtClose (SrvConnectionHandle);
+ break;
+ }
+
+ DbgPrint( "\n****** Receive Test: Listen FAILED Status: %lC ******\n", Status );
+ return FALSE;
+ } else {
+
+ //
+ // successful return, what length is the data?
+ //
+
+ CurrentBufferLength = Iosb1.Information;
+ }
+ }
+
+ //
+ // send the data back
+ //
+
+ KeInitializeEvent (
+ &Event1,
+ SynchronizationEvent,
+ FALSE);
+
+ Irp = TdiBuildInternalDeviceControlIrp (
+ TDI_SEND,
+ DeviceObject,
+ ConnectionObject,
+ &Event1,
+ &Iosb1);
+
+ TdiBuildSend (Irp,
+ DeviceObject,
+ ConnectionObject,
+ TSTRCVCompletion,
+ &Event1,
+ ReceiveMdl,
+ 0,
+ CurrentBufferLength);
+
+ Status = IoCallDriver (DeviceObject, Irp);
+
+ if (Status == STATUS_PENDING) {
+ Status = KeWaitForSingleObject (&Event1, Suspended, KernelMode, TRUE, NULL);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Event1 Wait Send: %lC ******\n", Status );
+ return FALSE;
+ }
+ if (!NT_SUCCESS(Iosb1.Status)) {
+ DbgPrint( "\n****** Receive Test: FAILED Send Iosb status: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ } else {
+ if (!NT_SUCCESS (Status)) {
+
+ DbgPrint( "\n****** Receive Test: Send FAILED Status: %lC ******\n", Status );
+ NtClose (SrvConnectionHandle);
+ break;
+
+ }
+ }
+ } // end of receive/send while
+
+ IoFreeMdl (ReceiveMdl);
+ ExFreePool (MessageBuffer);
+
+ }
+
+ //
+ // We're done with this address. Close it and get out.
+ //
+
+ Status = CloseAddress (RdrHandle);
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint( "\n****** Send Test: FAILED on 2nd Close: %lC ******\n", Status );
+ return FALSE;
+ }
+
+ DbgPrint( "\n****** End of Send Test ******\n" );
+ return TRUE;
+} /* Server */
diff --git a/private/ntos/tdi/nbf/testtdi.c b/private/ntos/tdi/nbf/testtdi.c
new file mode 100644
index 000000000..6cf1b335f
--- /dev/null
+++ b/private/ntos/tdi/nbf/testtdi.c
@@ -0,0 +1,291 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ tstrcv.c
+
+Abstract:
+
+ start receive side tests utility
+
+Author:
+
+ Dave Beaver (dbeaver) 24-Mar-1991
+
+Revision History:
+
+--*/
+
+//
+// download a ub board
+//
+
+typedef unsigned char uchar_t;
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <string.h>
+//#include <windows.h>
+#include <nbf.h>
+
+#define TDIDEV "\\Device\\Nbf"
+char Tdidevice[] = TDIDEV; /* default device */
+char *Tdidev = Tdidevice;
+
+HANDLE FileHandle;
+
+VOID
+usage(
+ VOID
+ );
+
+
+NTSTATUS
+main (
+ IN SHORT argc,
+ IN PSZ argv[]
+ )
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ STRING NameString;
+ UNICODE_STRING unicodeString;
+ PUCHAR buffer;
+ ULONG IoControlCode;
+ int n;
+ CHAR c;
+
+ for( n = 1; n < argc && argv[n][0] == '-' ; ++n ) {
+ c = argv[n][1];
+
+ switch( c ) {
+
+ case 's': // send test
+ IoControlCode = IOCTL_TDI_SEND_TEST;
+ break;
+
+ case 'r': // receive test
+ IoControlCode = IOCTL_TDI_RECEIVE_TEST;
+
+ break;
+
+ case 'b': /* both test */
+ IoControlCode = IOCTL_TDI_SERVER_TEST;
+
+ break;
+
+ default:
+ usage ();
+ break;
+
+ }
+ }
+
+ printf ("Opening TDI device: %s \n", Tdidev);
+ RtlInitString (&NameString, Tdidev);
+ Status = RtlAnsiStringToUnicodeString(
+ &unicodeString,
+ &NameString,
+ TRUE);
+
+ buffer = (PUCHAR)malloc (100);
+
+ Status = TdiOpenNetbiosAddress (&FileHandle, buffer, (PVOID)&NameString, NULL);
+
+ RtlFreeUnicodeString(&unicodeString);
+ free (buffer);
+
+ if (!NT_SUCCESS( Status )) {
+ printf ("FAILURE, Unable to open TDI driver %s, status: %lx.\n",
+ Tdidev,Status);
+ return (Status);
+ }
+
+ if (!(NT_SUCCESS( IoStatusBlock.Status ))) {
+ printf ("FAILURE, Unable to open TDI driver %s, IoStatusBlock.Status: %lx.\n",
+ Tdidev, IoStatusBlock.Status);
+ return (IoStatusBlock.Status);
+ }
+
+ //
+ // start the test
+ //
+
+ printf("Starting test.... ");
+ Status = NtDeviceIoControlFile(
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IoControlCode,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS( Status )) {
+ printf ("FAILURE, Unable to start test: %lx.\n", Status);
+ return (Status);
+ }
+
+ if (!(NT_SUCCESS( IoStatusBlock.Status ))) {
+ printf ("FAILURE, Unable to start test: %lx.\n", IoStatusBlock.Status);
+ return (IoStatusBlock.Status);
+ }
+
+ NtClose (FileHandle);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+NTSTATUS
+TdiOpenNetbiosAddress (
+ IN OUT PHANDLE FileHandle,
+ IN PUCHAR Buffer,
+ IN PVOID DeviceName,
+ IN PVOID Address)
+
+/*++
+
+Routine Description:
+
+ Opens an address on the given file handle and device.
+
+Arguments:
+
+ FileHandle - the returned handle to the file object that is opened.
+
+ Buffer - pointer to a buffer that the ea is to be built in. This buffer
+ must be at least 40 bytes long.
+
+ DeviceName - the Unicode string that points to the device object.
+
+ Name - the address to be registered. If this pointer is NULL, the routine
+ will attempt to open a "control channel" to the device; that is, it
+ will attempt to open the file object with a null ea pointer, and if the
+ transport provider allows for that, will return that handle.
+
+Return Value:
+
+ An informative error code if something goes wrong. STATUS_SUCCESS if the
+ returned file handle is valid.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PFILE_FULL_EA_INFORMATION EaBuffer;
+ PTRANSPORT_ADDRESS TAAddress;
+ PTA_ADDRESS AddressType;
+ PTDI_ADDRESS_NETBIOS AddressName;
+ PSZ Name;
+ ULONG Length;
+ int i;
+
+ if (Address != NULL) {
+ Name = (PSZ)Address;
+ try {
+ Length = sizeof (FILE_FULL_EA_INFORMATION) +
+ sizeof (TRANSPORT_ADDRESS) +
+ sizeof (TDI_ADDRESS_NETBIOS);
+ EaBuffer = (PFILE_FULL_EA_INFORMATION)Buffer;
+
+ if (EaBuffer == NULL) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ EaBuffer->NextEntryOffset =0;
+ EaBuffer->Flags = 0;
+ EaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+ EaBuffer->EaValueLength = sizeof (TDI_ADDRESS_NETBIOS) +
+ sizeof (TRANSPORT_ADDRESS);
+
+ for (i=0;i<(int)EaBuffer->EaNameLength;i++) {
+ EaBuffer->EaName[i] = TdiTransportAddress[i];
+ }
+
+ TAAddress = (PTRANSPORT_ADDRESS)&EaBuffer->EaName[EaBuffer->EaNameLength+1];
+ TAAddress->TAAddressCount = 1;
+
+ AddressType = (PTA_ADDRESS)((PUCHAR)TAAddress + sizeof (TAAddress->TAAddressCount));
+
+ AddressType->AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ AddressType->AddressLength = TDI_ADDRESS_LENGTH_NETBIOS;
+
+ AddressName = (PTDI_ADDRESS_NETBIOS)((PUCHAR)AddressType +
+ sizeof (AddressType->AddressType) + sizeof (AddressType->AddressLength));
+ AddressName->NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+
+ for (i=0;i<16;i++) {
+ AddressName->NetbiosName[i] = Name[i];
+ }
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ //
+ // Couldn't touch the passed parameters; just return an error
+ // status.
+ //
+
+ return GetExceptionCode();
+ }
+ } else {
+ EaBuffer = NULL;
+ Length = 0;
+ }
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ DeviceName,
+ 0,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile (
+ FileHandle,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, // desired access.
+ &ObjectAttributes, // object attributes.
+ &IoStatusBlock, // returned status information.
+ 0, // block size (unused).
+ 0, // file attributes.
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share access.
+ FILE_CREATE, // create disposition.
+ 0, // create options.
+ EaBuffer, // EA buffer.
+ Length); // EA length.
+
+ if (!NT_SUCCESS( Status )) {
+ return Status;
+ }
+
+ Status = IoStatusBlock.Status;
+
+ if (!(NT_SUCCESS( Status ))) {
+ }
+
+ return Status;
+} /* TdiOpenNetbiosAddress */
+
+VOID
+usage(
+ VOID
+ )
+{
+ printf( "usage: tsttdi [-r] [-s] -[b]\n");
+ printf( "usage: -r run receive test.\n" );
+ printf( "usage: -b run server test.\n" );
+ printf( "usage: -s run send test.\n" );
+ printf( "\n" );
+ exit( 1 );
+}
+
diff --git a/private/ntos/tdi/nbf/timer.c b/private/ntos/tdi/nbf/timer.c
new file mode 100644
index 000000000..0664f0aa6
--- /dev/null
+++ b/private/ntos/tdi/nbf/timer.c
@@ -0,0 +1,2762 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code that implements the lightweight timer system
+ for the NBF protocol provider. This is not a general-purpose timer system;
+ rather, it is specific to servicing LLC (802.2) links with three timers
+ each.
+
+ Services are provided in macro form (see NBFPROCS.H) to start and stop
+ timers. This module contains the code that gets control when the timer
+ in the device context expires as a result of calling kernel services.
+ The routine scans the device context's link database, looking for timers
+ that have expired, and for those that have expired, their expiration
+ routines are executed.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+ULONG StartTimer = 0;
+ULONG StartTimerSet = 0;
+ULONG StartTimerT1 = 0;
+ULONG StartTimerT2 = 0;
+ULONG StartTimerDelayedAck = 0;
+ULONG StartTimerLinkDeferredAdd = 0;
+ULONG StartTimerLinkDeferredDelete = 0;
+
+
+#if DBG
+extern ULONG NbfDebugPiggybackAcks;
+ULONG NbfDebugShortTimer = 0;
+#endif
+
+#if DBG
+//
+// These are temp, to track how the timers are working
+//
+ULONG TimerInsertsAtEnd = 0;
+ULONG TimerInsertsEmpty = 0;
+ULONG TimerInsertsInMiddle = 0;
+#endif
+
+//
+// These are constants calculated by InitializeTimerSystem
+// to be the indicated amound divided by the tick increment.
+//
+
+ULONG NbfTickIncrement = 0;
+ULONG NbfTwentyMillisecondsTicks = 0;
+ULONG NbfShortTimerDeltaTicks = 0;
+ULONG NbfMaximumIntervalTicks = 0; // usually 60 seconds in ticks
+
+LARGE_INTEGER DueTimeDelta = { (ULONG)(-SHORT_TIMER_DELTA), -1 };
+
+VOID
+ExpireT2Timer(
+ PTP_LINK Link
+ );
+
+VOID
+StopStalledConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+
+ULONG
+GetTimerInterval(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ GetTimerInterval returns the difference in time between the
+ current time and Link->CurrentTimerStart (in ticks).
+ We limit the interval to 60 seconds. A value of 0 may
+ be returned which should be interpreted as 1/2.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ The interval.
+
+--*/
+
+{
+
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER Interval;
+
+
+ //
+ // Determine the current tick; the start tick has been saved
+ // in Link->CurrentTimerStart.
+ //
+
+ KeQueryTickCount (&CurrentTick);
+
+ //
+ // Determine the difference between now and then.
+ //
+
+ Interval.QuadPart = CurrentTick.QuadPart -
+ (Link->CurrentTimerStart).QuadPart;
+
+ //
+ // If the gap is too big, return 1 minute.
+ //
+
+ if (Interval.HighPart != 0 || (Interval.LowPart > NbfMaximumIntervalTicks)) {
+ return NbfMaximumIntervalTicks;
+ }
+
+ return Interval.LowPart;
+
+} /* GetTimerInterval */
+
+
+VOID
+BackoffCurrentT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called if T1 expires and we are about to
+ retransmit a poll frame. It backs off CurrentT1Timeout,
+ up to a limit of 10 seconds.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+ // BUGBUG: we need spinlock guarding for MP.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ ++Link->CurrentPollRetransmits;
+
+ //
+ // T1 backs off 1.5 times each time.
+ //
+
+ Link->CurrentT1Timeout += (Link->CurrentT1Timeout >> 1);
+
+ //
+ // Limit T1 to 10 seconds.
+ //
+
+ if (Link->CurrentT1Timeout > ((10 * SECONDS) / SHORT_TIMER_DELTA)) {
+ Link->CurrentT1Timeout = (10 * SECONDS) / SHORT_TIMER_DELTA;
+ }
+
+} /* BackoffCurrentT1Timeout */
+
+
+VOID
+UpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response to a poll frame is
+ received. StartT1 will have been called when the frame is
+ sent. The routine updates the link's T1 timeout as well
+ as delay and throughput.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Delay;
+ ULONG ShiftedTicksDelay;
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ Delay = GetTimerInterval (Link);
+
+ if (Link->CurrentPollRetransmits == 0) {
+
+ //
+ // Convert the delay into NBF ticks, shifted by
+ // DLC_TIMER_ACCURACY and also multiplied by 4.
+ // We want to divide by SHORT_TIMER_DELTA, then
+ // shift left by DLC_TIMER_ACCURACY+2. We divide
+ // by NbfShortTimerDeltaTicks because the Delay
+ // is returned in ticks.
+ //
+ // We treat a delay of 0 as 1/2, so we use 1
+ // shifted left by (DLC_TIMER_ACCURACY+1).
+ //
+
+ if (Delay == 0) {
+
+ ShiftedTicksDelay = (1 << (DLC_TIMER_ACCURACY + 1)) /
+ NbfShortTimerDeltaTicks;
+
+ } else {
+
+ ShiftedTicksDelay = (Delay << (DLC_TIMER_ACCURACY + 2)) /
+ NbfShortTimerDeltaTicks;
+
+ }
+
+
+ //
+ // Use the timing information to update BaseT1Timeout,
+ // if the last frame sent was large enough to matter
+ // (we use half of the max frame size here). This is
+ // so we don't shrink the timeout too much after sending
+ // a short frame. However, we update even for small frames
+ // if the last time we sent a poll we had to retransmit
+ // it, since that means T1 is much too small and we should
+ // increase it as much as we can. We also update for any
+ // size frame if the new delay is bigger than the current
+ // value, so we can ramp up quickly if needed.
+ //
+
+ if (ShiftedTicksDelay > Link->BaseT1Timeout) {
+
+ //
+ // If our new delay is more, than we weight it evenly
+ // with the previous value.
+ //
+
+ Link->BaseT1Timeout = (Link->BaseT1Timeout +
+ ShiftedTicksDelay) / 2;
+
+ } else if (Link->CurrentT1Backoff) {
+
+ //
+ // If we got a retransmit last time, then weight
+ // the new timer more heavily than usual.
+ //
+
+ Link->BaseT1Timeout = ((Link->BaseT1Timeout * 3) +
+ ShiftedTicksDelay) / 4;
+
+ } else if (Link->CurrentPollSize >= Link->BaseT1RecalcThreshhold) {
+
+ //
+ // Normally, the new timeout is 7/8 the previous value and
+ // 1/8 the newly observed delay.
+ //
+
+ Link->BaseT1Timeout = ((Link->BaseT1Timeout * 7) +
+ ShiftedTicksDelay) / 8;
+
+ }
+
+ //
+ // Restrict the real timeout to a minimum based on
+ // the link speed (always >= 400 ms).
+ //
+
+ if (Link->BaseT1Timeout < Link->MinimumBaseT1Timeout) {
+
+ Link->BaseT1Timeout = Link->MinimumBaseT1Timeout;
+
+ }
+
+
+ //
+ // Update link delay and throughput also. Remember
+ // that a delay of 0 should be interpreted as 1/2.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+
+ //
+ // We had no retransmits last time, so go back to current base.
+ //
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ Link->CurrentT1Backoff = FALSE;
+
+ } else {
+
+ Link->CurrentT1Backoff = TRUE;
+
+ if (!(Link->ThroughputAccurate)) {
+
+ //
+ // If we are just starting up, we have to update the
+ // throughput even on a retransmit, so we get *some*
+ // value there.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+ }
+
+ }
+
+} /* UpdateBaseT1Timeout */
+
+
+VOID
+CancelT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have not received any
+ responses to a poll frame and are giving up rather
+ than retransmitting.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // We must have previously sent a poll frame if we are
+ // calling this.
+ //
+ // BUGBUG: We need spinlock guarding for MP.
+ //
+
+ if (!Link->CurrentPollOutstanding) {
+ return;
+ }
+
+ //
+ // We are stopping a polling condition, so reset T1.
+ //
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ Link->CurrentT1Backoff = FALSE;
+
+ //
+ // Again, this isn't safe on MP (or UP, maybe).
+ //
+
+ Link->CurrentPollOutstanding = FALSE;
+
+} /* CancelT1Timeout */
+
+
+VOID
+UpdateDelayAndThroughput(
+ IN PTP_LINK Link,
+ IN ULONG TimerInterval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response packet used to time
+ link delay has been received. It is assumed that StartT1
+ or FakeStartT1 was called when the initial packet was sent.
+
+ NOTE: For now, we also calculate throughput based on this.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ TimerInterval - The link delay measured.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG PacketSize;
+
+
+ if (Link->Delay == 0xffffffff) {
+
+ //
+ // If delay is unknown, use this.
+ //
+
+ Link->Delay = TimerInterval;
+
+ } else if (Link->CurrentPollSize <= 64) {
+
+ //
+ // Otherwise, for small frames calculate the new
+ // delay by averaging with the old one.
+ //
+
+ Link->Delay = (Link->Delay + TimerInterval) / 2;
+
+ }
+
+
+ //
+ // Calculate the packet size times the number of time units
+ // in 10 milliseconds, which will allow us to calculate
+ // throughput in bytes/10ms (we later multiply by 100
+ // to obtain the real throughput in bytes/s).
+ //
+ // Given the size of MILLISECONDS, this allows packets of up
+ // to ~20K, so for bigger packets we just assume that (since
+ // throughput won't be an issue there).
+ //
+
+ if (Link->CurrentPollSize > 20000) {
+ PacketSize = 20000 * (10 * MILLISECONDS);
+ } else {
+ PacketSize = Link->CurrentPollSize * (10*MILLISECONDS);
+ }
+
+ //
+ // If throughput is not accurate, then we will use this
+ // packet only to calculate it. To avoid being confused
+ // by very small packets, assume a minimum size of 64.
+ //
+
+ if ((!Link->ThroughputAccurate) && (PacketSize < (64*(10*MILLISECONDS)))) {
+ PacketSize = 64 * (10*MILLISECONDS);
+ }
+
+ //
+ // PacketSize is going to be divided by TimerInterval;
+ // to prevent a zero throughput, we boost it up if needed.
+ //
+
+ if (PacketSize < TimerInterval) {
+ PacketSize = TimerInterval;
+ }
+
+
+ if (Link->CurrentPollSize >= 512) {
+
+ //
+ // Calculate throughput here by removing the established delay
+ // from the time.
+ //
+
+ if ((Link->Delay + (2*MILLISECONDS)) < TimerInterval) {
+
+ //
+ // If the current delay is less than the new timer
+ // interval (plus 2 ms), then subtract it off for a
+ // more accurate throughput calculation.
+ //
+
+ TimerInterval -= Link->Delay;
+
+ }
+
+ //
+ // We assume by this point (sending a > 512-byte frame) we
+ // already have something established as Link->Throughput.
+ //
+
+ if (!(Link->ThroughputAccurate)) {
+
+ Link->Throughput.QuadPart =
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ Link->ThroughputAccurate = TRUE;
+
+#if 0
+ NbfPrint2 ("INT: %ld.%1.1d us\n",
+ TimerInterval / 10, TimerInterval % 10);
+ NbfPrint4 ("D: %ld.%1.1d us T: %ld (%d)/s\n",
+ Link->Delay / 10, Link->Delay % 10,
+ Link->Throughput.LowPart, Link->CurrentPollSize);
+#endif
+
+ } else {
+
+ LARGE_INTEGER TwiceThroughput;
+
+ //
+ // New throughput is the average of the old throughput, and
+ // the current packet size divided by the delay just observed.
+ // First we calculate the sum, then we shift right by one.
+ //
+
+ TwiceThroughput.QuadPart = Link->Throughput.QuadPart +
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ Link->Throughput.QuadPart = TwiceThroughput.QuadPart >> 1;
+ }
+
+ } else if (!(Link->ThroughputAccurate)) {
+
+ //
+ // We don't have accurate throughput, so just get an estimate
+ // by ignoring the delay on this small frame.
+ //
+
+ Link->Throughput.QuadPart =
+ UInt32x32To64((PacketSize / TimerInterval), 100);
+
+ }
+
+} /* UpdateDelayAndThroughput */
+
+
+VOID
+FakeStartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called before sending a packet that will be used
+ to time link delay, but where StartT1 will not be started.
+ It is assumed that FakeUpdateBaseT1Timeout will be called
+ when the response is received. This is used for timing
+ frames that have a known immediate response, but are not
+ poll frames.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+ PacketSize - The size of the packet that was just sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ Link->CurrentPollSize = PacketSize;
+ KeQueryTickCount(&Link->CurrentTimerStart);
+
+} /* FakeStartT1 */
+
+
+VOID
+FakeUpdateBaseT1Timeout(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a response to a frame is
+ received, and we called FakeStartT1 when the initial
+ frame was sent. This is used for timing frames that have
+ a known immediate response, but are not poll frames.
+
+ NOTE: This routine should be called with the link spinlock
+ held.
+
+Arguments:
+
+ Link - Pointer to a transport link object.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+ ULONG Delay;
+
+ Delay = GetTimerInterval (Link);
+
+ //
+ // Convert the delay into NBF ticks, shifted by
+ // DLC_TIMER_ACCURACY and also multiplied by 4.
+ // We want to divide by SHORT_TIMER_DELTA, then
+ // shift left by DLC_TIMER_ACCURACY+2. We divide
+ // by NbfShortTimerDeltaTicks because the Delay
+ // is returned in ticks. We treat a Delay of 0
+ // as 1/2 and calculate ((1/2) << x) as (1 << (x-1)).
+ //
+ // This timeout is treated as the correct value.
+ //
+
+ if (Delay == 0) {
+
+ Link->BaseT1Timeout = (1 << (DLC_TIMER_ACCURACY + 1)) /
+ NbfShortTimerDeltaTicks;
+
+ } else {
+
+ Link->BaseT1Timeout = (Delay << (DLC_TIMER_ACCURACY + 2)) /
+ NbfShortTimerDeltaTicks;
+
+ }
+
+ //
+ // Restrict the real timeout to a minimum based on
+ // the link speed (always >= 400 ms).
+ //
+
+ if (Link->BaseT1Timeout < Link->MinimumBaseT1Timeout) {
+ Link->BaseT1Timeout = Link->MinimumBaseT1Timeout;
+ }
+
+ Link->CurrentT1Timeout = Link->BaseT1Timeout >> DLC_TIMER_ACCURACY;
+
+ //
+ // Update link delay and throughput also.
+ //
+
+ UpdateDelayAndThroughput(
+ Link,
+ (Delay == 0) ?
+ (NbfTickIncrement / 2) :
+ (Delay * NbfTickIncrement));
+
+} /* FakeUpdateBaseT1Timeout */
+
+
+VOID
+StartT1(
+ IN PTP_LINK Link,
+ IN ULONG PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the T1 timer for the given link. If the link was
+ already on the list, it is moved to the tail. If not, it is inserted at
+ tail.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+ PollPacketSize - If a poll packet was just sent it is its size;
+ otherwise this will be 0 (when non-poll I-frames are sent).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+ if (PacketSize > 0) {
+
+ //
+ // If we are sending an initial poll frame, then do timing stuff.
+ //
+
+ Link->CurrentPollRetransmits = 0;
+ Link->CurrentPollSize = PacketSize;
+ Link->CurrentPollOutstanding = TRUE;
+ KeQueryTickCount(&Link->CurrentTimerStart);
+
+ } else {
+
+ Link->CurrentPollOutstanding = FALSE;
+
+ }
+
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Link->T1 = DeviceContext->ShortAbsoluteTime+Link->CurrentT1Timeout;
+
+ if (!Link->OnShortList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnShortList) {
+ Link->OnShortList = TRUE;
+ InsertTailList (&DeviceContext->ShortList, &Link->ShortList);
+ }
+
+ if (!DeviceContext->a.i.ShortListActive) {
+
+ StartTimerT1++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.ShortListActive = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+}
+
+
+VOID
+StartT2(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given link to the T2 queue and starts the timer.
+ If the link is already on the queue, it is moved to the queue end.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+
+ if (DeviceContext->MacInfo.MediumAsync) {
+
+ //
+ // On an async line, expire it as soon as possible.
+ //
+
+ Link->T2 = DeviceContext->ShortAbsoluteTime;
+
+ } else {
+
+ Link->T2 = DeviceContext->ShortAbsoluteTime+Link->T2Timeout;
+
+ }
+
+
+ if (!Link->OnShortList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnShortList) {
+ Link->OnShortList = TRUE;
+ InsertTailList (&DeviceContext->ShortList, &Link->ShortList);
+ }
+
+ if (!DeviceContext->a.i.ShortListActive) {
+
+ StartTimerT2++;
+ NbfStartShortTimer (DeviceContext);
+ DeviceContext->a.i.ShortListActive = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+}
+
+
+VOID
+StartTi(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given link to the Ti queue and starts the timer.
+ As above, if the link is already on the queue it is moved to the queue end.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext = Link->Provider;
+
+
+ //
+ // On an easily disconnected link, with only server connections
+ // on this link, we set a long Ti timeout, and when it
+ // expires with no activity we start checkpointing, otherwise
+ // we assume things are OK.
+ //
+
+ if (DeviceContext->EasilyDisconnected && Link->NumberOfConnectors == 0) {
+ Link->Ti = DeviceContext->LongAbsoluteTime + (2 * Link->TiTimeout);
+ Link->TiStartPacketsReceived = Link->PacketsReceived;
+ } else {
+ Link->Ti = DeviceContext->LongAbsoluteTime+Link->TiTimeout;
+ }
+
+
+ if (!Link->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (!Link->OnLongList) {
+ Link->OnLongList = TRUE;
+ InsertTailList (&DeviceContext->LongList, &Link->LongList);
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+
+}
+
+#if DBG
+
+VOID
+StopT1(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Again, this isn't safe on MP (or UP, maybe).
+ //
+
+ Link->CurrentPollOutstanding = FALSE;
+ Link->T1 = 0;
+
+}
+
+
+VOID
+StopT2(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Link->ConsecutiveIFrames = 0;
+ Link->T2 = 0;
+
+}
+
+
+VOID
+StopTi(
+ IN PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+ Link - pointer to the link of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Link->Ti = 0;
+}
+#endif
+
+
+VOID
+ExpireT1Timer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's T1 timer expires. T1 is the
+ retransmission timer, and is used to remember that a response is
+ expected to any of the following: (1) a checkpoint, (2) a transmitted
+ I-frame, (3) a SABME, or (4) a DISC. Cases 3 and 4 are actually
+ special forms of a checkpoint, since they are sent by this protocol
+ implementation with the poll bit set, effectively making them a
+ checkpoint sequence.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose T1 timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDLC_I_FRAME DlcHeader;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ switch (Link->State) {
+
+ case LINK_STATE_ADM:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: State=ADM, timeout not expected.\n");
+ }
+ break;
+
+ case LINK_STATE_READY:
+
+ //
+ // We've sent an I-frame and haven't received an acknowlegement
+ // yet, or we are checkpointing, and must retry the checkpoint.
+ // Another possibility is that we're rejecting, and he hasn't
+ // sent anything yet.
+ //
+
+ switch (Link->SendState) {
+
+ case SEND_STATE_DOWN:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link READY but SendState=DOWN.\n");
+ }
+ break;
+
+ case SEND_STATE_READY:
+
+ //
+ // We sent an I-frame and didn't get an acknowlegement.
+ // Initiate a checkpoint sequence.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ {PTP_PACKET packet;
+ PLIST_ENTRY p;
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=READY .\n");
+ NbfDumpLinkInfo (Link);
+ p=Link->WackQ.Flink;
+ NbfPrint0 ("ExpireT1Timer: Link WackQ entries:\n");
+ while (p != &Link->WackQ) {
+ packet = CONTAINING_RECORD (p, TP_PACKET, Linkage);
+ DlcHeader = (PDLC_I_FRAME)&(packet->Header[Link->HeaderLength]);
+ NbfPrint2 (" %08lx %03d\n", p,
+ (DlcHeader->SendSeq >> 1));
+ p = p->Flink;
+ }}
+ }
+
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ // Don't BackoffT1Timeout yet.
+ NbfSendRr (Link, TRUE, TRUE);// send RR-c/p, StartT1, release lock
+ break;
+
+ case SEND_STATE_REJECTING:
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=REJECTING.\n");
+ NbfPrint0 ("so what do we do here? consult the manual...\n");
+ }
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+// Link->SendRetries = Link->LlcRetries;
+// break; // DGB: doing nothing is obviously wrong, we've
+// // gotten a T1 expiration during resend. Try
+// // an RR to say hey.
+
+ case SEND_STATE_CHECKPOINTING:
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=READY, SendState=CHECKPOINTING.\n");
+ NbfDumpLinkInfo (Link);
+ }
+ if (--Link->SendRetries == 0) {
+
+ //
+ // We have not gotten any response to RR-p packets,
+ // initiate orderly link teardown.
+ //
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_W_DISC_RSP; // we are awaiting a DISC/f.
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfStopLink (Link);
+
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer sending DISC (checkpoint failed)\n" );
+ }
+#endif
+ } else {
+
+ BackoffCurrentT1Timeout (Link);
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock.
+
+ }
+ break;
+
+ default:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint1 ("ExpireT1Timer: Link State=READY, SendState=%ld (UNKNOWN).\n",
+ Link->SendState);
+ }
+ }
+ break;
+
+ case LINK_STATE_CONNECTING:
+
+ //
+ // We sent a SABME-c/p and have not yet received UA-r/f. This
+ // means we must decrement the retry count and if it is not yet
+ // zero, we issue another SABME command, because he has probably
+ // dropped our first one.
+ //
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no response to SABME)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in CONNECTING mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+ } else {
+ BackoffCurrentT1Timeout (Link);
+ NbfSendSabme (Link, TRUE); // send SABME/p, StartT1, release lock
+ }
+ break;
+
+ case LINK_STATE_W_POLL:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: State=W_POLL, timeout not expected.\n");
+ }
+ break;
+
+ case LINK_STATE_W_FINAL:
+
+ //
+ // We sent our initial RR-c/p and have not received his RR-r/f.
+ // We have to restart the checkpoint, unless our retries have
+ // run out, in which case we just abort the link.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT1Timer: Link State=W_FINAL.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no final received)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_FINAL mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+
+ } else {
+
+ BackoffCurrentT1Timeout (Link);
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock
+
+ }
+ break;
+
+ case LINK_STATE_W_DISC_RSP:
+
+ //
+ // We sent a DISC-c/p to disconnect this link and are awaiting
+ // his response, either a UA-r/f or DM-r/f. We have to issue
+ // the DISC again, unless we've tried a few times, in which case
+ // we just shut the link down.
+ //
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint0 ("ExpireT1Timer: Link State=W_DISC_RESP.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (--Link->SendRetries == 0) {
+
+ CancelT1Timeout (Link); // we are stopping a polling state
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no response to DISC)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_DISC_RSP mode", Link, LREF_NOT_ADM);
+
+ return; // skip extra spinlock release.
+
+ } else {
+
+ // we don't bother calling BackoffCurrentT1Timeout for DISCs.
+ ++Link->CurrentPollRetransmits;
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // startup timer again.
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfSendDisc (Link, TRUE); // send DISC/p.
+
+ }
+ break;
+
+ default:
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint1 ("ExpireT1Timer: State=%ld (UNKNOWN), timeout not expected.\n",
+ Link->State);
+ }
+ }
+
+
+} /* ExpireT1Timer */
+
+
+VOID
+ExpireT2Timer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's T2 timer expires. T2 is the
+ delayed acknowlegement timer in the LLC connection-oriented procedures.
+ The T2 timer is started when a valid I-frame is received but not
+ immediately acknowleged. Then, if reverse I-frame traffic is sent,
+ the timer is stopped, since the reverse traffic will acknowlege the
+ received I-frames. If no reverse I-frame traffic becomes available
+ to send, then this timer fires, causing a RR-r/0 to be sent so as
+ to acknowlege the received but as yet unacked I-frames.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose T2 timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireT2Timer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ NbfSendRr (Link, FALSE, FALSE); // send RR-r/f, release lock.
+
+} /* ExpireT2Timer */
+
+
+VOID
+ExpireTiTimer(
+ PTP_LINK Link
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a link's Ti timer expires. Ti is the
+ inactivity timer, and serves as a keep-alive on a link basis, to
+ periodically perform some protocol exchange with the remote connection
+ partner that will implicitly reveal whether the link is still active
+ or not. This implementation simply uses a checkpoint sequence, but
+ some other protocols may choose to add protocol, including sending
+ a NetBIOS SESSION_ALIVE frame. If a checkpoint sequence is already
+ in progress, then we do nothing.
+
+ This timer expiration routine is self-perpetuating; that is, it starts
+ itself after finishing its tasks every time.
+
+Arguments:
+
+ Link - Pointer to the TP_LINK object whose Ti timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireTiTimer: Entered.\n");
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ if ((Link->State != LINK_STATE_ADM) &&
+ (Link->State != LINK_STATE_W_DISC_RSP) &&
+ (Link->SendState != SEND_STATE_CHECKPOINTING)) {
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpireTiTimer: Entered.\n");
+ NbfDumpLinkInfo (Link);
+ }
+
+ if (Link->Provider->EasilyDisconnected && Link->NumberOfConnectors == 0) {
+
+ //
+ // On an easily disconnected network with only server connections,
+ // if there has been no activity in this timeout period then
+ // we trash the connection.
+ //
+
+ if (Link->PacketsReceived == Link->TiStartPacketsReceived) {
+
+ Link->State = LINK_STATE_ADM;
+ NbfSendDm (Link, FALSE); // send DM/0, release lock
+#if DBG
+ if (NbfDisconnectDebug) {
+ NbfPrint0( "ExpireT1Timer calling NbfStopLink (no final received)\n" );
+ }
+#endif
+ NbfStopLink (Link);
+
+ // moving to ADM, remove reference
+ NbfDereferenceLinkSpecial("Expire T1 in W_FINAL mode", Link, LREF_NOT_ADM);
+
+ } else {
+
+ //
+ // There was traffic, restart the timer.
+ //
+
+ StartTi (Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+
+ }
+
+ } else {
+
+#if 0
+ if ((Link->SendState == SEND_STATE_READY) &&
+ (Link->T1 == 0) &&
+ (!IsListEmpty (&Link->WackQ))) {
+
+ //
+ // If we think the link is idle but there are packets
+ // on the WackQ, the link is messed up, disconnect it.
+ //
+
+ NbfPrint1 ("NBF: Link %d hung at Ti expiration, recovering\n", Link);
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+
+ } else {
+#endif
+
+ Link->SendState = SEND_STATE_CHECKPOINTING;
+ Link->PacketsSent = 0;
+ Link->PacketsResent = 0;
+ Link->PacketsReceived = 0;
+ NbfSendRr (Link, TRUE, TRUE); // send RR-c/p, StartT1, release lock.
+
+#if 0
+ }
+#endif
+
+ }
+
+ } else {
+
+ Link->PacketsSent = 0;
+ Link->PacketsResent = 0;
+ Link->PacketsReceived = 0;
+
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+#if DBG
+ if (Link->SendState == SEND_STATE_REJECTING) {
+ NbfPrint0 ("ExpireTiTimer: link state == rejecting, shouldn't be\n");
+ }
+#endif
+
+ }
+
+#if 0
+ //
+ // Startup the inactivity timer again.
+ //
+
+ if (Link->State != LINK_STATE_ADM) {
+ StartTi (Link);
+ }
+#endif
+
+} /* ExpireTiTimer */
+
+#if 0
+
+VOID
+ExpirePurgeTimer(
+ PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the device context's periodic adaptive
+ window algorithm timer expires. The timer perpetuates itself on a
+ regular basis.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context whose purge timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PTP_LINK Link;
+ PLIST_ENTRY p;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("ExpirePurgeTimer: Entered.\n");
+ }
+
+ //
+ // Scan through the link database on this device context and clear
+ // their worst window size limit. This will allow stuck links to
+ // grow their window again even though they encountered temporary
+ // congestion at the remote link station's adapter.
+ //
+
+ while (!IsListEmpty (&DeviceContext->PurgeList)) {
+ p = RemoveHeadList (&DeviceContext->PurgeList);
+ Link = CONTAINING_RECORD (p, TP_LINK, PurgeList);
+ Link->WorstWindowSize = Link->MaxWindowSize; // maximum window possible.
+
+ }
+
+ //
+ // Restart purge timer.
+ //
+
+ DeviceContext->AdaptivePurge = DeviceContext->ShortAbsoluteTime + TIMER_PURGE_TICKS;
+
+
+} /* ExpirePurgeTimer */
+#endif
+
+
+VOID
+ScanShortTimersDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at DISPATCH_LEVEL by the system at regular
+ intervals to determine if any link-level timers have expired, and
+ if they have, to execute their expiration routines.
+
+Arguments:
+
+ DeferredContext - Pointer to our DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_TIMERDPC) {
+ NbfPrint0 ("ScanShortTimersDpc: Entered.\n");
+ }
+
+ DeviceContext = DeferredContext;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ DeviceContext->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ (DeviceContext->ShortTimerStart).QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbfShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ DeviceContext->ShortAbsoluteTime += TickDelta;
+
+ if (DeviceContext->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ DeviceContext->ShortAbsoluteTime -= 0xe0000000;
+
+ p = DeviceContext->ShortList.Flink;
+ while (p != &DeviceContext->ShortList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, ShortList);
+
+ Timeout = Link->T1;
+ if (Timeout) {
+ Link->T1 = Timeout - 0xe0000000;
+ }
+
+ Timeout = Link->T2;
+ if (Timeout) {
+ Link->T2 = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ //
+ // now, as the timers are started, links are added to the end of the
+ // respective queue for that timer. since we know the additions are
+ // done in an orderly fashion and are sequential, we must only traverse
+ // a particular timer list to the first entry that is greater than our
+ // timer. That entry and all further entries will not need service.
+ // When a timer is cancelled, we remove the link from the list. With all
+ // of this fooling around, we wind up only visiting those links that are
+ // actually in danger of timing out, minimizing time in this routine.
+ //
+
+ // T1 timers first; this is the link-level response expected timer, and is
+ // the shortest one.
+ // T2 timers. This is the iframe response expected timer, and is typically
+ // about 300 ms.
+
+ p = DeviceContext->ShortList.Flink;
+ while (p != &DeviceContext->ShortList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, ShortList);
+
+ ASSERT (Link->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Link->State != LINK_STATE_ADM) {
+
+ if (Link->T1 && (DeviceContext->ShortAbsoluteTime > Link->T1)) {
+
+ Link->T1 = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireT1Timer (Link); // no spinlocks held
+ INCREMENT_COUNTER (DeviceContext, ResponseTimerExpirations);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ if (Link->T2 && (DeviceContext->ShortAbsoluteTime > Link->T2)) {
+
+ Link->T2 = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireT2Timer (Link); // no spinlocks held
+ INCREMENT_COUNTER (DeviceContext, AckTimerExpirations);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ }
+
+ if (!Link->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBF: Stop processing ShortList, %lx removed\n", Link);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if ((Link->T1 == 0) && (Link->T2 == 0)) {
+ Link->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Link->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if ((Link->T1 != 0) || (Link->T2 != 0)) {
+ InsertTailList(&DeviceContext->ShortList, &Link->ShortList);
+ Link->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&DeviceContext->ShortList)) {
+ DeviceContext->a.i.ShortListActive = FALSE;
+ }
+
+ //
+ // NOTE: DeviceContext->TimerSpinLock is held here.
+ //
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for NbfDeferredPasses times through
+ // here. If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+ // NOTE: There is no expiration time for connections on this
+ // queue; it "expires" every time ScanShortTimersDpc runs.
+ //
+
+
+ for (p = DeviceContext->DataAckQueue.Flink;
+ p != &DeviceContext->DataAckQueue;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) == 0) &&
+ ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) == 0)) {
+ continue;
+ }
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ (Connection->ConnectStartTime).QuadPart;
+
+ if ((TickDifference.HighPart == 0) &&
+ (TickDifference.LowPart <= NbfTwentyMillisecondsTicks)) {
+ continue;
+ }
+
+ NbfReferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ DeviceContext->DataAckQueueChanged = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ if (((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) &&
+ ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_NOT_Q) == 0)) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ //
+ // We have to ensure we nest the spin lock acquisition
+ // correctly.
+ //
+
+ Connection->DeferredFlags &= ~CONNECTION_FLAGS_DEFERRED_ACK;
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ INCREMENT_COUNTER (DeviceContext, PiggybackAckTimeouts);
+
+#if DBG
+ if (NbfDebugPiggybackAcks) {
+ NbfPrint0("T");
+ }
+#endif
+
+ NbfSendDataAck (Connection);
+
+ } else {
+
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ }
+
+ NbfDereferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (DeviceContext->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&DeviceContext->DataAckQueue)) {
+ DeviceContext->a.i.DataAckQueueActive = FALSE;
+ }
+
+#if 0
+
+ //
+ // NOTE: This is currently disabled, it may be reenabled
+ // at some point - adamba 9/1/92
+ //
+ // If the adaptive purge timer has expired, then run the purge
+ // algorithm on all affected links.
+ //
+
+ if (DeviceContext->ShortAbsoluteTime > DeviceContext->AdaptivePurge) {
+ DeviceContext->AdaptivePurge = DeviceContext->ShortAbsoluteTime +
+ TIMER_PURGE_TICKS;
+ ExpirePurgeTimer (DeviceContext);
+ }
+#endif
+
+ //
+ // deferred processing. We will handle all link structure additions and
+ // deletions here; we must be the exclusive user of the link tree to do
+ // this. We verify that we are by examining the semaphore that tells us
+ // how many readers of the tree are curretly processing it. If there are
+ // any readers, we simply increment our "deferred processing locked out"
+ // counter and do something else. If we defer too many times, we simply
+ // bugcheck, as something is wrong somewhere in the system.
+ //
+
+ if (!IsListEmpty (&DeviceContext->LinkDeferred)) {
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // now do additions or deletions if we can.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ while (!IsListEmpty (&DeviceContext->LinkDeferred)) {
+ p = RemoveHeadList (&DeviceContext->LinkDeferred);
+ DeviceContext->DeferredNotSatisfied = 0;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // now do an addition or deletion if we can.
+ //
+
+ Link = CONTAINING_RECORD (p, TP_LINK, DeferredList);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint4 ("ScanShortTimersDPC: link off deferred queue %lx %lx %lx Flags: %lx \n",
+ Link, DeviceContext->LinkDeferred.Flink,
+ DeviceContext->LinkDeferred.Blink, Link->DeferredFlags);
+ }
+ Link->DeferredList.Flink = Link->DeferredList.Blink =
+ &Link->DeferredList;
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_MASK) == 0) {
+ // Tried to do an operation we don't understand; whine.
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint2 ("ScanTimerDPC: Attempting deferred operation on nothing! \nScanTimerDPC: Link: %lx, DeviceContext->DeferredQueue: %lx\n",
+ Link, &DeviceContext->LinkDeferred);
+ DbgBreakPoint ();
+ }
+ InitializeListHead (&DeviceContext->LinkDeferred);
+ // We could have a hosed deferred operations queue here;
+ // BUGBUG: take some time to figure out if it is ok.
+
+ }
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_ADD) != 0) {
+
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_ADD;
+
+ if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+
+ //
+ // It is being added and deleted; just destroy it.
+ //
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfDestroyLink (Link);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: Add AND Delete link: %lx\n",Link);
+ }
+
+ } else {
+
+ NbfAddLinkToTree (DeviceContext, Link);
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: Added link to tree: %lx\n",Link);
+ }
+
+ }
+
+ } else if ((Link->DeferredFlags & LINK_FLAGS_DEFERRED_DELETE) != 0) {
+ Link->DeferredFlags &= ~LINK_FLAGS_DEFERRED_DELETE;
+ NbfRemoveLinkFromTree (DeviceContext, Link);
+ NbfDestroyLink (Link);
+
+ IF_NBFDBG (NBF_DEBUG_TEARDOWN) {
+ NbfPrint1 ("ScanTimerDPC: deferred processing: returning link %lx to LinkPool.\n", Link);
+ }
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ }
+
+ InitializeListHead (&DeviceContext->LinkDeferred);
+
+ DeviceContext->a.i.LinkDeferredActive = FALSE;
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->LinkSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DataFrameBytesSent,
+ DeviceContext->TempIFrameBytesSent);
+ DeviceContext->Statistics.DataFramesSent += DeviceContext->TempIFramesSent;
+
+ DeviceContext->TempIFrameBytesSent = 0;
+ DeviceContext->TempIFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->Statistics.DataFrameBytesReceived,
+ DeviceContext->TempIFrameBytesReceived);
+ DeviceContext->Statistics.DataFramesReceived += DeviceContext->TempIFramesReceived;
+
+ DeviceContext->TempIFrameBytesReceived = 0;
+ DeviceContext->TempIFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ DeviceContext->ProcessingShortTimer = FALSE;
+
+ if (DeviceContext->a.AnyActive &&
+ (DeviceContext->State != DEVICECONTEXT_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&DeviceContext->ShortTimerStart);
+ KeSetTimer (
+ &DeviceContext->ShortSystemTimer,
+ DueTimeDelta,
+ &DeviceContext->ShortTimerSystemDpc);
+
+ } else {
+
+#if DBG
+ if (NbfDebugShortTimer) {
+ DbgPrint("x");
+ }
+#endif
+ NbfDereferenceDeviceContext ("Don't restart short timer", DeviceContext, DCREF_SCAN_TIMER);
+
+ }
+
+
+ LEAVE_NBF;
+ return;
+
+} /* ScanShortTimersDpc */
+
+
+VOID
+ScanLongTimersDpc(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at DISPATCH_LEVEL by the system at regular
+ intervals to determine if any long timers have expired, and
+ if they have, to execute their expiration routines.
+
+Arguments:
+
+ DeferredContext - Pointer to our DEVICE_CONTEXT object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER DueTime;
+ PLIST_ENTRY p, nextp;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_LINK Link;
+ PTP_CONNECTION Connection;
+
+ Dpc, SystemArgument1, SystemArgument2; // prevent compiler warnings
+
+ ENTER_NBF;
+
+ IF_NBFDBG (NBF_DEBUG_TIMERDPC) {
+ NbfPrint0 ("ScanLongTimersDpc: Entered.\n");
+ }
+
+ DeviceContext = DeferredContext;
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ if (++DeviceContext->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ DeviceContext->LongAbsoluteTime = 0x10000000;
+
+ p = DeviceContext->LongList.Flink;
+ while (p != &DeviceContext->LongList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, LongList);
+
+ Timeout = Link->Ti;
+ if (Timeout) {
+ Link->Ti = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ //
+ // now, as the timers are started, links are added to the end of the
+ // respective queue for that timer. since we know the additions are
+ // done in an orderly fashion and are sequential, we must only traverse
+ // a particular timer list to the first entry that is greater than our
+ // timer. That entry and all further entries will not need service.
+ // When a timer is cancelled, we remove the link from the list. With all
+ // of this fooling around, we wind up only visiting those links that are
+ // actually in danger of timing out, minimizing time in this routine.
+ //
+
+
+ //
+ // Ti timers. This is the inactivity timer for the link, used when no
+ // activity has occurred on the link in some time. We only check this
+ // every four expirations of the timer since the granularity is usually
+ // in the 30 second range.
+ // NOTE: DeviceContext->TimerSpinLock is held here.
+ //
+
+ if ((DeviceContext->LongAbsoluteTime % 4) == 0) {
+
+ p = DeviceContext->LongList.Flink;
+ while (p != &DeviceContext->LongList) {
+
+ Link = CONTAINING_RECORD (p, TP_LINK, LongList);
+
+ ASSERT (Link->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+#if DBG
+ if (Link->SendState == SEND_STATE_REJECTING) {
+ NbfPrint0 ("Timer: link state == rejecting, shouldn't be\n");
+ }
+#endif
+
+ if (Link->State != LINK_STATE_ADM) {
+
+ if (Link->Ti && (DeviceContext->LongAbsoluteTime > Link->Ti)) {
+
+ Link->Ti = 0;
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ExpireTiTimer (Link); // no spinlocks held
+ ++DeviceContext->TiExpirations;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ }
+
+ }
+
+ if (!Link->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBF: Stop processing LongList, %lx removed\n", Link);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Link->Ti == 0) {
+
+ Link->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Link->Ti != 0) {
+ InsertTailList(&DeviceContext->LongList, &Link->LongList);
+ Link->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ p = DeviceContext->DataAckQueue.Flink;
+
+ while (p != &DeviceContext->DataAckQueue &&
+ !DeviceContext->DataAckQueueChanged) {
+
+ Connection = CONTAINING_RECORD (DeviceContext->DataAckQueue.Flink, TP_CONNECTION, DataAckLinkage);
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+ p = p->Flink;
+ continue;
+ }
+
+ NbfReferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped.
+ //
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if ((Connection->DeferredFlags & CONNECTION_FLAGS_DEFERRED_ACK) != 0) {
+ InsertTailList (&DeviceContext->DataAckQueue, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ DeviceContext->DataAckQueueChanged = TRUE;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+ RELEASE_DPC_SPIN_LOCK (Connection->LinkSpinLock);
+
+ NbfDereferenceConnection ("ScanShortTimersDpc", Connection, CREF_DATA_ACK_QUEUE);
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->TimerSpinLock);
+
+
+ //
+ // See if we got any multicast traffic last time.
+ //
+
+ if (DeviceContext->MulticastPacketCount == 0) {
+
+ ++DeviceContext->LongTimeoutsWithoutMulticast;
+
+ if (DeviceContext->EasilyDisconnected &&
+ (DeviceContext->LongTimeoutsWithoutMulticast > 5)) {
+
+ PLIST_ENTRY p;
+ PTP_ADDRESS address;
+
+ //
+ // We have had five timeouts in a row with no
+ // traffic, mark all the addresses as needing
+ // reregistration next time a connect is
+ // done on them.
+ //
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+ address->Flags |= ADDRESS_FLAGS_NEED_REREGISTER;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ }
+
+ } else {
+
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ }
+
+ DeviceContext->MulticastPacketCount = 0;
+
+
+ //
+ // Every thirty seconds, check for stalled connections
+ //
+
+ ++DeviceContext->StalledConnectionCount;
+
+ if (DeviceContext->StalledConnectionCount ==
+ (USHORT)((30 * SECONDS) / LONG_TIMER_DELTA)) {
+
+ DeviceContext->StalledConnectionCount = 0;
+ StopStalledConnections (DeviceContext);
+
+ }
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbfReceiveComplete((NDIS_HANDLE)DeviceContext);
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_STOPPING) {
+ DueTime.HighPart = -1;
+ DueTime.LowPart = (ULONG)-(LONG_TIMER_DELTA); // delta time to next click.
+ KeSetTimer (
+ &DeviceContext->LongSystemTimer,
+ DueTime,
+ &DeviceContext->LongTimerSystemDpc);
+ } else {
+ NbfDereferenceDeviceContext ("Don't restart long timer", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ LEAVE_NBF;
+ return;
+
+} /* ScanLongTimersDpc */
+
+
+VOID
+StopStalledConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from ScanLongTimersDpc every 30 seconds.
+ It checks for connections that have not made any progress in
+ their sends in the last two minutes, and stops them.
+
+Arguments:
+
+ DeviceContext - The device context to check.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PTP_ADDRESS Address, PrevAddress;
+ PTP_CONNECTION Connection, StalledConnection;
+ PLIST_ENTRY p, q;
+
+
+ //
+ // If we have crossed a thirty-second interval, then
+ // check each address for connections that have not
+ // made any progress in two minutes.
+ //
+
+ PrevAddress = NULL;
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ for (p = DeviceContext->AddressDatabase.Flink;
+ p != &DeviceContext->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (
+ p,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ //
+ // By referencing the address, we ensure that it will stay
+ // in the AddressDatabase, this its Flink will stay valid.
+ //
+
+ NbfReferenceAddress("checking for dead connections", Address, AREF_TIMER_SCAN);
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (PrevAddress) {
+ NbfDereferenceAddress ("done checking", PrevAddress, AREF_TIMER_SCAN);
+ }
+
+ //
+ // Scan this addresses connection database for connections
+ // that have not made progress in the last two minutes; we
+ // kill the first one we find.
+ //
+
+ StalledConnection = NULL;
+
+ ACQUIRE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ for (q = Address->ConnectionDatabase.Flink;
+ q != &Address->ConnectionDatabase;
+ q = q->Flink) {
+
+ Connection = CONTAINING_RECORD (q, TP_CONNECTION, AddressList);
+
+ ACQUIRE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+ if (!IsListEmpty (&Connection->SendQueue)) {
+
+ //
+ // If there is a connection on the queue...
+ //
+
+ if (Connection->StallBytesSent == Connection->sp.MessageBytesSent) {
+
+ //
+ // ...and it has not made any progress...
+ //
+
+ if (Connection->StallCount >= 4) {
+
+ //
+ // .. four times in a row, the connection is dead.
+ //
+
+ if (!StalledConnection) {
+ StalledConnection = Connection;
+ NbfReferenceConnection ("stalled", Connection, CREF_STALLED);
+ }
+#if DBG
+ DbgPrint ("NBF: Found connection %lx [%d for %d] stalled on %lx\n",
+ Connection, Connection->StallBytesSent, Connection->StallCount, Address);
+#endif
+
+ } else {
+
+ //
+ // If it is stuck, increment the count.
+ //
+
+ ++Connection->StallCount;
+
+ }
+
+ } else {
+
+ Connection->StallBytesSent = Connection->sp.MessageBytesSent;
+
+ }
+
+ }
+
+ RELEASE_DPC_C_SPIN_LOCK (&Connection->SpinLock);
+
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&Address->SpinLock);
+
+ if (StalledConnection) {
+
+ PTP_LINK Link = StalledConnection->Link;
+
+#if DBG
+ DbgPrint("NBF: Stopping stalled connection %lx, link %lx\n", StalledConnection, Link);
+#endif
+
+ FailSend (StalledConnection, STATUS_IO_TIMEOUT, TRUE); // fail the send
+ ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock);
+ if (Link->State == LINK_STATE_READY) {
+ CancelT1Timeout (Link);
+ Link->State = LINK_STATE_W_DISC_RSP;
+ Link->SendState = SEND_STATE_DOWN;
+ Link->ReceiveState = RECEIVE_STATE_DOWN;
+ Link->SendRetries = (UCHAR)Link->LlcRetries;
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+ StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); // retransmit timer.
+ NbfSendDisc (Link, TRUE); // send DISC-c/p.
+ } else {
+ RELEASE_DPC_SPIN_LOCK (&Link->SpinLock);
+ NbfStopLink (Link);
+ }
+
+ NbfDereferenceConnection ("stalled", StalledConnection, CREF_STALLED);
+
+ }
+
+ ACQUIRE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ PrevAddress = Address;
+
+ }
+
+ RELEASE_DPC_SPIN_LOCK (&DeviceContext->SpinLock);
+
+ if (PrevAddress) {
+ NbfDereferenceAddress ("done checking", PrevAddress, AREF_TIMER_SCAN);
+ }
+
+} /* StopStalledConnections */
+
+
+VOID
+NbfStartShortTimer(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+ // We use a trick to check all four active lists at the
+ // same time, but this depends on some alignment and
+ // size assumptions.
+ //
+
+ ASSERT (sizeof(ULONG) >= 3 * sizeof(BOOLEAN));
+ ASSERT ((PVOID)&DeviceContext->a.AnyActive ==
+ (PVOID)&DeviceContext->a.i.ShortListActive);
+
+ StartTimer++;
+
+ if ((!DeviceContext->ProcessingShortTimer) &&
+ (!(DeviceContext->a.AnyActive))) {
+
+#if DBG
+ if (NbfDebugShortTimer) {
+ DbgPrint("X");
+ }
+#endif
+
+ NbfReferenceDeviceContext ("Start short timer", DeviceContext, DCREF_SCAN_TIMER);
+
+ KeQueryTickCount(&DeviceContext->ShortTimerStart);
+ StartTimerSet++;
+ KeSetTimer (
+ &DeviceContext->ShortSystemTimer,
+ DueTimeDelta,
+ &DeviceContext->ShortTimerSystemDpc);
+
+ }
+
+} /* NbfStartShortTimer */
+
+
+VOID
+NbfInitializeTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LARGE_INTEGER DueTime;
+
+ IF_NBFDBG (NBF_DEBUG_TIMER) {
+ NbfPrint0 ("NbfInitializeTimerSystem: Entered.\n");
+ }
+
+ //
+ // Set these up.
+ //
+
+ NbfTickIncrement = KeQueryTimeIncrement();
+
+ if (NbfTickIncrement > (20 * MILLISECONDS)) {
+ NbfTwentyMillisecondsTicks = 1;
+ } else {
+ NbfTwentyMillisecondsTicks = (20 * MILLISECONDS) / NbfTickIncrement;
+ }
+
+ if (NbfTickIncrement > (SHORT_TIMER_DELTA)) {
+ NbfShortTimerDeltaTicks = 1;
+ } else {
+ NbfShortTimerDeltaTicks = (SHORT_TIMER_DELTA) / NbfTickIncrement;
+ }
+
+ //
+ // MaximumIntervalTicks represents 60 seconds, unless the value
+ // when shifted out by the accuracy required is too big.
+ //
+
+ if ((((ULONG)0xffffffff) >> (DLC_TIMER_ACCURACY+2)) > ((60 * SECONDS) / NbfTickIncrement)) {
+ NbfMaximumIntervalTicks = (60 * SECONDS) / NbfTickIncrement;
+ } else {
+ NbfMaximumIntervalTicks = ((ULONG)0xffffffff) >> (DLC_TIMER_ACCURACY + 2);
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ DeviceContext->ShortAbsoluteTime = 0x10000000; // initialize our timer click up-counter.
+ DeviceContext->LongAbsoluteTime = 0x10000000; // initialize our timer click up-counter.
+
+ DeviceContext->AdaptivePurge = TIMER_PURGE_TICKS;
+
+ DeviceContext->MulticastPacketCount = 0;
+ DeviceContext->LongTimeoutsWithoutMulticast = 0;
+
+ KeInitializeDpc(
+ &DeviceContext->ShortTimerSystemDpc,
+ ScanShortTimersDpc,
+ DeviceContext);
+
+ KeInitializeDpc(
+ &DeviceContext->LongTimerSystemDpc,
+ ScanLongTimersDpc,
+ DeviceContext);
+
+ KeInitializeTimer (&DeviceContext->ShortSystemTimer);
+
+ KeInitializeTimer (&DeviceContext->LongSystemTimer);
+
+ DueTime.HighPart = -1;
+ DueTime.LowPart = (ULONG)-(LONG_TIMER_DELTA);
+
+ //
+ // One reference for the long timer.
+ //
+
+ NbfReferenceDeviceContext ("Long timer active", DeviceContext, DCREF_SCAN_TIMER);
+
+ KeSetTimer (
+ &DeviceContext->LongSystemTimer,
+ DueTime,
+ &DeviceContext->LongTimerSystemDpc);
+
+ DeviceContext->TimersInitialized = TRUE;
+
+} /* NbfInitializeTimerSystem */
+
+
+VOID
+NbfStopTimerSystem(
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // For now we ignore what happens if the timer is currently
+ // running when we do this.
+ //
+
+ if (DeviceContext->TimersInitialized) {
+
+ if (KeCancelTimer(
+ &DeviceContext->LongSystemTimer)) {
+ NbfDereferenceDeviceContext ("Long timer cancelled", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ if (KeCancelTimer(
+ &DeviceContext->ShortSystemTimer)) {
+ NbfDereferenceDeviceContext ("Short timer cancelled", DeviceContext, DCREF_SCAN_TIMER);
+ }
+
+ }
+
+}
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 */
+