summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/tdi/st')
-rw-r--r--private/ntos/tdi/st/address.c2247
-rw-r--r--private/ntos/tdi/st/connect.c1137
-rw-r--r--private/ntos/tdi/st/connobj.c1375
-rw-r--r--private/ntos/tdi/st/devctx.c256
-rw-r--r--private/ntos/tdi/st/event.c185
-rw-r--r--private/ntos/tdi/st/framesnd.c371
-rw-r--r--private/ntos/tdi/st/iframes.c808
-rw-r--r--private/ntos/tdi/st/ind.c829
-rw-r--r--private/ntos/tdi/st/info.c865
-rw-r--r--private/ntos/tdi/st/makefile6
-rw-r--r--private/ntos/tdi/st/oemnxpts.inf446
-rw-r--r--private/ntos/tdi/st/packet.c597
-rw-r--r--private/ntos/tdi/st/rcv.c247
-rw-r--r--private/ntos/tdi/st/rcveng.c383
-rw-r--r--private/ntos/tdi/st/request.c801
-rw-r--r--private/ntos/tdi/st/send.c385
-rw-r--r--private/ntos/tdi/st/sendeng.c1505
-rw-r--r--private/ntos/tdi/st/sources62
-rw-r--r--private/ntos/tdi/st/st.h46
-rw-r--r--private/ntos/tdi/st/st.rc12
-rw-r--r--private/ntos/tdi/st/stcnfg.c1277
-rw-r--r--private/ntos/tdi/st/stcnfg.h57
-rw-r--r--private/ntos/tdi/st/stconst.h127
-rw-r--r--private/ntos/tdi/st/stdrvr.c1627
-rw-r--r--private/ntos/tdi/st/sthdrs.h69
-rw-r--r--private/ntos/tdi/st/stmac.c356
-rw-r--r--private/ntos/tdi/st/stmac.h635
-rw-r--r--private/ntos/tdi/st/stndis.c986
-rw-r--r--private/ntos/tdi/st/stprocs.h923
-rw-r--r--private/ntos/tdi/st/sttypes.h1103
-rw-r--r--private/ntos/tdi/st/uframes.c980
31 files changed, 20703 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/address.c b/private/ntos/tdi/st/address.c
new file mode 100644
index 000000000..3a4434a95
--- /dev/null
+++ b/private/ntos/tdi/st/address.c
@@ -0,0 +1,2247 @@
+/*++
+
+Copyright (c) 1989-1993 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.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+STATIC GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+VOID
+StDestroyAddress(
+ IN PVOID Parameter
+ );
+
+
+NTSTATUS
+StOpenAddress(
+ 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 ST 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;
+ PST_NETBIOS_ADDRESS networkName; // Network name string.
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *addressName;
+ TDI_ADDRESS_NETBIOS UNALIGNED *netbiosName;
+ ULONG DesiredShareAccess;
+ KIRQL oldirql;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = 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) {
+ StPrint1("OpenAddress: IRP %lx has no EA\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ addressName = (PTA_ADDRESS)&name->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one.
+ //
+
+ for (i=0;i<name->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if (addressName->AddressLength != 0) {
+ netbiosName = (PTDI_ADDRESS_NETBIOS)&addressName->Address[0];
+ networkName = (PST_NETBIOS_ADDRESS)ExAllocatePool (
+ NonPagedPool,
+ sizeof (ST_NETBIOS_ADDRESS));
+ if (networkName == NULL) {
+ PANIC ("StOpenAddress: PANIC! could not allocate networkName!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 1);
+ 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);
+
+ found = TRUE;
+ } else {
+ networkName = NULL;
+ found = TRUE;
+ }
+
+ break;
+
+ } else {
+
+ addressName = (PTA_ADDRESS)(addressName->Address +
+ addressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ StPrint1("OpenAddress: IRP %lx has no NETBIOS address\n", Irp);
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ status = StCreateAddressFile (DeviceContext, &addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ 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 = StLookupAddress (DeviceContext, networkName);
+
+ if (address == NULL) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ //
+ // This address doesn't exist. Create it, and start the process of
+ // registering it.
+ //
+
+ status = StCreateAddress (
+ DeviceContext,
+ networkName,
+ &address);
+
+ 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->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 (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &address->ShareAccess);
+ ExReleaseResource (&DeviceContext->AddressResource);
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (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_STOPPING) {
+ StDereferenceAddress ("Device context stopping", address);
+ StDereferenceAddressFile (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;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+ InsertTailList (&address->AddressFileDatabase, &addressFile->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+
+ //
+ // 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.
+ //
+
+ if ((networkName != NULL) &&
+ (!RtlEqualMemory (networkName->NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ StRegisterAddress (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;
+
+ }
+
+ }
+
+ } 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);
+ }
+
+ StDereferenceAddressFile (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 (AccessAllowed) {
+
+ //
+ // Access was successful, make sure Status is right.
+ //
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Check that the name is of the correct type (unique vs. group)
+ // We don't need to check this for the broadcast address.
+ //
+
+ if (networkName != NULL) {
+ if (address->NetworkName->NetbiosNameType !=
+ networkName->NetbiosNameType) {
+
+ status = STATUS_DUPLICATE_NAME;
+
+ }
+ }
+
+ }
+
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (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->ShareAccess,
+ TRUE);
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&DeviceContext->AddressResource);
+
+ StDereferenceAddressFile (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;
+
+ StReferenceAddress("open ready", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ 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;
+
+ StReferenceAddress("open registering", address);
+
+ IrpSp->FileObject->FsContext = (PVOID)addressFile;
+ IrpSp->FileObject->FsContext2 =
+ (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ status = STATUS_PENDING;
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ StDereferenceAddressFile (addressFile);
+
+ status = STATUS_DRIVER_INTERNAL_ERROR;
+
+ }
+ }
+ }
+ }
+
+ //
+ // Remove the reference from StLookupAddress.
+ //
+
+ StDereferenceAddress ("Done opening", address);
+ }
+
+ return status;
+} /* StOpenAddress */
+
+
+VOID
+StAllocateAddress(
+ 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;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + sizeof(TP_ADDRESS)) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate address: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 101);
+ *TransportAddress = NULL;
+ return;
+ }
+
+ Address = (PTP_ADDRESS)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS));
+ if (Address == NULL) {
+ PANIC("ST: Could not allocate address: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 201);
+ *TransportAddress = NULL;
+ return;
+ }
+ RtlZeroMemory (Address, sizeof(TP_ADDRESS));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS);
+ ++DeviceContext->AddressAllocated;
+
+ StAllocateSendPacket (DeviceContext, &(Address->Packet));
+ if (Address->Packet == NULL) {
+ ExFreePool (Address);
+ *TransportAddress = NULL;
+ return;
+ }
+ --DeviceContext->PacketAllocated; // AllocatePacket added one
+
+ //
+ // Need to modify the address packets to belong to
+ // the address, not the device context.
+ //
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+
+ Address->Type = ST_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (TP_ADDRESS);
+
+ Address->Provider = DeviceContext;
+ KeInitializeSpinLock (&Address->SpinLock);
+
+ InitializeListHead (&Address->ConnectionDatabase);
+ InitializeListHead (&Address->AddressFileDatabase);
+ InitializeListHead (&Address->SendDatagramQueue);
+
+ //
+ // For each address, allocate a receive packet, a receive buffer,
+ // and a UI frame.
+ //
+
+ StAddReceivePacket (DeviceContext);
+ StAddReceiveBuffer (DeviceContext);
+
+ *TransportAddress = Address;
+
+} /* StAllocateAddress */
+
+
+VOID
+StDeallocateAddress(
+ 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.
+
+--*/
+
+{
+
+ if (TransportAddress->NetworkName != NULL) {
+ ExFreePool (TransportAddress->NetworkName);
+ }
+ StDeallocateSendPacket (DeviceContext, TransportAddress->Packet);
+ ++DeviceContext->PacketAllocated;
+
+ ExFreePool (TransportAddress);
+ --DeviceContext->AddressAllocated;
+ DeviceContext->MemoryUsage -= sizeof(TP_ADDRESS);
+
+ //
+ // Remove the resources which allocating this caused.
+ //
+
+ StRemoveReceivePacket (DeviceContext);
+ StRemoveReceiveBuffer (DeviceContext);
+
+} /* StDeallocateAddress */
+
+
+NTSTATUS
+StCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_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 ST_NETBIOS_ADDRESS type containing the network
+ name to be associated with this address, if any.
+
+ 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)) {
+
+ StAllocateAddress (DeviceContext, &pAddress);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS), 401);
+ pAddress = NULL;
+
+ }
+
+ if (pAddress == NULL) {
+ ++DeviceContext->AddressExhausted;
+ PANIC ("StCreateConnection: 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;
+
+
+ //
+ // Initialize all of the static data for this address.
+ //
+
+ pAddress->ReferenceCount = 1;
+
+ pAddress->Flags = ADDRESS_FLAGS_NEEDS_REG;
+ InitializeListHead (&pAddress->AddressFileDatabase);
+
+ ExInitializeWorkItem(
+ &pAddress->DestroyAddressQueueItem,
+ StDestroyAddress,
+ (PVOID)pAddress);
+
+ pAddress->NetworkName = NetworkName;
+ if ((NetworkName != (PST_NETBIOS_ADDRESS)NULL) &&
+ (NetworkName->NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP)) {
+
+ pAddress->Flags |= ADDRESS_FLAGS_GROUP;
+
+ }
+
+ //
+ // 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;
+ StReferenceDeviceContext ("Create Address", DeviceContext); // count refs to the device context.
+
+ *Address = pAddress; // return the address.
+ return STATUS_SUCCESS; // not finished yet.
+} /* StCreateAddress */
+
+
+VOID
+StRegisterAddress(
+ 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;
+ PLIST_ENTRY p;
+ PIRP irp;
+ PTP_ADDRESS_FILE addressFile;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ if (!(Address->Flags & ADDRESS_FLAGS_NEEDS_REG)) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return;
+ }
+
+ Address->Flags &= ~ADDRESS_FLAGS_NEEDS_REG;
+ Address->Flags |= ADDRESS_FLAGS_REGISTERING;
+
+ //
+ // 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.
+ //
+
+ StReferenceAddress ("start registration", Address);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Normally we would add the name on the network, then
+ // do the following in our timeout logic, but for ST
+ // we assume that all names are OK.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ 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 (addressFile->Irp != NULL) {
+ irp = addressFile->Irp;
+ addressFile->Irp = NULL;
+ addressFile->State = ADDRESSFILE_STATE_OPEN;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Dereference the address if we're all done.
+ //
+
+ StDereferenceAddress ("Timer, registered", Address);
+
+} /* StRegisterAddress */
+
+
+NTSTATUS
+StVerifyAddressObject (
+ 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->Size == sizeof (TP_ADDRESS_FILE)) &&
+ (AddressFile->Type == ST_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ address = AddressFile->Address;
+
+ if ((address->Size == sizeof (TP_ADDRESS)) &&
+ (address->Type == ST_ADDRESS_SIGNATURE) ) {
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock, &oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) == 0) {
+
+ StReferenceAddress ("verify", address);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx closing\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
+
+ } else {
+
+ StPrint1("StVerifyAddress: A %lx bad signature\n", address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ StPrint1("StVerifyAddress: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ StPrint1("StVerifyAddress: AF %lx exception\n", address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+VOID
+StDestroyAddress(
+ 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 StfDerefAddress. 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;
+
+ 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);
+
+ RemoveEntryList (&Address->Linkage);
+
+ //
+ // Now we can deallocate the transport address object.
+ //
+
+ DeviceContext->AddressTotal += DeviceContext->AddressInUse;
+ ++DeviceContext->AddressSamples;
+ --DeviceContext->AddressInUse;
+
+ if ((DeviceContext->AddressAllocated - DeviceContext->AddressInUse) >
+ DeviceContext->AddressInitAllocated) {
+ StDeallocateAddress (DeviceContext, Address);
+ } else {
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ StDereferenceDeviceContext ("Destroy Address", DeviceContext); // just housekeeping.
+
+} /* StDestroyAddress */
+
+
+VOID
+StRefAddress(
+ 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);
+
+} /* StRefAddress */
+
+
+VOID
+StDerefAddress(
+ 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
+ StDestroyAddress 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);
+
+ //
+ // Defer the actual call to StDestroyAddress to a thread
+ // so the paged security descriptor can be accessed at IRQL 0.
+ //
+
+ if (result == 0) {
+ ExQueueWorkItem(&Address->DestroyAddressQueueItem, DelayedWorkQueue);
+ }
+} /* StDerefAddress */
+
+
+
+VOID
+StAllocateAddressFile(
+ 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("ST: Could not allocate address file: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 102);
+ *TransportAddressFile = NULL;
+ return;
+ }
+
+ AddressFile = (PTP_ADDRESS_FILE)ExAllocatePool (NonPagedPool, sizeof (TP_ADDRESS_FILE));
+ if (AddressFile == NULL) {
+ PANIC("ST: Could not allocate address file: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 202);
+ *TransportAddressFile = NULL;
+ return;
+ }
+ RtlZeroMemory (AddressFile, sizeof(TP_ADDRESS_FILE));
+
+ DeviceContext->MemoryUsage += sizeof(TP_ADDRESS_FILE);
+ ++DeviceContext->AddressFileAllocated;
+
+ AddressFile->Type = ST_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (TP_ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ *TransportAddressFile = AddressFile;
+
+} /* StAllocateAddressFile */
+
+
+VOID
+StDeallocateAddressFile(
+ 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);
+
+} /* StDeallocateAddressFile */
+
+
+NTSTATUS
+StCreateAddressFile(
+ 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)) {
+
+ StAllocateAddressFile (DeviceContext, &addressFile);
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_ADDRESS_FILE), 402);
+ addressFile = NULL;
+
+ }
+
+ if (addressFile == NULL) {
+ ++DeviceContext->AddressFileExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: 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;
+
+} /* StCreateAddress */
+
+
+NTSTATUS
+StDestroyAddressFile(
+ 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 StDereferenceAddressFile. 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.
+ //
+
+ StDereferenceAddress ("Close", address); // 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) {
+ StDeallocateAddressFile (DeviceContext, 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;
+
+} /* StDestroyAddress */
+
+
+VOID
+StReferenceAddressFile(
+ 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);
+
+} /* StReferenceAddressFile */
+
+
+VOID
+StDereferenceAddressFile(
+ 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
+ StDestroyAddressFile 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) {
+ StDestroyAddressFile (AddressFile);
+ }
+} /* StDerefAddressFile */
+
+
+PTP_ADDRESS
+StLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_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 ST_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.
+ //
+
+ StReferenceAddress ("lookup", address);
+ return address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* StLookupAddress */
+
+
+PTP_CONNECTION
+StLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connections associated with an
+ address, and determines if there is an connection
+ associated with the specific remote address.
+
+Arguments:
+
+ Address - Pointer to the address.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY p;
+ PTP_CONNECTION connection;
+
+
+ //
+ // 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);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if (((connection->Flags2 & CONNECTION_FLAGS2_REMOTE_VALID) != 0) &&
+ ((connection->Flags & CONNECTION_FLAGS_READY) != 0)) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ //
+ // If the remote names match, then return the
+ // connection.
+ //
+
+ if (RtlEqualMemory(RemoteName, connection->RemoteName, NETBIOS_NAME_LENGTH)) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ StReferenceConnection ("Lookup found", connection);
+ return connection;
+
+ }
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return (PTP_CONNECTION)NULL;
+
+}
+
+
+BOOLEAN
+StMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ 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.
+
+ 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;
+ }
+
+ //
+ // 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;
+ }
+
+} /* StMatchNetbiosAddress */
+
+
+VOID
+StStopAddress(
+ 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)) {
+
+ 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 StStopAddress
+ // 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.
+ //
+
+ StStopAddressFile (addressFile, Address);
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ StDereferenceAddressFile (addressFile);
+
+ StDereferenceAddress ("stop address", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return;
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+} /* StStopAddress */
+
+
+NTSTATUS
+StStopAddressFile(
+ 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 localList;
+ PLIST_ENTRY p, pFlink;
+ PTP_REQUEST request;
+ PTP_CONNECTION connection;
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+ InitializeListHead (&localList);
+
+ //
+ // Run down all connections on this addressfile, and
+ // preform the equivalent of StDestroyAssociation
+ // on them.
+ //
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressFileList);
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql1);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+
+ //
+ // It is in the process of being disassociated already.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+ continue;
+ }
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ connection->Flags |= CONNECTION_FLAGS_DESTROY; // BUGBUG: Is this needed?
+ RemoveEntryList (&connection->AddressList);
+ InitializeListHead (&connection->AddressList);
+ InitializeListHead (&connection->AddressFileList);
+ connection->AddressFile = NULL;
+
+ StReferenceConnection ("Close AddressFile", connection);
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql1);
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ StDereferenceConnection ("Close AddressFile", connection);
+
+ StDereferenceAddress ("Destroy association", Address);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ }
+
+ //
+ // now remove all of the datagrams owned by this addressfile
+ //
+
+ for (p = Address->SendDatagramQueue.Flink;
+ p != &Address->SendDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if ((PTP_ADDRESS_FILE)(request->Owner) == AddressFile) {
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, p);
+ }
+
+ }
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = pFlink ) {
+
+ pFlink = p->Flink;
+ RemoveEntryList (p);
+ InitializeListHead (p);
+ InsertTailList (&localList, 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;
+ AddressFile->Irp = NULL;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ irp->IoStatus.Information = 0;
+ irp->IoStatus.Status = STATUS_DUPLICATE_NAME;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+ }
+
+ //
+ // cancel all the datagrams on this address file
+ //
+
+ while (!IsListEmpty (&localList)) {
+
+ p = RemoveHeadList (&localList);
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ StCompleteRequest (request, STATUS_NETWORK_NAME_DELETED, 0);
+
+ }
+
+
+} /* StStopAddressFile */
+
+
+NTSTATUS
+StCloseAddress(
+ 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;
+ 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->ShareAccess);
+ ExReleaseResource (&addressFile->Provider->AddressResource);
+
+
+ StStopAddressFile (addressFile, address);
+ StDereferenceAddressFile (addressFile);
+
+ //
+ // This removes a reference added by our caller.
+ //
+
+ StDereferenceAddress ("IRP_MJ_CLOSE", address);
+
+ return STATUS_PENDING;
+
+} /* StCloseAddress */
+
+
+NTSTATUS
+StSendDatagramsOnAddress(
+ 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 StSendUIMdlFrame to actually do the work. When StSendUIMdlFrame
+ 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.
+
+Arguments:
+
+ Address - a pointer to the address object to send the datagram on.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY p;
+ PTP_REQUEST request;
+ PTA_NETBIOS_ADDRESS remoteTA;
+ PIO_STACK_LOCATION irpSp;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PST_HEADER StHeader;
+ PSEND_PACKET_TAG SendTag;
+
+ DeviceContext = Address->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ StReferenceAddress ("Send datagram", Address); // keep it around
+
+ 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);
+ StDereferenceAddress ("Queue empty", Address);
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Mark the address's send datagram queue as held so that the
+ // MDL and ST 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);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ //
+ // 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 (request->IoRequestPacket);
+
+ remoteTA = ((PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters))->
+ SendDatagramInformation->RemoteAddress;
+
+ //
+ // Build the MAC header. DATAGRAM frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Address->Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER) + request->Buffer2Length,
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+ //
+ // Build the header: 'G', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Address->Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_DATAGRAM;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Source, Address->NetworkName->NetbiosName, 16);
+
+ if (remoteTA->Address[0].AddressLength == 0) {
+
+ //
+ // A broadcast datagram
+ //
+
+ RtlZeroMemory (StHeader->Destination, 16);
+ StHeader->Flags |= ST_FLAGS_BROADCAST;
+
+ } else {
+
+ RtlCopyMemory (StHeader->Destination, remoteTA->Address[0].Address[0].NetbiosName, 16);
+
+ }
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ SendTag = (PSEND_PACKET_TAG)(Address->Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_G_FRAME;
+ SendTag->Packet = Address->Packet;
+ SendTag->Owner = (PVOID)Address;
+
+ //
+ // Update our statistics for this datagram.
+ //
+
+ ++DeviceContext->DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->DatagramBytesSent,
+ request->Buffer2Length);
+
+
+ //
+ // Munge the packet length, append the data, and send it.
+ //
+
+ StSetNdisPacketLength(Address->Packet->NdisPacket, HeaderLength);
+
+ if (request->Buffer2) {
+ NdisChainBufferAtBack (Address->Packet->NdisPacket, (PNDIS_BUFFER)request->Buffer2);
+ }
+
+ (VOID)StSendAddressFrame (
+ Address);
+
+
+ //
+ // The hold will be released in the I/O completion handler.
+ // 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);
+ }
+
+ StDereferenceAddress ("Sent datagram", Address); // all done
+
+ return STATUS_SUCCESS;
+
+} /* StSendDatagramsOnAddress */
diff --git a/private/ntos/tdi/st/connect.c b/private/ntos/tdi/st/connect.c
new file mode 100644
index 000000000..8cb05b03b
--- /dev/null
+++ b/private/ntos/tdi/st/connect.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1989-1993 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
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiAccept(
+ 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;
+
+ //
+ // Get the connection this is associated with; if there is none, get out.
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // This adds a connection reference if successful.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // just set the connection flags to allow reads and writes to proceed.
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // Turn off the stopping flag for this connection.
+ //
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+
+ if (connection->AddressFile->ConnectIndicationInProgress) {
+ connection->Flags2 |= CONNECTION_FLAGS2_INDICATING;
+ }
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_WAIT_ACCEPT) != 0) {
+
+ //
+ // We previously completed a listen, now the user is
+ // coming back with an accept, Set this flag to allow
+ // the connection to proceed.
+ //
+
+ connection->Flags |= CONNECTION_FLAGS_READY;
+
+ INCREMENT_COUNTER (connection->Provider, OpenConnections);
+
+ //
+ // Set this flag to enable disconnect indications; once
+ // the client has accepted he expects those.
+ //
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_WAIT_ACCEPT;
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Pended listen completed", connection);
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } 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.
+ //
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ }
+
+ StDereferenceConnection ("Temp TdiAccept", connection);
+
+ return STATUS_SUCCESS;
+
+} /* StTdiAccept */
+
+
+NTSTATUS
+StTdiAssociateAddress(
+ 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;
+
+ 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 = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ //
+ // Make sure this connection is ready to be associated.
+ //
+
+ oldAddress = (PTP_ADDRESS)NULL;
+
+ ACQUIRE_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_SPIN_LOCK (&connection->SpinLock, oldirql2);
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ 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) {
+
+ //
+ // 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_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ //
+ // If we removed an old association, dereference the
+ // address.
+ //
+
+ if (oldAddress != (PTP_ADDRESS)NULL) {
+
+ StDereferenceAddress("Removed old association", oldAddress);
+
+ }
+
+
+ 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 (NT_SUCCESS (StVerifyAddressObject (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) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql2);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ StReferenceAddress (
+ "Connection associated",
+ addressFile->Address);
+
+ InsertTailList (
+ &addressFile->Address->ConnectionDatabase,
+ &connection->AddressList);
+
+ 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_SPIN_LOCK (&connection->SpinLock, oldirql2);
+
+ } else {
+
+ status = STATUS_INVALID_HANDLE;
+ }
+
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ StDereferenceAddress ("Temp associate", addressFile->Address);
+
+ } 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;
+ }
+
+ StDereferenceConnection ("Temp Ref Associate", connection);
+
+ return status;
+
+} /* TdiAssociateAddress */
+
+
+NTSTATUS
+StTdiDisassociateAddress(
+ 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;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // 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_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ if ((connection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) &&
+ ((connection->Flags2 & CONNECTION_FLAGS2_DISASSOCIATED) == 0)) {
+ connection->Flags2 |= CONNECTION_FLAGS2_DISASSOCIATED;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ StDereferenceConnection ("Temp use in Associate", connection);
+
+ return STATUS_SUCCESS;
+
+} /* TdiDisassociateAddress */
+
+
+NTSTATUS
+StTdiConnect(
+ 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;
+ PSTRING GeneralBroadcastSourceRoute = NULL; // BUGBUG: define this later.
+ LARGE_INTEGER timeout = {0,0};
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST tpRequest;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL parameters;
+ PTA_NETBIOS_ADDRESS RemoteAddress;
+ ULONG RemoteAddressLength;
+
+ //
+ // is the file object a connection?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ 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)) {
+
+ 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;
+ }
+ }
+
+ //
+ // Check that the remote is a Netbios address.
+ //
+
+ RemoteAddress = (PTA_NETBIOS_ADDRESS)
+ (parameters->RequestConnectionInformation->RemoteAddress);
+
+ if (RemoteAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_NETBIOS) {
+
+ StDereferenceConnection ("Not Netbios", connection);
+ return STATUS_BAD_NETWORK_PATH; // don't even try to find it.
+
+ }
+
+ //
+ // copy the called address someplace we can use it.
+ //
+
+ RemoteAddressLength = parameters->RequestConnectionInformation->RemoteAddressLength;
+
+ if (RemoteAddressLength > sizeof(TA_NETBIOS_ADDRESS)) {
+ RemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
+ }
+
+ RtlCopyMemory(
+ connection->CalledAddress.NetbiosName,
+ RemoteAddress->Address[0].Address[0].NetbiosName,
+ 16);
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ 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.
+ StDereferenceConnection ("Throw away", connection);
+ return status; // return with failure.
+ } else {
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ StReferenceConnection("For connect request", connection);
+
+ tpRequest->Owner = ConnectionType;
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock (cancelirql);
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temporary Use 1", connection);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+
+ connection->Flags |= CONNECTION_FLAGS_CONNECTOR; // we're the initiator.
+
+ connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ connection->Status = STATUS_PENDING;
+
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+ }
+
+ status = StSendConnect (
+ connection);
+
+ if (!NT_SUCCESS(status)) { // can't send the name request
+ StStopConnection (connection, status);
+ StDereferenceConnection("Temporary Use 2", connection);
+
+ //
+ // Note that this return status isn't really a lie. We are waiting
+ // for the connection to run down.
+ //
+
+ return STATUS_PENDING;
+ }
+
+
+ StDereferenceConnection("Temporary Use 3", connection);
+
+ return STATUS_PENDING; // things are started.
+
+} /* TdiConnect */
+
+
+NTSTATUS
+StTdiDisconnect(
+ 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;
+
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ //
+ // if the connection is currently stopping, there's no reason to blow
+ // it away...
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection ("Ignoring disconnect", connection); // release our lookup reference.
+ return connection->Status;
+
+ } else {
+ connection->Flags2 &= ~ (CONNECTION_FLAGS2_ACCEPTED |
+ CONNECTION_FLAGS2_PRE_ACCEPT |
+ CONNECTION_FLAGS2_WAIT_ACCEPT);
+ connection->Flags2 |= CONNECTION_FLAGS2_DISCONNECT;
+
+ //
+ // Set this flag so the disconnect IRP is completed.
+ //
+ // BUGBUG: If the connection goes down before we can
+ // call StStopConnection with STATUS_LOCAL_DISCONNECT,
+ // the disconnect IRP won't get completed.
+ //
+
+ connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ connection->DisconnectIrp = Irp;
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+ //
+ // 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)) {
+
+ 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->Flags |= CONNECTION_FLAGS_DESTROY;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_ABORT) {
+ connection->Flags |= CONNECTION_FLAGS_ABORT;
+ } else if ((ULONG)(parameters->RequestFlags) & (ULONG)TDI_DISCONNECT_WAIT) {
+ connection->Flags |= CONNECTION_FLAGS_ORDREL;
+ }
+
+ //
+ // This will get passed to IoCompleteRequest during TdiDestroyConnection
+ //
+
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT); // starts the abort sequence.
+ StDereferenceConnection ("Disconnecting", connection); // release our lookup reference.
+
+ //
+ // This request will be completed by TdiDestroyConnection once
+ // the connection reference count drops to 0.
+ //
+
+ return STATUS_PENDING;
+} /* TdiDisconnect */
+
+
+NTSTATUS
+StTdiListen(
+ 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;
+
+ //
+ // validate this connection
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ connection = irpSp->FileObject->FsContext;
+
+ //
+ // If successful this adds a reference.
+ //
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ parameters = (PTDI_REQUEST_KERNEL_LISTEN)&irpSp->Parameters;
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the new connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ NULL,
+ 0,
+ timeout, // timeout value (can be 0).
+ &tpRequest);
+
+
+ if (!NT_SUCCESS (status)) { // couldn't make the request.
+
+ StDereferenceConnection ("For create", connection);
+ return status; // return with failure.
+ }
+
+ // Reference the connection since StDestroyRequest derefs it.
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ tpRequest->Owner = ConnectionType;
+
+ StReferenceConnection("For listen request", connection);
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ StDereferenceConnection("Temp create", connection);
+ return STATUS_PENDING;
+
+ } else {
+
+ InsertTailList (&connection->InProgressRequest,&tpRequest->Linkage);
+ connection->Flags |= CONNECTION_FLAGS_LISTENER | // we're the passive one.
+ CONNECTION_FLAGS_WAIT_LISTEN; // waiting for a connect
+ connection->Flags2 &= ~CONNECTION_FLAGS2_INDICATING;
+ connection->Flags &= ~CONNECTION_FLAGS_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_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // Check if the IRP has been cancelled.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelConnection((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelConnection;
+ 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.
+ //
+
+ StDereferenceConnection("Temp create", connection);
+
+ return STATUS_PENDING; // things are started.
+} /* TdiListen */
+
+
+NTSTATUS
+StOpenConnection (
+ 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);
+
+ 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 StCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ status = StCreateConnection (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;
+
+ return status;
+
+} /* StOpenConnection */
+
+
+NTSTATUS
+StCloseConnection (
+ 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);
+
+ //
+ // is the file object a connection?
+ //
+
+ connection = IrpSp->FileObject->FsContext;
+
+
+ //
+ // 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 == ST_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // We recognize it; is it closing already?
+ //
+
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+
+ if ((connection->Flags2 & CONNECTION_FLAGS2_CLOSING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StDereferenceConnection("Temp Close", connection);
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ connection->Flags2 |= CONNECTION_FLAGS2_CLOSING;
+
+ //
+ // if there is activity on the connection, tear it down.
+ //
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) == 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ StStopConnection (connection, STATUS_LOCAL_DISCONNECT);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock, &oldirql);
+ }
+
+ //
+ // 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_SPIN_LOCK (&connection->SpinLock, oldirql);
+ } else {
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ }
+
+
+ //
+ // Save this to complete the IRP later.
+ //
+
+ connection->CloseIrp = Irp;
+
+ //
+ // make it impossible to use this connection from the file object
+ //
+
+ IrpSp->FileObject->FsContext = NULL;
+ IrpSp->FileObject->FsContext2 = NULL;
+ connection->FileObject = NULL;
+
+ //
+ // dereference for the creation. Note that this dereference
+ // here won't have any effect until the regular reference count
+ // hits zero.
+ //
+
+ StDereferenceConnectionSpecial (" Closing Connection", connection);
+
+ return STATUS_PENDING;
+
+} /* StCloseConnection */
+
diff --git a/private/ntos/tdi/st/connobj.c b/private/ntos/tdi/st/connobj.c
new file mode 100644
index 000000000..27c28665a
--- /dev/null
+++ b/private/ntos/tdi/st/connobj.c
@@ -0,0 +1,1375 @@
+/*++
+
+Copyright (c) 1989-1993 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.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+VOID
+StAllocateConnection(
+ 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("ST: Could not allocate connection: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 103);
+ *TransportConnection = NULL;
+ return;
+ }
+
+ Connection = (PTP_CONNECTION)ExAllocatePool (NonPagedPool,
+ sizeof (TP_CONNECTION));
+ if (Connection == NULL) {
+ PANIC("ST: Could not allocate connection: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 203);
+ *TransportConnection = NULL;
+ return;
+ }
+ RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
+
+ DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
+ ++DeviceContext->ConnectionAllocated;
+
+ Connection->Type = ST_CONNECTION_SIGNATURE;
+ Connection->Size = sizeof (TP_CONNECTION);
+
+ Connection->Provider = DeviceContext;
+ Connection->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Connection->SpinLock);
+
+ InitializeListHead (&Connection->LinkList);
+ InitializeListHead (&Connection->AddressFileList);
+ InitializeListHead (&Connection->AddressList);
+ InitializeListHead (&Connection->PacketWaitLinkage);
+ InitializeListHead (&Connection->PacketizeLinkage);
+ InitializeListHead (&Connection->SendQueue);
+ InitializeListHead (&Connection->ReceiveQueue);
+ InitializeListHead (&Connection->InProgressRequest);
+
+ StAddSendPacket (DeviceContext);
+
+ *TransportConnection = Connection;
+
+} /* StAllocateConnection */
+
+
+VOID
+StDeallocateConnection(
+ 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);
+
+ StRemoveSendPacket (DeviceContext);
+
+} /* StDeallocateConnection */
+
+
+NTSTATUS
+StCreateConnection(
+ 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;
+ UINT TempDataLen;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ if (p == &DeviceContext->ConnectionPool) {
+
+ if ((DeviceContext->ConnectionMaxAllocated == 0) ||
+ (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
+
+ StAllocateConnection (DeviceContext, &Connection);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 403);
+ Connection = NULL;
+
+ }
+
+ if (Connection == NULL) {
+ ++DeviceContext->ConnectionExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: Could not allocate connection object!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ }
+
+ ++DeviceContext->ConnectionInUse;
+ if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
+ ++DeviceContext->ConnectionMaxInUse;
+ }
+
+ DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
+ ++DeviceContext->ConnectionSamples;
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+
+ //
+ // 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
+
+ //
+ // 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->MessageBytesReceived = (USHORT)0; // no data yet
+ Connection->MessageBytesAcked = (USHORT)0;
+ Connection->Context = NULL; // no context yet.
+ Connection->Status = STATUS_PENDING; // default StStopConnection status.
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
+ Connection->DisconnectIrp = (PIRP)NULL;
+ Connection->CloseIrp = (PIRP)NULL;
+ Connection->AddressFile = NULL;
+ Connection->IndicationInProgress = FALSE;
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ NULL,
+ 0,
+ DeviceContext->MaxSendPacketSize,
+ &TempDataLen);
+ Connection->MaximumDataSize = TempDataLen - sizeof(ST_HEADER);
+
+ StReferenceDeviceContext ("Create Connection", DeviceContext);
+
+ *TransportConnection = Connection; // return the connection.
+
+ return STATUS_SUCCESS;
+} /* StCreateConnection */
+
+
+NTSTATUS
+StVerifyConnectionObject (
+ 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->Size == sizeof (TP_CONNECTION)) &&
+ (Connection->Type == ST_CONNECTION_SIGNATURE)) {
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
+
+ StReferenceConnection ("Verify Temp Use", Connection);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ } else {
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+}
+
+
+NTSTATUS
+StDestroyAssociation(
+ 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 StDereferenceConnection. 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;
+
+
+ ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
+ if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ return STATUS_SUCCESS;
+ } else {
+ TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ }
+
+ 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);
+ ACQUIRE_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_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
+ RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
+
+ //
+ // and remove a reference to the address
+ //
+
+ StDereferenceAddress ("Destroy association", addressFile->Address);
+
+
+ return STATUS_SUCCESS;
+
+} /* StDestroyAssociation */
+
+
+NTSTATUS
+StIndicateDisconnect(
+ 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 StDereferenceConnection. 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;
+
+ ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
+
+ if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
+
+ //
+ // Turn off all but the still-relevant bits in the flags.
+ //
+
+ ASSERT (TransportConnection->Flags & CONNECTION_FLAGS_STOPPING);
+
+ TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
+ TransportConnection->Flags2 &=
+ (CONNECTION_FLAGS2_ASSOCIATED |
+ CONNECTION_FLAGS2_DISASSOCIATED |
+ CONNECTION_FLAGS2_CLOSING);
+
+ //
+ // 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->MessageBytesReceived = (USHORT)0; // no data yet
+ TransportConnection->MessageBytesAcked = (USHORT)0;
+
+ TransportConnection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
+
+ DisconnectIrp = TransportConnection->DisconnectIrp;
+ TransportConnection->DisconnectIrp = (PIRP)NULL;
+
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+
+ DeviceContext = TransportConnection->Provider;
+ addressFile = TransportConnection->AddressFile;
+
+
+ //
+ // 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) {
+
+ //
+ // 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->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
+ // StStopConnection, where we know addressFile is valid).
+ //
+
+ //
+ // 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.
+ //
+
+ //
+ // 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->Flags & CONNECTION_FLAGS_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (TransportConnection->Flags & CONNECTION_FLAGS_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ (*addressFile->DisconnectHandler)(
+ addressFile->DisconnectHandlerContext,
+ TransportConnection->Context,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ DisconnectReason);
+
+ }
+
+ } else {
+
+ //
+ // The client does not yet think that this connection
+ // is up...generally this happens due to request count
+ // fluctuation during connection setup.
+ //
+
+ RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* StIndicateDisconnect */
+
+
+NTSTATUS
+StDestroyConnection(
+ 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 StDereferenceConnection. 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;
+
+
+ DeviceContext = TransportConnection->Provider;
+
+ //
+ // Destroy any association that this connection has.
+ //
+
+ StDestroyAssociation (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.
+ //
+
+ TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
+ TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
+ TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet
+ TransportConnection->MessageBytesAcked = (USHORT)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);
+
+ }
+
+ //
+ // 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) {
+ StDeallocateConnection (DeviceContext, TransportConnection);
+ } else {
+ InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ StDereferenceDeviceContext ("Destroy Connection", DeviceContext);
+
+ return STATUS_SUCCESS;
+
+} /* StDestroyConnection */
+
+
+VOID
+StRefConnection(
+ 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;
+
+ 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);
+
+ }
+
+ ASSERT (result >= 0);
+
+} /* StRefConnection */
+
+
+VOID
+StDerefConnection(
+ 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
+ StDestroyConnection to remove it from the system.
+
+Arguments:
+
+ TransportConnection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ 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 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.
+ //
+
+ StIndicateDisconnect (TransportConnection);
+
+ //
+ // Now it is OK to let the connection go away.
+ //
+
+ StDereferenceConnectionSpecial ("Regular ref gone", TransportConnection);
+
+ }
+
+} /* StDerefConnection */
+
+
+VOID
+StDerefConnectionSpecial(
+ 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;
+
+ 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.
+ //
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ StDestroyConnection (TransportConnection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
+
+ }
+
+} /* StDerefConnectionSpecial */
+
+
+PTP_CONNECTION
+StFindConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR LocalName,
+ IN PUCHAR RemoteName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connections associated with a
+ device context, and determines if there is an connection
+ associated with the specific remote address on the
+ specific local address.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ LocalName - The 16-character Netbios name of the local address.
+
+ RemoteName - The 16-character Netbios name of the remote.
+
+Return Value:
+
+ The connection if one is found, NULL otherwise.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PLIST_ENTRY Flink;
+ PTP_ADDRESS Address;
+ BOOLEAN MatchedAddress = FALSE;
+ PTP_CONNECTION Connection;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (Flink = DeviceContext->AddressDatabase.Flink;
+ Flink != &DeviceContext->AddressDatabase;
+ Flink = Flink->Flink) {
+
+ Address = CONTAINING_RECORD (
+ Flink,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ if (StMatchNetbiosAddress (Address, LocalName)) {
+
+ StReferenceAddress ("Looking for connection", Address); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (!MatchedAddress) {
+ return NULL;
+ }
+
+ Connection = StLookupRemoteName (Address, RemoteName);
+
+ StDereferenceAddress ("Looking for connection", Address);
+
+ return Connection;
+
+}
+
+
+PTP_CONNECTION
+StLookupConnectionByContext(
+ 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;
+ PTP_CONNECTION Connection;
+
+ //
+ // 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);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if ((Connection->Context == ConnectionContext) &&
+ ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0)) {
+ // This reference is removed by the calling function
+ StReferenceConnection ("Lookup up for request", Connection);
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return Connection;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* StLookupConnectionByContext */
+
+
+PTP_CONNECTION
+StLookupListeningConnection(
+ IN PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the connection database on an address to find
+ a TP_CONNECTION object which has 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.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+
+
+ 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->Flags & CONNECTION_FLAGS_WAIT_LISTEN) {
+
+ // This reference is removed by the calling function
+ StReferenceConnection ("Found Listening", Connection);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags &= ~CONNECTION_FLAGS_WAIT_LISTEN;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return Connection;
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return NULL;
+
+} /* StLookupListeningConnection */
+
+
+VOID
+StStopConnection(
+ 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.
+
+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 oldirql, oldirql1, cancelirql;
+ PLIST_ENTRY p;
+ PIRP Irp;
+ PTP_REQUEST Request;
+ ULONG DisconnectReason;
+ PULONG StopCounter;
+ PDEVICE_CONTEXT DeviceContext;
+ BOOLEAN WasConnected;
+
+
+ DeviceContext = Connection->Provider;
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
+
+ //
+ // We are stopping the connection, record statistics
+ // about it.
+ //
+
+ if (Connection->Flags & CONNECTION_FLAGS_READY) {
+
+ DECREMENT_COUNTER (DeviceContext, OpenConnections);
+ WasConnected = TRUE;
+
+ } else {
+
+ WasConnected = FALSE;
+
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_READY; // no longer open for business
+ Connection->Flags |= CONNECTION_FLAGS_STOPPING;
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->Status = Status;
+
+ //
+ // 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->Flags & CONNECTION_FLAGS_SUSPENDED) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ RemoveEntryList (&Connection->PacketWaitLinkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+ }
+
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+
+ //
+ // Run down all TdiSend requests on this connection.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->SendQueue);
+ if (p == &Connection->SendQueue) {
+ break;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteSendIrp (Irp, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+ //
+ // 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;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (Request, Connection->Status, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+
+ //
+ // NOTE: We hold the connection spinlock AND the
+ // cancel spinlock here.
+ //
+
+ //
+ // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
+ //
+
+ while (TRUE) {
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+ break;
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StCompleteRequest (Request, Connection->Status, 0);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ 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.
+ //
+
+ DisconnectReason = 0;
+ if (Connection->Flags & CONNECTION_FLAGS_ABORT) {
+ DisconnectReason |= TDI_DISCONNECT_ABORT;
+ }
+ if (Connection->Flags & CONNECTION_FLAGS_DESTROY) {
+ DisconnectReason |= TDI_DISCONNECT_RELEASE;
+ }
+
+ //
+ // When this completes we will dereference the connection.
+ //
+
+ if (WasConnected) {
+ StSendDisconnect (Connection);
+ }
+
+
+ switch (Status) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ StopCounter = &DeviceContext->LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ StopCounter = &DeviceContext->RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ StopCounter = &DeviceContext->LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ StopCounter = &DeviceContext->SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ StopCounter = &DeviceContext->CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ StopCounter = &DeviceContext->RemoteResourceFailures;
+ break;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ StopCounter = &DeviceContext->LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ StopCounter = &DeviceContext->NotFoundFailures;
+ break;
+ case STATUS_REMOTE_NOT_LISTENING:
+ StopCounter = &DeviceContext->NoListenFailures;
+ break;
+
+ default:
+ StopCounter = NULL;
+ break;
+
+ }
+
+ if (StopCounter != NULL) {
+
+ *StopCounter = *StopCounter + 1;
+
+ }
+
+
+ //
+ // Note that we've blocked all new requests being queued during the
+ // time we have been in this teardown code; StDestroyConnection 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.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ }
+
+} /* StStopConnection */
+
+
+VOID
+StCancelConnection(
+ 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;
+
+ 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_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ StReferenceConnection ("Cancelling Send", Connection);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ ASSERT (p != &Connection->InProgressRequest);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ ASSERT (Request->IoRequestPacket == Irp);
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+
+ IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+ StCompleteRequest (Request, STATUS_CANCELLED, 0);
+ StStopConnection (Connection, STATUS_CANCELLED);
+
+ StDereferenceConnection ("Cancel done", Connection);
+
+}
+
diff --git a/private/ntos/tdi/st/devctx.c b/private/ntos/tdi/st/devctx.c
new file mode 100644
index 000000000..94cc2f385
--- /dev/null
+++ b/private/ntos/tdi/st/devctx.c
@@ -0,0 +1,256 @@
+/*++
+
+Copyright (c) 1989-1993 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.
+
+ 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.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+VOID
+StRefDeviceContext(
+ 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.
+
+--*/
+
+{
+ ASSERT (DeviceContext->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&DeviceContext->ReferenceCount);
+
+} /* StRefDeviceContext */
+
+
+VOID
+StDerefDeviceContext(
+ 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;
+
+ result = InterlockedDecrement (&DeviceContext->ReferenceCount);
+
+ ASSERT (result >= 0);
+
+ if (result == 0) {
+ StDestroyDeviceContext (DeviceContext);
+ }
+
+} /* StDerefDeviceContext */
+
+
+
+NTSTATUS
+StCreateDeviceContext(
+ 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 the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors).
+ //
+
+ 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 the reference count.
+ //
+
+ deviceContext->ReferenceCount = 1;
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ KeInitializeSpinLock (&deviceContext->Interlock);
+ KeInitializeSpinLock (&deviceContext->SpinLock);
+
+ deviceContext->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&deviceContext->ConnectionPool);
+ InitializeListHead (&deviceContext->AddressPool);
+ InitializeListHead (&deviceContext->AddressFilePool);
+ InitializeListHead (&deviceContext->AddressDatabase);
+ InitializeListHead (&deviceContext->PacketWaitQueue);
+ InitializeListHead (&deviceContext->PacketizeQueue);
+ InitializeListHead (&deviceContext->RequestPool);
+ deviceContext->PacketPool.Next = NULL;
+ deviceContext->ReceivePacketPool.Next = NULL;
+ deviceContext->ReceiveBufferPool.Next = NULL;
+ InitializeListHead (&deviceContext->ReceiveInProgress);
+ InitializeListHead (&deviceContext->IrpCompletionQueue);
+
+
+ deviceContext->State = DEVICECONTEXT_STATE_CLOSED;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&deviceContext->AddressResource);
+
+ //
+ // 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->MulticastAddress.Address [i] = 0;
+ }
+
+ deviceContext->Type = ST_DEVICE_CONTEXT_SIGNATURE;
+ deviceContext->Size - sizeof (DEVICE_CONTEXT);
+
+ *DeviceContext = deviceContext;
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+StDestroyDeviceContext(
+ 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/st/event.c b/private/ntos/tdi/st/event.c
new file mode 100644
index 000000000..9c98c9596
--- /dev/null
+++ b/private/ntos/tdi/st/event.c
@@ -0,0 +1,185 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiSetEventHandler(
+ 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 = StVerifyAddressObject (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);
+
+ StDereferenceAddress ("Set event handler", address);
+
+ return rc;
+} /* TdiSetEventHandler */
diff --git a/private/ntos/tdi/st/framesnd.c b/private/ntos/tdi/st/framesnd.c
new file mode 100644
index 000000000..0d9f5cff7
--- /dev/null
+++ b/private/ntos/tdi/st/framesnd.c
@@ -0,0 +1,371 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ framesnd.c
+
+Abstract:
+
+ This module contains routines which build and send Sample transport
+ frames for other modules.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NTSTATUS
+StSendConnect(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a CONNECT frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PSEND_PACKET_TAG SendTag;
+ PTP_PACKET Packet;
+ PST_HEADER StHeader;
+
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ Status = StCreatePacket (DeviceContext, &Packet);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_C_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)Connection;
+
+ //
+ // Build the MAC header.
+ //
+
+ //
+ // CONNECT frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the header: 'C', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_CONNECT;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StNdisSend (Packet);
+
+ return STATUS_SUCCESS;
+} /* StSendConnect */
+
+
+NTSTATUS
+StSendDisconnect(
+ IN PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a DISCONNECT frame of the appropriate type given the
+ state of the specified connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE_CONTEXT DeviceContext;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ UINT HeaderLength;
+ PSEND_PACKET_TAG SendTag;
+ PTP_PACKET Packet;
+ PST_HEADER StHeader;
+
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ Status = StCreatePacket (DeviceContext, &Packet);
+ if (!NT_SUCCESS (Status)) { // couldn't make frame.
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_D_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)Connection;
+
+ //
+ // Build the MAC header.
+ //
+
+ //
+ // CONNECT frames go out as
+ // single-route source routing.
+ //
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+
+ //
+ // Build the header: 'D', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_DISCONNECT;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StNdisSend (Packet);
+
+ return STATUS_SUCCESS;
+
+} /* StSendDisconnect */
+
+
+NTSTATUS
+StSendAddressFrame(
+ PTP_ADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ 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
+ frames are sequenced through the address they are sent on.
+
+Arguments:
+
+ Address - pointer to the address from which to send this datagram.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+
+ //
+ // Send the packet.
+ //
+
+ DeviceContext = Address->Provider;
+
+ INCREMENT_COUNTER (DeviceContext, PacketsSent);
+
+ StNdisSend (Address->Packet);
+
+ return STATUS_PENDING;
+} /* StSendAddressFrame */
+
+
+VOID
+StSendDatagramCompletion(
+ 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
+ StSendUIMdlFrame send request is completed. Because this handler is only
+ associated with StSendUIMdlFrame, and because StSendUIMdlFrame 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.
+
+--*/
+
+{
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ PNDIS_BUFFER HeaderBuffer;
+
+ UNREFERENCED_PARAMETER(NdisPacket);
+
+ StReferenceAddress ("Complete datagram", Address);
+
+ //
+ // 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.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ p = RemoveHeadList (&Address->SendDatagramQueue);
+
+ if (p != &Address->SendDatagramQueue) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Address->Packet->NdisPacket, &HeaderBuffer);
+
+ // drop the rest of the packet
+
+ NdisReinitializePacket (Address->Packet->NdisPacket);
+
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+ NdisChainBufferAtFront (Address->Packet->NdisPacket, HeaderBuffer);
+
+ //
+ // Ignore NdisStatus; datagrams always "succeed".
+ //
+
+ StCompleteRequest (Request, STATUS_SUCCESS, Request->Buffer2Length);
+
+ 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.
+ //
+
+ StSendDatagramsOnAddress (Address); // do more datagrams.
+
+ } else {
+
+ Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS;
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ }
+
+ StDereferenceAddress ("Complete datagram", Address);
+
+} /* StSendDatagramCompletion */
diff --git a/private/ntos/tdi/st/iframes.c b/private/ntos/tdi/st/iframes.c
new file mode 100644
index 000000000..59b171c92
--- /dev/null
+++ b/private/ntos/tdi/st/iframes.c
@@ -0,0 +1,808 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ iframes.c
+
+Abstract:
+
+ This module contains routines called to handle i-frames received
+ from the NDIS driver. Most of these routines are called at receive
+ indication time.
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+#if 27
+ULONG StNoisyReceives = 0;
+ULONG StRcvLoc = 0;
+ULONG StRcvs[10];
+#endif
+
+
+
+NTSTATUS
+StProcessIIndicate(
+ IN PTP_CONNECTION Connection,
+ IN PST_HEADER StHeader,
+ IN UINT StIndicatedLength,
+ IN UINT StTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last
+ )
+
+/*++
+
+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.
+
+Arguments:
+
+ Connection - The connection that the data is destined for.
+
+ StHeader - A pointer to the start of the ST header in the packet.
+
+ StIndicatedLength - The length of the packet indicated, starting at
+ StHeader.
+
+ StTotalLength - The total length of the packet, starting at StHeader.
+
+ ReceiveContext - A magic value for NDIS that indicates which packet we're
+ talking about, used for calling TransferData
+
+ Last - TRUE if this is the last packet in a send.
+
+Return Value:
+
+ STATUS_SUCCESS if we've consumed the packet, but
+ STATUS_MORE_PROCESSING_REQUIRED if we did so and also
+ activated a receive; this tells the caller not to
+ remove the connection refcount.
+
+--*/
+
+{
+ KIRQL oldirql;
+ NTSTATUS status, tmpstatus;
+ KIRQL cancelirql;
+ 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 ndisBytesTransferred;
+ PUCHAR DataHeader;
+ ULONG DataTotalLength;
+ ULONG DataIndicatedLength;
+ UINT BytesToTransfer;
+ ULONG bytesIndicated;
+ PRECEIVE_PACKET_TAG receiveTag;
+ PTP_ADDRESS address;
+ PTP_ADDRESS_FILE addressFile;
+ PMDL SavedCurrentMdl;
+ ULONG SavedCurrentByteOffset;
+ LARGE_INTEGER time;
+ ULONG DumpData[2];
+ BOOLEAN CancelSpinLockHeld = FALSE;
+#if 27
+ if (StNoisyReceives) {
+ DbgPrint ("Indicate %d, Total %d\n", StIndicatedLength, StTotalLength);
+ }
+ if (StTotalLength > 1000) {
+ StRcvs[StRcvLoc] = StTotalLength;
+ StRcvLoc = (StRcvLoc + 1) % 10;
+ }
+#endif
+
+
+ //
+ // copy this packet into our receive buffer.
+ //
+
+ deviceContext = Connection->Provider;
+ addressFile = Connection->AddressFile;
+ address = addressFile->Address;
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // If we have a previous receive that is pending
+ // completion, then we need to ignore this frame.
+ // This may be common on MP.
+ //
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+ }
+
+ DataHeader = (PUCHAR)StHeader + sizeof(ST_HEADER);
+ DataTotalLength = StTotalLength - sizeof(ST_HEADER);
+ DataIndicatedLength = StIndicatedLength - sizeof(ST_HEADER);
+
+ //
+ // 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) {
+
+ //
+ // 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->CurrentReceiveRequest =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ TP_REQUEST, Linkage);
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveRequest->Buffer2;
+ Connection->ReceiveLength =
+ Connection->CurrentReceiveRequest->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ status = STATUS_SUCCESS;
+ goto NormalReceive;
+ }
+
+ //
+ // A receive is not active. Post a receive event.
+ //
+
+ if (!addressFile->RegisteredReceiveHandler) {
+
+ //
+ // 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.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+ }
+
+ if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ return STATUS_SUCCESS;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ //
+ // Indicate to the user. For BytesAvailable we
+ // always use DataTotalLength; for BytesIndicated we use
+ // MIN (DataIndicatedLength, 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 DataIndicatedLength
+ // will be shorter.
+ //
+
+ bytesIndicated = DataIndicatedLength;
+ if (DataTotalLength < bytesIndicated) {
+ bytesIndicated = DataTotalLength;
+ }
+
+ status = (*addressFile->ReceiveHandler)(
+ addressFile->ReceiveHandlerContext,
+ Connection->Context,
+ deviceContext->MacInfo.CopyLookahead ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0, // ReceiveFlags
+ bytesIndicated,
+ DataTotalLength, // BytesAvailable
+ &indicateBytesTransferred,
+ DataHeader,
+ &irp);
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // The client has accepted some or all of the indicated data in
+ // the event handler. Update MessageBytesReceived variable in
+ // the Connection.
+ //
+
+ Connection->MessageBytesReceived += indicateBytesTransferred;
+ Connection->IndicationInProgress = FALSE;
+
+ return STATUS_SUCCESS;
+
+ } else if (status == STATUS_DATA_NOT_ACCEPTED) {
+
+ //
+ // 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_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ 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.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // 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->CurrentReceiveRequest =
+ CONTAINING_RECORD (Connection->ReceiveQueue.Flink,
+ TP_REQUEST, Linkage);
+ Connection->CurrentReceiveMdl =
+ Connection->CurrentReceiveRequest->Buffer2;
+ Connection->ReceiveLength =
+ Connection->CurrentReceiveRequest->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ }
+
+ } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ PTP_REQUEST SpecialIrpRequest;
+ ULONG SpecialIrpLength;
+
+ //
+ // 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.
+ //
+
+ //
+ // 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);
+
+ SpecialIrpLength =
+ ((PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters)->ReceiveLength;
+
+ //
+ // The normal path, for longer receives.
+ //
+
+ time.HighPart = 0;
+ time.LowPart = 0;
+
+ status = StCreateRequest (
+ irp,
+ Connection,
+ REQUEST_FLAGS_CONNECTION | REQUEST_FLAGS_SEND_RCV,
+ irp->MdlAddress,
+ ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength,
+ time,
+ &SpecialIrpRequest);
+
+ if (!NT_SUCCESS (status)) {
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ Connection->ReceiveByteOffset = 0;
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ Connection->IndicationInProgress = FALSE;
+
+ irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // If the Connection is stopping, abort this request.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteRequest (
+ SpecialIrpRequest,
+ Connection->Status,
+ 0);
+ return STATUS_SUCCESS; // we have consumed the packet
+
+ }
+
+ //
+ // Insert the request on the head of the connection's
+ // receive queue, so it can be handled like a normal
+ // receive.
+ //
+
+ InsertHeadList (&Connection->ReceiveQueue, &SpecialIrpRequest->Linkage);
+
+ Connection->Flags |= CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ Connection->ReceiveLength = ((PTDI_REQUEST_KERNEL_RECEIVE )&irpSp->Parameters)->ReceiveLength;
+ Connection->MessageBytesReceived = indicateBytesTransferred;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest = SpecialIrpRequest;
+ Connection->CurrentReceiveMdl = irp->MdlAddress;
+ Connection->ReceiveByteOffset = 0;
+ Connection->CurrentReceiveRequest->Owner = ConnectionType;
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (irp->Cancel) {
+
+ Connection->Flags |= CONNECTION_FLAGS_RECEIVE_WAKEUP;
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock,oldirql);
+ irp->CancelIrql = cancelirql;
+ StCancelReceive((PDEVICE_OBJECT)deviceContext, irp);
+
+ return STATUS_SUCCESS;
+
+ } else {
+
+ irp->CancelRoutine = StCancelReceive;
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ //
+ // Make a note so we know to release the cancel
+ // spinlock below.
+ //
+
+ CancelSpinLockHeld = TRUE;
+
+ }
+
+ } else {
+
+ //
+ // An unknown return code has been returned by the
+ // client's event handler. This is a client programming
+ // error. Because this can only occur when kernel-mode
+ // clients have been coded incorrectly, we should beat
+ // him with a stick. We have to do SOMETHING, or this
+ // Connection will HANG.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+ return STATUS_SUCCESS;
+
+ }
+
+ } 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);
+
+ //
+ // The status should be SUCCESS (we found an active receive)
+ // or MORE_PROCESSING_REQUIRED (we made a new receive active).
+ //
+
+ ASSERT ((status == STATUS_SUCCESS) || (status == STATUS_MORE_PROCESSING_REQUIRED));
+
+ destBytes = Connection->ReceiveLength - Connection->MessageBytesReceived;
+ StReferenceRequest ("Transfer Data", Connection->CurrentReceiveRequest);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ if (CancelSpinLockHeld) {
+ IoReleaseCancelSpinLock (cancelirql);
+ }
+
+ //
+ // 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 {
+ (VOID)InterlockedIncrement((PLONG)&deviceContext->ReceivePacketExhausted);
+
+ StDereferenceRequest ("No receive packet", Connection->CurrentReceiveRequest);
+
+ // We could not get a receive packet.
+ //
+
+ 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;
+
+
+ //
+ // Determine how much data remains to be transferred.
+ //
+
+ BytesToTransfer = DataTotalLength - indicateBytesTransferred;
+ ASSERT (BytesToTransfer >= 0);
+
+ 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.
+ //
+
+ receiveTag->EndOfMessage = FALSE;
+ receiveTag->CompleteReceive = 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.
+ //
+
+ receiveTag->EndOfMessage = Last;
+ receiveTag->CompleteReceive = TRUE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ receiveTag->EndOfMessage = Last;
+ receiveTag->CompleteReceive = Last;
+
+ }
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+ Connection->IndicationInProgress = FALSE;
+ receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ receiveTag->TransferDataPended = FALSE;
+ StTransferDataComplete (
+ 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 it. 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) &&
+ (receiveTag->CompleteReceive)) {
+
+ //
+ // 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->NdisBufferPoolHandle,
+ 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;
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ tmpstatus,
+ NULL,
+ 2,
+ DumpData);
+
+ StDereferenceRequest ("No MDL chain", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+
+ Connection->IndicationInProgress = FALSE;
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ return status;
+ }
+
+ NdisChainBufferAtFront (ndisPacket, ndisBuffer);
+
+ //
+ // 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
+ //
+
+ receiveTag->NdisStatus = NDIS_STATUS_PENDING;
+
+ //
+ // update the number of bytes received; OK to do this
+ // unprotected since IndicationInProgress is still FALSE.
+ //
+ //
+
+ Connection->MessageBytesReceived += BytesToTransfer;
+
+ //
+ // We have now updated all the connection counters (BUG,
+ // assuming the TransferData will succeed) and this
+ // packet's location in the request is secured, so we
+ // can be reentered.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ NdisTransferData (
+ &ndisStatus,
+ deviceContext->NdisBindingHandle,
+ ReceiveContext,
+ sizeof (ST_HEADER) + indicateBytesTransferred,
+ BytesToTransfer,
+ ndisPacket,
+ (PUINT)&ndisBytesTransferred);
+
+ //
+ // handle the various completion codes
+ //
+
+ switch (ndisStatus) {
+
+ case NDIS_STATUS_SUCCESS:
+
+ receiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ if (ndisBytesTransferred != BytesToTransfer) { // Did we get the entire packet?
+
+ DumpData[0] = ndisBytesTransferred;
+ DumpData[1] = BytesToTransfer;
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ ndisStatus,
+ NULL,
+ 2,
+ DumpData);
+
+ if (receiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ while (ndisBuffer != NULL) {
+ NdisFreeBuffer (ndisBuffer);
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (ndisPacket);
+ }
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ StDereferenceRequest ("Bad byte count", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+ Connection->MessageBytesReceived -= BytesToTransfer;
+
+ return status;
+ }
+
+ //
+ // deallocate the buffers and such that we've used if at indicate
+ //
+
+ receiveTag->TransferDataPended = FALSE;
+
+ StTransferDataComplete (
+ deviceContext,
+ ndisPacket,
+ ndisStatus,
+ BytesToTransfer);
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+
+ //
+ // 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".
+ //
+
+ StReferenceConnection ("TransferData pended", Connection);
+ break;
+
+ default:
+
+ //
+ // Something broke; certainly we'll never get NdisTransferData
+ // asynch completion.
+ //
+ // BUGBUG: The driver should recover from this situation.
+ //
+
+ StWriteGeneralErrorLog(
+ deviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 604,
+ ndisStatus,
+ NULL,
+ 0,
+ NULL);
+
+ if (receiveTag->AllocatedNdisBuffer) {
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ while (ndisBuffer != NULL) {
+ NdisFreeBuffer (ndisBuffer);
+ NdisUnchainBufferAtFront (ndisPacket, &ndisBuffer);
+ }
+ } else {
+ NdisReinitializePacket (ndisPacket);
+ }
+
+ ExInterlockedPushEntryList(
+ &deviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&receiveTag->Linkage,
+ &deviceContext->Interlock);
+
+ StDereferenceRequest ("TransferData failed", Connection->CurrentReceiveRequest);
+
+ //
+ // Restore our old state.
+ //
+
+ Connection->CurrentReceiveMdl = SavedCurrentMdl;
+ Connection->ReceiveByteOffset = SavedCurrentByteOffset;
+ Connection->MessageBytesReceived -= BytesToTransfer;
+
+ return status;
+ } // switch ndisStatus
+
+ return status; // which only means we've dealt with the packet
+
+} /* ProcessIIndicate */
diff --git a/private/ntos/tdi/st/ind.c b/private/ntos/tdi/st/ind.c
new file mode 100644
index 000000000..68dc3bffb
--- /dev/null
+++ b/private/ntos/tdi/st/ind.c
@@ -0,0 +1,829 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the NT Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NDIS_STATUS
+StReceiveIndication (
+ 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;
+ HARDWARE_ADDRESS SourceAddressBuffer;
+ PHARDWARE_ADDRESS SourceAddress;
+ UINT RealPacketSize;
+ PST_HEADER StHeader;
+
+ 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
+ );
+
+ if (RealPacketSize < 2) {
+ 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.
+ //
+
+ StHeader = (PST_HEADER)LookaheadBuffer;
+
+ if (StHeader->Signature != ST_SIGNATURE) {
+ return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
+ }
+
+
+ //
+ // Check that the packet is not too long.
+ //
+
+ if (PacketSize > DeviceContext->MaxReceivePacketSize) {
+#if DBG
+ StPrint2("StReceiveIndication: Ignoring packet length %d, max %d\n",
+ PacketSize, DeviceContext->MaxReceivePacketSize);
+#endif
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+ MacReturnSourceAddress(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceAddressBuffer,
+ &SourceAddress
+ );
+
+
+ return StGeneralReceiveHandler(
+ DeviceContext,
+ ReceiveContext,
+ SourceAddress,
+ HeaderBuffer, // header
+ RealPacketSize, // total data length in packet
+ (PST_HEADER)LookaheadBuffer, // lookahead data
+ LookaheadBufferSize // lookahead data length
+ );
+
+}
+
+
+NDIS_STATUS
+StGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PST_HEADER StHeader,
+ IN UINT StSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from StReceiveIndication.
+ It continues the processing of indicated data.
+
+ 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.
+
+ 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.
+
+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.
+
+--*/
+{
+
+ KIRQL oldirql;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ PSINGLE_LIST_ENTRY linkage;
+ UINT BytesTransferred;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PTP_ADDRESS DatagramAddress;
+ UINT NdisBufferLength;
+ PTP_CONNECTION Connection;
+ PVOID BufferPointer;
+
+
+ INCREMENT_COUNTER (DeviceContext, PacketsReceived);
+
+ Status = STATUS_SUCCESS; // assume no further processing required
+
+
+ //
+ // See what type of frame this is.
+ //
+
+ if ((StHeader->Command == ST_CMD_CONNECT) ||
+ (StHeader->Command == ST_CMD_DATAGRAM)) {
+
+ MacReturnSourceRouting(
+ &DeviceContext->MacInfo,
+ HeaderBuffer,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ Status = StProcessConnectionless (
+ DeviceContext,
+ SourceAddress,
+ StHeader,
+ StSize,
+ SourceRouting,
+ SourceRoutingLength,
+ &DatagramAddress);
+
+ } else if ((StHeader->Command == ST_CMD_INFORMATION) ||
+ (StHeader->Command == ST_CMD_DISCONNECT)) {
+
+ //
+ // If successful this adds a connection reference.
+ //
+
+ if (!(Connection = StFindConnection(DeviceContext, StHeader->Destination, StHeader->Source))) {
+ return NDIS_STATUS_NOT_RECOGNIZED;
+ }
+
+
+ if (StHeader->Command == ST_CMD_INFORMATION) {
+
+ Status = StProcessIIndicate (
+ Connection,
+ StHeader,
+ StSize,
+ PacketSize,
+ ReceiveContext,
+ (BOOLEAN)((StHeader->Flags & ST_FLAGS_LAST) != 0)
+ );
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ StDereferenceConnection ("Information done", Connection);
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ } else {
+
+ StStopConnection (Connection, STATUS_REMOTE_DISCONNECT);
+ StDereferenceConnection ("Disconnect done", Connection);
+ Status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ //
+ // An unrecognized frame.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // If the above routines return success, the packet has been processed
+ // and can be discarded. If they return anything else, the packet needs
+ // to be copied to local storage for handling in a more lesurely
+ // fashion.
+ //
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ linkage = ExInterlockedPopEntryList(
+ &DeviceContext->ReceivePacketPool,
+ &DeviceContext->Interlock);
+
+ if (linkage != NULL) {
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
+ } else {
+ (VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceivePacketExhausted);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+ 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,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+ (VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceiveBufferExhausted);
+
+ return NDIS_STATUS_RESOURCES;
+ }
+
+ NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
+ NdisChainBufferAtFront (NdisPacket, (PNDIS_BUFFER)BufferTag->NdisBuffer);
+
+ //
+ // DatagramAddress has a reference added already.
+ //
+
+ 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
+ //
+
+ ReceiveTag->NdisStatus = NDIS_STATUS_PENDING;
+ ReceiveTag->PacketType = TYPE_AT_COMPLETE;
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->ReceiveInProgress,
+ &ReceiveTag->Linkage,
+ &DeviceContext->SpinLock);
+
+ //
+ // receive packet is mapped at initalize
+ //
+
+ NdisTransferData (
+ &NdisStatus,
+ DeviceContext->NdisBindingHandle,
+ ReceiveContext,
+ 0,
+ PacketSize,
+ NdisPacket,
+ &BytesTransferred);
+
+ //
+ // handle the various error codes
+ //
+
+ switch (NdisStatus) {
+ case NDIS_STATUS_SUCCESS: // received packet
+ ReceiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
+ if (BytesTransferred == PacketSize) { // Did we get the entire packet?
+ return NDIS_STATUS_SUCCESS;
+ }
+ break;
+
+ case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
+ return NDIS_STATUS_SUCCESS;
+ 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
+ //
+
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ RemoveEntryList (&ReceiveTag->Linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+ BufferTag = CONTAINING_RECORD (
+ BufferPointer,
+ BUFFER_TAG,
+ Buffer[0]
+ );
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ if (DatagramAddress) {
+ StDereferenceAddress ("DG TransferData failed", DatagramAddress);
+ }
+
+ return NDIS_STATUS_FAILURE;
+
+} // StReceiveIndication
+
+
+
+VOID
+StTransferDataComplete (
+ 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;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PTP_CONNECTION Connection;
+ PNDIS_BUFFER NdisBuffer;
+ KIRQL oldirql, cancelirql;
+
+ //
+ // 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.
+ //
+
+ 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: // normal handling
+ ReceiveTag->NdisStatus = NdisStatus;
+ break;
+
+ case TYPE_AT_INDICATE:
+
+ DeviceContext = (PDEVICE_CONTEXT)BindingContext;
+ Connection = ReceiveTag->Connection;
+
+ //
+ // The transfer for this packet is complete. Was it successful??
+ //
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ ULONG DumpData[1];
+ DumpData[0] = BytesTransferred;
+
+ StWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_TRANSFER_DATA,
+ 603,
+ NdisStatus,
+ NULL,
+ 1,
+ DumpData);
+
+ //
+ // Drop the packet. BUGBUG: The driver should recover
+ // from this, but this transport has no way to cause
+ // the remote to resend.
+ //
+
+ }
+
+ //
+ // Now dereference the request to say we've got no more local
+ // references to the memory owned by it.
+ //
+
+ Connection->CurrentReceiveRequest->IoRequestPacket->IoStatus.Information += BytesTransferred;
+ StDereferenceRequest ("TransferData complete", Connection->CurrentReceiveRequest);
+
+ //
+ // see if we've completed the current receive. If so, move to the next one.
+ //
+
+ if (ReceiveTag->CompleteReceive) {
+
+ if (ReceiveTag->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_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_RC_PENDING;
+
+ } else {
+
+ //
+ // If there is a receive posted, make it current and
+ // send a receive outstanding.
+ //
+
+ ActivateReceive (Connection);
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ }
+
+ //
+ // NOTE: This releases the cancel and connection locks.
+ //
+
+ CompleteReceive (Connection, ReceiveTag->EndOfMessage, oldirql, cancelirql);
+
+ }
+
+ //
+ // dereference the connection to say we've done the I frame processing.
+ // This reference was done before calling NdisTransferData.
+ //
+
+ if (ReceiveTag->TransferDataPended) {
+ StDereferenceConnection("TransferData done", 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);
+ }
+
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ return;
+
+} /* StTransferDataComplete */
+
+
+VOID
+StReceiveComplete (
+ 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.
+ ST uses the DeviceContext for this parameter.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+ NTSTATUS Status;
+ KIRQL oldirql, oldirql1;
+ PLIST_ENTRY linkage;
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ UINT NdisBufferLength;
+ PVOID BufferPointer;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ PTP_ADDRESS Address;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_CONNECTION Connection;
+
+
+ DeviceContext = (PDEVICE_CONTEXT) BindingContext;
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
+
+ linkage = ExInterlockedRemoveHeadList(
+ &DeviceContext->IrpCompletionQueue,
+ &DeviceContext->SpinLock);
+
+ if (linkage != NULL) {
+
+ Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+
+ if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_RC_PENDING;
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ StDereferenceConnection ("receive completed", Connection);
+
+ } else {
+
+ //
+ // ExInterlockedRemoveHeadList returned NULL, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // Packetize all waiting connections
+ //
+
+ if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
+
+ PacketizeConnections (DeviceContext);
+
+ }
+
+
+ //
+ // Get every waiting packet, in order...
+ //
+
+
+ if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
+
+ linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
+ NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // 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.
+ //
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ if (ReceiveTag->NdisStatus == NDIS_STATUS_PENDING) {
+ InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return;
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (ReceiveTag->NdisStatus != NDIS_STATUS_SUCCESS) {
+ goto FreePacket; // skip the packet, continue with while loop
+ }
+
+ NdisQueryPacket (NdisPacket, NULL, NULL, &NdisBuffer, NULL);
+
+ //
+ // Have a packet. Since I allocated the storage for it, I know it's
+ // virtually contiguous and can treat it that way, which I will
+ // henceforth.
+ //
+
+ NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
+
+ //
+ // Determine what address this is for, which is stored
+ // in the buffer tag header.
+ //
+
+ BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
+ 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.
+ //
+
+ ASSERT (Address != NULL);
+
+ //
+ // Indicate it or complete posted datagrams.
+ //
+
+ Status = StIndicateDatagram (
+ DeviceContext,
+ Address,
+ BufferPointer,
+ NdisBufferLength);
+
+
+ //
+ // Dereference the address.
+ //
+
+ StDereferenceAddress ("Datagram done", Address);
+
+ //
+ // Finished with packet; return to pool.
+ //
+
+FreePacket:;
+
+ NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceivePacketPool,
+ (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
+ &DeviceContext->Interlock);
+
+ NdisAdjustBufferLength (NdisBuffer, BufferTag->Length);
+ ExInterlockedPushEntryList(
+ &DeviceContext->ReceiveBufferPool,
+ &BufferTag->Linkage,
+ &DeviceContext->Interlock);
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ } // if queue not empty
+
+ return;
+
+} /* StReceiveComplete */
+
diff --git a/private/ntos/tdi/st/info.c b/private/ntos/tdi/st/info.c
new file mode 100644
index 000000000..2a2122753
--- /dev/null
+++ b/private/ntos/tdi/st/info.c
@@ -0,0 +1,865 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define StGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+//
+// Local functions used to satisfy various requests.
+//
+
+VOID
+StStoreProviderStatistics(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTDI_PROVIDER_STATISTICS ProviderStatistics
+ );
+
+VOID
+StStoreAdapterStatus(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN PVOID StatusBuffer
+ );
+
+VOID
+StStoreNameBuffers(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ULONG NamesToSkip,
+ OUT PULONG NamesWritten,
+ OUT PULONG TotalNameCount OPTIONAL,
+ OUT PBOOLEAN Truncated
+ );
+
+
+NTSTATUS
+StTdiQueryInformation(
+ 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;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS TaAddressBuffer;
+ } AddressInfo;
+ ULONG NamesWritten, TotalNameCount, BytesWritten;
+ PLIST_ENTRY p;
+ KIRQL oldirql;
+ BOOLEAN Truncated;
+ BOOLEAN UsedConnection;
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&irpSp->Parameters;
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = StVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ ConnectionInfo = ExAllocatePool (
+ NonPagedPool,
+ sizeof (TDI_CONNECTION_INFO));
+
+ if (ConnectionInfo == NULL) {
+
+ PANIC ("StQueryInfo: Cannot allocate connection info!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TDI_CONNECTION_INFO), 6);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+
+ status = Connection->Status;
+ ExFreePool (ConnectionInfo);
+
+ } else if ((Connection->Flags & CONNECTION_FLAGS_READY) == 0) {
+
+ status = STATUS_INVALID_CONNECTION;
+ ExFreePool (ConnectionInfo);
+
+ } else {
+
+ RtlZeroMemory ((PVOID)ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+
+ //
+ // Fill in connection information here.
+ //
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ConnectionInfo,
+ 0L,
+ sizeof(TDI_CONNECTION_INFO),
+ Irp->MdlAddress,
+ 0,
+ &(Irp->IoStatus.Information));
+
+ ExFreePool (ConnectionInfo);
+ }
+
+ StDereferenceConnection ("query connection info", Connection);
+
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // Information about an address, can also be queried on a
+ // connection object to get information about its address.
+ //
+
+ if (irpSp->FileObject->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = irpSp->FileObject->FsContext;
+
+ status = StVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (irpSp->FileObject->FsContext2 == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = irpSp->FileObject->FsContext;
+
+ status = StVerifyConnectionObject (Connection);
+
+ if (!NT_SUCCESS (status)) {
+ 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) {
+
+ StDereferenceConnection ("query address info", Connection);
+
+ } else {
+
+ StDereferenceAddress ("query address info", Address);
+
+ }
+
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ broadcastAddress = ExAllocatePool (
+ NonPagedPool,
+ sizeof (TA_NETBIOS_ADDRESS));
+ if (broadcastAddress == NULL) {
+ PANIC ("StQueryInfo: Cannot allocate broadcast address!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TA_NETBIOS_ADDRESS), 2);
+ 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:
+
+ StGetMdlChainLength (Irp->MdlAddress, &TargetBufferLength);
+
+ if (TargetBufferLength < sizeof(TDI_PROVIDER_STATISTICS) + ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS))) {
+
+ Irp->IoStatus.Information = 0;
+ status = STATUS_BUFFER_OVERFLOW;
+
+ } else {
+
+ ProviderStatistics = ExAllocatePool(
+ NonPagedPool,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((ST_TDI_RESOURCES-1) * sizeof(TDI_PROVIDER_RESOURCE_STATS)));
+
+ if (ProviderStatistics == NULL) {
+
+ PANIC ("StQueryInfo: Cannot allocate provider statistics!\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TDI_PROVIDER_STATISTICS), 7);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ StStoreProviderStatistics (DeviceContext, ProviderStatistics);
+
+ status = TdiCopyBufferToMdl (
+ (PVOID)ProviderStatistics,
+ 0L,
+ sizeof(TDI_PROVIDER_STATISTICS) +
+ ((ST_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:
+
+ StGetMdlChainLength (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.
+ //
+
+ if ((query->RequestConnectionInformation != NULL) &&
+ (!RtlEqualMemory(
+ ((PTA_NETBIOS_ADDRESS)(query->RequestConnectionInformation->RemoteAddress))->
+ Address[0].Address[0].NetbiosName,
+ DeviceContext->ReservedNetBIOSAddress,
+ NETBIOS_NAME_LENGTH))) {
+
+ //
+ // Remote, not supported here.
+ //
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ } else {
+
+ //
+ // Local.
+ //
+
+ adapterStatus = ExAllocatePool (
+ NonPagedPool,
+ TargetBufferLength);
+
+ if (adapterStatus == NULL) {
+ PANIC("StQueryInfo: PANIC! Could not allocate adapter status buffer\n");
+ StWriteResourceErrorLog (DeviceContext, TargetBufferLength, 3);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ StStoreAdapterStatus (
+ DeviceContext,
+ NULL,
+ 0,
+ adapterStatus);
+
+ StStoreNameBuffers (
+ 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:
+
+ //
+ // Find name, not supported here.
+ //
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* StTdiQueryInformation */
+
+//
+// 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
+StStoreProviderStatistics(
+ 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.
+
+--*/
+
+{
+
+ ProviderStatistics->Version = 0x0100;
+
+ //
+ // Copy all the statistics from OpenConnections to WastedSpace
+ // Packets in one move.
+ //
+
+ RtlCopyMemory(
+ (PVOID)&(ProviderStatistics->OpenConnections),
+ (PVOID)&(DeviceContext->OpenConnections),
+ sizeof(TDI_PROVIDER_STATISTICS));
+
+ //
+ // Copy the resource statistics.
+ //
+
+ ProviderStatistics->NumberOfResources = ST_TDI_RESOURCES;
+
+ STORE_RESOURCE_STATS_1 (0, 12, Address);
+ STORE_RESOURCE_STATS_1 (1, 13, AddressFile);
+ STORE_RESOURCE_STATS_1 (2, 14, Connection);
+ STORE_RESOURCE_STATS_1 (3, 15, Request);
+
+ STORE_RESOURCE_STATS_2 (4, 22, Packet);
+ STORE_RESOURCE_STATS_2 (5, 23, ReceivePacket);
+ STORE_RESOURCE_STATS_2 (6, 24, ReceiveBuffer);
+
+} /* StStoreProviderStatistics */
+
+
+VOID
+StStoreAdapterStatus(
+ 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; StStoreNameBuffers 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 = 0;
+ AdapterStatus->frmr_xmit = 0;
+
+ AdapterStatus->recv_buff_unavail = (WORD)(DeviceContext->ReceivePacketExhausted + DeviceContext->ReceiveBufferExhausted);
+ AdapterStatus->xmit_buf_unavail = (WORD)DeviceContext->PacketExhausted;
+
+ AdapterStatus->xmit_success = (WORD)(DeviceContext->IFramesSent - DeviceContext->IFramesResent);
+ AdapterStatus->recv_success = (WORD)DeviceContext->IFramesReceived;
+ AdapterStatus->iframe_recv_err = (WORD)DeviceContext->IFramesRejected;
+ AdapterStatus->iframe_xmit_err = (WORD)DeviceContext->IFramesResent;
+
+ AdapterStatus->t1_timeouts = 0;
+ AdapterStatus->ti_timeouts = 0;
+ AdapterStatus->xmit_aborts = 0;
+
+
+ AdapterStatus->free_ncbs = 0xffff;
+ AdapterStatus->max_cfg_ncbs = 0xffff;
+ AdapterStatus->max_ncbs = 0xffff;
+ AdapterStatus->pending_sess = (WORD)DeviceContext->OpenConnections;
+ AdapterStatus->max_cfg_sess = 0xffff;
+ AdapterStatus->max_sess = 0xffff;
+
+
+ MacReturnMaxDataSize(
+ &DeviceContext->MacInfo,
+ SourceRouting,
+ SourceRoutingLength,
+ DeviceContext->MaxSendPacketSize,
+ &MaxUserData);
+
+ AdapterStatus->max_dgram_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
+ AdapterStatus->max_sess_pkt_size = (WORD)(MaxUserData - sizeof(ST_HEADER));
+
+ return;
+
+} /* StStoreAdapterStatus */
+
+
+VOID
+StStoreNameBuffers(
+ 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;
+
+} /* StStoreNameBuffers */
+
+
+NTSTATUS
+StTdiSetInformation(
+ 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);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* StTdiQueryInformation */
+
diff --git a/private/ntos/tdi/st/makefile b/private/ntos/tdi/st/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/st/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/st/oemnxpts.inf b/private/ntos/tdi/st/oemnxpts.inf
new file mode 100644
index 000000000..da0cdaab7
--- /dev/null
+++ b/private/ntos/tdi/st/oemnxpts.inf
@@ -0,0 +1,446 @@
+[Identification]
+ OptionType = NetTransport
+[Options]
+ ST
+[FileConstants]
+UtilityInf = "UTILITY.INF"
+subroutineinf = "SUBROUTN.INF"
+SoftwareType = "transport"
+Exit_Code = 0
+NetEventDLL = "%SystemRoot%\System32\netevent.dll"
+Manufacturer = "Microsoft"
+ProductMajorVersion = "3"
+ProductMinorVersion = "1"
+ProductVersion = $(ProductMajorVersion)"."$(ProductMinorVersion)
+ProductSoftwareName = "St"
+ProductSoftwareImagePath = "\SystemRoot\System32\drivers\st.sys"
+NetRuleSoftwareType = "st netBiosTransport"
+NetRuleSoftwareClass = {"netBiosTransport"}
+NetRuleSoftwareUse = $(SoftwareType)" yes yes"
+NetRuleSoftwareBindForm = """St"" yes yes simple"
+ProductKeyName = $(!NTN_SoftwareBase)"\"$(Manufacturer)"\"$(ProductSoftwareName)"\CurrentVersion"
+ParamKeyName = $(!NTN_ServiceBase)"\"$(ProductSoftwareName)"\Parameters"
+[GeneralConstants]
+from = ""
+to = ""
+ExitCodeOk = 0
+ExitCodeCancel = 1
+ExitCodeFatal = 2
+KeyNull = ""
+MAXIMUM_ALLOWED = 33554432
+RegistryErrorIndex = NO_ERROR
+KeyProduct = ""
+KeyParameters = ""
+TRUE = 1
+FALSE = 0
+NoTitle = 0
+ExitState = "Active"
+OldVersionExisted = $(FALSE)
+DriverPath = $(!STF_NTPATH)\drivers
+[date]
+ Now = {} ? $(!LIBHANDLE) GetSystemDate
+[Identify]
+ read-syms Identification
+ set Status = STATUS_SUCCESSFUL
+ set Identifier = $(OptionType)
+ set Media = #("Source Media Descriptions", 1, 1)
+ Return $(Status) $(Identifier) $(Media)
+[ReturnOptions]
+ set Status = STATUS_FAILED
+ set OptionList = {}
+ set OptionTextList = {}
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) in $(LanguageList)
+ goto returnoptions
+ else
+ set Status = STATUS_NOLANGUAGE
+ goto finish_ReturnOptions
+ endif
+returnoptions = +
+ set OptionList = ^(Options, 1)
+ set OptionTextList = ^(OptionsText$($0), 1)
+ set Status = STATUS_SUCCESSFUL
+finish_ReturnOptions = +
+ Return $(Status) $(OptionList) $(OptionTextList)
+[InstallOption]
+ set Option = $($1)
+ set SrcDir = $($2)
+ set AddCopy = $($3)
+ set DoCopy = $($4)
+ set DoConfig = $($5)
+ set LanguageList = ^(LanguagesSupported, 1)
+ Ifcontains(i) $($0) NOT-IN $(LanguageList)
+ Return STATUS_NOLANGUAGE
+ endif
+ Debug-Output "OEMNXPNB.INF: STF_CWDDIR is: "$(!STF_CWDDIR)
+ Debug-Output "OEMNXPNB.INF: STF_LANGUAGE is: "$(!STF_LANGUAGE)
+ set-subst LF = "\n"
+ read-syms GeneralConstants
+ read-syms FileConstants
+ read-syms DialogConstants$(!STF_LANGUAGE)
+ ifstr(i) $(!NTN_Origination) == "NCPA"
+ set Continue = $(OK)
+ endif
+ read-syms FileConstants$(!STF_LANGUAGE)
+ detect date
+ set-title $(FunctionTitle)
+ set to = Begin
+ set from = Begin
+ set CommonStatus = STATUS_SUCCESSFUL
+ EndWait
+Begin = +
+ Ifstr(i) $(!NTN_InstallMode) == deinstall
+ set StartLabel = removeadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == Update
+ set StartLabel = UpgradeSoftware
+ else-Ifstr(i) $(!NTN_InstallMode) == bind
+ set StartLabel = bindingadapter
+ else-Ifstr(i) $(!NTN_InstallMode) == configure
+ Shell $(UtilityInf),RegistryErrorString,CANNOT_CONFIGURE_SOFTWARE
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "OEMNXPNB.INF: ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ set from = end
+ set to = end
+ goto nonfatalinfo
+ else
+ set StartLabel = installadapter
+ endif
+ set RadioDefault = 2
+ set RadioIn = {$(RadioDefault)}
+ set Size = 2
+ set from = $(fatal)
+ set to = $(fatal)
+ goto $(StartLabel)
+installadapter = +
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ Ifstr $(KeyProduct) != $(KeyNull)
+ CloseRegKey $(KeyProduct)
+ Shell $(UtilityInf), VerExistedDlg, $(ProductSoftwareTitle),+
+ $(ProductVersion)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error: cannot get an error string."
+ goto ShellCodeError
+ endif
+ goto end
+ endif
+ CloseRegKey $(KeyProduct)
+ goto installproduct
+installproduct = +
+ StartWait
+ ifint $(OldVersionExisted) == $(FALSE)
+ Ifstr(i) $(DoCopy) == "YES"
+ Shell $(UtilityInf), DoAskSource, $(!STF_CWDDIR), $(SrcDir) YES
+ Ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Goto ShellCodeError
+ Else-Ifstr(i) $($R0) == STATUS_FAILED
+ Shell $(UtilityInf) RegistryErrorString "ASK_SOURCE_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ Goto fatal
+ Else-Ifstr(i) $($R0) == STATUS_USERCANCEL
+ Goto successful
+ Endif
+ Set SrcDir = $($R1)
+ Endif
+ install "Install-Option"
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ Shell $(UtilityInf) RegistryErrorString "UNABLE_COPY_FILE"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+ endif
+ set OEM_ABANDON_ON = TRUE
+ Shell $(UtilityInf), AddSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareName), +
+ $(ProductSoftwareDisplayName), $(STF_CONTEXTINFNAME), +
+ $(ProductSoftwareImagePath), "kernel", "TDI", {}, "",+
+ $(NetEventDLL)
+ set RegistryErrorIndex = $($R0)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ EndWait
+ CloseRegKey $($R1)
+ CloseRegKey $($R2)
+ CloseRegKey $($R3)
+ CloseRegKey $($R4)
+ CloseRegKey $($R5)
+ goto fatalRegistry
+ endif
+ Set SoftProductKey = $($R1)
+ Set SoftNetRuleKey = $($R2)
+ Set SoftServiceKey = $($R3)
+ set KeyParameters = $($R4)
+ Set SoftLinkageKey = $($R5)
+ set NewValueList = {{SoftwareType,$(NoTitle),$(!REG_VT_SZ),$(SoftwareType)},+
+ {MajorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMajorVersion)},+
+ {MinorVersion,$(NoTitle),$(!REG_VT_DWORD),$(ProductMinorVersion)},+
+ {Title,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareTitle)},+
+ {Description,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareDescription)},+
+ {ServiceName,$(NoTitle),$(!REG_VT_SZ),$(ProductSoftwareName)},+
+ {InstallDate,$(NoTitle),$(!REG_VT_DWORD),*($(Now),1)}}
+ Shell $(UtilityInf), AddValueList, $(SoftProductKey), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ set NewValueList = {{type ,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareType)}, +
+ {use ,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareUse)}, +
+ {class,$(NoTitle),$(!REG_VT_MULTI_SZ),$(NetRuleSoftwareClass)}, +
+ {bindform,$(NoTitle),$(!REG_VT_SZ),$(NetRuleSoftwareBindForm)}, +
+ {InfOption,$(NoTitle),$(!REG_VT_SZ),$(Option)}}
+ Shell $(UtilityInf), AddValueList, $(SoftNetRuleKey), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ Set NewValueList = {{NbProvider,$(NoTitle),$(!REG_VT_SZ),"_nb"}}
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ goto fatalRegistry
+ endif
+ CreateRegKey $(SoftServiceKey) {"Performance",$(NoTitle),GenericClass} "" +
+ $(MAXIMUM_ALLOWED) "" KeyPerformance
+ set NewValueList = {{Library,$(NoTitle),$(!REG_VT_SZ),"Perfctrs.dll"},+
+ {Open,$(NoTitle),$(!REG_VT_SZ),"OpenNbfPerformanceData"},+
+ {Collect,$(NoTitle),$(!REG_VT_SZ),"CollectNbfPerformanceData"},+
+ {Close,$(NoTitle),$(!REG_VT_SZ),"CloseNbfPerformanceData"}}
+ Shell $(UtilityInf), AddValueList, $(KeyPerformance), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ Ifstr $(RegistryErrorIndex) != NO_ERROR
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ CloseRegKey $(KeyParameters)
+ goto fatalRegistry
+ endif
+ CloseRegKey $(KeyPerformance)
+ CloseRegKey $(SoftProductKey)
+ CloseRegKey $(SoftNetRuleKey)
+ CloseRegKey $(SoftServiceKey)
+ CloseRegKey $(SoftLinkageKey)
+ endif
+ goto writeparameters
+writeparameters = +
+ set NewValueList = {{Size,$(NoTitle),$(!REG_VT_DWORD),$(Size)}}
+ ifint $(OldVersionExisted) == $(TRUE)
+ OpenRegKey $(!REG_H_LOCAL) "" $(ParamKeyName) $(MAXIMUM_ALLOWED) KeyParameters
+ endif
+ Shell $(UtilityInf), AddValueList, $(KeyParameters), $(NewValueList)
+ set RegistryErrorIndex = $($R0)
+ CloseRegKey $(KeyParameters)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalRegistry
+ endif
+ EndWait
+ goto successful
+bindingadapter =+
+ set Error = "Binding: Sorry, not yet implemented."
+ goto fatal
+removeadapter = +
+ Shell $(UtilityInf), RemoveSoftwareComponent, $(Manufacturer), +
+ $(ProductSoftwareName)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+ set RegistryErrorIndex = $($R0)
+ Ifstr(i) $(RegistryErrorIndex) != NO_ERROR
+ goto fatalregistry
+ endif
+ goto end
+UpgradeSoftware = +
+ ifstr(i) $(ProductKeyName) == $(!NTN_RegBase)
+ OpenRegKey $(!REG_H_LOCAL) "" $(ProductKeyName) $(MAXIMUM_ALLOWED) KeyProduct
+ Ifstr $(KeyProduct) != $(KeyNull)
+ GetRegValue $(KeyProduct),"MajorVersion", VersionInfo
+ set Version = *($(VersionInfo), 4)
+ Shell $(UtilityInf), GetInfFileNameFromRegistry, $(KeyProduct)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ Debug-Output "ShellCode error"
+ goto ShellCodeError
+ endif
+ set !UG_Filename = $($R0)
+ ifstr(i) $(!UG_Filename) != ""
+ install "Install-Update"
+ ifstr(i) $(STF_INSTALL_OUTCOME) != STF_SUCCESS
+ goto fatal
+ endif
+ endif
+ SetRegValue $(KeyProduct) {MajorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMajorVersion)}
+ SetRegValue $(KeyProduct) {MinorVersion,$(NoTitle),$(!REG_VT_SZ),$(ProductMinorVersion)}
+ ifint $(Version) != $(ProductVersion)
+ endif
+ CloseRegKey $(KeyProduct)
+ else
+ goto fatalregistry
+ endif
+ endif
+ goto end
+successful = +
+ goto end
+warning = +
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "WARNING", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(to)
+ else-ifstr(i) $($R1) == "CANCEL"
+ goto $(from)
+ else
+ goto "end"
+ endif
+nonfatalinfo = +
+ Set CommonStatus = STATUS_USERCANCEL
+ Set Severity = STATUS
+ goto nonfatalmsg
+nonfatal = +
+ Set Severity = NONFATAL
+ goto nonfatalmsg
+nonfatalmsg = +
+ ifstr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), $(Severity), $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ ifstr(i) $($R1) == "OK"
+ goto $(from)
+ else
+ goto "end"
+ endif
+fatalregistry = +
+ Shell $(UtilityInf) RegistryErrorString $(RegistryErrorIndex)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ goto fatal
+fatal = +
+ ifstr(i) $(Error) == ""
+ Shell $(UtilityInf) RegistryErrorString "SETUP_FAIL"
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ set Error = $($R0)
+ endif
+ Shell $(subroutineinf) SetupMessage, $(!STF_LANGUAGE), "FATAL", $(Error)
+ ifint $($ShellCode) != $(!SHELL_CODE_OK)
+ goto ShellCodeError
+ endif
+ goto setfailed
+ShellCodeError = +
+ set DlgType = "MessageBox"
+ set STF_MB_TITLE = $(ShellCodeErrorTitle)
+ set STF_MB_TEXT = $(ShellCodeErrorText)
+ set STF_MB_TYPE = 1
+ set STF_MB_ICON = 3
+ set STF_MB_DEF = 1
+ ui start "Error Message"
+ goto setfailed
+setfailed = +
+ set CommonStatus = STATUS_FAILED
+ ifstr(i) $(OEM_ABANDON_ON) == TRUE
+ set OEM_ABANDON_ON = FALSE
+ goto removeadapter
+ endif
+ goto end
+end = +
+ goto term
+term = +
+ Return $(CommonStatus)
+[Install-Option]
+ set STF_VITAL = ""
+ ifstr(i) $(AddCopy) == "YES"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ endif
+ ifstr(i) $(DoCopy) == "YES"
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ endif
+ ifstr(i) $(DoConfig) == "YES"
+ endif
+ Exit
+[Install-Update]
+ set STF_VITAL = ""
+ set STF_OVERWRITE = "VERIFYSOURCEOLDER"
+ AddSectionFilesToCopyList Files-$(Option) $(SrcDir) $(!STF_WINDOWSSYSPATH)\drivers
+ AddSectionFilesToCopyList Files-Inf $(SrcDir) $(!STF_WINDOWSSYSPATH)
+ set !STF_NCPA_FLUSH_COPYLIST = TRUE
+ CopyFilesInCopyList
+ exit
+[Source Media Descriptions]
+ 1 = "Windows NT Setup Disk #1" , TAGFILE = disk1
+ 2 = "Windows NT Setup CD-ROM Disk" , TAGFILE = disk2
+[ProductType]
+STF_PRODUCT = Winnt
+STF_PLATFORM = Mips
+[Files-Inf]
+2, oemsetup.inf, SIZE=1000, RENAME=$(!UG_Filename)
+[Files-ST]
+2,ST.SYS , SIZE=88888
+[LanguagesSupported]
+ ENG
+[OptionsTextENG]
+ ST = "Sample Transport"
+[FileConstantsENG]
+ProCaption = "Windows NT Setup"
+ProCancel = "Cancel"
+ProCancelMsg = "Windows NT Networking is not correctly installed. "+
+ "Are you sure you want to cancel copying files?"
+ProCancelCap = "Network Setup Message"
+ProText1 = "Copying:"
+ProText2 = "To:"
+FunctionTitle = "Sample Transport"
+ProductSoftwareDescription = "Microsoft Sample TDI Transport"
+ProductSoftwareDisplayName = "Sample Transport"
+ProductSoftwareTitle = "Sample Transport"
+ShellCodeErrorTitle = "Error: "$(FunctionTitle)
+ShellCodeErrorText = "Shell Code Error."
+[DialogConstantsENG]
+Help = "&Help"
+Exit = "Cancel"
+OK = "OK"
+HelpContext = ""
+Continue = "Continue"
+Cancel = "Cancel"
+[FileDependentDlgENG]
+GroupLabel = "Optimization:"
+Radio1 = "&Minimize Memory Used"
+Radio2 = "&Balance"
+Radio3 = "M&aximize Throughput && Connections"
+DlgType = "Radio"
+DlgTemplate = "ST"
+Caption = $(FunctionTitle)
+OptionsGreyed = {}
+HelpContext = $(!IDH_DB_OEMNXPNB_INS)
+
+
+
diff --git a/private/ntos/tdi/st/packet.c b/private/ntos/tdi/st/packet.c
new file mode 100644
index 000000000..29e9fe1b8
--- /dev/null
+++ b/private/ntos/tdi/st/packet.c
@@ -0,0 +1,597 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the TP_PACKET object, which
+ describes an NDIS packet.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+//
+// 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
+
+
+
+
+VOID
+StAllocateSendPacket(
+ 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;
+
+ if ((DeviceContext->MemoryLimit != 0) &&
+ ((DeviceContext->MemoryUsage + DeviceContext->PacketLength) >
+ DeviceContext->MemoryLimit)) {
+ PANIC("ST: Could not allocate send packet: limit\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 107);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ Packet = (PTP_PACKET)ExAllocatePool (NonPagedPool, DeviceContext->PacketLength);
+ if (Packet == NULL) {
+ PANIC("ST: Could not allocate send packet: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->PacketLength, 207);
+ *TransportSendPacket = NULL;
+ return;
+ }
+ RtlZeroMemory (Packet, DeviceContext->PacketLength);
+
+ DeviceContext->MemoryUsage += DeviceContext->PacketLength;
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->SendPacketPoolHandle);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (Packet);
+ StWriteResourceErrorLog (DeviceContext, 0, 307);
+ *TransportSendPacket = NULL;
+ return;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPoolHandle,
+ Packet->Header,
+ DeviceContext->PacketHeaderLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ 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->Packet = Packet;
+ SendTag->Owner = NULL;
+
+ Packet->Type = ST_PACKET_SIGNATURE;
+ Packet->Size = sizeof (TP_PACKET);
+ Packet->Provider = DeviceContext;
+
+ ++DeviceContext->PacketAllocated;
+
+ *TransportSendPacket = Packet;
+
+} /* StAllocateSendPacket */
+
+
+VOID
+StDeallocateSendPacket(
+ 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;
+
+} /* StDeallocateSendPacket */
+
+
+VOID
+StAllocateReceivePacket(
+ 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.
+ //
+
+ NdisAllocatePacket (
+ &NdisStatus,
+ &NdisPacket,
+ DeviceContext->ReceivePacketPoolHandle);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StWriteResourceErrorLog (DeviceContext, 0, 309);
+ *TransportReceivePacket = NULL;
+ return;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
+ ReceiveTag->PacketType = TYPE_AT_INDICATE;
+
+ ++DeviceContext->ReceivePacketAllocated;
+
+ *TransportReceivePacket = NdisPacket;
+
+} /* StAllocateReceivePacket */
+
+
+VOID
+StDeallocateReceivePacket(
+ 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;
+
+} /* StDeallocateReceivePacket */
+
+
+VOID
+StAllocateReceiveBuffer(
+ 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("ST: Could not allocate receive buffer: limit\n");
+ StWriteResourceErrorLog (DeviceContext, RECEIVE_BUFFER_QUOTA(DeviceContext), 108);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag = (PBUFFER_TAG)ExAllocatePool (
+ NonPagedPoolCacheAligned,
+ DeviceContext->ReceiveBufferLength);
+
+ if (BufferTag == NULL) {
+ PANIC("ST: Could not allocate receive buffer: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->ReceiveBufferLength, 208);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ DeviceContext->MemoryUsage += RECEIVE_BUFFER_QUOTA(DeviceContext);
+
+ //
+ // point to the buffer for NDIS
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ DeviceContext->NdisBufferPoolHandle,
+ BufferTag->Buffer,
+ DeviceContext->MaxReceivePacketSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ ExFreePool (BufferTag);
+ *TransportReceiveBuffer = NULL;
+ return;
+ }
+
+ BufferTag->Length = DeviceContext->MaxReceivePacketSize;
+ BufferTag->NdisBuffer = NdisBuffer;
+
+ ++DeviceContext->ReceiveBufferAllocated;
+
+ *TransportReceiveBuffer = BufferTag;
+
+} /* StAllocateReceiveBuffer */
+
+
+VOID
+StDeallocateReceiveBuffer(
+ 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);
+
+} /* StDeallocateReceiveBuffer */
+
+
+NTSTATUS
+StCreatePacket(
+ PDEVICE_CONTEXT DeviceContext,
+ 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.
+
+ 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;
+
+ s = ExInterlockedPopEntryList (
+ &DeviceContext->PacketPool,
+ &DeviceContext->Interlock);
+
+ if (s == NULL) {
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+ ++DeviceContext->PacketExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ThePacket = CONTAINING_RECORD (s, TP_PACKET, Linkage);
+
+ ThePacket->Provider = DeviceContext; // who owns this packet
+ ThePacket->PacketSent = FALSE;
+ ThePacket->PacketNoNdisBuffer = FALSE;
+
+ *Packet = ThePacket; // return pointer to the packet.
+ return STATUS_SUCCESS;
+} /* StCreatePacket */
+
+
+VOID
+StDestroyPacket(
+ 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.
+
+--*/
+
+{
+ KIRQL oldirql1;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ //
+ // Strip off and unmap the buffers describing data and header.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &HeaderBuffer);
+
+ // data buffers get thrown away
+
+ 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.
+ //
+
+ NdisReinitializePacket (Packet->NdisPacket);
+
+ } else {
+
+ //
+ // Return all the NDIS_BUFFERs to the system.
+ //
+
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ while (NdisBuffer != NULL) {
+ NdisFreeBuffer (NdisBuffer);
+ NdisUnchainBufferAtFront (Packet->NdisPacket, &NdisBuffer);
+ }
+
+ }
+
+ ASSERT (HeaderBuffer != NULL);
+ NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL;
+
+ NdisChainBufferAtFront (Packet->NdisPacket, HeaderBuffer);
+
+
+ //
+ // Put the packet back for use again.
+ //
+
+ DeviceContext = Packet->Provider;
+
+ ExInterlockedPushEntryList (
+ &DeviceContext->PacketPool,
+ (PSINGLE_LIST_ENTRY)&Packet->Linkage,
+ &DeviceContext->Interlock);
+
+ //
+ // 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;
+ }
+
+ p = ExInterlockedRemoveHeadList(
+ &DeviceContext->PacketWaitQueue,
+ &DeviceContext->SpinLock);
+
+ if (p != NULL) {
+
+ //
+ // Remove a connection from the "packet starved" queue.
+ //
+
+ Connection = CONTAINING_RECORD (p, TP_CONNECTION, PacketWaitLinkage);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ Connection->Flags &= ~CONNECTION_FLAGS_SUSPENDED;
+
+ //
+ // 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.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_PACKETIZE;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING) &&
+ !(Connection->Flags & CONNECTION_FLAGS_PACKETIZE)) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ StReferenceConnection ("Packet available", Connection);
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ PacketizeConnections (DeviceContext);
+
+ }
+
+} /* StDestroyPacket */
+
diff --git a/private/ntos/tdi/st/rcv.c b/private/ntos/tdi/st/rcv.c
new file mode 100644
index 000000000..b2f0e779d
--- /dev/null
+++ b/private/ntos/tdi/st/rcv.c
@@ -0,0 +1,247 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rcv.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceive
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiReceive(
+ 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, cancelirql;
+ PTP_REQUEST tpRequest;
+ LARGE_INTEGER timeout = {0,0};
+ PIO_STACK_LOCATION irpSp;
+ PMDL ReceiveBuffer;
+ ULONG ReceiveBufferLength;
+ PTDI_REQUEST_KERNEL_RECEIVE parameters;
+
+ //
+ // 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;
+
+ status = StVerifyConnectionObject (connection);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ //
+ // Initialize bytes transferred here.
+ //
+
+ Irp->IoStatus.Information = 0; // reset byte transfer count.
+
+
+ parameters = (PTDI_REQUEST_KERNEL_RECEIVE)(&irpSp->Parameters);
+ ReceiveBuffer = Irp->MdlAddress;
+ ReceiveBufferLength =parameters->ReceiveLength;
+
+ //
+ // Queue up this receive to the connection object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ connection, // context.
+ REQUEST_FLAGS_CONNECTION, // partial flags.
+ ReceiveBuffer,
+ ReceiveBufferLength,
+ timeout,
+ &tpRequest);
+
+ //
+ // We have a request, now queue it. If the connection has gone south on us
+ // while we were getting things going, we will avoid actually queing the
+ // request.
+ //
+
+ if (NT_SUCCESS (status)) {
+
+ // This reference is removed by StDestroyRequest.
+
+ StReferenceConnection("TdiReceive request", connection);
+ tpRequest->Owner = ConnectionType;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteRequest (
+ tpRequest,
+ connection->Status,
+ 0);
+ status = STATUS_PENDING;
+ } else {
+
+ //
+ // Insert onto the receive queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->ReceiveQueue,&tpRequest->Linkage);
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ Irp->CancelIrql = cancelirql;
+ StCancelReceive((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelReceive;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ AwakenReceive (connection); // awaken if sleeping.
+
+ status = STATUS_PENDING;
+ }
+ }
+
+ StDereferenceConnection("temp TdiReceive", connection);
+
+ return status;
+} /* TdiReceive */
+
+
+NTSTATUS
+StTdiReceiveDatagram(
+ 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;
+ PTP_REQUEST tpRequest;
+ LARGE_INTEGER timeout = {0,0};
+ PIO_STACK_LOCATION irpSp;
+ PMDL ReceiveBuffer;
+ ULONG ReceiveBufferLength;
+
+ //
+ // 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 = StVerifyAddressObject (addressFile);
+
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+
+ ReceiveBuffer = Irp->MdlAddress;
+ ReceiveBufferLength =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength;
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ address, // context
+ REQUEST_FLAGS_ADDRESS, // partial flags.
+ ReceiveBuffer,
+ ReceiveBufferLength,
+ timeout,
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+ StReferenceAddress ("Receive datagram", address);
+ tpRequest->Owner = AddressType;
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0);
+ status = STATUS_PENDING;
+ } else {
+ InsertTailList (&addressFile->ReceiveDatagramQueue,&tpRequest->Linkage);
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ }
+
+ status = STATUS_PENDING;
+ }
+
+ StDereferenceAddress ("Temp rcv datagram", address);
+
+ return status;
+} /* TdiReceiveDatagram */
+
diff --git a/private/ntos/tdi/st/rcveng.c b/private/ntos/tdi/st/rcveng.c
new file mode 100644
index 000000000..8e104a954
--- /dev/null
+++ b/private/ntos/tdi/st/rcveng.c
@@ -0,0 +1,383 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rcveng.c
+
+Abstract:
+
+ This module contains code that implements the receive engine for the
+ Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+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.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PTP_REQUEST Request;
+
+ //
+ // 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_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ 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;
+
+ Request = CONTAINING_RECORD (
+ Connection->ReceiveQueue.Flink,
+ TP_REQUEST,
+ Linkage);
+ Connection->MessageBytesReceived = 0;
+ Connection->MessageBytesAcked = 0;
+ Connection->CurrentReceiveRequest = Request;
+ Connection->CurrentReceiveMdl = Request->Buffer2;
+ Connection->ReceiveLength = Request->Buffer2Length;
+ Connection->ReceiveByteOffset = 0;
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+} /* 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.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+
+ //
+ // If the RECEIVE_WAKEUP bitflag is set, then awaken the connection.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ 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, and activate
+ // the next receive.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ ActivateReceive (Connection);
+
+ return;
+ }
+ }
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+} /* AwakenReceive */
+
+
+VOID
+CompleteReceive(
+ PTP_CONNECTION Connection,
+ BOOLEAN EndOfRecord,
+ KIRQL ConnectionIrql,
+ KIRQL CancelIrql
+ )
+
+/*++
+
+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 EndOfRecord flag will be set accordingly
+ by the caller to indicate that a message boundary was received.
+
+ NOTE: This function is called with the connection and cancel
+ IRQLs held, and returns with them released.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+ EndOfRecord - BOOLEAN set to true if TDI_END_OF_RECORD should be reported.
+
+ ConnectionIrql - The IRQL at which the connection spinlock was acquired.
+
+ CancelIrql - The IRQL at which the cancel spinlock was acquired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PTP_REQUEST Request;
+ KIRQL oldirql = ConnectionIrql;
+ KIRQL cancelirql = CancelIrql;
+ ULONG BytesReceived;
+
+
+ if (IsListEmpty (&Connection->ReceiveQueue)) {
+
+ ASSERT ((Connection->Flags & CONNECTION_FLAGS_STOPPING) != 0);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ return;
+ }
+
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+ BytesReceived = Connection->MessageBytesReceived;
+
+
+ //
+ // Complete the TdiReceive request at the head of the
+ // connection's ReceiveQueue.
+ //
+
+ p = RemoveHeadList (&Connection->ReceiveQueue);
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+
+ Request->Flags |= REQUEST_FLAGS_DELAY;
+
+ StCompleteRequest(
+ Request,
+ EndOfRecord ? STATUS_SUCCESS : STATUS_BUFFER_OVERFLOW,
+ BytesReceived);
+
+} /* CompleteReceive */
+
+
+VOID
+StCancelReceive(
+ 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;
+ PTP_CONNECTION Connection;
+ PTP_REQUEST Request;
+ 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->SpinLock, &oldirql);
+
+ BytesReceived = Connection->MessageBytesReceived;
+
+ p = Connection->ReceiveQueue.Flink;
+
+ //
+ // If there is a receive active, then see if this is it.
+ //
+
+ if ((Connection->Flags & CONNECTION_FLAGS_ACTIVE_RECEIVE) != 0) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+
+ if (Request->IoRequestPacket == 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->Flags2 |= CONNECTION_FLAGS2_RCV_CANCELLED;
+ Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
+
+ (VOID)RemoveHeadList (&Connection->ReceiveQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->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.
+ //
+
+ StCompleteRequest (Request, 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) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+ Found = TRUE;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->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.
+ //
+
+ StCompleteRequest (Request, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+}
diff --git a/private/ntos/tdi/st/request.c b/private/ntos/tdi/st/request.c
new file mode 100644
index 000000000..de553c0cc
--- /dev/null
+++ b/private/ntos/tdi/st/request.c
@@ -0,0 +1,801 @@
+/*++
+
+Copyright (c) 1989-1993 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.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+
+
+VOID
+StTdiRequestTimeoutHandler(
+ 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;
+ PIO_STACK_LOCATION IrpSp;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+
+ Request = (PTP_REQUEST)DeferredContext;
+
+ ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql);
+ Request->Flags &= ~REQUEST_FLAGS_TIMER;
+ if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) {
+
+ //
+ // 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:
+
+ ASSERT (FALSE);
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ StCompleteRequest (Request, STATUS_IO_TIMEOUT, 0);
+ break;
+
+
+ case TDI_LISTEN:
+ case TDI_CONNECT:
+
+ 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.
+ //
+
+ StStopConnection (Connection, STATUS_IO_TIMEOUT);
+ break;
+
+ case TDI_DISCONNECT:
+
+ //
+ // We don't create requests for TDI_DISCONNECT any more.
+ //
+
+ ASSERT(FALSE);
+ break;
+
+ default:
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ break;
+
+ } // end of switch
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+ StDereferenceRequest ("Timeout", Request); // for the timeout
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ StDereferenceRequest ("Timeout: stopping", Request); // for the timeout
+
+ }
+
+ return;
+
+} /* RequestTimeoutHandler */
+
+
+VOID
+StAllocateRequest(
+ 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("ST: Could not allocate request: limit\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 104);
+ *TransportRequest = NULL;
+ return;
+ }
+
+ Request = (PTP_REQUEST)ExAllocatePool (NonPagedPool, sizeof (TP_REQUEST));
+ if (Request == NULL) {
+ PANIC("ST: Could not allocate request: no pool\n");
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 204);
+ *TransportRequest = NULL;
+ return;
+ }
+ RtlZeroMemory (Request, sizeof(TP_REQUEST));
+
+ DeviceContext->MemoryUsage += sizeof(TP_REQUEST);
+ ++DeviceContext->RequestAllocated;
+
+ Request->Type = ST_REQUEST_SIGNATURE;
+ Request->Size = sizeof (TP_REQUEST);
+
+ Request->Provider = DeviceContext;
+ Request->ProviderInterlock = &DeviceContext->Interlock;
+ KeInitializeSpinLock (&Request->SpinLock);
+ KeInitializeDpc (&Request->Dpc, StTdiRequestTimeoutHandler, (PVOID)Request);
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+
+ *TransportRequest = Request;
+
+} /* StAllocateRequest */
+
+
+VOID
+StDeallocateRequest(
+ 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);
+
+} /* StDeallocateRequest */
+
+
+NTSTATUS
+StCreateRequest(
+ 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;
+
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+ DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject;
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&DeviceContext->RequestPool);
+ if (p == &DeviceContext->RequestPool) {
+
+ if ((DeviceContext->RequestMaxAllocated == 0) ||
+ (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) {
+
+ StAllocateRequest (DeviceContext, &Request);
+
+ } else {
+
+ StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 404);
+ Request = NULL;
+
+ }
+
+ if (Request == NULL) {
+ ++DeviceContext->RequestExhausted;
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ PANIC ("StCreateConnection: 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 ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) {
+
+ // no timeout
+ } else {
+
+ Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request.
+ KeInitializeTimer (&Request->Timer); // set to not-signaled state.
+ StReferenceRequest ("Create: timer", Request); // one for the timer
+ KeSetTimer (&Request->Timer, Timeout, &Request->Dpc);
+ }
+
+ *TpRequest = Request;
+
+ return STATUS_SUCCESS;
+} /* StCreateRequest */
+
+
+VOID
+StDestroyRequest(
+ 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;
+
+ //
+ // Return the request to the caller with whatever status is in the IRP.
+ //
+
+ //
+ // 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:
+ if (!(Request->Flags & REQUEST_FLAGS_DELAY)) {
+ StDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context));
+ }
+ break;
+
+ case AddressType:
+ StDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context));
+ break;
+
+ case DeviceContextType:
+ StDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context));
+ break;
+ }
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ DeviceContext = Request->Provider;
+
+ if (Request->Flags & REQUEST_FLAGS_DELAY) {
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ InsertTailList(
+ &DeviceContext->IrpCompletionQueue,
+ &Request->IoRequestPacket->Tail.Overlay.ListEntry);
+
+ } else {
+
+ IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT);
+
+ 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) {
+ StDeallocateRequest (DeviceContext, Request);
+ } else {
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+} /* StDestroyRequest */
+
+
+VOID
+StRefRequest(
+ 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.
+
+--*/
+
+{
+ ASSERT (Request->ReferenceCount > 0);
+
+ InterlockedIncrement (&Request->ReferenceCount);
+
+} /* StRefRequest */
+
+
+VOID
+StDerefRequest(
+ 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
+ StDestroyRequest to remove it from the system.
+
+Arguments:
+
+ Request - Pointer to a transport request object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ 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) {
+ StDestroyRequest (Request);
+ }
+
+} /* StDerefRequest */
+
+
+VOID
+StCompleteRequest(
+ 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;
+ NTSTATUS FinalStatus = Status;
+ BOOLEAN TimerWasSet;
+
+ ASSERT (Status != STATUS_PENDING);
+
+ if (Request->Flags & REQUEST_FLAGS_SEND_RCV) {
+
+ //
+ // Sends and receives we check for since we know
+ // they don't have timers and should only complete
+ // once.
+ //
+
+ Request->Flags |= REQUEST_FLAGS_STOPPING;
+ Irp = Request->IoRequestPacket;
+ Irp->IoStatus.Status = FinalStatus;
+ Irp->IoStatus.Information = Information;
+
+ StDereferenceRequest ("Complete", Request); // remove creation reference.
+ return;
+ }
+
+
+ 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) {
+ StDereferenceRequest ("Complete: stop timer", Request);
+ }
+
+ } else {
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+ }
+
+ Irp = Request->IoRequestPacket;
+
+
+ //
+ // Install the return code in the IRP so that when we call StDestroyRequest,
+ // 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.
+ //
+
+ StDereferenceRequest ("Complete", Request); // remove creation reference.
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql);
+
+ }
+
+} /* StCompleteRequest */
+
+
+VOID
+StRefSendIrp(
+ 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.
+
+--*/
+
+{
+ ASSERT (IRP_REFCOUNT(IrpSp) > 0);
+
+ InterlockedIncrement (&IRP_REFCOUNT(IrpSp));
+
+} /* StRefSendIrp */
+
+
+VOID
+StDerefSendIrp(
+ 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.
+
+ NOTE: This assume that IRP_CONNECTION(IrpSp) has been changed
+ to point to the IRP instead of the connection.
+
+Arguments:
+
+ Request - Pointer to a transport send IRP's stack location.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&IRP_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 = (PIRP)IRP_CONNECTION(IrpSp);
+
+ IRP_REFCOUNT(IrpSp) = 0;
+ IRP_CONNECTION (IrpSp) = NULL;
+
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+} /* StDerefSendIrp */
+
+
+VOID
+StCompleteSendIrp(
+ 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_CONNECTION(IrpSp);
+
+
+ //
+ // Sends and receives we check for since we know
+ // they don't have timers and should only complete
+ // once.
+ //
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information = Information;
+
+ IRP_CONNECTION(IrpSp) = Irp;
+
+ StDereferenceSendIrp ("Complete", IrpSp); // remove creation reference.
+
+ StDereferenceConnection ("Removing Connection", Connection);
+
+} /* StCompleteSendIrp */
diff --git a/private/ntos/tdi/st/send.c b/private/ntos/tdi/st/send.c
new file mode 100644
index 000000000..0e6a2b9f6
--- /dev/null
+++ b/private/ntos/tdi/st/send.c
@@ -0,0 +1,385 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSend
+ o TdiSendDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+NTSTATUS
+StTdiSend(
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSend request for the transport provider.
+
+Arguments:
+
+ Irp - Pointer to the I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ NTSTATUS status;
+ PTP_CONNECTION connection;
+ PMDL SendBuffer;
+ ULONG SendBufferLength;
+ 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 != ST_CONNECTION_SIGNATURE)) {
+ return STATUS_INVALID_CONNECTION;
+ }
+
+ //
+ // Now map the data in to SVA space.
+ //
+
+ parameters = (PTDI_REQUEST_KERNEL_SEND)(&irpSp->Parameters);
+ SendBuffer = Irp->MdlAddress;
+ SendBufferLength = parameters->SendLength;
+
+ //
+ // Interpret send options.
+ //
+
+ //
+ // Now we have a reference on the connection object. Queue up this
+ // send to the connection object.
+ //
+
+
+ // This reference is removed by TdiDestroyRequest
+
+ StReferenceConnection("TdiSend", connection);
+
+ IRP_CONNECTION(irpSp) = connection;
+ IRP_REFCOUNT(irpSp) = 1;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&connection->SpinLock,&oldirql);
+
+ if ((connection->Flags & CONNECTION_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ StCompleteSendIrp(
+ Irp,
+ connection->Status,
+ 0);
+ status = STATUS_PENDING;
+ } else {
+
+ StReferenceConnection ("Verify Temp Use", connection);
+
+ //
+ // Insert onto the send queue, and make the IRP
+ // cancellable.
+ //
+
+ InsertTailList (&connection->SendQueue,&Irp->Tail.Overlay.ListEntry);
+
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ Irp->CancelIrql = cancelirql;
+ StCancelSend((PDEVICE_OBJECT)(connection->Provider), Irp);
+ StDereferenceConnection ("IRP cancelled", connection); // release lookup hold.
+ return STATUS_PENDING;
+ }
+
+ Irp->CancelRoutine = StCancelSend;
+
+ //
+ // 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) {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // BUGBUG: Should we save status from real failure?
+ //
+
+ FailSend (connection, STATUS_LINK_FAILED, TRUE);
+
+ if ( (parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+ connection->Flags &= ~CONNECTION_FLAGS_FAILING_TO_EOR;
+ }
+
+ StDereferenceConnection ("Failing to EOR", connection); // 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.
+ //
+
+ 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)) &&
+ (!(connection->Flags & CONNECTION_FLAGS_STOPPING))) {
+
+ connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ PacketizeSend (connection);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StDereferenceConnection ("Stopping or already packetizing", connection); // release lookup hold.
+
+ }
+
+ 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 (connection, TRUE, oldirql, cancelirql);
+ break;
+
+ default:
+
+ //
+ // 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;
+ }
+ RELEASE_SPIN_LOCK (&connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ StDereferenceConnection("temp TdiSend", connection);
+
+ }
+
+ }
+
+ status = STATUS_PENDING;
+
+
+ return status;
+} /* TdiSend */
+
+
+NTSTATUS
+StTdiSendDatagram(
+ 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_REQUEST tpRequest;
+ PTP_ADDRESS_FILE addressFile;
+ PTP_ADDRESS address;
+ PMDL SendBuffer;
+ ULONG SendBufferLength;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_REQUEST_KERNEL_SENDDG parameters;
+ LARGE_INTEGER timeout = {0,0};
+ UINT MaxUserData;
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+ addressFile = irpSp->FileObject->FsContext;
+
+ status = StVerifyAddressObject (addressFile);
+ if (!NT_SUCCESS (status)) {
+ return status;
+ }
+
+ address = addressFile->Address;
+ parameters = (PTDI_REQUEST_KERNEL_SENDDG)(&irpSp->Parameters);
+ SendBuffer = Irp->MdlAddress;
+ SendBufferLength = parameters->SendLength;
+
+ //
+ // Check that the length is short enough.
+ //
+
+ MacReturnMaxDataSize(
+ &address->Provider->MacInfo,
+ NULL,
+ 0,
+ address->Provider->MaxSendPacketSize,
+ &MaxUserData);
+
+ if (SendBufferLength >
+ (MaxUserData - sizeof(ST_HEADER))) {
+
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // We need a request object to keep track of this TDI request.
+ // Attach this request to the address object.
+ //
+
+ status = StCreateRequest (
+ Irp, // IRP for this request.
+ address, // context.
+ REQUEST_FLAGS_ADDRESS, // partial flags.
+ SendBuffer, // the data to be sent.
+ SendBufferLength, // length of the data.
+ timeout,
+ &tpRequest);
+
+ if (!NT_SUCCESS (status)) {
+ StDereferenceAddress ("no send request", address);
+ return status; // if we couldn't queue the request.
+ }
+
+ StReferenceAddress ("Send datagram", address);
+ tpRequest->Owner = AddressType;
+
+ ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
+
+ if ((address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
+ StCompleteRequest (tpRequest, STATUS_NETWORK_NAME_DELETED, 0);
+ return STATUS_PENDING;
+ } else {
+ InsertTailList (
+ &address->SendDatagramQueue,
+ &tpRequest->Linkage);
+ 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 ST datagram header needs to be statically
+ // allocated for reuse by all send datagram requests.
+ //
+
+ (VOID)StSendDatagramsOnAddress (address);
+
+ StDereferenceAddress("tmp send datagram", address);
+
+ return STATUS_PENDING;
+
+} /* StTdiSendDatagram */
diff --git a/private/ntos/tdi/st/sendeng.c b/private/ntos/tdi/st/sendeng.c
new file mode 100644
index 000000000..4019291de
--- /dev/null
+++ b/private/ntos/tdi/st/sendeng.c
@@ -0,0 +1,1505 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sendeng.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ Sample transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+#if 27
+ULONG StNoisySend = 0;
+ULONG StSndLoc = 0;
+ULONG StSnds[10];
+#endif
+
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate,
+ IN KIRQL ConnectionIrql,
+ IN KIRQL CancelIrql
+ )
+
+/*++
+
+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 spin lock must be held on entry to this routine.
+ Optionally, the cancel spin lock may be held. If so, the cancel
+ spin lock must have been acquired first.
+
+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.
+
+ ConnectionIrql - The OldIrql value when the connection spin lock
+ was acquired.
+
+ CancelIrql - The OldIrql value when the cancel spin lock was
+ acquired. -1 means that the cancel spin lock isn't held.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ 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_STOPPING))) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ if (!Immediate) {
+ StReferenceConnection ("Packetize", Connection);
+ }
+
+ ExInterlockedInsertTailList(
+ &DeviceContext->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &DeviceContext->SpinLock);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, ConnectionIrql);
+ if (Immediate) {
+ StDereferenceConnection("temp TdiSend", Connection);
+ }
+ }
+
+ if (CancelIrql != (KIRQL)-1) {
+ IoReleaseCancelSpinLock (CancelIrql);
+ }
+
+ if (Immediate) {
+ PacketizeConnections (DeviceContext);
+ }
+
+} /* StartPacketizingConnection */
+
+
+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;
+
+ //
+ // 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);
+ PacketizeSend (Connection);
+ }
+
+} /* PacketizeConnections */
+
+
+VOID
+PacketizeSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+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.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1;
+ ULONG MaxFrameSize, FrameSize;
+ ULONG PacketBytes;
+ TP_SEND_POINTER SavedSendPointer;
+ PNDIS_BUFFER PacketDescriptor;
+ PUCHAR SourceRouting;
+ UINT SourceRoutingLength;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_PACKET Packet;
+ NTSTATUS Status;
+ PST_HEADER StHeader;
+ UINT HeaderLength;
+ PIO_STACK_LOCATION IrpSp;
+ PSEND_PACKET_TAG SendTag;
+ ULONG LastPacketLength;
+
+ DeviceContext = Connection->Provider;
+
+ //
+ // Just loop until one of three events happens: (1) we run out of
+ // packets from StCreatePacket, (2) we completely packetize the send.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ if (Connection->SendState != CONNECTION_SENDSTATE_PACKETIZE) {
+ Connection->Flags &= ~CONNECTION_FLAGS_PACKETIZE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ StDereferenceConnection ("No longer packetizing", Connection);
+ return;
+ }
+
+ MaxFrameSize = Connection->MaximumDataSize;
+
+ //
+ // 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 (StCreatePacket (DeviceContext, &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 StDestroyPacket 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.
+ //
+
+ 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;
+
+ if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
+ Connection->Flags |= CONNECTION_FLAGS_SUSPENDED;
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
+ InsertTailList (&DeviceContext->PacketWaitQueue, &Connection->PacketWaitLinkage);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ StDereferenceConnection ("No packet", Connection);
+ return;
+
+ }
+
+ //
+ // Add a reference count to the IRP, and keep track of
+ // which request it is. Send completion will remove the
+ // reference.
+
+ IrpSp = IoGetCurrentIrpStackLocation(Connection->sp.CurrentSendIrp);
+
+ SendTag = (PSEND_PACKET_TAG)(Packet->NdisPacket->ProtocolReserved);
+ SendTag->Type = TYPE_I_FRAME;
+ SendTag->Packet = Packet;
+ SendTag->Owner = (PVOID)IrpSp;
+
+ Packet->CompleteSend = FALSE;
+
+
+ //
+ // Build the MAC header. All frames go out as
+ // single-route source routing.
+ //
+
+
+ MacReturnSingleRouteSR(
+ &DeviceContext->MacInfo,
+ &SourceRouting,
+ &SourceRoutingLength);
+
+ MacConstructHeader (
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ DeviceContext->MulticastAddress.Address,
+ DeviceContext->LocalAddress.Address,
+ sizeof(ST_HEADER),
+ SourceRouting,
+ SourceRoutingLength,
+ &HeaderLength);
+
+ //
+ // Build the header: 'I', dest, source
+ //
+
+ StHeader = (PST_HEADER)(&Packet->Header[HeaderLength]);
+
+ StHeader->Signature = ST_SIGNATURE;
+ StHeader->Command = ST_CMD_INFORMATION;
+ StHeader->Flags = 0;
+
+ RtlCopyMemory (StHeader->Destination, Connection->CalledAddress.NetbiosName, 16);
+ RtlCopyMemory (StHeader->Source, Connection->AddressFile->Address->NetworkName->NetbiosName, 16);
+
+ HeaderLength += sizeof(ST_HEADER);
+
+
+ //
+ // Modify the packet length and send the it.
+ //
+
+ StSetNdisPacketLength(Packet->NdisPacket, HeaderLength);
+
+ StReferenceSendIrp ("Packetize", IrpSp);
+
+ //
+ // Save our complex send pointer in case we have to restore it
+ // because StNdisSend fails.
+ //
+
+ SavedSendPointer = Connection->sp;
+
+ //
+ // 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;
+
+ }
+#if 27
+ if (StNoisySend) {
+ DbgPrint ("Send %d of %d\n", FrameSize, Connection->CurrentSendLength);
+ }
+ if (FrameSize > 1000) {
+ StSnds[StSndLoc] = FrameSize;
+ StSndLoc = (StSndLoc + 1) % 10;
+ }
+#endif
+
+
+ //
+ // 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;
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Status = BuildBufferChainFromMdlChain (
+ DeviceContext->NdisBufferPoolHandle,
+ Connection->sp.CurrentSendMdl,
+ Connection->sp.SendByteOffset,
+ FrameSize,
+ &PacketDescriptor,
+ &Connection->sp.CurrentSendMdl,
+ &Connection->sp.SendByteOffset,
+ &PacketBytes);
+
+ }
+
+ } else {
+
+ PacketBytes = 0;
+ Connection->sp.CurrentSendMdl = NULL;
+ Status = STATUS_SUCCESS;
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+
+ Connection->sp.MessageBytesSent += PacketBytes;
+
+ //
+ // Chain the buffers to the packet, unless there
+ // are zero bytes of data.
+ //
+
+ if (FrameSize != 0) {
+ NdisChainBufferAtBack (Packet->NdisPacket, PacketDescriptor);
+ }
+
+
+ //
+ // Have we run out of Mdl Chain in this request?
+ //
+
+ if ((PacketBytes < FrameSize) ||
+ (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 (!(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL)) {
+
+ //
+ // We are sending the last packet in a message. Change
+ // the packet type to a "last" frame.
+ //
+
+ StHeader->Flags |= ST_FLAGS_LAST;
+ Packet->CompleteSend = TRUE;
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+
+ } 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.
+ //
+
+ if (Connection->sp.CurrentSendIrp->Tail.Overlay.ListEntry.Flink == &Connection->SendQueue) {
+
+ Connection->SendState = CONNECTION_SENDSTATE_W_EOR;
+
+ } 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));
+ }
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ LastPacketLength = sizeof(ST_HEADER) + PacketBytes;
+
+ MacModifyHeader(
+ &DeviceContext->MacInfo,
+ Packet->Header,
+ LastPacketLength);
+
+ Packet->NdisIFrameLength = LastPacketLength;
+
+ StNdisSend (Packet);
+
+ //
+ // Update our counters (this is done unprotected by a lock).
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->IFrameBytesSent,
+ PacketBytes);
+ ++DeviceContext->IFramesSent;
+
+ } else {
+
+ //
+ // BuildBufferChainFromMdlChain failed; we need to
+ // release the lock since the long if() above
+ // exits with it released.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ }
+
+ //
+ // 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)) {
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // Restore old complex send pointer.
+ //
+
+ Connection->sp = SavedSendPointer;
+
+
+ //
+ // 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_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ StDestroyPacket (Packet);
+ StDereferenceSendIrp("Send failed", IrpSp);
+ StDereferenceConnection ("Send failed", Connection);
+
+ return;
+ }
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // It is probable that a 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_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ StDereferenceConnection ("PacketizeSend done", Connection);
+
+} /* PacketizeSend */
+
+
+VOID
+CompleteSend(
+ PTP_CONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to complete a TDI send back to the
+ caller. In the sample transport we assume that all sends
+ complete successfully, but in other transports we would
+ wait for a response from the remote.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+
+ //
+ // Pick off TP_REQUEST objects from the connection's SendQueue until
+ // we find one with an END_OF_RECORD mark embedded in it.
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ while (TRUE) {
+
+ //
+ // We know for a fact that we wouldn't be calling this routine if
+ // we hadn't completed sending an entire message, since we
+ // only set the ST_LAST bit in that case. 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.
+ //
+
+ if (Connection->SendQueue.Flink == &Connection->SendQueue) {
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // no requests to complete, things must have failed; just get out.
+ //
+
+ break;
+ }
+
+ p = RemoveHeadList (&Connection->SendQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ EndOfRecord = !(IRP_SEND_FLAGS(IrpSp) & TDI_SEND_PARTIAL);
+
+ Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // 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.
+ //
+
+ StCompleteSendIrp (
+ Irp,
+ STATUS_SUCCESS,
+ IRP_SEND_LENGTH(IrpSp));
+
+ if (EndOfRecord) {
+ break;
+ }
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ };
+
+ //
+ // Acquire the lock that we will return with.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ 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_STOPPING))) {
+
+ Connection->Flags |= CONNECTION_FLAGS_PACKETIZE;
+
+ StReferenceConnection ("Packetize", Connection);
+
+ ExInterlockedInsertTailList(
+ &Connection->Provider->PacketizeQueue,
+ &Connection->PacketizeLinkage,
+ &Connection->Provider->SpinLock);
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+} /* 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.
+
+Arguments:
+
+ Connection - Pointer to a TP_CONNECTION object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+ PLIST_ENTRY p;
+ BOOLEAN EndOfRecord;
+ BOOLEAN GotCurrent = FALSE;
+
+
+ //
+ // 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 ST does not provide stream mode sends.)
+ //
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ StReferenceConnection ("Failing Send", Connection);
+
+ 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);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ Irp->CancelRoutine = (PDRIVER_CANCEL)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.
+ //
+
+ StCompleteSendIrp (Irp, RequestStatus, 0);
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+ } while (!EndOfRecord & !GotCurrent);
+
+ //
+ // We've finished processing the current send. Update our state.
+ //
+
+ Connection->SendState = CONNECTION_SENDSTATE_IDLE;
+ Connection->sp.CurrentSendIrp = NULL;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+
+ if (StopConnection) {
+ StStopConnection (Connection, STATUS_LINK_FAILED);
+ }
+
+ StDereferenceConnection ("FailSend", Connection);
+
+} /* FailSend */
+
+
+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 (Connection->SendQueue.Flink != &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));
+
+ }
+} /* InitializeSend */
+
+
+VOID
+StCancelSend(
+ 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;
+ 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->SpinLock, &oldirql);
+ StReferenceConnection ("Cancelling Send", Connection);
+
+ 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.
+ //
+
+ p = RemoveHeadList (&Connection->SendQueue);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->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.
+ //
+
+ StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+
+ //
+ // Since we are cancelling the current send, blow away
+ // the connection.
+ //
+
+ StStopConnection (Connection, STATUS_CANCELLED);
+
+ } else {
+
+ //
+ // Scan through the list, looking for this IRP.
+ //
+
+ 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;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->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.
+ //
+
+ StCompleteSendIrp (SendIrp, STATUS_CANCELLED, 0);
+ break;
+
+ }
+
+ p = p->Flink;
+
+ }
+
+ if (!Found) {
+
+ //
+ // We didn't find it!
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ }
+
+ }
+
+ StDereferenceConnection ("Cancelling Send", Connection);
+
+}
+
+
+
+VOID
+StSendCompletionHandler(
+ 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 oldirql, cancelirql;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_CONNECTION Connection;
+ PLIST_ENTRY p;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_REQUEST request;
+ TA_NETBIOS_ADDRESS TempAddress;
+ ULONG returnLength;
+ NTSTATUS status;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+
+ UNREFERENCED_PARAMETER(ProtocolBindingContext);
+
+ SendContext = (PSEND_PACKET_TAG)&NdisPacket->ProtocolReserved[0];
+ Packet = SendContext->Packet;
+
+ DeviceContext = Packet->Provider;
+
+ Packet->PacketSent = TRUE;
+
+ switch (SendContext->Type) {
+
+ case TYPE_I_FRAME:
+
+ //
+ // Dereference the IRP that this packet was sent for.
+ //
+
+ IrpSp = (PIO_STACK_LOCATION)(SendContext->Owner);
+
+ if (Packet->CompleteSend) {
+ CompleteSend(IRP_CONNECTION(IrpSp));
+ }
+ StDereferenceSendIrp("Destroy packet", IrpSp);
+ break;
+
+ case TYPE_D_FRAME:
+
+ //
+ // Finish tearing down the connection.
+ //
+
+ StDereferenceConnection("Disconnect completed", (PTP_CONNECTION)(SendContext->Owner));
+ break;
+
+ case TYPE_G_FRAME:
+
+ //
+ // Addresses get their own frames; let the address know it's ok to
+ // use the frame again, and exit to avoid normal packet completion.
+ //
+
+ StSendDatagramCompletion ((PTP_ADDRESS)(SendContext->Owner),
+ NdisPacket,
+ NdisStatus);
+ return;
+
+ case TYPE_C_FRAME:
+
+ //
+ // Complete the TdiConnect request; note that he better
+ // have accepted it quickly since we will immediately
+ // start sending data if required.
+ //
+
+ Connection = (PTP_CONNECTION)(SendContext->Owner);
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+
+ //
+ // 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.
+ //
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ //
+ // Now complete the request and get out.
+ //
+
+ if (p == &Connection->InProgressRequest) {
+ Connection->IndicationInProgress = FALSE;
+ PANIC ("ProcessSessionConfirm: TdiConnect evaporated!\n");
+ IoReleaseCancelSpinLock (cancelirql);
+ break;
+ }
+
+ //
+ // We have a completed connection with a queued connect. Complete
+ // the connect.
+ //
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock(cancelirql);
+
+ IrpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&IrpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ RtlCopyMemory( Connection->RemoteName, Connection->CalledAddress.NetbiosName, 16 );
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ //
+ // Reference the connection so it stays around after
+ // the request is completed.
+ //
+
+ StReferenceConnection("Connect completed", Connection);
+
+ StCompleteRequest (request, status, returnLength);
+
+ break;
+
+ }
+
+ StDestroyPacket(Packet);
+
+} /* StSendCompletionHandler */
+
+
+VOID
+StNdisSend(
+ IN PTP_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends an NDIS packet
+ 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.
+
+Arguments:
+
+ Packet - Pointer to a TP_PACKET object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+
+ NdisSend (
+ &NdisStatus,
+ ((PDEVICE_CONTEXT)(Packet->Provider))->NdisBindingHandle,
+ Packet->NdisPacket);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ StSendCompletionHandler(
+ Packet->Provider,
+ Packet->NdisPacket,
+ NdisStatus);
+ }
+
+} /* StNdisSend */
+
+
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ 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;
+
+
+ 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,
+ BufferPoolHandle,
+ OldMdl,
+ ByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewByteOffset = ByteOffset;
+ *TrueLength = 0;
+ *Destination = NULL;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *Destination = NewNdisBuffer;
+
+ //
+ // 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)),
+ BufferPoolHandle,
+ 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 (*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/st/sources b/private/ntos/tdi/st/sources
new file mode 100644
index 000000000..f47518792
--- /dev/null
+++ b/private/ntos/tdi/st/sources
@@ -0,0 +1,62 @@
+!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=st
+
+TARGETNAME=st
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..\..\inc;..\..\..\inc
+
+SOURCES=\
+ address.c \
+ connect.c \
+ connobj.c \
+ devctx.c \
+ event.c \
+ framesnd.c \
+ iframes.c \
+ ind.c \
+ info.c \
+ packet.c \
+ rcv.c \
+ rcveng.c \
+ request.c \
+ send.c \
+ sendeng.c \
+ st.rc \
+ stcnfg.c \
+ stdrvr.c \
+ stmac.c \
+ stndis.c \
+ uframes.c
+
+!IFNDEF 386_WARNING_LEVEL
+386_WARNING_LEVEL=/W3
+!ENDIF
diff --git a/private/ntos/tdi/st/st.h b/private/ntos/tdi/st/st.h
new file mode 100644
index 000000000..590ccac89
--- /dev/null
+++ b/private/ntos/tdi/st/st.h
@@ -0,0 +1,46 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ st.h
+
+Abstract:
+
+ Private include file for the NT Sample transport provider.
+
+Revision History:
+
+--*/
+
+#ifndef _ST_
+#define _ST_
+
+#include <ntddk.h>
+
+#include <windef.h> // these two are needed by info.c
+#include <nb30.h>
+
+#include <tdikrnl.h> // Transport Driver Interface.
+#include <ndis.h> // Network Driver Interface.
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+#include "stconst.h" // private constants.
+#include "stmac.h" // mac-specific definitions
+#include "sthdrs.h" // private protocol headers.
+#include "sttypes.h" // private types.
+#include "stcnfg.h" // configuration information.
+#include "stprocs.h" // private function prototypes.
+
+
+#define ACQUIRE_SPIN_LOCK(lock,irql) KeAcquireSpinLock(lock,irql)
+#define RELEASE_SPIN_LOCK(lock,irql) KeReleaseSpinLock(lock,irql)
+
+
+#endif // def _ST_
diff --git a/private/ntos/tdi/st/st.rc b/private/ntos/tdi/st/st.rc
new file mode 100644
index 000000000..591897aa9
--- /dev/null
+++ b/private/ntos/tdi/st/st.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 "Sample TDI 3.0 Transport Driver"
+#define VER_INTERNALNAME_STR "st.sys"
+#define VER_ORIGINALFILENAME_STR "st.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/st/stcnfg.c b/private/ntos/tdi/st/stcnfg.c
new file mode 100644
index 000000000..40438eedb
--- /dev/null
+++ b/private/ntos/tdi/st/stcnfg.c
@@ -0,0 +1,1277 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stcnfg.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of ST.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ );
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+StOpenParametersKey(
+ IN HANDLE StConfigHandle,
+ OUT PHANDLE ParametersHandle
+ );
+
+VOID
+StCloseParametersKey(
+ IN HANDLE ParametersHandle
+ );
+
+NTSTATUS
+StCountEntries(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+StAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+StAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+VOID
+StReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ );
+
+UINT
+StReadSizeInformation(
+ IN HANDLE ParametersHandle
+ );
+
+ULONG
+StReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ );
+
+VOID
+StWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ );
+
+VOID
+StSaveConfigInRegistry(
+ IN HANDLE ParametersHandle,
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+UINT
+StWstrLength(
+ IN PWSTR Wstr
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,StWstrLength)
+#pragma alloc_text(INIT,StConfigureTransport)
+#pragma alloc_text(INIT,StFreeConfigurationInfo)
+#pragma alloc_text(INIT,StOpenParametersKey)
+#pragma alloc_text(INIT,StCloseParametersKey)
+#pragma alloc_text(INIT,StCountEntries)
+#pragma alloc_text(INIT,StAddBind)
+#pragma alloc_text(INIT,StAddExport)
+#pragma alloc_text(INIT,StReadLinkageInformation)
+#pragma alloc_text(INIT,StReadSingleParameter)
+#pragma alloc_text(INIT,StWriteSingleParameter)
+#pragma alloc_text(INIT,StSaveConfigInRegistry)
+#endif
+
+
+UINT
+StWstrLength(
+ 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 = StWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
+ if (_S != NULL) { \
+ RtlCopyMemory(_S, _N, _L); \
+ RtlInitUnicodeString (&(ConfigurationInfo)->Names[Subscript], _S); \
+ } \
+}
+
+#define InsertDevice(ConfigurationInfo, Subscript, Name) \
+{ \
+ PWSTR _S; \
+ PWSTR _N = (Name); \
+ UINT _L = StWstrLength(_N)+sizeof(WCHAR); \
+ _S = (PWSTR)ExAllocatePool(NonPagedPool, _L); \
+ 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_) STATIC WCHAR Str ## _str_[] = L#_str_
+
+DECLARE_STRING(Large);
+DECLARE_STRING(Medium);
+DECLARE_STRING(Small);
+
+DECLARE_STRING(InitRequests);
+DECLARE_STRING(InitConnections);
+DECLARE_STRING(InitAddressFiles);
+DECLARE_STRING(InitAddresses);
+
+DECLARE_STRING(MaxRequests);
+DECLARE_STRING(MaxConnections);
+DECLARE_STRING(MaxAddressFiles);
+DECLARE_STRING(MaxAddresses);
+
+DECLARE_STRING(InitPackets);
+DECLARE_STRING(InitReceivePackets);
+DECLARE_STRING(InitReceiveBuffers);
+
+DECLARE_STRING(SendPacketPoolSize);
+DECLARE_STRING(ReceivePacketPoolSize);
+DECLARE_STRING(MaxMemoryUsage);
+
+
+#define READ_HIDDEN_CONFIG(_Field) \
+{ \
+ ConfigurationInfo->_Field = \
+ StReadSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+#define WRITE_HIDDEN_CONFIG(_Field) \
+{ \
+ StWriteSingleParameter( \
+ ParametersHandle, \
+ Str ## _Field, \
+ ConfigurationInfo->_Field); \
+}
+
+
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigurationInfoPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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 ST'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;
+ UINT StSize;
+ HANDLE StConfigHandle;
+ NTSTATUS Status;
+ ULONG Disposition;
+ PWSTR RegistryPathBuffer;
+ OBJECT_ATTRIBUTES TmpObjectAttributes;
+ PCONFIG_DATA ConfigurationInfo;
+
+
+ //
+ // Open the registry.
+ //
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ RegistryPath, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ NULL, // root
+ NULL // security descriptor
+ );
+
+ Status = ZwCreateKey(
+ &StConfigHandle,
+ KEY_WRITE,
+ &TmpObjectAttributes,
+ 0, // title index
+ NULL, // class
+ 0, // create options
+ &Disposition); // disposition
+
+ if (!NT_SUCCESS(Status)) {
+ StPrint1("ST: Could not open/create ST key: %lx\n", Status);
+ return Status;
+ }
+
+
+ OpenStatus = StOpenParametersKey (StConfigHandle, &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).
+ //
+ // StReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)ExAllocatePool(
+ NonPagedPool,
+ RegistryPath->Length + sizeof(WCHAR));
+ if (RegistryPathBuffer == NULL) {
+ StCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ StReadLinkageInformation (RegistryPathBuffer, ConfigurationInfoPtr);
+
+ if (*ConfigurationInfoPtr == NULL) {
+ ExFreePool (RegistryPathBuffer);
+ StCloseParametersKey (ParametersHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ ConfigurationInfo = *ConfigurationInfoPtr;
+
+
+ //
+ // Read the size parameter; this returns 0 if none is
+ // present, or 1 (Small), 2 (Medium) and 3 (Large).
+ //
+
+ StSize = StReadSizeInformation (ParametersHandle);
+
+ switch (StSize) {
+
+ case 0:
+ case 1:
+
+ //
+ // Default is Small.
+ //
+
+ //
+ // These are the initial value used; the comment after
+ // each one shows the expected maximum (if every resource
+ // is at the expected maximum, ST should be very close
+ // to being out of memory).
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 5; // 30
+ ConfigurationInfo->InitConnections = 1; // 10
+ ConfigurationInfo->InitAddressFiles = 0; // 10
+ ConfigurationInfo->InitAddresses = 0; // 10
+
+ //
+ // 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 + conn (40)
+ ConfigurationInfo->InitReceivePackets = 10; // + link + addr (30)
+ ConfigurationInfo->InitReceiveBuffers = 5; // + addr (15)
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 100;
+ ConfigurationInfo->ReceivePacketPoolSize = 30;
+ ConfigurationInfo->MaxMemoryUsage = 100000;
+
+ break;
+
+ case 2:
+
+ //
+ // Medium ST.
+ //
+
+ //
+ // These are the initial value used; the comment after
+ // each one shows the expected maximum (if every resource
+ // is at the expected maximum, ST should be very close
+ // to being out of memory).
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 10; // 100
+ ConfigurationInfo->InitConnections = 2; // 64
+ ConfigurationInfo->InitAddressFiles = 1; // 20
+ ConfigurationInfo->InitAddresses = 1; // 20
+
+ //
+ // 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 = 50; // + link + conn (150)
+ ConfigurationInfo->InitReceivePackets = 15; // + link + addr (100)
+ ConfigurationInfo->InitReceiveBuffers = 10; // + addr (30)
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 250;
+ ConfigurationInfo->ReceivePacketPoolSize = 100;
+ ConfigurationInfo->MaxMemoryUsage = 250000;
+
+ break;
+
+ case 3:
+
+ //
+ // Big ST.
+ //
+
+ //
+ // These are the initial value used.
+ //
+ // For now the "Max" values default to 0 (no limit).
+ //
+
+ ConfigurationInfo->InitRequests = 15;
+ ConfigurationInfo->InitConnections = 3;
+ ConfigurationInfo->InitAddressFiles = 2;
+ ConfigurationInfo->InitAddresses = 2;
+
+ //
+ // 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 = 75; // + link + conn
+ ConfigurationInfo->InitReceivePackets = 25; // + link + addr
+ ConfigurationInfo->InitReceiveBuffers = 20; // + addr
+
+ //
+ // Set the size of the packet pools and the total
+ // allocateable by ST.
+ //
+
+ ConfigurationInfo->SendPacketPoolSize = 500;
+ ConfigurationInfo->ReceivePacketPoolSize = 200;
+ ConfigurationInfo->MaxMemoryUsage = 0; // no limit
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ //
+ // 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 (InitConnections);
+ READ_HIDDEN_CONFIG (InitAddressFiles);
+ READ_HIDDEN_CONFIG (InitAddresses);
+
+ READ_HIDDEN_CONFIG (MaxRequests);
+ 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 (SendPacketPoolSize);
+ READ_HIDDEN_CONFIG (ReceivePacketPoolSize);
+ READ_HIDDEN_CONFIG (MaxMemoryUsage);
+
+
+ //
+ // Now that we are completely configured, save the information
+ // in the registry.
+ //
+
+ StSaveConfigInRegistry (ParametersHandle, ConfigurationInfo);
+
+ ExFreePool (RegistryPathBuffer);
+ StCloseParametersKey (ParametersHandle);
+ ZwClose (StConfigHandle);
+
+ return STATUS_SUCCESS;
+
+} /* StConfigureTransport */
+
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to get free any storage that was allocated
+ by StConfigureTransport 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);
+
+} /* StFreeConfigurationInfo */
+
+
+NTSTATUS
+StOpenParametersKey(
+ IN HANDLE StConfigHandle,
+ OUT PHANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to open the ST "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 ST parameters key.
+ //
+
+ RtlInitUnicodeString (&ParametersKeyName, ParametersString);
+
+ InitializeObjectAttributes(
+ &TmpObjectAttributes,
+ &ParametersKeyName, // name
+ OBJ_CASE_INSENSITIVE, // attributes
+ StConfigHandle, // root
+ NULL // security descriptor
+ );
+
+
+ Status = ZwOpenKey(
+ &ParamHandle,
+ KEY_READ,
+ &TmpObjectAttributes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ StPrint1("Could not open parameters key: %lx\n", Status);
+ return Status;
+
+ }
+
+ *ParametersHandle = ParamHandle;
+
+
+ //
+ // All keys successfully opened or created.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* StOpenParametersKey */
+
+VOID
+StCloseParametersKey(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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);
+
+} /* StCloseParametersKey */
+
+
+NTSTATUS
+StCountEntries(
+ 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;
+
+ ASSERT (ValueType == REG_MULTI_SZ);
+
+ //
+ // 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 = ExAllocatePool(
+ NonPagedPool,
+ sizeof (CONFIG_DATA) +
+ ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ if (*ConfigurationInfo == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(
+ *ConfigurationInfo,
+ sizeof(CONFIG_DATA) + ((*TotalCount-1) * sizeof(NDIS_STRING)));
+
+ (*ConfigurationInfo)->DevicesOffset = OldTotalCount;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* StCountEntries */
+
+
+NTSTATUS
+StAddBind(
+ 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;
+
+} /* StAddBind */
+
+
+NTSTATUS
+StAddExport(
+ 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;
+
+} /* StAddExport */
+
+
+VOID
+StReadLinkageInformation(
+ IN PWSTR RegistryPathBuffer,
+ IN PCONFIG_DATA * ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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 ST.
+
+Arguments:
+
+ RegistryPathBuffer - The null-terminated root of the ST registry tree.
+
+ ConfigurationInfo - Returns ST'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 ST
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call StCountEntries for the "Bind" multi-string
+ //
+
+ QueryTable[1].QueryRoutine = StCountEntries;
+ 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 StCountEntries for the "Export" multi-string
+ //
+
+ QueryTable[2].QueryRoutine = StCountEntries;
+ 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 StAddBind for each string in "Bind"
+ //
+
+ QueryTable[3].QueryRoutine = StAddBind;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = Bind;
+ QueryTable[3].EntryContext = (PVOID)&BindCount;
+ QueryTable[3].DefaultType = REG_NONE;
+
+ //
+ // 5) Call StAddExport for each string in "Export"
+ //
+
+ QueryTable[4].QueryRoutine = StAddExport;
+ 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;
+
+} /* StReadLinkageInformation */
+
+
+UINT
+StReadSizeInformation(
+ IN HANDLE ParametersHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to read the Size information
+ from the registry.
+
+Arguments:
+
+ RegistryHandle - A pointer to the open registry.
+
+Return Value:
+
+ 0 - no Size specified
+ 1 - Small
+ 2 - Medium
+ 3 - Big / Large
+
+--*/
+
+{
+
+ UINT SizeToReturn;
+// STRING KeywordName;
+// PCONFIG_KEYWORD Keyword;
+
+ ULONG InformationBuffer[16]; // declare ULONG to get it aligned
+ PKEY_VALUE_FULL_INFORMATION Information =
+ (PKEY_VALUE_FULL_INFORMATION)InformationBuffer;
+ ULONG InformationLength;
+ WCHAR SizeString[] = L"Size";
+ UNICODE_STRING SizeValueName;
+ NTSTATUS Status;
+ PUCHAR InformationData;
+ ULONG InformationLong;
+
+
+ //
+ // Read the size parameter out of the registry.
+ //
+
+ RtlInitUnicodeString (&SizeValueName, SizeString);
+
+ Status = ZwQueryValueKey(
+ ParametersHandle,
+ &SizeValueName,
+ KeyValueFullInformation,
+ (PVOID)Information,
+ sizeof (InformationBuffer),
+ &InformationLength);
+
+ //
+ // Compare to the expected values.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ InformationData = ((PUCHAR)Information) + Information->DataOffset;
+ InformationLong = *((PULONG)InformationData);
+
+ if ((Information->DataLength == sizeof(ULONG)) &&
+ (InformationLong >= 1 && InformationLong <= 3)) {
+
+ SizeToReturn = InformationLong;
+
+ } else {
+
+ if ((Information->DataLength >= 10) &&
+ (RtlEqualMemory (StrLarge, InformationData, 10))) {
+
+ SizeToReturn = 3;
+
+ } else if ((Information->DataLength >= 12) &&
+ (RtlEqualMemory (StrMedium, InformationData, 12))) {
+
+ SizeToReturn = 2;
+
+ } else if ((Information->DataLength >= 10) &&
+ (RtlEqualMemory (StrSmall, InformationData, 10))) {
+
+ SizeToReturn = 1;
+
+ } else {
+
+ SizeToReturn = 0;
+
+ }
+
+ }
+
+ } else {
+
+ SizeToReturn = 0;
+
+ }
+
+ return SizeToReturn;
+
+} /* StReadSizeInformation */
+
+
+ULONG
+StReadSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG DefaultValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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[16]; // 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;
+
+} /* StReadSingleParameter */
+
+
+VOID
+StWriteSingleParameter(
+ IN HANDLE ParametersHandle,
+ IN PWCHAR ValueName,
+ IN ULONG ValueData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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)) {
+ StPrint1("ST: Could not write dword key: %lx\n", Status);
+ }
+
+} /* StWriteSingleParameter */
+
+
+VOID
+StSaveConfigInRegistry(
+ IN HANDLE ParametersHandle,
+ IN PCONFIG_DATA ConfigurationInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by ST to save its configuraition
+ information in the registry. It saves the information if
+ the registry structure did not exist before this boot.
+
+Arguments:
+
+ ParametersHandle - The handle used to read other parameters.
+
+ ConfigurationInfo - Describes ST's current configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Save the "hidden" parameters, these may not exist in
+ // the registry.
+ //
+ // NOTE: These macros expect "ConfigurationInfo" and
+ // "ParametersHandle" to exist when they are expanded.
+ //
+
+ //
+ // 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 (MaxConnections);
+ WRITE_HIDDEN_CONFIG (MaxAddressFiles);
+ WRITE_HIDDEN_CONFIG (MaxAddresses);
+
+} /* StSaveConfigInRegistry */
+
diff --git a/private/ntos/tdi/st/stcnfg.h b/private/ntos/tdi/st/stcnfg.h
new file mode 100644
index 000000000..d09098a6c
--- /dev/null
+++ b/private/ntos/tdi/st/stcnfg.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stcnfg.h
+
+Abstract:
+
+ Private include file for the NT Sample transport. This
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+#ifndef _STCONFIG_
+#define _STCONFIG_
+
+//
+// configuration structure.
+//
+
+typedef struct {
+
+ ULONG InitRequests;
+ ULONG InitConnections;
+ ULONG InitAddressFiles;
+ ULONG InitAddresses;
+ ULONG MaxRequests;
+ ULONG MaxConnections;
+ ULONG MaxAddressFiles;
+ ULONG MaxAddresses;
+ ULONG InitPackets;
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG SendPacketPoolSize;
+ ULONG ReceivePacketPoolSize;
+ ULONG MaxMemoryUsage;
+
+ //
+ // 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/st/stconst.h b/private/ntos/tdi/st/stconst.h
new file mode 100644
index 000000000..45837dc71
--- /dev/null
+++ b/private/ntos/tdi/st/stconst.h
@@ -0,0 +1,127 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stconst.h
+
+Abstract:
+
+ This header file defines manifest constants for the NT Sample transport
+ provider. It is included by st.h.
+
+Revision History:
+
+--*/
+
+#ifndef _STCONST_
+#define _STCONST_
+
+
+//
+// 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
+
+
+//
+// MAJOR PROTOCOL IDENTIFIERS THAT CHARACTERIZE THIS DRIVER.
+//
+
+#define ST_DEVICE_NAME "\\Device\\St" // name of our driver.
+#define ST_DEVICE_NAME_LENGTH 10
+#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 ST_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
+
+
+//
+// NETBIOS PROTOCOL CONSTANTS.
+//
+
+//
+// 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 ST_MAX_TSDU_SIZE 65535 // maximum TSDU size supported by NetBIOS.
+#define ST_MAX_DATAGRAM_SIZE 512 // maximum Datagram size supported by NetBIOS.
+#define ST_MAX_CONNECTION_USER_DATA 0 // no user data supported on connect.
+#define ST_SERVICE_FLAGS ( \
+ TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_CONNECTIONLESS_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY | \
+ TDI_SERVICE_BROADCAST_SUPPORTED | \
+ TDI_SERVICE_MULTICAST_SUPPORTED | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE )
+
+#define ST_MIN_LOOKAHEAD_DATA 256 // minimum guaranteed lookahead data.
+#define ST_MAX_LOOKAHEAD_DATA 256 // maximum guaranteed lookahead data.
+
+#define ST_MAX_LOOPBACK_LOOKAHEAD 192 // how much is copied over for loopback
+
+//
+// Number of TDI resources that we report.
+//
+
+#define ST_TDI_RESOURCES 7
+
+
+//
+// More debugging stuff
+//
+
+#define ST_REQUEST_SIGNATURE ((CSHORT)0x5501)
+#define ST_CONNECTION_SIGNATURE ((CSHORT)0x5502)
+#define ST_ADDRESSFILE_SIGNATURE ((CSHORT)0x5503)
+#define ST_ADDRESS_SIGNATURE ((CSHORT)0x5504)
+#define ST_DEVICE_CONTEXT_SIGNATURE ((CSHORT)0x5505)
+#define ST_PACKET_SIGNATURE ((CSHORT)0x5506)
+
+#endif // _STCONST_
diff --git a/private/ntos/tdi/st/stdrvr.c b/private/ntos/tdi/st/stdrvr.c
new file mode 100644
index 000000000..d04fcd2a1
--- /dev/null
+++ b/private/ntos/tdi/st/stdrvr.c
@@ -0,0 +1,1627 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stdrvr.c
+
+Abstract:
+
+ This module contains code which defines the NT Sample
+ transport provider's device object.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "st.h"
+
+
+//
+// This is a list of all the device contexts that ST owns,
+// used while unloading.
+//
+
+LIST_ENTRY StDeviceList = {0,0}; // initialized for real at runtime.
+
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+StUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+StConfigureTransport (
+ IN PUNICODE_STRING RegistryPath,
+ IN PCONFIG_DATA * ConfigData
+ );
+
+VOID
+StFreeConfigurationInfo (
+ IN PCONFIG_DATA ConfigurationInfo
+ );
+
+NTSTATUS
+StDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StOpenAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StCloseAddress(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StOpenConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StCloseConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+NTSTATUS
+StTdiAccept(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiConnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiDisconnect(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiDisassociateAddress (
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiAssociateAddress(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiListen(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiQueryInformation(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiReceive(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiReceiveDatagram(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSend(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSendDatagram(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSetEventHandler(
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StTdiSetInformation(
+ IN PIRP Irp
+ );
+
+VOID
+StDeallocateResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the sample
+ 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 ST's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ ULONG i, j;
+ STRING nameString;
+ PDEVICE_CONTEXT DeviceContext;
+ PTP_REQUEST Request;
+ PTP_CONNECTION Connection;
+ PTP_ADDRESS_FILE AddressFile;
+ PTP_ADDRESS Address;
+ PTP_PACKET Packet;
+ PNDIS_PACKET NdisPacket;
+ PRECEIVE_PACKET_TAG ReceiveTag;
+ PBUFFER_TAG BufferTag;
+ NTSTATUS status;
+ UINT SuccessfulOpens;
+ UINT MaxUserData;
+
+ PCONFIG_DATA StConfig = NULL;
+
+
+ ASSERT (sizeof (SHORT) == 2);
+
+ //
+ // This allocates the CONFIG_DATA structure and returns
+ // it in StConfig.
+ //
+
+ status = StConfigureTransport(RegistryPath, &StConfig);
+
+ if (!NT_SUCCESS (status)) {
+ PANIC (" Failed to initialize transport, St initialization failed.\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ RtlInitString( &nameString, ST_DEVICE_NAME );
+
+ status = StRegisterProtocol (&nameString);
+
+ if (!NT_SUCCESS (status)) {
+
+ StFreeConfigurationInfo(StConfig);
+ PANIC ("StInitialize: RegisterProtocol failed!\n");
+
+ StWriteGeneralErrorLog(
+ (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] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = StDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = StDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = StDispatch;
+
+ DriverObject->DriverUnload = StUnload;
+
+ //
+ // Initialize the global list of devices.
+ //
+
+ InitializeListHead (&StDeviceList);
+
+ SuccessfulOpens = 0;
+
+ for (j=0;j<StConfig->NumAdapters;j++ ) {
+
+
+ //
+ // Loop through all the adapters that are in the configuration
+ // information structure. Allocate a device object for each
+ // one that we find.
+ //
+
+ status = StCreateDeviceContext (DriverObject, &StConfig->Names[StConfig->DevicesOffset+j], &DeviceContext);
+
+ if (!NT_SUCCESS (status)) {
+ continue;
+ }
+
+ //
+ // Initialize our counter that records memory usage.
+ //
+
+ DeviceContext->MemoryUsage = 0;
+ DeviceContext->MemoryLimit = StConfig->MaxMemoryUsage;
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = StInitializeNdis (DeviceContext,
+ StConfig,
+ j);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ StWriteGeneralErrorLog(
+ DeviceContext,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ StConfig->Names[j].Buffer,
+ 0,
+ NULL);
+
+ StDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext);
+ continue;
+
+ }
+
+
+ //
+ // 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,
+ &MaxUserData);
+
+ DeviceContext->Information.Version = 0x0100;
+ DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
+ DeviceContext->Information.MaxConnectionUserData = 0;
+ DeviceContext->Information.MaxDatagramSize = MaxUserData - sizeof(ST_HEADER);
+ DeviceContext->Information.ServiceFlags = ST_SERVICE_FLAGS;
+ DeviceContext->Information.MinimumLookaheadData = 128;
+ DeviceContext->Information.MaximumLookaheadData =
+ DeviceContext->MaxReceivePacketSize - sizeof(ST_HEADER);
+ DeviceContext->Information.NumberOfResources = ST_TDI_RESOURCES;
+ KeQuerySystemTime (&DeviceContext->Information.StartTime);
+
+
+ //
+ // Allocate various structures we will need.
+ //
+
+
+ //
+ // 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.
+ //
+
+ DeviceContext->PacketHeaderLength =
+ DeviceContext->MacInfo.MaxHeaderLength +
+ sizeof (ST_HEADER);
+
+ 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]);
+
+
+ for (i=0; i<StConfig->InitRequests; i++) {
+
+ StAllocateRequest (DeviceContext, &Request);
+
+ if (Request == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate requests.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
+ }
+
+ DeviceContext->RequestInitAllocated = StConfig->InitRequests;
+ DeviceContext->RequestMaxAllocated = StConfig->MaxRequests;
+
+
+ for (i=0; i<StConfig->InitConnections; i++) {
+
+ StAllocateConnection (DeviceContext, &Connection);
+
+ if (Connection == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate connections.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
+ }
+
+ DeviceContext->ConnectionInitAllocated = StConfig->InitConnections;
+ DeviceContext->ConnectionMaxAllocated = StConfig->MaxConnections;
+
+
+ for (i=0; i<StConfig->InitAddressFiles; i++) {
+
+ StAllocateAddressFile (DeviceContext, &AddressFile);
+
+ if (AddressFile == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate Address Files.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
+ }
+
+ DeviceContext->AddressFileInitAllocated = StConfig->InitAddressFiles;
+ DeviceContext->AddressFileMaxAllocated = StConfig->MaxAddressFiles;
+
+
+ for (i=0; i<StConfig->InitAddresses; i++) {
+
+ StAllocateAddress (DeviceContext, &Address);
+ if (Address == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate addresses.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
+ }
+
+ DeviceContext->AddressInitAllocated = StConfig->InitAddresses;
+ DeviceContext->AddressMaxAllocated = StConfig->MaxAddresses;
+
+
+ for (i=0; i<StConfig->InitPackets; i++) {
+
+ StAllocateSendPacket (DeviceContext, &Packet);
+ if (Packet == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate packets.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
+ }
+
+ DeviceContext->PacketInitAllocated = StConfig->InitPackets;
+
+
+ for (i=0; i<StConfig->InitReceivePackets; i++) {
+
+ StAllocateReceivePacket (DeviceContext, &NdisPacket);
+
+ if (NdisPacket == NULL) {
+ PANIC ("StInitialize: insufficient memory to allocate packet MDLs.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
+ PushEntryList (&DeviceContext->ReceivePacketPool, (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage);
+
+ }
+
+ DeviceContext->ReceivePacketInitAllocated = StConfig->InitReceivePackets;
+
+
+ for (i=0; i<StConfig->InitReceiveBuffers; i++) {
+
+ StAllocateReceiveBuffer (DeviceContext, &BufferTag);
+
+ if (BufferTag == NULL) {
+ PANIC ("StInitialize: Unable to allocate receive packet.\n");
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ PushEntryList (&DeviceContext->ReceiveBufferPool, &BufferTag->Linkage);
+
+ }
+
+ DeviceContext->ReceiveBufferInitAllocated = StConfig->InitReceiveBuffers;
+
+
+ //
+ // Now link the device into the global list.
+ //
+
+ InsertTailList (&StDeviceList, &DeviceContext->Linkage);
+
+ DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
+
+ ++SuccessfulOpens;
+
+ continue;
+
+cleanup:
+
+ StWriteResourceErrorLog (DeviceContext, DeviceContext->MemoryUsage, 501);
+
+ //
+ // Cleanup whatever device context we were initializing
+ // when we failed.
+ //
+
+ StFreeResources (DeviceContext);
+ StCloseNdis (DeviceContext);
+ StDereferenceDeviceContext ("Load failed", DeviceContext);
+
+ }
+
+ StFreeConfigurationInfo(StConfig);
+
+ return ((SuccessfulOpens > 0) ? STATUS_SUCCESS : STATUS_DEVICE_DOES_NOT_EXIST);
+
+}
+
+VOID
+StUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample 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 ST 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);
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ while (!IsListEmpty (&StDeviceList)) {
+
+ p = RemoveHeadList (&StDeviceList);
+ DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
+
+ //
+ // Remove all the storage associated with the device.
+ //
+
+ StFreeResources (DeviceContext);
+
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ StCloseNdis (DeviceContext);
+
+ //
+ // And remove the creation reference from the device
+ // context.
+ //
+
+ StDereferenceDeviceContext ("Unload", DeviceContext);
+
+ }
+
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ StDeregisterProtocol();
+
+ return;
+
+}
+
+
+VOID
+StFreeResources (
+ IN PDEVICE_CONTEXT DeviceContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by ST 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_ADDRESS address;
+ PTP_CONNECTION connection;
+ PTP_REQUEST request;
+ PTP_ADDRESS_FILE addressFile;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+
+
+ //
+ // Clean up packet pool.
+ //
+
+ while ( DeviceContext->PacketPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ StDeallocateSendPacket (DeviceContext, packet);
+ }
+
+ //
+ // Clean up address pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressPool);
+ address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
+
+ StDeallocateAddress (DeviceContext, address);
+ }
+
+ //
+ // Clean up address file pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
+ p = RemoveHeadList (&DeviceContext->AddressFilePool);
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+
+ StDeallocateAddressFile (DeviceContext, addressFile);
+ }
+
+ //
+ // Clean up connection pool.
+ //
+
+ while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
+ p = RemoveHeadList (&DeviceContext->ConnectionPool);
+ connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
+
+ StDeallocateConnection (DeviceContext, connection);
+ }
+
+ //
+ // Clean up request pool.
+ //
+
+ while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
+ p = RemoveHeadList( &DeviceContext->RequestPool );
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
+
+ StDeallocateRequest (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]);
+
+ StDeallocateReceivePacket (DeviceContext, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &DeviceContext->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ StDeallocateReceiveBuffer (DeviceContext, BufferTag);
+ }
+
+
+ return;
+
+} /* StFreeResources */
+
+
+NTSTATUS
+StDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST 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;
+
+ //
+ // Check to see if ST 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) {
+ 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:
+ Status = StDeviceControl (DeviceObject, Irp, IrpSp);
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+} /* StDispatch */
+
+
+NTSTATUS
+StDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST 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;
+
+ //
+ // Check to see if ST 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) {
+ 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:
+
+ 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 = StOpenAddress (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 = StOpenConnection (DeviceObject, Irp, IrpSp);
+ break;
+ }
+
+ } else {
+
+ 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)ST_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.
+ //
+
+ 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 StCloseAddress.
+ //
+
+ Status = StVerifyAddressObject(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = StCloseAddress (DeviceObject, Irp, IrpSp);
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ //
+ // This is a connection
+ //
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = StVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+
+ Status = StCloseConnection (DeviceObject, Irp, IrpSp);
+ StDereferenceConnection ("Temporary Use",Connection);
+
+ }
+
+ break;
+
+ case ST_FILE_TYPE_CONTROL:
+
+ //
+ // this always succeeds
+ //
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ 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.
+ //
+
+ switch ((ULONG)IrpSp->FileObject->FsContext2) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
+ Status = StVerifyAddressObject(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ StStopAddressFile (AddressFile, AddressFile->Address);
+ StDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
+ Status = StVerifyConnectionObject (Connection);
+ if (NT_SUCCESS (Status)) {
+ StStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
+ Status = STATUS_SUCCESS;
+ StDereferenceConnection ("Temporary Use",Connection);
+ }
+
+ break;
+
+ case ST_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+} /* StDispatchOpenClose */
+
+
+NTSTATUS
+StDeviceControl(
+ 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;
+
+
+ //
+ // 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) {
+
+ default:
+
+ //
+ // 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.
+ //
+ // StDispatchInternal expects to complete the IRP,
+ // so we change Status to PENDING so we don't.
+ //
+
+ (VOID)StDispatchInternal (DeviceObject, Irp);
+ Status = STATUS_PENDING;
+
+ }
+ }
+
+ return Status;
+} /* StDeviceControl */
+
+
+NTSTATUS
+StDispatchInternal (
+ 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;
+
+
+ //
+ // 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) {
+ 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;
+
+
+ //
+ // 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:
+ Status = StTdiAccept (Irp);
+ break;
+
+ case TDI_ACTION:
+ Status = STATUS_SUCCESS;
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+ Status = StTdiAssociateAddress (Irp);
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+ Status = StTdiDisassociateAddress (Irp);
+ break;
+
+ case TDI_CONNECT:
+ Status = StTdiConnect (Irp);
+ break;
+
+ case TDI_DISCONNECT:
+ Status = StTdiDisconnect (Irp);
+ break;
+
+ case TDI_LISTEN:
+ Status = StTdiListen (Irp);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = StTdiQueryInformation (DeviceContext, Irp);
+ break;
+
+ case TDI_RECEIVE:
+ Status = StTdiReceive (Irp);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = StTdiReceiveDatagram (Irp);
+ break;
+
+ case TDI_SEND:
+ Status = StTdiSend (Irp);
+ break;
+
+ case TDI_SEND_DATAGRAM:
+ Status = StTdiSendDatagram (Irp);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+
+ //
+ // 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 = StTdiSetEventHandler (Irp);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = StTdiSetInformation (Irp);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* StDispatchInternal */
+
+
+VOID
+StWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ DeviceContext - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ UINT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ DeviceContext->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)DeviceContext,
+ EntrySize
+ );
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--) {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ 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, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* StWriteResourceErrorLog */
+
+
+VOID
+StWriteGeneralErrorLog(
+ 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;
+ static WCHAR DriverName[3] = L"St";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceContext->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ 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, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* StWriteGeneralErrorLog */
+
+
+VOID
+StWriteOidErrorLog(
+ 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;
+ static WCHAR OidBuffer[9] = L"00000000";
+ UINT 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');
+ }
+ }
+
+ 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);
+
+ }
+
+} /* StWriteOidErrorLog */
diff --git a/private/ntos/tdi/st/sthdrs.h b/private/ntos/tdi/st/sthdrs.h
new file mode 100644
index 000000000..737832fc1
--- /dev/null
+++ b/private/ntos/tdi/st/sthdrs.h
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sthdrs.h
+
+Abstract:
+
+ This module defines private structure definitions describing the layout
+ of the NT Sample Transport frames.
+
+Revision History:
+
+--*/
+
+#ifndef _STHDRS_
+#define _STHDRS_
+
+//
+// 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 ST_SIGNATURE 0x37
+
+#define ST_CMD_CONNECT 'C'
+#define ST_CMD_DISCONNECT 'D'
+#define ST_CMD_INFORMATION 'I'
+#define ST_CMD_DATAGRAM 'G'
+
+#define ST_FLAGS_LAST 0x0001 // for information frames
+#define ST_FLAGS_BROADCAST 0x0002 // for datagrams
+
+typedef struct _ST_HEADER {
+ UCHAR Signature; // set to ST_SIGNATURE
+ UCHAR Command; // command byte
+ UCHAR Flags; // packet flags
+ UCHAR Reserved; // unused
+ UCHAR Destination[16]; // destination Netbios address
+ UCHAR Source[16]; // source Netbios address
+} ST_HEADER, *PST_HEADER;
+
+
+//
+// Resume previous structure packing method.
+//
+
+#ifdef PACKING
+
+#ifdef __STDC__
+#pragma Pop(Align_members)
+#else
+#pragma pack()
+#endif // def __STDC__
+
+#endif // def PACKING
+
+#endif // def _STHDRS_
diff --git a/private/ntos/tdi/st/stmac.c b/private/ntos/tdi/st/stmac.c
new file mode 100644
index 000000000..157c96a17
--- /dev/null
+++ b/private/ntos/tdi/st/stmac.c
@@ -0,0 +1,356 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbfmac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the ST transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+UCHAR SingleRouteSourceRouting[] = { 0xc2, 0x70 };
+UCHAR GeneralRouteSourceRouting[] = { 0x82, 0x70 };
+ULONG DefaultSourceRoutingLength = 2;
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ );
+
+//
+// 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(INIT,MacInitializeMacInfo)
+#pragma alloc_text(INIT,MacSetMulticastAddress)
+#endif
+
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ 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;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->DestinationOffset = 2;
+ MacInfo->SourceOffset = 8;
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->AddressLength = 6;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->DestinationOffset = 1;
+ MacInfo->SourceOffset = 7;
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->AddressLength = 6;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ default:
+ ASSERT(FALSE);
+ }
+}
+
+VOID
+MacConstructHeader (
+ IN PST_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 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 PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ 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 headers
+ 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.
+
+ 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 NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ 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 (DeviceMaxFrameSize < 548) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 516;
+ }
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ }
+}
+
+
+
+VOID
+MacSetMulticastAddress (
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the multicast 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 NdisMediumFddi:
+ Buffer[0] = 0x03;
+ Buffer[1] = 0x07;
+ Buffer[2] = 0x03;
+ Buffer[3] = 0x07;
+ Buffer[4] = 0x03;
+ Buffer[5] = 0x07;
+ break;
+
+ case NdisMedium802_5:
+ Buffer[0] = 0xc0;
+ Buffer[3] = 0x20;
+ break;
+
+ default:
+ PANIC ("MacSetMulticastAddress: PANIC! called with unsupported Mac type.\n");
+ }
+}
diff --git a/private/ntos/tdi/st/stmac.h b/private/ntos/tdi/st/stmac.h
new file mode 100644
index 000000000..cea2feff0
--- /dev/null
+++ b/private/ntos/tdi/st/stmac.h
@@ -0,0 +1,635 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stmac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+#ifndef _STMAC_
+#define _STMAC_
+
+//
+// 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 stmac routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _ST_NDIS_IDENTIFICATION {
+ NDIS_MEDIUM MediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ BOOLEAN CopyLookahead;
+ ULONG DestinationOffset;
+ ULONG SourceOffset;
+ ULONG AddressLength;
+ ULONG MaxHeaderLength;
+} ST_NDIS_IDENTIFICATION, *PST_NDIS_IDENTIFICATION;
+
+
+
+VOID
+MacConstructHeader(
+ IN PST_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 PST_NDIS_IDENTIFICATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PST_NDIS_IDENTIFICATION MacInfo
+ );
+
+
+extern UCHAR SingleRouteSourceRouting[];
+extern UCHAR GeneralRouteSourceRouting[];
+extern ULONG DefaultSourceRoutingLength;
+
+
+//++
+//
+// VOID
+// MacReturnDestinationAddress(
+// IN PST_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 PST_NDIS_IDENTIFICATION MacInfo,
+// IN PVOID Packet,
+// OUT PHARDWARE_ADDRESS SourceAddressBuffer,
+// OUT PHARDWARE_ADDRESS * SourceAddress,
+// );
+//
+// 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) \
+{ \
+ PUCHAR TmpPacket = (PUCHAR)(_Packet); \
+ PUCHAR SrcBuffer = (PUCHAR)(_SourceAddressBuffer); \
+ \
+ switch ((_MacInfo)->MediumType) { \
+ case NdisMedium802_5: \
+ *(PULONG)SrcBuffer = *(ULONG UNALIGNED *)(&TmpPacket[8]) & ~0x80;\
+ SrcBuffer[4] = TmpPacket[12]; \
+ SrcBuffer[5] = TmpPacket[13]; \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)SrcBuffer; \
+ break; \
+ default: \
+ *(_SourceAddress) = (PHARDWARE_ADDRESS)(TmpPacket + \
+ (_MacInfo)->SourceOffset); \
+ break; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacReturnSourceRouting(
+// IN PST_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); \
+ if ((_MacInfo)->SourceRouting) { \
+ if (TmpPacket[8] & 0x80) { \
+ *(_SourceRouting) = TmpPacket + 14; \
+ *(_SourceRoutingLength) = TmpPacket[14] & 0x1f; \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+ } else { \
+ *(_SourceRouting) = NULL; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnPacketLength(
+// IN PST_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) \
+{ \
+ 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; \
+ } \
+}
+
+//++
+//
+// VOID
+// MacReturnHeaderLength(
+// IN PST_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: \
+ *(_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 PST_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 PST_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 PST_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) | 0x70; \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+#endif
+
+
+//++
+//
+// VOID
+// MacCreateNonBroadcastReplySR(
+// IN PST_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) | 0x70; \
+ *(_NewSR) = (_ExistingSR); \
+ } \
+ break; \
+ default: \
+ *(_NewSR) = (_ExistingSR); \
+ break; \
+ } \
+ } else { \
+ *(_NewSR) = NULL; \
+ } \
+}
+
+
+//++
+//
+// VOID
+// MacModifyHeader(
+// IN PST_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; \
+ } \
+}
+
+
+VOID
+MacSetMulticastAddress(
+ IN NDIS_MEDIUM Type,
+ IN PUCHAR Buffer
+ );
+
+
+
+// VOID
+// StSetNdisPacketLength (
+// 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 StSetNdisPacketLength(_packet,_length) { \
+ PNDIS_BUFFER NdisBuffer; \
+ NdisQueryPacket((_packet), NULL, NULL, &NdisBuffer, NULL); \
+ NdisAdjustBufferLength(NdisBuffer, (_length)); \
+ NdisRecalculatePacketCounts(_packet); \
+}
+
+#endif // ifdef _STMAC_
+
diff --git a/private/ntos/tdi/st/stndis.c b/private/ntos/tdi/st/stndis.c
new file mode 100644
index 000000000..43279f815
--- /dev/null
+++ b/private/ntos/tdi/st/stndis.c
@@ -0,0 +1,986 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to interface
+ ST and NDIS. All callback routines (except for Transfer Data,
+ Send Complete, and ReceiveIndication) are here, as well as those routines
+ called to initialize NDIS.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "st.h"
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE StNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+StSubmitNdisRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,StRegisterProtocol)
+#pragma alloc_text(INIT,StSubmitNdisRequest)
+#pragma alloc_text(INIT,StInitializeNdis)
+#endif
+
+
+NTSTATUS
+StRegisterProtocol (
+ IN 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;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+
+ ProtChars.MajorNdisVersion = 3;
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name.Length = NameString->Length;
+ ProtChars.Name.Buffer = (PVOID)NameString->Buffer;
+
+ ProtChars.OpenAdapterCompleteHandler = StOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = StCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = StResetComplete;
+ ProtChars.RequestCompleteHandler = StRequestComplete;
+
+ ProtChars.SendCompleteHandler = StSendCompletionHandler;
+ ProtChars.TransferDataCompleteHandler = StTransferDataComplete;
+
+ ProtChars.ReceiveHandler = StReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = StReceiveComplete;
+ ProtChars.StatusHandler = StStatusIndication;
+ ProtChars.StatusCompleteHandler = StStatusComplete;
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &StNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+VOID
+StDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (StNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ StNdisProtocolHandle);
+ StNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+}
+
+
+NDIS_STATUS
+StSubmitNdisRequest(
+ 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) {
+
+ //
+ // 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) {
+
+ StWriteOidErrorLog(
+ 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
+StInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA StConfig,
+ 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 StSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi };
+ UINT SelectedMedium;
+ NDIS_REQUEST StRequest;
+ UCHAR StDataBuffer[6];
+ NDIS_OID StOid;
+ ULONG MinimumLookahead = 128 + sizeof(ST_HEADER);
+ ULONG ProtocolOptions, MacOptions;
+ PNDIS_STRING AdapterString;
+
+ //
+ // Initialize this adapter for ST 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)&StConfig->Names[ConfigInfoNameIndex];
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &DeviceContext->NdisBindingHandle,
+ &SelectedMedium,
+ StSupportedMedia,
+ sizeof (StSupportedMedia) / sizeof(NDIS_MEDIUM),
+ StNdisProtocolHandle,
+ (NDIS_HANDLE)DeviceContext,
+ AdapterString,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // 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) {
+
+ StWriteGeneralErrorLog(
+ 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(
+ StSupportedMedia[SelectedMedium],
+ &DeviceContext->MacInfo);
+
+
+ //
+ // Set the multicast/functional addresses first so we avoid windows where we
+ // receive only part of the addresses.
+ //
+
+ MacSetMulticastAddress (
+ DeviceContext->MacInfo.MediumType,
+ DeviceContext->MulticastAddress.Address);
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(StDataBuffer, DeviceContext->MulticastAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_802_3_MULTICAST_LIST;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.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 data for our functional address.
+ //
+
+ RtlCopyMemory(StDataBuffer, ((PUCHAR)(DeviceContext->MulticastAddress.Address)) + 2, 4);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = 4;
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // Fill in the data for our multicast list.
+ //
+
+ RtlCopyMemory(StDataBuffer, DeviceContext->MulticastAddress.Address, 6);
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_FDDI_LONG_MULTICAST_LIST;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = 6;
+
+ break;
+
+ }
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+
+ switch (DeviceContext->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ StOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ StOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ StOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = StOid;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = DeviceContext->LocalAddress.Address;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (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.
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxReceivePacketSize);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MaxSendPacketSize);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(DeviceContext->MediumSpeed);
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ StRequest.RequestType = NdisRequestQueryInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Since the sample transport does not try to optimize for the
+ // cases where transfer data is always synchronous or indications
+ // are not reentered, we ignore those bits in MacOptions.
+ //
+
+ DeviceContext->MacInfo.CopyLookahead =
+ (BOOLEAN)((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0);
+
+
+ //
+ // Now set our options if needed. We can only support
+ // partial indications if running over 802.3 where the
+ // real packet length can be obtained from the header.
+ //
+
+ if (DeviceContext->MacInfo.MediumType == NdisMedium802_3) {
+
+ ProtocolOptions = NDIS_PROT_OPTION_ESTIMATED_LENGTH;
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_PROTOCOL_OPTIONS;
+ StRequest.DATA.QUERY_INFORMATION.InformationBuffer = &ProtocolOptions;
+ StRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ }
+
+
+ //
+ // 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 = StConfig->SendPacketPoolSize;
+
+ //
+ // The receive packet pool is used in transfer data.
+ //
+
+ ReceivePacketPoolSize = StConfig->ReceivePacketPoolSize;
+
+
+ NdisAllocatePacketPool (
+ &NdisStatus,
+ &DeviceContext->SendPacketPoolHandle,
+ SendPacketPoolSize,
+ SendPacketReservedLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->SendPacketPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MemoryUsage +=
+ (SendPacketPoolSize *
+ (sizeof(NDIS_PACKET) + SendPacketReservedLength));
+
+
+ NdisAllocatePacketPool(
+ &NdisStatus,
+ &DeviceContext->ReceivePacketPoolHandle,
+ ReceivePacketPoolSize,
+ ReceivePacketReservedLen);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->ReceivePacketPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DeviceContext->MemoryUsage +=
+ (ReceivePacketPoolSize *
+ (sizeof(NDIS_PACKET) + ReceivePacketReservedLen));
+
+
+ //
+ // Allocate the buffer pool; as an estimate, allocate
+ // one per send or receive packet.
+ //
+
+ NdisAllocateBufferPool (
+ &NdisStatus,
+ &DeviceContext->NdisBufferPoolHandle,
+ SendPacketPoolSize + ReceivePacketPoolSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ DeviceContext->NdisBufferPoolHandle = NULL;
+ StCloseNdis (DeviceContext);
+ 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 NdisMediumFddi:
+
+ RtlStoreUlong((PULONG)StDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_MULTICAST));
+ break;
+
+ case NdisMedium802_5:
+
+ RtlStoreUlong((PULONG)StDataBuffer,
+ (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_FUNCTIONAL));
+ break;
+
+ default:
+
+ ASSERT (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ StRequest.RequestType = NdisRequestSetInformation;
+ StRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ StRequest.DATA.SET_INFORMATION.InformationBuffer = &StDataBuffer;
+ StRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = StSubmitNdisRequest (DeviceContext, &StRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ StCloseNdis (DeviceContext);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* StInitializeNdis */
+
+
+VOID
+StCloseNdis (
+ 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 StInitializeNdis.
+ It is written so that it can be called from within StInitializeNdis
+ 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) {
+
+ //
+ // 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->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->SendPacketPoolHandle);
+ }
+
+ if (DeviceContext->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (DeviceContext->ReceivePacketPoolHandle);
+ }
+
+ if (DeviceContext->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (DeviceContext->NdisBufferPoolHandle);
+ }
+
+} /* StCloseNdis */
+
+
+VOID
+StOpenAdapterComplete (
+ 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;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StCloseAdapterComplete (
+ 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;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StResetComplete (
+ 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);
+
+ return;
+}
+
+VOID
+StRequestComplete (
+ 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;
+
+ DeviceContext->NdisRequestStatus = NdisStatus;
+ KeSetEvent(
+ &DeviceContext->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+ return;
+}
+
+VOID
+StStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PDEVICE_CONTEXT DeviceContext;
+
+ DeviceContext = (PDEVICE_CONTEXT)NdisBindingContext;
+
+ switch (NdisStatus) {
+
+ //
+ // Handle various status codes here.
+ //
+
+ default:
+ break;
+
+ }
+}
+
+
+VOID
+StStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+}
diff --git a/private/ntos/tdi/st/stprocs.h b/private/ntos/tdi/st/stprocs.h
new file mode 100644
index 000000000..480927f48
--- /dev/null
+++ b/private/ntos/tdi/st/stprocs.h
@@ -0,0 +1,923 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ stprocs.h
+
+Abstract:
+
+ This header file defines private functions for the NT Sample transport
+ provider.
+
+Author:
+
+ David Beaver (dbeaver) 1-July-1991
+
+Revision History:
+
+--*/
+
+#ifndef _STPROCS_
+#define _STPROCS_
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// IF_STDBG(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define IF_STDBG(flags) \
+ if (StDebug & (flags))
+#else
+#define IF_STDBG(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 StPrint0(fmt) DbgPrint(fmt)
+#define StPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define StPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define StPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define StPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define StPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define StPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define StPrint0(fmt)
+#define StPrint1(fmt,v0)
+#define StPrint2(fmt,v0,v1)
+#define StPrint3(fmt,v0,v1,v2)
+#define StPrint4(fmt,v0,v1,v2,v3)
+#define StPrint5(fmt,v0,v1,v2,v3,v4)
+#define StPrint6(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_STDBG (ST_DEBUG_REFCOUNTS)
+#else
+#define IF_REFDBG if (0)
+#endif
+
+#define StReferenceConnection(Reason, Connection)\
+ StRefConnection (Connection)
+
+#define StDereferenceConnection(Reason, Connection)\
+ StDerefConnection (Connection)
+
+#define StDereferenceConnectionSpecial(Reason, Connection)\
+ StDerefConnectionSpecial (Connection)
+
+#define StReferenceRequest(Reason, Request)\
+ (VOID)InterlockedIncrement( \
+ &(Request)->ReferenceCount)
+
+#define StDereferenceRequest(Reason, Request)\
+ StDerefRequest (Request)
+
+#define StReferenceSendIrp(Reason, IrpSp)\
+ (VOID)InterlockedIncrement( \
+ &IRP_REFCOUNT(IrpSp))
+
+#define StDereferenceSendIrp(Reason, IrpSp)\
+ StDerefSendIrp (IrpSp)
+
+#define StReferenceAddress(Reason, Address)\
+ (VOID)InterlockedIncrement( \
+ &(Address)->ReferenceCount)
+
+#define StDereferenceAddress(Reason, Address)\
+ StDerefAddress (Address)
+
+#define StReferenceDeviceContext(Reason, DeviceContext)\
+ StRefDeviceContext (DeviceContext)
+
+#define StDereferenceDeviceContext(Reason, DeviceContext)\
+ StDerefDeviceContext (DeviceContext)
+
+#define StReferencePacket(Packet) \
+ (VOID)InterlockedIncrement( \
+ &(Packet)->ReferenceCount)
+
+//
+// These macros are used to create and destroy packets, due
+// to the allocation or deallocation of structure which
+// need them.
+//
+
+
+#define StAddSendPacket(DeviceContext) { \
+ PTP_PACKET _SendPacket; \
+ StAllocateSendPacket ((DeviceContext), &_SendPacket); \
+ if (_SendPacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->PacketPool, \
+ (PSINGLE_LIST_ENTRY)&_SendPacket->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveSendPacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->PacketAllocated > DeviceContext->PacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->PacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateSendPacket((DeviceContext), \
+ (PTP_PACKET)CONTAINING_RECORD(s, TP_PACKET, Linkage)); \
+ } \
+ } \
+}
+
+
+#define StAddReceivePacket(DeviceContext) { \
+ PNDIS_PACKET _ReceivePacket; \
+ StAllocateReceivePacket ((DeviceContext), &_ReceivePacket); \
+ if (_ReceivePacket != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ (PSINGLE_LIST_ENTRY)&((PRECEIVE_PACKET_TAG)_ReceivePacket->ProtocolReserved)->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveReceivePacket(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceivePacketAllocated > DeviceContext->ReceivePacketInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceivePacketPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateReceivePacket((DeviceContext), \
+ (PNDIS_PACKET)CONTAINING_RECORD(s, NDIS_PACKET, ProtocolReserved[0])); \
+ } \
+ } \
+}
+
+
+#define StAddReceiveBuffer(DeviceContext) { \
+ PBUFFER_TAG _ReceiveBuffer; \
+ StAllocateReceiveBuffer ((DeviceContext), &_ReceiveBuffer); \
+ if (_ReceiveBuffer != NULL) { \
+ ExInterlockedPushEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &_ReceiveBuffer->Linkage, \
+ &(DeviceContext)->Interlock); \
+ } \
+}
+
+#define StRemoveReceiveBuffer(DeviceContext) { \
+ PSINGLE_LIST_ENTRY s; \
+ if (DeviceContext->ReceiveBufferAllocated > DeviceContext->ReceiveBufferInitAllocated) { \
+ s = ExInterlockedPopEntryList( \
+ &(DeviceContext)->ReceiveBufferPool, \
+ &(DeviceContext)->Interlock); \
+ if (s != NULL) { \
+ StDeallocateReceiveBuffer(DeviceContext, \
+ (PBUFFER_TAG)CONTAINING_RECORD(s, BUFFER_TAG, Linkage)); \
+ } \
+ } \
+}
+
+
+//
+// These routines are used to maintain counters.
+//
+
+#define INCREMENT_COUNTER(_DeviceContext,_Field) \
+ ++(_DeviceContext)->_Field
+
+#define DECREMENT_COUNTER(_DeviceContext,_Field) \
+ --(_DeviceContext)->_Field
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger), (ULONG)(_Ulong))
+
+
+
+//
+// Routines in PACKET.C (TP_PACKET object manager).
+//
+
+VOID
+StAllocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *TransportSendPacket
+ );
+
+VOID
+StAllocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PNDIS_PACKET *TransportReceivePacket
+ );
+
+VOID
+StAllocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PBUFFER_TAG *TransportReceiveBuffer
+ );
+
+VOID
+StDeallocateSendPacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_PACKET TransportSendPacket
+ );
+
+VOID
+StDeallocateReceivePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNDIS_PACKET TransportReceivePacket
+ );
+
+VOID
+StDeallocateReceiveBuffer(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PBUFFER_TAG TransportReceiveBuffer
+ );
+
+NTSTATUS
+StCreatePacket(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_PACKET *Packet
+ );
+
+VOID
+StDestroyPacket(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+StWaitPacket(
+ IN PTP_CONNECTION Connection,
+ IN ULONG Flags
+ );
+
+//
+// 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 EndOfRecord,
+ KIRQL ConnectionIrql,
+ KIRQL CancelIrql
+ );
+
+VOID
+StCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routines in SENDENG.C (Send engine).
+//
+
+VOID
+InitializeSend(
+ PTP_CONNECTION Connection
+ );
+
+VOID
+StartPacketizingConnection(
+ PTP_CONNECTION Connection,
+ IN BOOLEAN Immediate,
+ IN KIRQL ConnectionIrql,
+ IN KIRQL CancelIrql
+ );
+
+VOID
+PacketizeConnections(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+PacketizeSend(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+CompleteSend(
+ IN PTP_CONNECTION Connection
+ );
+
+VOID
+FailSend(
+ IN PTP_CONNECTION Connection,
+ IN NTSTATUS RequestStatus,
+ IN BOOLEAN StopConnection
+ );
+
+VOID
+StCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+StNdisSend(
+ IN PTP_PACKET Packet
+ );
+
+VOID
+StSendCompletionHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+BuildBufferChainFromMdlChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ 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
+StRefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+VOID
+StDerefDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+NTSTATUS
+StCreateDeviceContext(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE_CONTEXT *DeviceContext
+ );
+
+VOID
+StDestroyDeviceContext(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// Routines in ADDRESS.C (TP_ADDRESS object manager).
+//
+
+VOID
+StRefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StDerefAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StAllocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE *TransportAddressFile
+ );
+
+VOID
+StDeallocateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS_FILE TransportAddressFile
+ );
+
+NTSTATUS
+StCreateAddressFile(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS_FILE * AddressFile
+ );
+
+VOID
+StReferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+StDereferenceAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+VOID
+StStopAddress(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StRegisterAddress(
+ IN PTP_ADDRESS Address
+ );
+
+BOOLEAN
+StMatchNetbiosAddress(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR NetBIOSName
+ );
+
+VOID
+StAllocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_ADDRESS *TransportAddress
+ );
+
+VOID
+StDeallocateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS TransportAddress
+ );
+
+NTSTATUS
+StCreateAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName,
+ OUT PTP_ADDRESS *Address
+ );
+
+PTP_ADDRESS
+StLookupAddress(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PST_NETBIOS_ADDRESS NetworkName
+ );
+
+PTP_CONNECTION
+StLookupRemoteName(
+ IN PTP_ADDRESS Address,
+ IN PUCHAR RemoteName
+ );
+
+NTSTATUS
+StStopAddressFile(
+ IN PTP_ADDRESS_FILE AddressFile,
+ IN PTP_ADDRESS Address
+ );
+
+NTSTATUS
+StVerifyAddressObject (
+ IN PTP_ADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+StSendDatagramsOnAddress(
+ PTP_ADDRESS Address
+ );
+
+//
+//
+// Routines in CONNOBJ.C (TP_CONNECTION object manager).
+//
+
+VOID
+StRefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StDerefConnection(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StDerefConnectionSpecial(
+ IN PTP_CONNECTION TransportConnection
+ );
+
+VOID
+StStopConnection(
+ IN PTP_CONNECTION TransportConnection,
+ IN NTSTATUS Status
+ );
+
+VOID
+StCancelConnection(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PTP_CONNECTION
+StLookupListeningConnection(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StAllocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+VOID
+StDeallocateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_CONNECTION TransportConnection
+ );
+
+NTSTATUS
+StCreateConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_CONNECTION *TransportConnection
+ );
+
+PTP_CONNECTION
+StLookupConnectionByContext(
+ IN PTP_ADDRESS Address,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PTP_CONNECTION
+StFindConnection(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PUCHAR LocalName,
+ IN PUCHAR RemoteName
+ );
+
+NTSTATUS
+StVerifyConnectionObject (
+ IN PTP_CONNECTION Connection
+ );
+
+//
+// Routines in REQUEST.C (TP_REQUEST object manager).
+//
+
+
+VOID
+TdiRequestTimeoutHandler(
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ );
+
+VOID
+StRefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+StDerefRequest(
+ IN PTP_REQUEST Request
+ );
+
+VOID
+StCompleteRequest(
+ IN PTP_REQUEST Request,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+StRefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+StDerefSendIrp(
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+VOID
+StCompleteSendIrp(
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ IN ULONG Information
+ );
+
+VOID
+StAllocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ OUT PTP_REQUEST *TransportRequest
+ );
+
+VOID
+StDeallocateRequest(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_REQUEST TransportRequest
+ );
+
+NTSTATUS
+StCreateRequest(
+ 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 DLC.C (entrypoints from NDIS interface).
+//
+
+NDIS_STATUS
+StReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+NDIS_STATUS
+StGeneralReceiveHandler (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PVOID HeaderBuffer,
+ IN UINT PacketSize,
+ IN PST_HEADER StHeader,
+ IN UINT StSize
+ );
+
+VOID
+StReceiveComplete (
+ IN NDIS_HANDLE BindingContext
+ );
+
+VOID
+StTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+//
+// Routines in UFRAMES.C, the UI-frame ST frame processor.
+//
+
+NTSTATUS
+StIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Header,
+ IN ULONG Length
+ );
+
+NTSTATUS
+StProcessConnectionless(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PST_HEADER StHeader,
+ IN ULONG StLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ );
+
+//
+// Routines in IFRAMES.C, the I-frame ST frame processor.
+//
+
+NTSTATUS
+StProcessIIndicate(
+ IN PTP_CONNECTION Connection,
+ IN PST_HEADER StHeader,
+ IN UINT StIndicatedLength,
+ IN UINT StTotalLength,
+ IN NDIS_HANDLE ReceiveContext,
+ IN BOOLEAN Last
+ );
+
+//
+// Routines in RCV.C (data copying routines for receives).
+//
+
+NTSTATUS
+StCopyMdlToBuffer(
+ IN PMDL SourceMdlChain,
+ IN ULONG SourceOffset,
+ IN PVOID DestinationBuffer,
+ IN ULONG DestinationOffset,
+ IN ULONG DestinationBufferSize,
+ IN PULONG BytesCopied
+ );
+
+//
+// Routines in FRAMESND.C, the UI-frame (non-link) shipper.
+//
+
+NTSTATUS
+StSendConnect(
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+StSendDisconnect(
+ IN PTP_CONNECTION Connection
+ );
+
+NTSTATUS
+StSendAddressFrame(
+ IN PTP_ADDRESS Address
+ );
+
+VOID
+StSendDatagramCompletion(
+ IN PTP_ADDRESS Address,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+
+//
+// Routines in stdrvr.c
+//
+
+NTSTATUS
+StDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+StDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+//
+// Routine in stndis.c
+//
+
+VOID
+StOpenAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+StCloseAdapterComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StResetComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StRequestComplete(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+StStatusIndication (
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+StStatusComplete (
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+#if DBG
+PUCHAR
+StGetNdisStatus (
+ IN NDIS_STATUS NdisStatus
+ );
+#endif
+
+VOID
+StWriteResourceErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+StWriteGeneralErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+StWriteOidErrorLog(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+VOID
+StFreeResources(
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+//
+// routines in stcnfg.c
+//
+
+NTSTATUS
+StConfigureProvider(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PIO_STACK_LOCATION IrpSp
+ );
+
+//
+// Routines in stndis.c
+//
+
+NTSTATUS
+StRegisterProtocol (
+ IN STRING *NameString
+ );
+
+VOID
+StDeregisterProtocol (
+ VOID
+ );
+
+
+NTSTATUS
+StInitializeNdis (
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PCONFIG_DATA ConfigInfo,
+ IN UINT ConfigInfoNameIndex
+ );
+
+VOID
+StCloseNdis (
+ IN PDEVICE_CONTEXT DeviceContext
+ );
+
+
+#endif // def _STPROCS_
diff --git a/private/ntos/tdi/st/sttypes.h b/private/ntos/tdi/st/sttypes.h
new file mode 100644
index 000000000..fdbc2195a
--- /dev/null
+++ b/private/ntos/tdi/st/sttypes.h
@@ -0,0 +1,1103 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ sttypes.h
+
+Abstract:
+
+ This module defines private data structures and types for the NT
+ Sample transport provider.
+
+Revision History:
+
+--*/
+
+#ifndef _STTYPES_
+#define _STTYPES_
+
+//
+// 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_LENGTH 16
+
+typedef struct _ST_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[NETBIOS_NAME_LENGTH];
+ USHORT NetbiosNameType;
+} ST_NETBIOS_ADDRESS, *PST_NETBIOS_ADDRESS;
+
+
+//
+// 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.
+//
+
+//
+// the types of potential owners of requests
+//
+
+typedef enum _REQUEST_OWNER {
+ ConnectionType,
+ AddressType,
+ DeviceContextType
+} REQUEST_OWNER;
+
+//
+// The request itself
+//
+
+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)
+ 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.
+
+ KTIMER Timer; // kernel timer for this request.
+ KDPC Dpc; // DPC object for timeouts.
+
+} TP_REQUEST, *PTP_REQUEST;
+
+#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_DC 0x0080 // request is attached to a TP_DEVICE_CONTEXT
+#define REQUEST_FLAGS_SEND_RCV 0x0100 // request is a TdiSend or TdiReceive
+#define REQUEST_FLAGS_DELAY 0x0200 // delay IoCompleteRequest until later
+
+//
+// This defines the TP_IRP_PARAMETERS, which is masked onto the
+// Parameters section of a send IRP's stack location.
+//
+
+typedef struct _TP_IRP_PARAMETERS {
+ TDI_REQUEST_KERNEL_SEND Request;
+ LONG ReferenceCount;
+ PVOID Connection;
+} TP_IRP_PARAMETERS, *PTP_IRP_PARAMETERS;
+
+#define IRP_SEND_LENGTH(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendLength)
+
+#define IRP_SEND_FLAGS(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Request.SendFlags)
+
+#define IRP_REFCOUNT(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->ReferenceCount)
+
+#define IRP_CONNECTION(_IrpSp) \
+ (((PTP_IRP_PARAMETERS)&(_IrpSp)->Parameters)->Connection)
+
+#define IRP_DEVICE_CONTEXT(_IrpSp) \
+ ((PDEVICE_CONTEXT)((_IrpSp)->DeviceObject))
+
+
+//
+// This structure defines the packet object, used to represent a packet
+// 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.
+ BOOLEAN PacketSent; // packet completed by NDIS.
+ BOOLEAN PacketNoNdisBuffer; // chain on this packet was not allocated.
+ BOOLEAN CompleteSend; // last packet in send.
+ PVOID Provider; // The device context of this packet.
+
+ UCHAR Header[1]; // the headers
+
+} TP_PACKET, *PTP_PACKET;
+
+
+
+//
+// This structure defines a TP_CONNECTION, or active transport connection,
+// maintained on a transport address.
+//
+
+//
+// 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 {
+
+ CSHORT Type;
+ USHORT Size;
+
+ LIST_ENTRY LinkList; // used for link thread or for free
+ // resource list
+ KSPIN_LOCK SpinLock; // spinlock for connection protection.
+
+ 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_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 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
+ // requests with this connection. New arrivals are placed at the end of
+ // the queues (really a linked list) and requests are processed at the
+ // front of the queues. The first TdiSend request on the SendQueue is
+ // the current TdiSend being processed, and the first TdiReceive request
+ // 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 request on the ReceiveQueue is not active.
+ // These queues are managed by the EXECUTIVE interlocked list manipuation
+ // routines. The actual objects that are on the queues are request control
+ // blocks (TP_REQUESTs).
+ //
+
+ 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.
+
+ //
+ // These fields are only valid if the CONNECTION_FLAGS_ACTIVE_RECEIVE
+ // flag is set.
+ //
+
+ PIRP SpecialReceiveIrp; // a "no-request" receive IRP exists.
+ PTP_REQUEST CurrentReceiveRequest; // ptr, current receive request.
+ PMDL CurrentReceiveMdl; // ptr, current MDL in receive chain.
+ ULONG ReceiveByteOffset; // current byte offset in current MDL.
+ ULONG ReceiveLength; // current receive length, in bytes (total)
+
+ //
+ // 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)
+
+ //
+ // 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.
+ //
+
+ UINT IndicationInProgress;
+
+ //
+ // 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;
+
+ //
+ // The following fields are used for connection housekeeping.
+ //
+
+ ULONG Flags; // attributes of the connection.
+ ULONG Flags2; // more attributes of the connection.
+ NTSTATUS Status; // status code for connection rundown.
+ ST_NETBIOS_ADDRESS CalledAddress; // TdiConnect request's T.A.
+ USHORT MaximumDataSize; // maximum I-frame data size.
+
+ CHAR RemoteName[16];
+
+} TP_CONNECTION, *PTP_CONNECTION;
+
+
+#define CONNECTION_FLAGS_REMOTE_BUSY 0x00000002 // remote netbios reported NO RECEIVE.
+#define CONNECTION_FLAGS_VERSION2 0x00000004 // remote netbios is version 2.0.
+#define CONNECTION_FLAGS_RECEIVE_WAKEUP 0x00000008 // send a RECEIVE_OUTSTANDING when a receive arrives.
+#define CONNECTION_FLAGS_ACTIVE_RECEIVE 0x00000010 // a receive is active.
+#define CONNECTION_FLAGS_LISTENER 0x00000020 // we were the passive listener.
+#define CONNECTION_FLAGS_CONNECTOR 0x00000040 // we were the active connector.
+#define CONNECTION_FLAGS_WAIT_LISTEN 0x00001000 // waiting for listen.
+#define CONNECTION_FLAGS_DESTROY 0x00002000 // destroy this connection.
+#define CONNECTION_FLAGS_ABORT 0x00004000 // abort this connection.
+#define CONNECTION_FLAGS_ORDREL 0x00008000 // we're in orderly release.
+#define CONNECTION_FLAGS_STOPPING 0x00020000 // connection is running down.
+#define CONNECTION_FLAGS_READY 0x00040000 // sends/rcvs/discons valid.
+#define CONNECTION_FLAGS_SUSPENDED 0x00100000 // we're on the PacketWaitQueue.
+#define CONNECTION_FLAGS_PACKETIZE 0x00200000 // we're on the PacketizeQueue.
+#define CONNECTION_FLAGS_NO_INDICATE 0x40000000 // don't take packets at indication time
+#define CONNECTION_FLAGS_FAILING_TO_EOR 0x80000000 // wait for an EOF in an incoming request before sending
+
+#define CONNECTION_FLAGS2_CLOSING 0x00000002 // connection is closing
+#define CONNECTION_FLAGS2_ASSOCIATED 0x00000004 // associated with address
+#define CONNECTION_FLAGS2_DISCONNECT 0x00000008 // disconnect done on connection
+#define CONNECTION_FLAGS2_ACCEPTED 0x00000010 // accept done on connection
+#define CONNECTION_FLAGS2_INDICATING 0x00000020 // connection was manipulated while
+ // indication was in progress
+#define CONNECTION_FLAGS2_WAIT_ACCEPT 0x00000040 // the connection is waiting for
+ // and accept to send the
+ // session confirm
+#define CONNECTION_FLAGS2_REQ_COMPLETED 0x00000080 // Listen/Connect request completed.
+#define CONNECTION_FLAGS2_DISASSOCIATED 0x00000100 // associate CRef has been removed
+#define CONNECTION_FLAGS2_DISCONNECTED 0x00000200 // disconnect has been indicated
+#define CONNECTION_FLAGS2_REMOTE_VALID 0x00000800 // Connection->RemoteName is valid
+#define CONNECTION_FLAGS2_RCV_CANCELLED 0x00002000 // current receive was cancelled
+#define CONNECTION_FLAGS2_PRE_ACCEPT 0x00008000 // no TdiAccept after listen completes
+#define CONNECTION_FLAGS2_RC_PENDING 0x00010000 // a receive is pending completion
+#define CONNECTION_FLAGS2_PEND_INDICATE 0x00020000 // new data received during RC_PENDING
+
+
+#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.
+
+
+//
+// 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 ST, 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.
+//
+
+typedef struct _TP_ADDRESS {
+
+ 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.
+ PST_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 following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ PTP_PACKET Packet; // header for datagram sends.
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // This structure is used to hold ACLs on the address.
+ // WARNING: It is allocated from paged pool and can
+ // only be accessed at IRQL 0.
+ //
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+ //
+ // Used for delaying StDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+} 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
+
+
+
+//
+// This structure defines the DEVICE_OBJECT and its extension allocated at
+// the time the transport provider creates its device object.
+//
+
+typedef struct _DEVICE_CONTEXT {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+ LIST_ENTRY Linkage; // links them on StDeviceList;
+
+ KSPIN_LOCK Interlock; // GLOBAL spinlock for reference count.
+ // (used in ExInterlockedXxx calls)
+ LONG ReferenceCount; // activity count/this provider.
+
+
+ //
+ // The queue of (currently receive only) IRPs waiting to complete.
+ //
+
+ LIST_ENTRY IrpCompletionQueue;
+
+ //
+ // 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;
+
+
+ //
+ // 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 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 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 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.
+
+ //
+ // 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.
+ //
+
+ NDIS_HANDLE SendPacketPoolHandle;
+ NDIS_HANDLE ReceivePacketPoolHandle;
+ NDIS_HANDLE NdisBufferPoolHandle;
+ PVOID BufferPoolPointer;
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ ST_NDIS_IDENTIFICATION MacInfo; // MAC type and other info
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalAddress; // our local hardware address.
+ HARDWARE_ADDRESS MulticastAddress; // used as dest in all send
+
+ //
+ // The reserved Netbios address; consists of 10 zeroes
+ // followed by LocalAddress;
+ //
+
+ UCHAR ReservedNetBIOSAddress[NETBIOS_NAME_LENGTH];
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+
+ //
+ // 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;
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+
+ //
+ // Counters for most of the statistics that ST maintains;
+ // some of these are kept elsewhere.
+ //
+ // *** NOTE: THE ELEMENTS THAT FOLLOW MATCH THE ***
+ // *** TDI_PROVIDER_STATISTICS STRUCTURE EXACTLY, ***
+ // *** ALLOWING THEM TO BE COPIED EASILY. DO NOT ***
+ // *** CHANGE THEM UNLESS THAT STRUCTURE CHANGES. ***
+ //
+
+ //
+ // Basic connections counters.
+ //
+
+ ULONG OpenConnections;
+ ULONG ConnectionsAfterNoRetry;
+ ULONG ConnectionsAfterRetry;
+
+ //
+ // Counters of previous connections, by disconnect reason.
+ //
+
+ ULONG LocalDisconnects;
+ ULONG RemoteDisconnects;
+ ULONG LinkFailures;
+ ULONG AdapterFailures;
+ ULONG SessionTimeouts;
+ ULONG CancelledConnections;
+
+ //
+ // Keep track of why connect attempts failed.
+ //
+
+ ULONG RemoteResourceFailures;
+ ULONG LocalResourceFailures;
+ ULONG NotFoundFailures;
+ ULONG NoListenFailures; // where WE sent "no listen" response
+
+ //
+ // Counters for datagrams.
+ //
+
+ ULONG DatagramsSent;
+ LARGE_INTEGER DatagramBytesSent;
+ ULONG DatagramsReceived;
+ LARGE_INTEGER DatagramBytesReceived;
+
+ //
+ // Counters for NDIS packets.
+ //
+
+ ULONG PacketsSent;
+ ULONG PacketsReceived;
+
+ //
+ // Counters for data packets.
+ //
+
+ ULONG IFramesSent;
+ LARGE_INTEGER IFrameBytesSent;
+ ULONG IFramesReceived;
+ LARGE_INTEGER IFrameBytesReceived;
+ ULONG IFramesResent;
+ LARGE_INTEGER IFrameBytesResent;
+ ULONG IFramesRejected;
+ LARGE_INTEGER IFrameBytesRejected;
+
+
+ //
+ // LLC stats.
+ //
+
+ ULONG T1Expirations;
+ ULONG T2Expirations;
+ ULONG MaximumSendWindow;
+ ULONG AverageSendWindow;
+
+ //
+ // Netbios stats.
+ //
+
+ ULONG PiggybackAckQueued;
+ ULONG PiggybackAckTimeouts;
+
+ //
+ // Keeps track of "wasted" packet space.
+ //
+
+ LARGE_INTEGER WastedPacketSpace;
+ ULONG WastedSpacePackets;
+
+ //
+ // *** END OF SECTION THAT MATCHES TDI_PROVIDER_STATISTICS ***
+ //
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER StStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // 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.
+
+} DEVICE_CONTEXT, *PDEVICE_CONTEXT;
+
+//
+// device context state definitions
+//
+
+#define DEVICECONTEXT_STATE_CLOSED 0x00
+#define DEVICECONTEXT_STATE_OPEN 0x01
+#define DEVICECONTEXT_STATE_STOPPING 0x02
+
+
+
+//
+// Types used to hold information in the send and receive NDIS packets.
+// These are storied in the ProtocolReserved section of the packet.
+//
+
+typedef struct _SEND_PACKET_TAG {
+ USHORT Type; // identifier for packet type
+ PTP_PACKET Packet; // backpointer to owning TP_PACKET
+ PVOID Owner; // backpointer to owning structure
+} SEND_PACKET_TAG, *PSEND_PACKET_TAG;
+
+//
+// Packet types used in send completion
+//
+
+#define TYPE_I_FRAME 1 // information
+#define TYPE_G_FRAME 2 // datagram
+#define TYPE_C_FRAME 3 // connect
+#define TYPE_D_FRAME 4 // disconnect
+
+
+//
+// receive packet used to hold information about this receive
+//
+
+typedef struct _RECEIVE_PACKET_TAG {
+ LIST_ENTRY Linkage; // used for threading on receive queue
+ NDIS_STATUS NdisStatus; // completion status for send
+ PTP_CONNECTION Connection; // connection this receive is occuring on
+ 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
+
+//
+// receive buffer descriptor (built in memory at the beginning of the buffer)
+//
+
+typedef struct _BUFFER_TAG {
+ SINGLE_LIST_ENTRY Linkage; // so we always know where it is
+ 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 _TYPES_
+
diff --git a/private/ntos/tdi/st/uframes.c b/private/ntos/tdi/st/uframes.c
new file mode 100644
index 000000000..c05f6eaa6
--- /dev/null
+++ b/private/ntos/tdi/st/uframes.c
@@ -0,0 +1,980 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ uframes.c
+
+Abstract:
+
+ This module contains a routine called StProcessConnectionless,
+ that gets control from routines in IND.C when a connectionless
+ frame is received.
+
+Environment:
+
+ Kernel mode, DISPATCH_LEVEL.
+
+Revision History:
+
+--*/
+
+#include "st.h"
+
+
+
+NTSTATUS
+StIndicateDatagram(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PUCHAR Header,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming DATAGRAM or DATAGRAM_BROADCAST frame.
+ BROADCAST and normal datagrams have the same receive logic, except
+ for broadcast datagrams Address will be the broadcast address.
+
+ When we return STATUS_MORE_PROCESSING_REQUIRED, the caller of
+ this routine will continue to call us for each address for the device
+ context. When we return STATUS_SUCCESS, the caller will switch to the
+ next address. When we return any other status code, including
+ STATUS_ABANDONED, the caller will stop distributing the frame.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ StHeader - Pointer to a buffer that contains the receive datagram.
+ The first byte of information is the ST header.
+
+ Length - The length of the MDL pointed to by StHeader.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PLIST_ENTRY p, q;
+ PIRP irp;
+ PIO_STACK_LOCATION irpSp;
+ PTP_REQUEST Request;
+ ULONG IndicateBytesCopied, MdlBytesCopied;
+ KIRQL oldirql;
+ TA_NETBIOS_ADDRESS SourceName;
+ TA_NETBIOS_ADDRESS DestinationName;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ ULONG returnLength;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+ PST_HEADER StHeader;
+
+ //
+ // If this datagram wasn't big enough for a transport header, then don't
+ // let the caller look at any data.
+ //
+
+ if (Length < sizeof(ST_HEADER)) {
+ return STATUS_ABANDONED;
+ }
+
+ //
+ // Update our statistics.
+ //
+
+ ++DeviceContext->DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &DeviceContext->DatagramBytesReceived,
+ Length - sizeof(ST_HEADER));
+
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ StHeader = (PST_HEADER)Header;
+
+ TdiBuildNetbiosAddress (StHeader->Source, FALSE, &SourceName);
+ TdiBuildNetbiosAddress (StHeader->Destination, FALSE, &DestinationName);
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ //
+ // Find the first open address file in the list.
+ //
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first.
+ //
+ // NOTE: We should check if this receive dataframs is for
+ // a specific address.
+ //
+
+ q = RemoveHeadList (&addressFile->ReceiveDatagramQueue);
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if (q != &addressFile->ReceiveDatagramQueue) {
+
+ Request = CONTAINING_RECORD (q, TP_REQUEST, Linkage);
+
+ //
+ // Copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ status = TdiCopyBufferToMdl (
+ StHeader,
+ sizeof(ST_HEADER), // offset
+ Length - sizeof(ST_HEADER), // length
+ Request->IoRequestPacket->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+
+ irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->
+ ReturnDatagramInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ sizeof (TA_NETBIOS_ADDRESS));
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ RtlCopyMemory (
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &SourceName,
+ remoteInformation->RemoteAddressLength);
+
+ returnLength = remoteInformation->RemoteAddressLength;
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ }
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ }
+
+ StCompleteRequest (Request, STATUS_SUCCESS, MdlBytesCopied);
+
+ } else {
+
+ //
+ // no receive datagram requests; is there a kernel client?
+ //
+
+ if (addressFile->RegisteredReceiveDatagramHandler) {
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Note that we can always set the COPY_LOOKAHEAD
+ // flag because we are indicating from our own
+ // buffer, not directly from a lookahead indication.
+ //
+
+ status = (*addressFile->ReceiveDatagramHandler)(
+ addressFile->ReceiveDatagramHandlerContext,
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ Length - sizeof(ST_HEADER), // indicated
+ Length - sizeof(ST_HEADER), // available
+ &IndicateBytesCopied,
+ Header + sizeof(ST_HEADER),
+ &irp);
+
+ if (status == STATUS_SUCCESS) {
+
+ //
+ // The client accepted the datagram and so we're done.
+ //
+
+ } else if (status == STATUS_DATA_NOT_ACCEPTED) {
+
+ //
+ // The client did not accept the datagram and we need to satisfy
+ // a TdiReceiveDatagram, if possible.
+ //
+
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ } else if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client returned an IRP that we should queue up to the
+ // address to satisfy the request.
+ //
+
+ irp->IoStatus.Status = STATUS_PENDING; // init status information.
+ irp->IoStatus.Information = 0;
+ irpSp = IoGetCurrentIrpStackLocation (irp); // get current stack loctn.
+ if ((irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL) ||
+ (irpSp->MinorFunction != TDI_RECEIVE_DATAGRAM)) {
+ irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return status;
+ }
+
+ //
+ // Now copy the actual user data.
+ //
+
+ MdlBytesCopied = 0;
+
+ status = TdiCopyBufferToMdl (
+ StHeader,
+ sizeof(ST_HEADER) + IndicateBytesCopied,
+ Length - sizeof(ST_HEADER) - IndicateBytesCopied,
+ irp->MdlAddress,
+ 0,
+ &MdlBytesCopied);
+
+ irp->IoStatus.Information = MdlBytesCopied;
+ irp->IoStatus.Status = status;
+ IoCompleteRequest (irp, IO_NETWORK_INCREMENT);
+ }
+ }
+ }
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ StDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ } // end of while loop
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ return status; // to dispatcher.
+} /* StIndicateDatagram */
+
+
+NTSTATUS
+StProcessConnect(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PTP_ADDRESS Address,
+ IN PST_HEADER Header,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an incoming connect frame. It scans for
+ posted listens, otherwise it indicates to connect handlers
+ on this address if they are registered.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ Address - Pointer to the transport address object.
+
+ Header - Pointer to the ST header of the frame.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ SourceRouting - Pointer to the source routing information in
+ the frame.
+
+ SourceRoutingLength - Length of the source routing information.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ KIRQL oldirql, oldirql1, cancelirql;
+ NTSTATUS status;
+ PTP_CONNECTION Connection;
+ BOOLEAN ConnectIndicationBlocked = FALSE;
+ PLIST_ENTRY p;
+ BOOLEAN UsedListeningConnection = FALSE;
+ PTP_ADDRESS_FILE addressFile, prevaddressFile;
+
+ PTP_REQUEST request;
+ PIO_STACK_LOCATION irpSp;
+ ULONG returnLength;
+ PTDI_CONNECTION_INFORMATION remoteInformation;
+ TA_NETBIOS_ADDRESS TempAddress;
+ PIRP acceptIrp;
+
+ CONNECTION_CONTEXT connectionContext;
+
+ //
+ // If we are just registering or deregistering this address, then don't
+ // allow state changes. Just throw the packet away, and let the frame
+ // distributor try the next address.
+ //
+
+ if (Address->Flags & (ADDRESS_FLAGS_REGISTERING | ADDRESS_FLAGS_DEREGISTERING)) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // This is an incoming connection request. If we have a listening
+ // connection on this address, then continue with the connection setup.
+ // If there is no outstanding listen, then indicate any kernel mode
+ // clients that want to know about this frame. If a listen was posted,
+ // then a connection has already been set up for it.
+ //
+
+ //
+ // First, check if we already have an active connection with
+ // this remote on this address. If so, we ignore this
+ // (NOTE: This is not the correct behaviour for a real
+ // transport).
+ //
+
+ //
+ // If successful this adds a reference.
+ //
+
+ if (Connection = StLookupRemoteName(Address, Header->Source)) {
+
+ StDereferenceConnection ("Lookup done", Connection);
+ return STATUS_ABANDONED;
+
+ }
+
+ // If successful, this adds a reference which is removed before
+ // this function returns.
+
+ Connection = StLookupListeningConnection (Address);
+ if (Connection == NULL) {
+
+ //
+ // not having a listening connection is not reason to bail out here.
+ // we need to indicate to the user that a connect attempt occurred,
+ // and see if there is a desire to use this connection. We
+ // indicate in order to all address files that are
+ // using this address.
+ //
+ // If we already have an indication pending on this address,
+ // we ignore this frame (the NAME_QUERY may have come from
+ // a different address, but we can't know that). Also, if
+ // there is already an active connection on this remote
+ // name, then we ignore the frame.
+ //
+
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = Address->AddressFileDatabase.Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ while (p != &Address->AddressFileDatabase) {
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if ((addressFile->RegisteredConnectionHandler == TRUE) &&
+ (!addressFile->ConnectIndicationInProgress)) {
+
+
+ TdiBuildNetbiosAddress (
+ Header->Source,
+ FALSE,
+ &TempAddress);
+
+ addressFile->ConnectIndicationInProgress = TRUE;
+
+ //
+ // we have a connection handler, now indicate that a connection
+ // attempt occurred.
+ //
+
+ status = (addressFile->ConnectionHandler)(
+ addressFile->ConnectionHandlerContext,
+ sizeof (TDI_ADDRESS_NETBIOS),
+ &TempAddress,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ &connectionContext,
+ &acceptIrp);
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ // the user has connected a currently open connection, but
+ // we have to figure out which one it is.
+ //
+
+ //
+ // If successful this adds a reference of type LISTENING
+ // (the same what StLookupListeningConnection adds).
+ //
+
+ Connection = StLookupConnectionByContext (
+ Address,
+ connectionContext);
+
+ if (Connection == NULL) {
+
+ //
+ // BUGBUG: We have to tell the client that
+ // his connection is bogus (or has this
+ // already happened??).
+ //
+
+ StPrint0("MORE_PROCESSING_REQUIRED, connection not found\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+
+ } else {
+
+ if (Connection->AddressFile->Address != Address) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ StPrint0("MORE_PROCESSING_REQUIRED, address wrong\n");
+ StStopConnection (Connection, STATUS_INVALID_ADDRESS);
+ StDereferenceConnection("Bad Address", Connection);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ //
+ // OK, we have a valid connection. If the response to
+ // this connection was disconnect, we need to reject
+ // the connection request and return. If it was accept
+ // or not specified (to be done later), we simply
+ // fall through and continue processing on the U Frame.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_DISCONNECT) != 0) {
+
+ Connection->Flags2 &= ~CONNECTION_FLAGS2_DISCONNECT;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+ StPrint0("MORE_PROCESSING_REQUIRED, disconnect\n");
+ addressFile->ConnectIndicationInProgress = FALSE;
+ StDereferenceConnection("Disconnecting", Connection);
+ Connection = NULL;
+ acceptIrp->IoStatus.Status = STATUS_INVALID_CONNECTION;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ goto whileend; // try next address file
+ }
+
+ }
+
+ //
+ // This connection is ready.
+ //
+
+ Connection->Flags &= ~CONNECTION_FLAGS_STOPPING;
+ Connection->Status = STATUS_PENDING;
+ Connection->Flags2 |= CONNECTION_FLAGS2_ACCEPTED;
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Indication completed", Connection);
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
+
+ //
+ // Make a note that we have to set
+ // addressFile->ConnectIndicationInProgress to
+ // FALSE once the address is safely stored
+ // in the connection.
+ //
+
+ ConnectIndicationBlocked = TRUE;
+ StDereferenceAddressFile (addressFile);
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+ break; // exit the while
+
+ } else if (status == STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // we know the address, but can't create a connection to
+ // use on it. This gets passed to the network as a response
+ // saying I'm here, but can't help.
+ //
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+
+ StDereferenceAddressFile (addressFile);
+ return STATUS_ABANDONED;
+
+ } else {
+
+ addressFile->ConnectIndicationInProgress = FALSE;
+ goto whileend; // try next address file
+
+ } // end status ifs
+
+ } else {
+
+ goto whileend; // try next address file
+
+ } // end no indication handler
+
+whileend:
+ //
+ // Jumping here is like a continue, except that the
+ // addressFile pointer is advanced correctly.
+ //
+
+ //
+ // Save this to dereference it later.
+ //
+
+ prevaddressFile = addressFile;
+
+ //
+ // Reference the next address file on the list, so it
+ // stays around.
+ //
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ p = p->Flink;
+ while (p != &Address->AddressFileDatabase) {
+ addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
+ if (addressFile->State != ADDRESSFILE_STATE_OPEN) {
+ p = p->Flink;
+ continue;
+ }
+ StReferenceAddressFile(addressFile);
+ break;
+ }
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ //
+ // Now dereference the previous address file with
+ // the lock released.
+ //
+
+ StDereferenceAddressFile (prevaddressFile);
+
+ ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
+
+ } // end of loop through the address files.
+
+ RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
+
+ if (Connection == NULL) {
+
+ //
+ // We used to return MORE_PROCESSING_REQUIRED, but
+ // since we matched with this address, no other
+ // address is going to match, so abandon it.
+ //
+
+ return STATUS_ABANDONED;
+
+ }
+
+ } else { // end connection == null
+
+ UsedListeningConnection = TRUE;
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
+
+ p = RemoveHeadList (&Connection->InProgressRequest);
+ if (p == &Connection->InProgressRequest) {
+
+ Connection->IndicationInProgress = FALSE;
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (cancelirql);
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // If this listen indicated that we should wait for a
+ // TdiAccept, then do that, otherwise the connection is
+ // ready.
+ //
+
+ if ((Connection->Flags2 & CONNECTION_FLAGS2_PRE_ACCEPT) == 0) {
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_WAIT_ACCEPT;
+
+ } else {
+
+ Connection->Flags |= CONNECTION_FLAGS_READY;
+ INCREMENT_COUNTER (Connection->Provider, OpenConnections);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REQ_COMPLETED;
+
+ StReferenceConnection("Listen completed", Connection);
+
+ }
+
+ //
+ // We have a completed connection with a queued listen. Complete
+ // the listen and let the user do an accept at some time down the
+ // road.
+ //
+
+ RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
+
+ request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
+ IoReleaseCancelSpinLock (cancelirql);
+
+ irpSp = IoGetCurrentIrpStackLocation (request->IoRequestPacket);
+ remoteInformation =
+ ((PTDI_REQUEST_KERNEL)(&irpSp->Parameters))->ReturnConnectionInformation;
+ if (remoteInformation != NULL) {
+ try {
+ if (remoteInformation->RemoteAddressLength != 0) {
+
+ //
+ // Build a temporary TA_NETBIOS_ADDRESS, then
+ // copy over as many bytes as fit.
+ //
+
+ TdiBuildNetbiosAddress(
+ Connection->CalledAddress.NetbiosName,
+ (BOOLEAN)(Connection->CalledAddress.NetbiosNameType ==
+ TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempAddress);
+
+ if (remoteInformation->RemoteAddressLength >=
+ sizeof (TA_NETBIOS_ADDRESS)) {
+
+ returnLength = sizeof(TA_NETBIOS_ADDRESS);
+ remoteInformation->RemoteAddressLength = returnLength;
+
+ } else {
+
+ returnLength = remoteInformation->RemoteAddressLength;
+
+ }
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)remoteInformation->RemoteAddress,
+ &TempAddress,
+ returnLength);
+
+ } else {
+
+ returnLength = 0;
+ }
+
+ status = STATUS_SUCCESS;
+
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+
+ returnLength = 0;
+ status = GetExceptionCode ();
+
+ }
+
+ } else {
+
+ status = STATUS_SUCCESS;
+ returnLength = 0;
+
+ }
+
+ //
+ // Don't clear this until now, so that the connection is all
+ // set up before we allow more indications.
+ //
+
+ Connection->IndicationInProgress = FALSE;
+
+ StCompleteRequest (request, status, 0);
+
+ }
+
+
+ //
+ // Before we continue, store the remote guy's transport address
+ // into the TdiListen's TRANSPORT_CONNECTION buffer. This allows
+ // the client to determine who called him.
+ //
+
+ Connection->CalledAddress.NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
+ NdisMoveFromMappedMemory(
+ Connection->CalledAddress.NetbiosName,
+ Header->Source,
+ 16);
+
+ NdisMoveFromMappedMemory(
+ Connection->RemoteName,
+ Header->Source,
+ 16);
+
+ Connection->Flags2 |= CONNECTION_FLAGS2_REMOTE_VALID;
+
+ if (ConnectIndicationBlocked) {
+ addressFile->ConnectIndicationInProgress = FALSE;
+ }
+
+ StDereferenceConnection("ProcessNameQuery done", Connection);
+
+ return STATUS_ABANDONED;
+
+} /* StProcessConnect */
+
+
+NTSTATUS
+StProcessConnectionless(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PHARDWARE_ADDRESS SourceAddress,
+ IN PST_HEADER StHeader,
+ IN ULONG StLength,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ OUT PTP_ADDRESS * DatagramAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the data link provider as an
+ indication that a connectionless frame has been received on the data link.
+ Here we dispatch to the correct handler.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ SourceAddress - Pointer to the source hardware address in the received
+ frame.
+
+ StHeader - Points to the ST header of the incoming packet.
+
+ StLength - Actual length in bytes of the packet, starting at the
+ StHeader.
+
+ SourceRouting - Source routing information in the MAC header.
+
+ SourceRoutingLength - The length of SourceRouting.
+
+ DatagramAddress - If this function returns STATUS_MORE_PROCESSING_
+ REQUIRED, this will be the address the datagram should be
+ indicated to.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PTP_ADDRESS Address;
+ KIRQL oldirql;
+ NTSTATUS status;
+ PLIST_ENTRY Flink;
+ BOOLEAN MatchedAddress;
+ PUCHAR MatchName;
+
+ //
+ // Verify that this frame is long enough to examine.
+ //
+
+ if (StLength < sizeof(ST_HEADER)) {
+ return STATUS_ABANDONED; // frame too small.
+ }
+
+ //
+ // We have a valid connectionless protocol frame that's not a
+ // datagram, so deliver it to every address which matches the
+ // destination name in the frame.
+ //
+
+ MatchedAddress = FALSE;
+
+ //
+ // Search for the address; for broadcast datagrams we
+ // search for the special "broadcast" address.
+ //
+
+ if ((StHeader->Command == ST_CMD_DATAGRAM) &&
+ (StHeader->Flags & ST_FLAGS_BROADCAST)) {
+
+ MatchName = NULL;
+
+ } else {
+
+ MatchName = StHeader->Destination;
+
+ }
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ for (Flink = DeviceContext->AddressDatabase.Flink;
+ Flink != &DeviceContext->AddressDatabase;
+ Flink = Flink->Flink) {
+
+ Address = CONTAINING_RECORD (
+ Flink,
+ TP_ADDRESS,
+ Linkage);
+
+ if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
+ continue;
+ }
+
+ if (StMatchNetbiosAddress (Address, MatchName)) {
+
+ StReferenceAddress ("UI Frame", Address); // prevent address from being destroyed.
+ MatchedAddress = TRUE;
+ break;
+
+ }
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ if (MatchedAddress) {
+
+ //
+ // Deliver the frame to the current address.
+ //
+
+ switch (StHeader->Command) {
+
+ case ST_CMD_CONNECT:
+
+ status = StProcessConnect (
+ DeviceContext,
+ Address,
+ StHeader,
+ SourceAddress,
+ SourceRouting,
+ SourceRoutingLength);
+
+ break;
+
+ case ST_CMD_DATAGRAM:
+
+ //
+ // Reference the datagram so it sticks around until the
+ // ReceiveComplete, when it is processed.
+ //
+
+ StReferenceAddress ("Datagram indicated", Address);
+ *DatagramAddress = Address;
+ status = STATUS_MORE_PROCESSING_REQUIRED;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+
+ } /* switch on frame command code */
+
+ StDereferenceAddress ("Done", Address); // done with previous address.
+
+ } else {
+
+ status = STATUS_ABANDONED;
+
+ }
+
+ return status;
+
+} /* StProcessConnectionless */
+