summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/nb
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/nb')
-rw-r--r--private/ntos/tdi/isn/nb/action.c221
-rw-r--r--private/ntos/tdi/isn/nb/address.c2406
-rw-r--r--private/ntos/tdi/isn/nb/autodial.c526
-rw-r--r--private/ntos/tdi/isn/nb/bind.c594
-rw-r--r--private/ntos/tdi/isn/nb/cache.c2746
-rw-r--r--private/ntos/tdi/isn/nb/config.c661
-rw-r--r--private/ntos/tdi/isn/nb/config.h70
-rw-r--r--private/ntos/tdi/isn/nb/connect.c3628
-rw-r--r--private/ntos/tdi/isn/nb/datagram.c1089
-rw-r--r--private/ntos/tdi/isn/nb/device.c461
-rw-r--r--private/ntos/tdi/isn/nb/dirs22
-rw-r--r--private/ntos/tdi/isn/nb/driver.c1794
-rw-r--r--private/ntos/tdi/isn/nb/event.c117
-rw-r--r--private/ntos/tdi/isn/nb/frame.c1096
-rw-r--r--private/ntos/tdi/isn/nb/isnnb.h787
-rw-r--r--private/ntos/tdi/isn/nb/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/mp/sources29
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/nbcount.c177
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/nbcount.rc11
-rw-r--r--private/ntos/tdi/isn/nb/nbcount/sources29
-rw-r--r--private/ntos/tdi/isn/nb/nbiprocs.h1533
-rw-r--r--private/ntos/tdi/isn/nb/nbitypes.h1511
-rw-r--r--private/ntos/tdi/isn/nb/nwlnknb.ini43
-rw-r--r--private/ntos/tdi/isn/nb/nwlnknb.rc12
-rw-r--r--private/ntos/tdi/isn/nb/packet.c1482
-rw-r--r--private/ntos/tdi/isn/nb/precomp.h42
-rw-r--r--private/ntos/tdi/isn/nb/query.c1817
-rw-r--r--private/ntos/tdi/isn/nb/receive.c1307
-rw-r--r--private/ntos/tdi/isn/nb/send.c2886
-rw-r--r--private/ntos/tdi/isn/nb/session.c2450
-rw-r--r--private/ntos/tdi/isn/nb/sources.inc69
-rw-r--r--private/ntos/tdi/isn/nb/timer.c1233
-rw-r--r--private/ntos/tdi/isn/nb/up/makefile6
-rw-r--r--private/ntos/tdi/isn/nb/up/sources29
35 files changed, 30896 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/nb/action.c b/private/ntos/tdi/isn/nb/action.c
new file mode 100644
index 000000000..9ff843a76
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/action.c
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which implements the TDI action
+ dispatch routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles action requests.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the action.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ union {
+ PNB_ACTION_GET_COUNTS GetCounts;
+ } u; // BUGBUG: Make these unaligned??
+ PNWLINK_ACTION NwlinkAction;
+ UINT i;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != NB_ADDRESSFILE_SIGNATURE)) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ case (I_MIPX | 351):
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(NB_ACTION_GET_COUNTS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetCounts = (PNB_ACTION_GET_COUNTS)(NwlinkAction->Data);
+
+ u.GetCounts->MaximumNicId = NbiDevice->MaximumNicId;
+
+ for (i = 0; i < 32 ; i++) {
+ u.GetCounts->NicIdCounts[i] = 0;
+ }
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[i].Connections;
+
+ while (Connection != NULL) {
+#if defined(_PNP_POWER)
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicHandle.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicHandle.NicId];
+ }
+#else
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicId];
+ }
+#endif _PNP_POWER
+ Connection = Connection->NextConnection;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ NB_DEBUG (QUERY, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* NbiTdiAction */
+
diff --git a/private/ntos/tdi/isn/nb/address.c b/private/ntos/tdi/isn/nb/address.c
new file mode 100644
index 000000000..2eb882b80
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/address.c
@@ -0,0 +1,2406 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS)) {
+ return ((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbiParseTdiAddress */
+
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbiPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbiValidateTdiAddress */
+
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+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:
+
+ Device - pointer to the device describing the Netbios transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+#if 0
+ TA_NETBIOS_ADDRESS FakeAddress;
+#endif
+
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // 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];
+#if 0
+ TdiBuildNetbiosAddress(
+ "ADAMBA67 ",
+ FALSE,
+ &FakeAddress);
+ name = (PTRANSPORT_ADDRESS)&FakeAddress;
+#endif
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type Netbios. This call returns (PVOID)-1 if the
+ // address is the broadcast address.
+ //
+
+ NetbiosAddress = NbiParseTdiAddress (name, TRUE);
+
+ if (NetbiosAddress == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = NbiCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // 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 (&Device->AddressResource, TRUE);
+
+#if defined(_PNP_POWER)
+
+ Address = NbiFindAddress (
+ Device,
+ ( NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1 : NetbiosAddress->NetbiosName
+ );
+
+ if (Address == NULL) {
+
+#else
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Address = NbiLookupAddress (Device, NetbiosAddress);
+
+ if (Address == NULL) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif _PNP_POWER
+
+ //
+ // This address doesn't exist. Create it.
+ // This initializes the address with a ref
+ // of type ADDRESS_FILE, so if we fail here
+ // we need to remove that.
+ //
+
+ Address = NbiCreateAddress (
+ Device,
+ NetbiosAddress);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+#else
+ if (Device->State == DEVICE_STATE_STOPPING) {
+#endif _PNP_POWER
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Address = Address;
+
+ NB_INSERT_TAIL_LIST(
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage,
+ &Address->Lock);
+
+ if (NetbiosAddress == (PVOID)-1) {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ NbiStartRegistration (Address);
+ }
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->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.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ NbiDestroyAddressFile (AddressFile);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+#if !defined(_PNP_POWER)
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif !_PNP_POWER
+ NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // Make sure the types do not conflict.
+ //
+
+ if ((NetbiosAddress != (PVOID)-1) &&
+ (NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) {
+
+ NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ 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);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // Insert the address file on the address
+ // list; we will pend this open if the address
+ // is still registering. If the address has
+ // already failed as duplicate, then we
+ // fail the open.
+ //
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address));
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ //
+ // Start registration unless it is registered or
+ // it is the broadcast address.
+ //
+
+ if ((Address->State == ADDRESS_STATE_REGISTERING) &&
+ (NetbiosAddress != (PVOID)-1)) {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ } else {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+ }
+
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+
+ NbiReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ }
+
+ }
+ }
+ }
+
+ //
+ // Remove the reference from NbiLookupAddress.
+ //
+
+ NbiDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* NbiOpenAddress */
+
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process for a netbios name
+ by sending out the first add name packet and starting the timer
+ so that NbiRegistrationTimeout is called after the correct timeout.
+
+Arguments:
+
+ Address - The address which is to be registered.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address));
+
+ //
+ // First send out an add name packet.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ Address->RegistrationCount = 0;
+
+ //
+ // Now start the timer.
+ //
+
+ NbiReferenceAddress (Address, AREF_TIMER);
+
+ CTEInitTimer (&Address->RegistrationTimer);
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+} /* NbiStartRegistration */
+
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the address registration
+ timer expires. It sends another add name if needed, or
+ checks the result if the correct number have been sent.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the address pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Context;
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PLIST_ENTRY p;
+
+ ++Address->RegistrationCount;
+
+ if ((Address->RegistrationCount < Address->Device->BroadcastCount) &&
+ ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) {
+
+ NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address));
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+ } else {
+
+ //
+ // The correct number of frames have been sent, see what
+ // happened.
+ //
+
+ NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address));
+
+ ReferencedAddressFile = NULL;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ Address->State = ADDRESS_STATE_OPEN;
+ } else {
+ Address->State = ADDRESS_STATE_STOPPING;
+ }
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING);
+ CTEAssert (AddressFile->OpenRequest != NULL);
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ //
+ // Now see what to do with this address file.
+ //
+
+ REQUEST_INFORMATION(AddressFile->OpenRequest) = 0;
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME;
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ }
+
+ NbiCompleteRequest (AddressFile->OpenRequest);
+ NbiFreeRequest (Address->Device, AddressFile->OpenRequest);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ ReferencedAddressFile = AddressFile;
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ NbiDereferenceAddress (Address, AREF_TIMER);
+
+ }
+
+} /* NbiRegistrationTimeout */
+
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_FIND_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Quick check for any names starting with this character.
+ //
+
+ if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) {
+ return;
+ }
+
+ //
+ // Always respond to broadcast requests.
+ //
+#if defined(_PNP_POWER)
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ } else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) {
+
+ NbiSendNameFrame(
+ NULL,
+ (UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+ }
+#else
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+#endif _PNP_POWER
+} /* NbiProcessFindName */
+
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_ADD_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ BOOLEAN LocalFrame;
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Ignore any frame that came from us, except for the purpose
+ // of updating the cache.
+ //
+
+ if ((Device->Bind.QueryHandler)(
+ IPX_QUERY_IS_ADDRESS_LOCAL,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ NbConnectionless->IpxHeader.SourceNetwork,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ LocalFrame = TRUE;
+
+ } else {
+
+ LocalFrame = FALSE;
+
+ }
+
+ if (!LocalFrame) {
+
+ if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) &&
+ (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) {
+
+ if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) {
+
+ //
+ // If this frame is an add name (identified because it is a
+ // broadcast frame) then respond if we have it registered
+ // unique, or we have it group and someone is trying to add
+ // it unique.
+ //
+
+ if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
+ ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) &&
+ ((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) {
+
+ //
+ // According to GeorgeJ's doc, on a name in use we just
+ // echo back the name type flags from the request.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ NbConnectionless->NameFrame.NameTypeFlag,
+ NB_CMD_NAME_IN_USE,
+ RemoteAddress,
+#if defined(_PNP_POWER)
+ NbConnectionless);
+#else
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+#endif _PNP_POWER
+ }
+
+ } else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork ==
+ *(UNALIGNED ULONG *)Device->Bind.Network) &&
+ NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) {
+
+ //
+ // If this is an add name response (which will be sent
+ // directly to us) then we need to mark the address
+ // as such.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ }
+
+
+ //
+ // Pass this frame over to the netbios cache management
+ // routines to check if they need to update their cache.
+ //
+
+ CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame);
+
+} /* NbiProcessAddName */
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+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 IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetbiosAddress - The name to assign to this address, or -1 if it
+ is the broadcast address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+
+ Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address %.16s failed\n",
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address,
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+ Address->Type = NB_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+ Address->State = ADDRESS_STATE_REGISTERING;
+ Address->Flags = 0;
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock.Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+
+ if (NetbiosAddress == (PVOID)-1) {
+ Address->NetbiosAddress.Broadcast = TRUE;
+ } else {
+ Address->NetbiosAddress.Broadcast = FALSE;
+ Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType;
+ RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16);
+ ++Device->AddressCounts[NetbiosAddress->NetbiosName[0]];
+ }
+
+ if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) {
+ Address->NameTypeFlag = NB_NAME_UNIQUE;
+ } else {
+ Address->NameTypeFlag = NB_NAME_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 (&Device->AddressDatabase, &Address->Linkage);
+ ++Device->AddressCount;
+
+ NbiReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* NbiCreateAddress */
+
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ )
+
+/*++
+
+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 ADDRESS_FILE object
+
+ ConflictIsOk - TRUE if we should succeed the verify even if the
+ corresponding address is in CONFLICT. ( For Close and
+ cleanup we return STATUS_SUCCESS even if we are in conflict
+ so that the addressfile can be destroyed)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+ BOOLEAN LockHeld = FALSE;
+
+ //
+ // 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 (ADDRESS_FILE)) &&
+ (AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == NB_ADDRESS_SIGNATURE) ) {
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+#if defined(_PNP_POWER)
+ if (Address->State != ADDRESS_STATE_STOPPING &&
+ ( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) {
+#else
+ if (Address->State != ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyAddressFile */
+
+
+VOID
+NbiDestroyAddress(
+ 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. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by NbiDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by NbiDerefAddress. 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.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address,
+ Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName));
+
+ 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.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!Address->NetbiosAddress.Broadcast) {
+ --Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]];
+ }
+ --Device->AddressCount;
+ RemoveEntryList (&Address->Linkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ NbiDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* NbiDestroyAddress */
+
+
+#if DBG
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+} /* NbiRefAddress */
+
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+
+} /* NbiRefAddressLock */
+#endif
+
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS 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
+ NbiDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = 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.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbiDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ NbiDestroyAddress(Address);
+#endif
+
+ }
+
+} /* NbiDerefAddress */
+
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+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:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+ UINT i;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address file failed\n"));
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = NB_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ for (i = 0; i < 6; i++) {
+ AddressFile->RegisteredHandler[i] = FALSE;
+ AddressFile->HandlerContexts[i] = NULL;
+ AddressFile->Handlers[i] = TdiDefaultHandlers[i];
+ }
+
+ CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler);
+ CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler);
+ CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler);
+ CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler);
+ CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler);
+ CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler);
+
+ return AddressFile;
+
+} /* NbiCreateAddressFile */
+
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_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 NbiDereferenceAddressFile. 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.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ BOOLEAN StopAddress;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // 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.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle1);
+ Address->State = ADDRESS_STATE_STOPPING;
+ NB_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ StopAddress = TRUE;
+
+ } else {
+
+ StopAddress = FALSE;
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ if (StopAddress && (!Address->NetbiosAddress.Broadcast)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag |
+ NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED),
+ NB_CMD_DELETE_NAME,
+ NULL,
+ NULL);
+ }
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ NbiCompleteRequest (CloseRequest);
+ NbiFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiDestroyAddressFile */
+
+
+#if DBG
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_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.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+} /* NbiRefAddressFile */
+
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+
+} /* NbiRefAddressFileLock */
+
+#endif
+
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_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
+ NbiDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = 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.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+ NbiDestroyAddressFile (AddressFile);
+ }
+
+} /* NbiDerefAddressFile */
+
+#if !defined(_PNP_POWER)
+
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+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
+ 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 Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosAddress - The name to look up, or -1 if the broadcast
+ address is being searched for.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosAddress != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if (NetbiosAddress == (PVOID)-1) {
+ continue;
+ }
+
+ if (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosAddress->NetbiosName,
+ 16)) {
+ 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.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* NbiLookupAddress */
+#endif !_PNP_POWER
+
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NetbiosName
+ values. If a match is found, the address is referenced and the
+ pointer is returned.
+
+ We ignore any addresses which are either STOPPING or are under
+ CONFLICT state.
+
+ A name in CONFLICT is dead for all practical purposes
+ except Close. This routine is called by various name service,
+ datagram and session sevice routines. We hide any names in CONFLICT
+ from these routines.
+
+ This routine is also called by NbiTdiOpenAddress().
+ A name could have been marked in CONFLICT ages ago(but is not closed
+ yet). We must allow another open of the same name as that might
+ succeed now.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosName - The name to look up, or -1 for the broadcast name.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+#if defined(_PNP_POWER)
+ if ( ( Address->State == ADDRESS_STATE_STOPPING ) ||
+ ( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) {
+#else
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosName != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if ((NetbiosName == (PVOID)-1) ||
+ (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosName,
+ 16))) {
+ 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.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_FIND);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+
+} /* NbiFindAddress */
+
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS 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 request
+ is not for a real address.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle1, LockHandle2;
+ LIST_ENTRY SendDatagramList;
+ PNB_SEND_RESERVED Reserved;
+ PREQUEST DatagramRequest;
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ LIST_ENTRY DatagramQ;
+
+
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // This prevents anybody else from being put on the
+ // ConnectionDatabase.
+ //
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ CTEAssert (Connection->AddressFile == AddressFile);
+ Connection->AddressFileLinked = FALSE;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // The refcount is already 0, so we can just
+ // NULL out this field to complete the disassociate.
+ //
+
+ Connection->AddressFile = NULL;
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ //
+ // Mark this so we know to disassociate when the
+ // count goes to 0, but that there is no specific
+ // request pending on it. We also stop the connection
+ // to shut it down.
+ //
+
+ Connection->DisassociatePending = (PVOID)-1;
+ NbiReferenceConnectionLock (Connection, CREF_DISASSOC);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3);
+
+ //
+ // This call frees the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle3));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_DISASSOC);
+
+ }
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Abort all pending send datagrams.
+ //
+ // BUGBUG: Also make them cancellable.
+ //
+
+ InitializeListHead (&SendDatagramList);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ if (Reserved->u.SR_DG.AddressFile == AddressFile) {
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&SendDatagramList, &Reserved->WaitLinkage);
+
+ }
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ for (p = SendDatagramList.Flink; p != &SendDatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+
+ //
+ // Abort all pending receive datagrams.
+ //
+
+ InitializeListHead( &DatagramQ );
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ // Insert it on a private Q, so it can be completed later.
+ InsertTailList( &DatagramQ, p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ for( p = DatagramQ.Flink; p != &DatagramQ; ) {
+ Request = LIST_ENTRY_TO_REQUEST ( p );
+
+ p = p->Flink;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbiStopAddressFile */
+
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+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:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ NbiStopAddressFile (AddressFile, Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* NbiCloseAddressFile */
+
+#if defined(_PNP_POWER)
+
+
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an adapter address sttuctures which stores
+ the netbios name of an adapter. the netbios name has 12 0's
+ followed by the mac address of the adapter.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AdapterMacAddress - pointer to the adapter mac address given to us
+ by IPX.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+ THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD.
+
+--*/
+
+{
+ PADAPTER_ADDRESS AdapterAddress;
+ CTELockHandle LockHandle;
+ PDEVICE Device = NbiDevice;
+
+ AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address");
+ if (AdapterAddress == NULL) {
+ NB_DEBUG (ADDRESS, ("Create Adapter Address %<2.2x><2.2x><2.2x><2.2x><2.2x><2.2x> failed\n",
+ AdapterMacAddress[0],
+ AdapterMacAddress[1],
+ AdapterMacAddress[2],
+ AdapterMacAddress[3],
+ AdapterMacAddress[4],
+ AdapterMacAddress[5]
+ ));
+ return NULL;
+ }
+
+ AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE;
+ AdapterAddress->Size = sizeof (ADDRESS);
+
+ RtlZeroMemory(AdapterAddress->NetbiosName, 10);
+ RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6);
+
+
+ InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ return AdapterAddress;
+
+} /* NbiCreateAdapterAddress */
+
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the adapter address structure and removes it
+ from the list.
+
+Arguments:
+
+ AdapterAddress - Pointer to an adapter address structure to be destroyed
+ NULL if AdapterMacAddress is given.
+
+ AdapterMacAddress - Mac Address of the adapter which just got deleted. so find
+ the corresponding adapter address structure and remove it.
+ NULL if AdapterAddress is supplied.
+
+Return Value:
+
+ STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found.
+
+ THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE];
+
+
+ //
+
+ CTEAssert( AdapterAddress || AdapterMacAddress );
+ if ( !AdapterAddress ) {
+ RtlZeroMemory( NetbiosName, 10);
+ RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 );
+
+ AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED );
+
+ if ( !AdapterAddress ) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName));
+ RemoveEntryList (&AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress");
+
+ return STATUS_SUCCESS;
+} /* NbiDestroyAdapterAddress */
+
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds an adapter address ( netbios name ) for the given
+ AdapterMacAddress and returns a pointer to it. Note that no reference
+ is done on this address, so if this routine is called without the device
+ lock, the caller must not use this pointer directly.
+
+Arguments:
+
+ NetbiosName - NetbiosName to be found.
+
+ LockHeld - is device lock already held or not.
+
+Return Value:
+
+ Pointer to the adapter address if found, NULL otherwise.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+ PADAPTER_ADDRESS AdapterAddress;
+ PDEVICE Device = NbiDevice;
+
+
+ if ( !LockHeld ) {
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ }
+ for ( p = Device->AdapterAddressDatabase.Flink;
+ p != &Device->AdapterAddressDatabase;
+ p = p->Flink ) {
+
+ AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage );
+ if ( RtlEqualMemory(
+ NetbiosName,
+ AdapterAddress->NetbiosName,
+ NB_NETBIOS_NAME_SIZE ) ) {
+ break;
+ }
+ }
+
+
+ if ( !LockHeld ) {
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+ }
+
+ if ( p == &Device->AdapterAddressDatabase ) {
+ return NULL;
+ } else {
+ return AdapterAddress;
+ }
+
+} /* NbiFindAdapterAddress */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/nb/autodial.c b/private/ntos/tdi/isn/nb/autodial.c
new file mode 100644
index 000000000..ec56e2351
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/autodial.c
@@ -0,0 +1,526 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ NT specific routines for interfacing with the
+ RAS AutoDial driver (rasacd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) Aug 30, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ adiscolo 08-30-95 created
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbi ';
+
+
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE pDevice = pArgs[0];
+ PCONNECTION pConnection = pArgs[1];
+ PREQUEST pRequest = pArgs[2];
+ CTELockHandle ConnectionLH, DeviceLH;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+#if notdef // DBG
+ DbgPrint("NbiRetryTdiConnect: fSuccess=%d, pConnection=0x%x\n", fSuccess, pConnection);
+#endif
+
+ status = NbiVerifyConnection(pConnection);
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "NbiRetryTdiConnect: NbiVerifyConnection failed on connection 0x%x (status=0x%x)\n",
+ pConnection,
+ status);
+ return;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&pConnection->Lock, &ConnectionLH);
+ NB_GET_LOCK (&pDevice->Lock, &DeviceLH);
+
+#if notdef // DBG
+ DbgPrint(
+ "NbiRetryTdiConnect: AddressFile=0x%x, DisassociatePending=0x%x, ClosePending=0x%x\n",
+ pConnection->AddressFile,
+ pConnection->DisassociatePending,
+ pConnection->ClosePending);
+#endif
+
+ if ((pConnection->AddressFile != NULL) &&
+ (pConnection->AddressFile != (PVOID)-1) &&
+ (pConnection->DisassociatePending == NULL) &&
+ (pConnection->ClosePending == NULL))
+ {
+ NbiReferenceConnectionLock(pConnection, CREF_CONNECT);
+ //
+ // Clear the AUTOCONNECTING flag since we
+ // done with the automatic connection attempt.
+ // Set the AUTOCONNECTED flag to prevent us
+ // from attempting an automatic connection
+ // for this connection again.
+ //
+ pConnection->Flags &= ~CONNECTION_FLAGS_AUTOCONNECTING;
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTED;
+
+ pConnection->State = CONNECTION_STATE_CONNECTING;
+ pConnection->Retries = pDevice->ConnectionCount;
+ status = NbiTdiConnectFindName(
+ pDevice,
+ pRequest,
+ pConnection,
+ CancelLH,
+ ConnectionLH,
+ DeviceLH,
+ &bLockFreed);
+ }
+ else {
+ DbgPrint("NbiRetryTdiConnect: Connect on invalid connection 0x%x\n", pConnection);
+
+ pConnection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&pDevice->Lock, DeviceLH);
+ status = STATUS_INVALID_CONNECTION;
+ }
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&pConnection->Lock, ConnectionLH);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+ }
+ //
+ // Complete the irp if necessary.
+ //
+ if (status != STATUS_PENDING) {
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = status;
+
+ NbiCompleteRequest(pRequest);
+ NbiFreeRequest(pDevice, pRequest);
+ }
+ NbiDereferenceConnection(pConnection, CREF_VERIFY);
+} /* NbiRetryTdiConnect */
+
+
+
+BOOLEAN
+NbiCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+#if notdef // DBG
+ DbgPrint("NbiCancelAutodialRequest: pArg=0x%x\n", pArg);
+#endif
+ if (nArgs != 2)
+ return FALSE;
+
+ return (pArgs[1] == pArg);
+} // NbiCancelAutoDialRequest
+
+
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDevice: a pointer to the device object for this driver
+
+ pRequest: a pointer to the irp to be cancelled
+
+ pConnection: a pointer to the connnection to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbiCancelTdiConnect: pIrp=0x%x, RemoteName=%-15.15s, pConnection=0x%x\n",
+ pRequest,
+ addr.cNetbios,
+ pConnection);
+#endif
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbiCancelAutoDialRequest,
+ pConnection);
+} // NbiCancelTdiConnect
+
+
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pDevice - a pointer to the DEVICE structure for this connection
+
+ pConnection - a pointer to the CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pRequest - a pointer to the request irp
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[3];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic connection
+ // on this connection, don't try it again.
+ //
+ if (pConnection->Flags & CONNECTION_FLAGS_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint("NbiAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbiRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pDevice;
+ pArgs[1] = pConnection;
+ pArgs[2] = pRequest;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 3,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the AUTOCONNECTING flag so we know
+ // to also cancel the connection in the
+ // automatic connection driver if this
+ // request gets canceled.
+ //
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTING;
+ }
+} // NbiAttemptAutoDial
+
+
+
+VOID
+NbiNoteNewConnection(
+ IN PCONNECTION pConnection
+ )
+{
+ NTSTATUS status;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG i;
+ TDI_ADDRESS_IPX tdiIpxAddress;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+ //
+ // Determine the mac address of the adapter
+ // over which the connection has been made.
+ //
+ status = (pConnection->Device->Bind.QueryHandler)(
+ IPX_QUERY_IPX_ADDRESS,
+#if defined(_PNP_POWER)
+ &pConnection->LocalTarget.NicHandle,
+#else
+ pConnection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &tdiIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+ if (status != STATUS_SUCCESS) {
+#if notdef // DBG
+ DbgPrint("NbiNoteNewConnection: QueryHandler(IPX_QUERY_IPX_ADDRESS) failed (status=0x%x)\n", status);
+ return;
+#endif
+ }
+ //
+ // Copy the source mac address to identify
+ // the adapter.
+ //
+ adapter.fType = ACD_ADAPTER_MAC;
+ for (i = 0; i < 6; i++)
+ adapter.cMac[i] = tdiIpxAddress.NodeAddress[i];
+#if notdef // DBG
+ DbgPrint(
+ "NbiNoteNewConnection: address=%-15.15s, remote mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr.cNetbios,
+ adapter.cMac[0],
+ adapter.cMac[1],
+ adapter.cMac[2],
+ adapter.cMac[3],
+ adapter.cMac[4],
+ adapter.cMac[5]);
+#endif
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbiNoteNewConnection
+
+
+
+VOID
+NbiAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdBind
+
+
+
+VOID
+NbiAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdUnbind
+
+#endif // RASAUTODIAL
diff --git a/private/ntos/tdi/isn/nb/bind.c b/private/ntos/tdi/isn/nb/bind.c
new file mode 100644
index 000000000..58509f692
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/bind.c
@@ -0,0 +1,594 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiBind)
+#endif
+
+#if defined(_PNP_POWER)
+//
+// local functions.
+//
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine binds the Netbios module of ISN to the IPX
+ module, which provides the NDIS binding services.
+
+Arguments:
+
+ Device - Pointer to the Netbios device.
+
+ Config - Pointer to the configuration information.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+/* union {
+ IPX_INTERNAL_BIND_INPUT Input;
+ IPX_INTERNAL_BIND_OUTPUT Output;
+ } Bind;
+*/
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Config->BindName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwCreateFile(
+ &Device->BindHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NB_DEBUG (BIND, ("Could not open IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ return Status;
+ }
+
+ //
+ // Fill in our bind data.
+ //
+
+#if defined(_PNP_POWER)
+ Device->BindInput.Version = ISN_VERSION;
+#else
+ Device->BindInput.Version = 1;
+#endif _PNP_POWER
+ Device->BindInput.Identifier = IDENTIFIER_NB;
+ Device->BindInput.BroadcastEnable = TRUE;
+ Device->BindInput.LookaheadRequired = 192;
+ Device->BindInput.ProtocolOptions = 0;
+ Device->BindInput.ReceiveHandler = NbiReceive;
+ Device->BindInput.ReceiveCompleteHandler = NbiReceiveComplete;
+ Device->BindInput.StatusHandler = NbiStatus;
+ Device->BindInput.SendCompleteHandler = NbiSendComplete;
+ Device->BindInput.TransferDataCompleteHandler = NbiTransferDataComplete;
+ Device->BindInput.FindRouteCompleteHandler = NbiFindRouteComplete;
+ Device->BindInput.LineUpHandler = NbiLineUp;
+ Device->BindInput.LineDownHandler = NbiLineDown;
+ Device->BindInput.ScheduleRouteHandler = NULL;
+#if defined(_PNP_POWER)
+ Device->BindInput.PnPHandler = NbiPnPNotification;
+#endif _PNP_POWER
+
+
+ Status = ZwDeviceIoControlFile(
+ Device->BindHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ &Device->BindInput, // Input Buffer
+ sizeof(Device->BindInput), // Input Buffer Length
+ &Device->Bind, // OutputBuffer
+ sizeof(Device->Bind)); // OutputBufferLength
+
+ //
+ // We open synchronous, so this shouldn't happen.
+ //
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ //
+ // Save the bind data.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (BIND, ("Successfully bound to IPX (%ws)\n",
+ Config->BindName.Buffer));
+// RtlCopyMemory (&Device->Bind, &Bind.Output, sizeof(IPX_INTERNAL_BIND_OUTPUT));
+
+#if !defined(_PNP_POWER)
+ RtlZeroMemory (Device->ReservedNetbiosName, 16);
+ RtlCopyMemory (&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ (USHORT)0,
+ &Device->MaximumNicId,
+ sizeof(Device->MaximumNicId),
+ NULL);
+ CTEAssert (Status == STATUS_SUCCESS);
+#endif !_PNP_POWER
+
+ } else {
+
+ NB_DEBUG (BIND, ("Could not bind to IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ ZwClose(Device->BindHandle);
+ }
+
+ return Status;
+
+} /* NbiBind */
+
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the binding between the Netbios over
+ IPX module and the IPX module previously established by
+ NbiBind.
+
+Arguments:
+
+ Device - The netbios device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ZwClose (Device->BindHandle);
+
+} /* NbiUnbind */
+
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives a status indication from IPX,
+ corresponding to a status indication from an underlying
+ NDIS driver.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ GeneralStatus - The general status code.
+
+ StatusBuffer - The status buffer.
+
+ StatusBufferLength - The length of the status buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiStatus */
+
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line up indications from IPX,
+ indicating that the specified adapter is now up with
+ the characteristics shown.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ LineInfo - Information about the adapter's medium.
+
+ DeviceType - The type of the adapter.
+
+ ConfigurationData - IPX-specific configuration data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPXCP_CONFIGURATION Configuration = (PIPXCP_CONFIGURATION)ConfigurationData;
+
+ //
+ // Update queries have NULL as the ConfigurationData. These
+ // only indicate changes in LineInfo. BUGBUG Ignore these
+ // for the moment.
+ //
+
+ if (Configuration == NULL) {
+ return;
+ }
+
+#if !defined(_PNP_POWER)
+ //
+ // Since Netbios outgoing queries only go out on network 1,
+ // we ignore this (BUGBUG for the moment) unless that is
+ // the NIC it is on.
+ //
+
+ if (NicId == 1) {
+
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNetwork, Configuration->Network, 4);
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNode, Configuration->LocalNode, 6);
+
+ }
+#endif !_PNP_POWER
+} /* NbiLineUp */
+
+
+VOID
+NbiLineDown(
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line down indications from IPX,
+ indicating that the specified adapter is no longer
+ up.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiLineDown */
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX.
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ UCHAR PrevReservedName[NB_NETBIOS_NAME_SIZE];
+ UNICODE_STRING UnicodeDeviceName;
+
+
+ NB_DEBUG2( DEVICE, ("Received a pnp notification, opcode %d\n",OpCode ));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ BOOLEAN ReallocReceiveBuffers = FALSE;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ if ( PnPInfo->NewReservedAddress ) {
+
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+// RtlZeroMemory(Device->ReservedNetbiosName, NB_NETBIOS_NAME_SIZE);
+// RtlCopyMemory(&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+ }
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->State != DEVICE_STATE_OPEN );
+
+
+ //
+ // we must do this while we still have the device lock.
+ //
+ if ( !Device->LongTimerRunning ) {
+ Device->LongTimerRunning = TRUE;
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ Device->State = DEVICE_STATE_OPEN;
+
+ CTEAssert( !Device->MaximumNicId );
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize;
+ ReallocReceiveBuffers = TRUE;
+ } else {
+ if ( PnPInfo->LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+ ReallocReceiveBuffers = TRUE;
+ }
+ //
+ // MaxSendSize could become smaller.
+ //
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ }
+
+ Device->MaximumNicId++;
+
+
+ //
+ //
+ NbiCreateAdapterAddress( PnPInfo->NodeAddress );
+
+ //
+ // And finally remove all the failed cache entries since we might
+ // find those routes using this new adapter
+ //
+ FlushFailedNetbiosCacheEntries(Device->NameCache);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ if ( ReallocReceiveBuffers ) {
+ PWORK_QUEUE_ITEM WorkItem;
+
+ WorkItem = NbiAllocateMemory( sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buffer work item");
+
+ if ( WorkItem ) {
+ ExInitializeWorkItem( WorkItem, NbiReAllocateReceiveBufferPool, (PVOID) WorkItem );
+ ExQueueWorkItem( WorkItem, DelayedWorkQueue );
+ } else {
+ NB_DEBUG( DEVICE, ("Cannt schdule work item to realloc receive buffer pool\n"));
+ }
+ }
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->DeviceNameLength;
+ UnicodeDeviceName.Length = Device->DeviceNameLength - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to register nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ CTEAssert( Device->MaximumNicId );
+ Device->MaximumNicId--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->State = DEVICE_STATE_LOADED;
+ Device->MaximumNicId = 0;
+
+ }
+
+
+ //
+ // MaximumSendSize could change if the card with the smallest send size just
+ // got removed. MaximumPacketSize could only become smaller and we ignore that
+ // since we dont need to(want to) realloc ReceiveBuffers.
+ //
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+ RemoveInvalidRoutesFromNetbiosCacheTable( Device->NameCache, &PnPInfo->NicHandle );
+
+ NbiDestroyAdapterAddress( NULL, PnPInfo->NodeAddress );
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+/* //
+ // Now mark the previous reserved name in conflict if it has
+ // been registered by any of our client
+ //
+ if ( Address = NbiFindAddress( Device, PrevReservedName ) ) {
+ NB_GET_LOCK( &Address->Lock, &LockHandle );
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+ NB_FREE_LOCK( &Address->Lock, LockHandle );
+
+ NB_DEBUG( ADDRESS, ("Reserved Address %lx<%.16s> is marked CONFLICT\n",Address,Address->NetbiosAddress.NetbiosName));
+ //
+ // nbifindaddress added a reference, so deref
+ //
+ NbiDereferenceAddress( Address, AREF_FIND );
+ }
+*/
+
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to Deregister nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ PADDRESS Address;
+ BOOLEAN ReservedNameClosing = FALSE;
+
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isn/nb/cache.c b/private/ntos/tdi/isn/nb/cache.c
new file mode 100644
index 000000000..cbd27ad67
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/cache.c
@@ -0,0 +1,2746 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ cache.c
+
+Abstract:
+
+ This module contains the name cache routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 20-December-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ );
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+#endif // RASAUTODIAL
+
+//
+// BUGBUG: We should change to monitor add name packets better,
+// so if we get an add for a different place we attempt to determine
+// if it is real or bogus and update if possible.
+//
+
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+)
+
+/*++
+
+Routine Description:
+
+ This routine looks up a particular remote name in the
+ Netbios name cache. If it cannot find it, a find name
+ request is queued up.
+
+ THIS REQUEST IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Type - Defines the type. The effect this has is:
+ FindNameConnect - On connects we will ignore an existing
+ cache entry if it got no response before.
+ FindNameNetbiosFindName - For these we ignore an existing
+ cache entry if it is for a group name -- this is
+ because the find name wants the address of every
+ machine, not just the network list.
+ FindNameOther - Normal handling is done.
+
+ RemoteName - The name to be discovered -- will be NULL if it
+ is the broadcast address.
+
+ CacheName - Returns the cache entry that was discovered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE FoundCacheName;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR RealRemoteName; // RemoteName or NetbiosBroadcastName
+
+ //
+ // First scan the netbios name cache to see if we know
+ // about this remote.
+ //
+
+ if (RemoteName) {
+ RealRemoteName = RemoteName;
+ } else {
+ RealRemoteName = NetbiosBroadcastName;
+ }
+
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ RealRemoteName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // If this is a netbios find name, we only can use unique
+ // names in the cache; for the group ones we need to requery
+ // because the cache only lists networks, not individual machines.
+ // For connect requests, if we find an empty cache entry we
+ // remove it and requery.
+ //
+
+ if ( FoundCacheName->Unique || (Type != FindNameNetbiosFindName) ) {
+
+ if (FoundCacheName->NetworksUsed > 0) {
+
+ *CacheName = FoundCacheName;
+ NB_DEBUG2 (CACHE, ("Found cache name <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_SUCCESS;
+
+ } else {
+
+ if (Type != FindNameConnect) {
+
+ if (FoundCacheName->FailedOnDownWan) {
+ NB_DEBUG2 (CACHE, ("Found cache name, but down wan <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ } else {
+ NB_DEBUG2 (CACHE, ("Found cache name, but no nets <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ //
+ // This is a connect and the current cache entry
+ // has zero names; delete it.
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+ CTEAssert (FoundCacheName->ReferenceCount == 1);
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free unneeded empty cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+ }
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // There was no suitable cache entry for this network, first see
+ // if there is one pending.
+ //
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // For this purpose we ignore a packet if a route
+ // has been found and it was for a unique name. This
+ // is because the cache information has already been
+ // inserted for this name. Otherwise if the name has
+ // since been deleted from the cache, the request
+ // that is looking for this name will starve because
+ // FindNameTimeout will just destroy the packet.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+ continue;
+ }
+
+ if (RtlEqualMemory(
+ Reserved->u.SR_FN.NetbiosName,
+ RealRemoteName, 16)) {
+
+ NB_DEBUG2 (CACHE, ("Cache name already pending <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+
+ //
+ // There is already one pending. If it is for a group
+ // name and this is a netbios find name, we make sure
+ // the retry count is such that at least one more
+ // query will be sent, so the netbios find name
+ // buffer can be filled with the responses from this.
+ //
+
+ if ((Type == FindNameNetbiosFindName) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) &&
+ (Reserved->u.SR_FN.RetryCount == Device->BroadcastCount)) {
+
+ --Reserved->u.SR_FN.RetryCount;
+ }
+
+ return STATUS_PENDING;
+ }
+ }
+
+ s = NbiPopSendPacket(Device, TRUE);
+
+ if (s == NULL) {
+ NB_DEBUG (CACHE, ("Couldn't get packet to find <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = FALSE;
+ Reserved->Type = SEND_TYPE_FIND_NAME;
+ RtlCopyMemory (Reserved->u.SR_FN.NetbiosName, RealRemoteName, 16);
+ Reserved->u.SR_FN.StatusAndSentOnUpLine = FNStatusNoResponse; // SentOnUpLine is FALSE
+ Reserved->u.SR_FN.RetryCount = 0;
+ Reserved->u.SR_FN.NewCache = NULL;
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+#if !defined(_PNP_POWER)
+ Reserved->u.SR_FN.CurrentNicId = 1;
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAX_TYPE_20_NIC_ID,
+ (USHORT)0,
+ &Reserved->u.SR_FN.MaximumNicId,
+ sizeof(USHORT),
+ NULL);
+
+ if (Reserved->u.SR_FN.MaximumNicId == 0) {
+ Reserved->u.SR_FN.MaximumNicId = 1; // code assumes at least one
+ }
+#endif !_PNP_POWER
+ NB_DEBUG2 (CACHE, ("Queued FIND_NAME %lx for <%.16s>\n",
+ Reserved, RemoteName ? RemoteName : "<broadcast>"));
+
+
+ InsertHeadList(
+ &Device->WaitingFindNames,
+ &Reserved->WaitLinkage);
+
+ ++Device->FindNamePacketCount;
+
+ if (!Device->FindNameTimerActive) {
+
+ Device->FindNameTimerActive = TRUE;
+ NbiReferenceDevice (Device, DREF_FN_TIMER);
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ 1, // 1 ms, i.e. expire immediately
+ FindNameTimeout,
+ (PVOID)Device);
+ }
+
+ NbiReferenceDevice (Device, DREF_FIND_NAME);
+
+ return STATUS_PENDING;
+
+} /* CacheFindName */
+
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the find name timer expires.
+ It is called every FIND_NAME_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, q;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PNETBIOS_CACHE FoundCacheName;
+ NDIS_STATUS NdisStatus;
+#if !defined(_PNP_POWER)
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif !_PNP_POWER
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->FindNameTime;
+
+ if (Device->FindNamePacketCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout exiting\n"));
+
+ Device->FindNameTimerActive = FALSE;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDereferenceDevice (Device, DREF_FN_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+#if defined(_PNP_POWER)
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ //
+
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If this is the first retry, we need to initialize the packet
+ //
+ if ( Reserved->u.SR_FN.RetryCount == 1 ) {
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+
+ }
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx\n", Reserved));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+
+ break;
+
+ }
+#else
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+ //
+ // Save this now, then change it if needed.
+ //
+
+ BroadcastTarget.NicId = Reserved->u.SR_FN.CurrentNicId;
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ }
+
+
+ //
+ // Increment the current NIC ID for next time.
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId >= Reserved->u.SR_FN.MaximumNicId) {
+ Reserved->u.SR_FN.CurrentNicId = 1;
+ } else {
+ ++Reserved->u.SR_FN.CurrentNicId;
+ }
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ // If we are going to wrap around the maximum NIC ID
+ // after sending this packet we wait the full configured
+ // amount, otherwise we wait almost the minimum (but still
+ // insert ourselves at the back of the queue to be fair).
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+ } else {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + 2);
+ }
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx to %d\n", Reserved, BroadcastTarget.NicId));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ if (NdisStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ //
+ // This send was done on a down wan line. To avoid
+ // extensive delays sending find names on systems
+ // with a lot of wan lines, we loop around immediately
+ // and do the next send. We put this packet back on
+ // the head of the list and change its SendTime so
+ // it will be resent immediately.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout resending %lx, wan send failed\n", Reserved));
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertHeadList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+
+ continue;
+
+ } else {
+
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ }
+
+
+ break;
+
+ }
+#endif _PNP_POWER
+
+ //
+ // Since we did something this time, we restart the timer.
+ //
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ FIND_NAME_GRANULARITY,
+ FindNameTimeout,
+ (PVOID)Device);
+
+} /* FindNameTimeout */
+
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams and connects
+ that were waiting for a route to be discovered to a
+ given Netbios NAME. THIS ROUTINE IS CALLED WITH
+ DEVICE->LOCK ACQUIRED AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ RemoteName - The netbios name that was being searched for.
+
+ Result - Indicates if the name was found, or not found due
+ to no response or wan lines being down.
+
+ CacheName - If Result is NetbiosNameFound, the cache entry for this name.
+ This entry has been referenced and this routine will deref it.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY ConnectList;
+ LIST_ENTRY AdapterStatusList;
+ LIST_ENTRY NetbiosFindNameList;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ PLIST_ENTRY p;
+ PREQUEST ConnectRequest, DatagramRequest, AdapterStatusRequest, NetbiosFindNameRequest;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&ConnectList);
+ InitializeListHead (&AdapterStatusList);
+ InitializeListHead (&NetbiosFindNameList);
+
+ //
+ // Put all connect requests on ConnectList. They will
+ // be continued or failed later.
+ //
+
+ p = Device->WaitingConnects.Flink;
+
+ while (p != &Device->WaitingConnects) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+ p = p->Flink;
+
+ if (RtlEqualMemory (Connection->RemoteName, RemoteName, 16)) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ConnectRequest));
+ InsertTailList (&ConnectList, REQUEST_LINKAGE(ConnectRequest));
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+ }
+
+ }
+
+
+ //
+ // Put all the datagrams on Datagram list. They will be
+ // sent or failed later.
+ //
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ //
+ // Check differently based on whether we were looking for
+ // the broadcast address or not.
+ //
+
+ if (Reserved->u.SR_DG.RemoteName == (PVOID)-1) {
+ if (!RtlEqualMemory (RemoteName, NetbiosBroadcastName, 16)) {
+ continue;
+ }
+ } else {
+
+ if (!RtlEqualMemory (RemoteName, Reserved->u.SR_DG.RemoteName->NetbiosName, 16)) {
+ continue;
+ }
+ }
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&DatagramList, &Reserved->WaitLinkage);
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the adapter status requests on AdapterStatus
+ // list. They will be sent or failed later.
+ //
+
+ p = Device->WaitingAdapterStatus.Flink;
+
+ while (p != &Device->WaitingAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(AdapterStatusRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the netbios find name requests on NetbiosFindName
+ // list. They will be completed later.
+ //
+
+ p = Device->WaitingNetbiosFindName.Flink;
+
+ while (p != &Device->WaitingNetbiosFindName) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(NetbiosFindNameRequest));
+ InsertTailList (&NetbiosFindNameList, REQUEST_LINKAGE(NetbiosFindNameRequest));
+
+ }
+
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Now that the lock is free, process all the packets on
+ // the various lists.
+ //
+
+ for (p = ConnectList.Flink; p != &ConnectList; ) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (CONNECTION, ("Found queued connect %lx on %lx\n", ConnectRequest, Connection));
+
+ //
+ // Continue with the connection sequence.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!ConnectRequest->Cancel) {
+
+ IoSetCancelRoutine (ConnectRequest, NbiCancelConnectWaitResponse);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1 );
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelling connect %lx on %lx\n", ConnectRequest, Connection));
+
+ goto AbortConnect;
+
+ //
+ // Jumps down into the else below.
+ //
+
+ }
+
+ } else {
+ BOOLEAN bAutodialAttempt = FALSE;
+
+ NB_DEBUG2 (CONNECTION, ("Timing out connect %lx on %lx\n", ConnectRequest, Connection));
+AbortConnect:
+
+ ASSERT (Connection->ConnectRequest == ConnectRequest);
+
+#ifdef RASAUTODIAL
+ if (fAcdLoadedG) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbiAttemptAutoDial(
+ Device,
+ Connection,
+ 0,
+ NbiRetryTdiConnect,
+ ConnectRequest))
+ {
+ NB_SYNC_FREE_LOCK(&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ bAutodialAttempt = TRUE;
+ }
+ }
+#endif // RASAUTODIAL
+
+ if (!bAutodialAttempt) {
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ IoSetCancelRoutine( ConnectRequest, (PDRIVER_CANCEL)NULL );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS(ConnectRequest) = STATUS_BAD_NETWORK_PATH;
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ } else {
+
+ // BUGBUG What happens to the IRP? Who completes it?
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+
+ }
+
+
+ for (p = DatagramList.Flink; p != &DatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (DATAGRAM, ("Found queued datagram %lx on %lx\n", Reserved->u.SR_DG.DatagramRequest, Reserved->u.SR_DG.AddressFile));
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER( Reserved->u.SR_DG.DatagramRequest )) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Reserved->u.SR_DG.DatagramRequest));
+ }
+
+ NbiTransmitDatagram (Reserved);
+
+ } else {
+
+ //
+ // BETABUGBUG: Should we send it once as a broadcast
+ // on net 0, just in case??
+ //
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Timing out datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // If the failure was due to a down wan line indicate
+ // that, otherwise return success (so the browser won't
+ // confuse this with a down wan line).
+ //
+
+ if (Result == NetbiosNameNotFoundWanDown) {
+ REQUEST_STATUS(DatagramRequest) = STATUS_DEVICE_DOES_NOT_EXIST;
+ REQUEST_INFORMATION(DatagramRequest) = 0;
+ } else {
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+ }
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ }
+
+ }
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (QUERY, ("Found queued AdapterStatus %lx\n", AdapterStatusRequest));
+
+ //
+ // Continue with the AdapterStatus sequence. We put
+ // it in ActiveAdapterStatus, it will either get
+ // completed when a response is received or timed
+ // out by the long timeout.
+ //
+
+ REQUEST_STATUS(AdapterStatusRequest) = (NTSTATUS)CacheName;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (AdapterStatusRequest),
+ &Device->Lock);
+
+ NbiSendStatusQuery (AdapterStatusRequest);
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Timing out AdapterStatus %lx\n", AdapterStatusRequest));
+
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ }
+
+
+ for (p = NetbiosFindNameList.Flink; p != &NetbiosFindNameList; ) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ //
+ // In fact there is not much difference between success or
+ // failure, since in the successful case the information
+ // will already have been written to the buffer. Just
+ // complete the request with the appropriate status,
+ // which will already be stored in the request.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ if (CacheName->Unique) {
+
+ NB_DEBUG2 (QUERY, ("Found queued unique NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Found queued group NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ } else {
+
+ CTEAssert (REQUEST_STATUS(NetbiosFindNameRequest) == STATUS_IO_TIMEOUT);
+ NB_DEBUG2 (QUERY, ("Timed out NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ //
+ // This sets REQUEST_INFORMATION(Request) to the correct value.
+ //
+
+ NbiSetNetbiosFindNameInformation (NetbiosFindNameRequest);
+
+ NbiCompleteRequest(NetbiosFindNameRequest);
+ NbiFreeRequest (Device, NetbiosFindNameRequest);
+
+ NbiDereferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ }
+
+
+ //
+ // We referenced this temporarily so we could use it in here,
+ // deref and check if we need to delete it.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free newly allocated cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free in CacheHandlePending");
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ }
+
+} /* CacheHandlePending */
+
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_NAME_RECOGNIZED frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ PNETBIOS_CACHE NameCache;
+ PREQUEST NetbiosFindNameRequest;
+ PNB_SEND_RESERVED Reserved;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteNetbiosAddress;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+#if 0
+ //
+ // BETABUGBUG: We should handle responses from network 0
+ // differently -- if they are for a group name, we should
+ // keep them around but only until we get a non-zero
+ // response from the same card.
+ //
+
+ if (*(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork) == 0) {
+ return;
+ }
+#endif
+
+
+ //
+ // We need to scan our queue of pending find name packets
+ // to see if someone is waiting for this name.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Find names which have already found unique names are
+ // "dead", waiting for FindNameTimeout to remove them,
+ // and should be ignored when scanning the list.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ continue;
+ }
+
+ if (RtlEqualMemory (Reserved->u.SR_FN.NetbiosName, Connectionless->NameFrame.Name, 16)) {
+ break;
+ }
+ }
+
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Scan for any netbios find name requests on the queue, and
+ // inform them about this remote. We need to do this on every
+ // response because group names need every computer recorded,
+ // but the normal cache only includes one entry per network.
+ //
+
+ for (p = Device->WaitingNetbiosFindName.Flink;
+ p != &Device->WaitingNetbiosFindName;
+ p = p->Flink) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ RemoteNetbiosAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ Connectionless->NameFrame.Name,
+ RemoteNetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ //
+ // This will update the request status if needed.
+ //
+
+ NbiUpdateNetbiosFindName(
+ NetbiosFindNameRequest,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ (TDI_ADDRESS_IPX UNALIGNED *)Connectionless->IpxHeader.SourceNetwork,
+ (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0));
+
+ }
+
+
+ //
+ // See what is up with this pending find name packet.
+ //
+
+ if (Reserved->u.SR_FN.NewCache == NULL) {
+
+ //
+ // This is the first response we have received, so we
+ // allocate the initial entry with room for a single
+ // entry.
+ //
+
+ NameCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (NameCache == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Alloc new cache %lx for <%.16s>, net %lx\n",
+ NameCache, Reserved->u.SR_FN.NetbiosName,
+ *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork)));
+
+ RtlCopyMemory (NameCache->NetbiosName, Connectionless->NameFrame.Name, 16);
+ NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
+ NameCache->ReferenceCount = 1;
+ RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ NameCache->NetworksAllocated = 1;
+ NameCache->NetworksUsed = 1;
+ NameCache->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+
+ if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16)) {
+
+ NB_SET_SR_FN_STATUS (Reserved, FNStatusResponseGroup);
+ NameCache->Unique = FALSE;
+
+ } else {
+
+ NB_SET_SR_FN_STATUS(
+ Reserved,
+ NameCache->Unique ? FNStatusResponseUnique : FNStatusResponseGroup);
+
+ }
+
+ Reserved->u.SR_FN.NewCache = NameCache;
+
+ //
+ // If this packet was not routed to us and is for a group name,
+ // rather than use whatever local target it happened to come
+ // from we set it up so that it is broadcast on that net.
+ //
+
+ if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[0].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
+ RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[0].LocalTarget = *RemoteAddress;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // Complete pending requests now, since it is a unique
+ // name we have all the information we will get.
+ //
+
+ NameCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ NameCache);
+
+ //
+ // Reference it since CacheHandlePending uses it
+ // with the lock released. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++NameCache->ReferenceCount;
+
+ //
+ // This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ NameCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We already have a response to this frame.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // BUGBUG: Should we check that the response is also
+ // unique? Not much to do since I don't know of an
+ // equivalent to the netbeui NAME_IN_CONFLICT.
+ //
+
+ } else {
+
+ //
+ // This is a group name.
+ //
+
+ if (Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) {
+
+ //
+ // Update our information about this network if needed.
+ // This may free the existing cache and allocate a new one.
+ //
+
+ Reserved->u.SR_FN.NewCache =
+ CacheUpdateNameCache(
+ Reserved->u.SR_FN.NewCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)
+ Connectionless->IpxHeader.SourceNetwork,
+ FALSE);
+
+ } else {
+
+ //
+ // BUGBUG: This respondent thinks it is a unique name
+ // but we think it is group, should we do something?
+ //
+
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessNameRecognized */
+
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update a netbios cache entry
+ with a new network, if it is does not already contain
+ information about the network. It is called when a frame
+ is received advertising the appropriate cache entry, which
+ is either a group name or the broadcast name.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH IT HELD.
+
+Arguments:
+
+ NameCache - The name cache entry to update.
+
+ RemoteAddress - The remote address on which a frame was received.
+
+ IpxAddress - The source IPX address of the frame.
+
+ ModifyQueue - TRUE if we should update the queue which this
+ cache entry is in, if we reallocate it.
+
+Return Value:
+
+ The netbios cache entry, either the original or a reallocated one.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT NewNetworks;
+ PNETBIOS_CACHE NewNameCache;
+ PLIST_ENTRY OldPrevious;
+ UINT i;
+
+ //
+ // See if we already know about this network.
+ //
+
+ for (i = 0; i < NameCache->NetworksUsed; i++) {
+ if (NameCache->Networks[i].Network == SourceAddress->NetworkAddress) {
+ return NameCache;
+ }
+ }
+
+ //
+ // We need to add information about this network
+ // to the name cache entry. If we have to allocate
+ // a new one we do that.
+ //
+
+ NB_DEBUG2 (CACHE, ("Got new net %lx for <%.16s>\n",
+ SourceAddress->NetworkAddress,
+ NameCache->NetbiosName));
+
+ if (NameCache->NetworksUsed == NameCache->NetworksAllocated) {
+
+ //
+ // We double the number of entries allocated until
+ // we hit 16, then add 8 at a time.
+ //
+
+ if (NameCache->NetworksAllocated < 16) {
+ NewNetworks = NameCache->NetworksAllocated * 2;
+ } else {
+ NewNetworks = NameCache->NetworksAllocated + 8;
+ }
+
+
+ NewNameCache = NbiAllocateMemory(
+ sizeof(NETBIOS_CACHE) + ((NewNetworks-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge cache entry");
+
+ if (NewNameCache == NULL) {
+ return NameCache;
+ }
+
+ NB_DEBUG2 (CACHE, ("Expand cache %lx to %lx for <%.16s>\n",
+ NameCache, NewNameCache, NameCache->NetbiosName));
+
+ //
+ // Copy the new current data to the new one.
+ //
+
+ RtlCopyMemory(
+ NewNameCache,
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)));
+
+ NewNameCache->NetworksAllocated = NewNetworks;
+ NewNameCache->ReferenceCount = 1;
+
+ if (ModifyQueue) {
+
+ //
+ // Insert at the same place as the old one. The time
+ // stamp is the same as the old one.
+ //
+
+
+ ReinsertInNetbiosCacheTable( Device->NameCache, NameCache, NewNameCache );
+
+ }
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ NameCache = NewNameCache;
+
+ }
+
+ NameCache->Networks[NameCache->NetworksUsed].Network =
+ SourceAddress->NetworkAddress;
+
+ //
+ // If this packet was not routed to us, then store the local
+ // target for a correct broadcast.
+ //
+
+ if (RtlEqualMemory (RemoteAddress->MacAddress, SourceAddress->NodeAddress, 6)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[NameCache->NetworksUsed].LocalTarget.MacAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget = *RemoteAddress;
+ }
+
+ ++NameCache->NetworksUsed;
+
+ return NameCache;
+
+} /* CacheUpdateNameCache */
+
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an add name frame is received.
+ If it is for a group name it checks if our cache entry for
+ that group name needs to be updated to include a new network;
+ for all frames it checks if our broadcast cache entry needs
+ to be updated to include a new network.
+
+Arguments:
+
+ RemoteAddress - The address the frame was received from.
+
+ Connectionless - The header of the received add name.
+
+ LocalFrame - TRUE if the frame was sent locally.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE NameCache;
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ //
+ // First look up the broadcast name.
+ //
+ // BUGBUG: We should cache a pointer to the cache name
+ // for the broadcast entry, if there is one.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!LocalFrame) {
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosBroadcastName,
+ &NameCache ) == STATUS_SUCCESS ) {
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+ }
+
+ }
+
+
+ //
+ // Now see if our database needs to be updated based on this.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Connectionless->NameFrame.Name,
+ &NameCache ) == STATUS_SUCCESS ) {
+
+
+ if (!NameCache->Unique) {
+
+ if (!LocalFrame) {
+
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+
+ }
+
+ } else {
+
+ //
+ // To be safe, delete any unique names we get add
+ // names for (we will requery next time we need it).
+ // BUGBUG: Update the database instead -- but then
+ // we may not get the best route??
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, NameCache );
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free add named cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+} /* CacheUpdateFromAddName */
+
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_DELETE_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // We want to update our netbios cache to reflect the
+ // fact that this name is no longer valid.
+ //
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosName,
+ &CacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // We don't track group names since we don't know if
+ // this is the last person that owns it. We also drop
+ // the frame if does not come from the person we think
+ // owns this name.
+ //
+
+ if ((!CacheName->Unique) ||
+ (CacheName->NetworksUsed == 0) ||
+ (!RtlEqualMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12))) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Found cache name to delete <%.16s>\n", NetbiosName));
+
+ }else {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // We have a cache entry, take it out of the list. If no
+ // one else is using it, delete it; if not, they will delete
+ // it when they are done.
+ //
+
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, CacheName);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessDeleteName */
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry in the hash table
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ USHORT HashIndex;
+
+ //
+ // Keep a threshold of how many entries do we keep in the table.
+ // If it crosses the threshold, just remove the oldest entry
+ //
+ if ( CacheTable->CurrentEntries >= CacheTable->MaxHashIndex * NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET ) {
+ PNETBIOS_CACHE OldestCacheEntry = NULL;
+ PNETBIOS_CACHE NextEntry;
+ PLIST_ENTRY p;
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ if ( (p = CacheTable->Bucket[ HashIndex ].Blink ) != &CacheTable->Bucket[ HashIndex ] ) {
+ NextEntry = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ if ( OldestCacheEntry ) {
+ if ( NextEntry->TimeStamp < OldestCacheEntry->TimeStamp ) {
+ OldestCacheEntry = NextEntry;
+ }
+ } else {
+ OldestCacheEntry = NextEntry;
+ }
+ }
+ }
+
+ CTEAssert( OldestCacheEntry );
+
+ NB_DEBUG2 (CACHE, ("Threshold exceeded, removing oldest cache entry %lx\n", OldestCacheEntry));
+ RemoveEntryList (&OldestCacheEntry->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--OldestCacheEntry->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed cache entry %lx\n", OldestCacheEntry));
+
+ NbiFreeMemory(
+ OldestCacheEntry,
+ sizeof(NETBIOS_CACHE) + ((OldestCacheEntry->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ }
+ HashIndex = ( ( CacheEntry->NetbiosName[0] & 0x0f ) << 4 ) + ( CacheEntry->NetbiosName[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ InsertHeadList( &CacheTable->Bucket[HashIndex], &CacheEntry->Linkage );
+ CacheTable->CurrentEntries++;
+} /* InsertInNetbiosCacheTable */
+
+
+__inline
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry at the same place where
+ the old entry was.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY OldPrevious;
+
+ OldPrevious = OldEntry->Linkage.Blink;
+ RemoveEntryList (&OldEntry->Linkage);
+ InsertHeadList (OldPrevious, &NewEntry->Linkage);
+} /* ReinsertInNetbiosCacheTable */
+
+__inline
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes an entry from the cache table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ RemoveEntryList( &CacheEntry->Linkage );
+ CacheTable->CurrentEntries--;
+} /* RemoveFromNetbiosCacheTable */
+
+
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the old entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ AgeLimit - All the entries older than AgeLimit will be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // see if any entries have been around for more than agelimit
+ //
+
+ if ((USHORT)(NbiDevice->CacheTimeStamp - CacheName->TimeStamp) >= AgeLimit ) {
+
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Aging out name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ } else {
+
+ break;
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushOldFromNetbiosCacheTable */
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the failed entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // flush all the failed cache entries.
+ // We do this when a new adapter appears, and there's a possiblity that
+ // the failed entries might succeed now on the new adapter.
+ //
+
+ if (CacheName->NetworksUsed == 0) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+ CTEAssert( CacheName->ReferenceCount == 1 );
+ CTEAssert( CacheName->NetworksAllocated == 1 );
+
+ NB_DEBUG2 (CACHE, ("Flushing out failed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushFailedNetbiosCacheEntries */
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all invalid route entries from the hash table.
+ Routes become invalid when the binding is deleted in Ipx due to PnP
+ event.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ InvalidRouteNicId - NicId of the invalid routes.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+ USHORT HashIndex;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+
+ for ( HashIndex = 0; HashIndex < Device->NameCache->MaxHashIndex; HashIndex++) {
+ for (p = Device->NameCache->Bucket[ HashIndex ].Flink;
+ p != &Device->NameCache->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Flink;
+
+
+ //
+ // Remove each of those routes which is using this NicId.
+ // if no routes left, then flush the cache entry also.
+ // ( unique names have only one route anyways )
+ //
+ for ( i = 0, NetworksRemoved = 0; i < CacheName->NetworksUsed; i++ ) {
+ if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId == InvalidNicHandle->NicId ) {
+ CTEAssert( RtlEqualMemory( &CacheName->Networks[i].LocalTarget.NicHandle, InvalidNicHandle, sizeof(NIC_HANDLE)));
+ for ( j = i+1; j < CacheName->NetworksUsed; j++ ) {
+ CacheName->Networks[j-1] = CacheName->Networks[j];
+ }
+ NetworksRemoved++;
+ } else if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId > InvalidNicHandle->NicId ) {
+ CacheName->Networks[i].LocalTarget.NicHandle.NicId--;
+ }
+ }
+ CTEAssert( NetworksRemoved <= CacheName->NetworksUsed );
+ if ( ! ( CacheName->NetworksUsed -= NetworksRemoved ) ) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ NB_DEBUG2 (CACHE, ("Removed cache entry %lx bcoz route(NicId %d) deleted\n", CacheName, InvalidNicHandle->NicId ));
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ }
+ } // for loop
+ } // for loop
+} /* RemoveInvalidRoutesFromNetbiosCacheTable */
+
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds a netbios name in the Hash Table and returns
+ the corresponding cache entry.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Pointer to the netbios cache entry if found.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_UNSUCCESSFUL - otherwise.
+
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE FoundCacheName;
+
+
+ HashIndex = ( ( NameToBeFound[0] & 0x0f ) << 4 ) + ( NameToBeFound[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ for (p = ( CacheTable->Bucket[ HashIndex ] ).Flink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ p = p->Flink) {
+
+ FoundCacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ //
+ // See if this entry is for the same name we are looking for.
+
+ if ( RtlEqualMemory (FoundCacheName->NetbiosName, NameToBeFound, 16) ) {
+ *CacheEntry = FoundCacheName;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL;
+} /* FindInNetbiosCacheTable */
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new hash table for netbios cache
+ and initializes it.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ NewTable - The pointer of the table to be created.
+
+ MaxHashIndex - Number of buckets in the hash table.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_INSUFFICIENT_RESOURCES - If cannot allocate memory.
+
+--*/
+
+{
+ USHORT i;
+
+ *NewTable = NbiAllocateMemory (sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Cache Table");
+
+ if ( *NewTable ) {
+ for ( i = 0; i < MaxHashIndex; i++ ) {
+ InitializeListHead(& (*NewTable)->Bucket[i] );
+ }
+
+ (*NewTable)->MaxHashIndex = MaxHashIndex;
+ (*NewTable)->CurrentEntries = 0;
+ return STATUS_SUCCESS;
+ }
+ else {
+ NB_DEBUG( CACHE, ("Cannot create Netbios Cache Table\n") );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+} /* CreateNetbiosCacheTable */
+
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all entries from the hash table.
+ and free up the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ while (!IsListEmpty ( &( CacheTable->Bucket[ HashIndex ] ) ) ) {
+
+ p = RemoveHeadList ( &( CacheTable->Bucket[ HashIndex ] ));
+ CacheTable->CurrentEntries--;
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ NB_DEBUG2 (CACHE, ("Free cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free entries");
+
+ }
+ } // for loop
+
+ CTEAssert( CacheTable->CurrentEntries == 0 );
+
+ NbiFreeMemory (CacheTable, sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( CacheTable->MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Free Cache Table");
+
+} /* DestroyNetbiosCacheTable */
+
+
diff --git a/private/ntos/tdi/isn/nb/config.c b/private/ntos/tdi/isn/nb/config.c
new file mode 100644
index 000000000..8689c5d20
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/config.c
@@ -0,0 +1,661 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN Netbios module.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiGetConfiguration)
+#pragma alloc_text(INIT,NbiFreeConfiguration)
+#pragma alloc_text(INIT,NbiGetConfigValue)
+#pragma alloc_text(INIT,NbiAddBind)
+#pragma alloc_text(INIT,NbiAddExport)
+#pragma alloc_text(INIT,NbiReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios 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 ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of Netbios' node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG One = 1;
+ ULONG Two = 2;
+ ULONG Three = 3;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG FortyEight = 48;
+ ULONG Sixty = 60;
+ ULONG TwoFifty = 250;
+ ULONG FiveHundred = 500;
+ ULONG MaxMTU = 0xffffffff;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"AckDelayTime", &TwoFifty } , // milliseconds
+ { L"AckWindow", &Two } ,
+ { L"AckWindowThreshold", &FiveHundred } , // milliseconds
+ { L"EnablePiggyBackAck", &One } ,
+ { L"Extensions", &One } ,
+ { L"RcvWindowMax", &Four } ,
+ { L"BroadcastCount", &Three } ,
+ { L"BroadcastTimeout", &One } , // half-seconds
+ { L"ConnectionCount", &Five } ,
+ { L"ConnectionTimeout", &Two } , // half-seconds
+ { L"InitPackets", &Eight } ,
+ { L"MaxPackets", &FortyEight } ,
+ { L"InitialRetransmissionTime", &FiveHundred } , // milliseconds
+ { L"Internet", &One } ,
+ { L"KeepAliveCount", &Eight } ,
+ { L"KeepAliveTimeout", &Sixty } , // half-seconds
+ { L"RetransmitMax", &Eight } ,
+ { L"RouterMTU", &MaxMTU } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = NbiAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, sizeof(CONFIG), MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ Config->BindName.Buffer = NULL;
+ Config->DriverObject = DriverObject; // save this to log errors
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbiReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)NbiAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG);
+ NbiFreeConfiguration(Config);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = NbiReadLinkageInformation (Config);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ return Status;
+ }
+
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-18) Call NbiSetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = NbiGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 19) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ NbiFreeConfiguration(Config);
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 701,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ NbiFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfiguration */
+
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get free any storage that was allocated
+ by NbiGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Config->BindName.Buffer) {
+ NbiFreeMemory (Config->BindName.Buffer, Config->BindName.MaximumLength, MEMORY_CONFIG, "BindName");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ NbiFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ NbiFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* NbiFreeConfig */
+
+
+NTSTATUS
+NbiGetConfigValue(
+ 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 entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ ULONG Data = *(UNALIGNED ULONG *)ValueData;
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ switch ( (ULONG) EntryContext ) {
+ case CONFIG_ROUTER_MTU:
+ if ( ( Data - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER) ) <= 0 ) {
+ Config->Parameters[CONFIG_ROUTER_MTU] = 0xffffffff;
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 704,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ NB_DEBUG2 (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, Data));
+ Config->Parameters[(ULONG)EntryContext] = Data;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfigValue */
+
+
+NTSTATUS
+NbiAddBind(
+ 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 Config 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.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read bind value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "BindName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->BindName.Buffer = NameBuffer;
+ Config->BindName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->BindName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddBind */
+
+
+NTSTATUS
+NbiAddExport(
+ 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. It
+ saves the first callback string in the Config 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.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddExport */
+
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk; // set to TRUE when a value is read correctly
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call NbiAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 702,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+
+ //
+ // 1) Change to call NbiAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 703,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiReadLinkageInformation */
+
diff --git a/private/ntos/tdi/isn/nb/config.h b/private/ntos/tdi/isn/nb/config.h
new file mode 100644
index 000000000..99b6c6357
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/config.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN Netbios module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_ACK_DELAY_TIME 0
+#define CONFIG_ACK_WINDOW 1
+#define CONFIG_ACK_WINDOW_THRESHOLD 2
+#define CONFIG_ENABLE_PIGGYBACK_ACK 3
+#define CONFIG_EXTENSIONS 4
+#define CONFIG_RCV_WINDOW_MAX 5
+#define CONFIG_BROADCAST_COUNT 6
+#define CONFIG_BROADCAST_TIMEOUT 7
+#define CONFIG_CONNECTION_COUNT 8
+#define CONFIG_CONNECTION_TIMEOUT 9
+#define CONFIG_INIT_PACKETS 10
+#define CONFIG_MAX_PACKETS 11
+#define CONFIG_INIT_RETRANSMIT_TIME 12
+#define CONFIG_INTERNET 13
+#define CONFIG_KEEP_ALIVE_COUNT 14
+#define CONFIG_KEEP_ALIVE_TIMEOUT 15
+#define CONFIG_RETRANSMIT_MAX 16
+#define CONFIG_ROUTER_MTU 17
+#define CONFIG_PARAMETERS 18
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ NDIS_STRING BindName; // device to bind to
+ PWSTR RegistryPathBuffer; // path to config info
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ );
+
diff --git a/private/ntos/tdi/isn/nb/connect.c b/private/ntos/tdi/isn/nb/connect.c
new file mode 100644
index 000000000..7ee7204b5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/connect.c
@@ -0,0 +1,3628 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This routine contains the code to handle connect requests
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a find route request
+ previously issued to IPX completes.
+
+Arguments:
+
+ FindRouteRequest - The find route request that was issued.
+
+ FoundRoute - TRUE if the route was found.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ UINT i;
+ BOOLEAN LocalRoute;
+ USHORT TickCount;
+ PREQUEST RequestToComplete;
+ PUSHORT Counts;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ Connection = CONTAINING_RECORD (FindRouteRequest, CONNECTION, FindRouteRequest);
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection->FindRouteInProgress = FALSE;
+
+ if (FoundRoute) {
+
+ //
+ // See if the route is local or not (for local routes
+ // we use the real MAC address in the local target, but
+ // the NIC ID may not be what we expect.
+ //
+
+ LocalRoute = TRUE;
+
+ for (i = 0; i < 6; i++) {
+ if (FindRouteRequest->LocalTarget.MacAddress[i] != 0x00) {
+ LocalRoute = FALSE;
+ }
+ }
+
+ if (LocalRoute) {
+
+#if defined(_PNP_POWER)
+ Connection->LocalTarget.NicHandle = FindRouteRequest->LocalTarget.NicHandle;
+#else
+ Connection->LocalTarget.NicId = FindRouteRequest->LocalTarget.NicId;
+#endif _PNP_POWER
+
+ } else {
+
+ Connection->LocalTarget = FindRouteRequest->LocalTarget;
+
+ }
+
+ Counts = (PUSHORT)(&FindRouteRequest->Reserved2);
+ TickCount = Counts[0];
+
+ if (TickCount > 1) {
+
+ //
+ // Each tick is 55 ms, and for our timeout we use 10 ticks
+ // worth (this makes tick count of 1 be about 500 ms, the
+ // default).
+ //
+ // We get 55 milliseconds from
+ //
+ // 1 second * 1000 milliseconds 55 ms
+ // -------- ----------------- = -----
+ // 18.21 ticks 1 second tick
+ //
+
+ Connection->TickCount = TickCount;
+ Connection->BaseRetransmitTimeout = (TickCount * 550) / SHORT_TIMER_DELTA;
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+ }
+
+ Connection->HopCount = Counts[1];
+
+ }
+
+ //
+ // If the call failed we just use whatever route we had before
+ // (on a connect it will be from the name query response, on
+ // a listen from whatever the incoming connect frame had).
+ //
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_W_ROUTE)) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // Continue on with the session init frame.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+ // Maximum packet size is the lower of RouterMtu and MaximumSendSize.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER) , Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION) ;
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ //
+ // Don't set RcvSequenceMax yet because we don't know
+ // if the connection is old or new netbios.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+
+ //
+ // We found a route, we need to start the connect
+ // process by sending out the session initialize
+ // frame. We start the timer to handle retries.
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiSendSessionInitialize (Connection);
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ROUTE)) {
+
+ if (Connection->ListenRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_ACTIVE);
+ RequestToComplete = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+
+ } else if (Connection->AcceptRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_ACCEPT, CREF_ACTIVE);
+ RequestToComplete = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ } else {
+
+ CTEAssert (FALSE);
+ RequestToComplete = NULL;
+
+ }
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+
+ // Take the lowest of MaximumPacketSize ( set from the sessionInit
+ // frame ), MaximumSendSize and RouterMtu.
+
+ if (Connection->MaximumPacketSize > Connection->LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)) {
+
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER), Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION);
+
+ } else {
+
+ // Connection->MaximumPacketSize is what was set by the sender so already
+ // accounts for the header.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER), Connection->MaximumPacketSize ) ;
+
+ }
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ if (Connection->NewNetbios) {
+ CTEAssert (Connection->LocalRcvSequenceMax == 4); // should have been set
+ Connection->LocalRcvSequenceMax = Connection->ReceiveWindowSize;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ ++Device->Statistics.OpenConnections;
+
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // StartWatchdog acquires TimerLock, so we have to
+ // free Lock first.
+ //
+
+
+ NbiStartWatchdog (Connection);
+
+ //
+ // This releases the connection lock, so that SessionInitAckData
+ // can't be freed before it is copied.
+ //
+
+ NbiSendSessionInitAck(
+ Connection,
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ &LockHandle1);
+
+ if (RequestToComplete != NULL) {
+
+ REQUEST_STATUS(RequestToComplete) = STATUS_SUCCESS;
+
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_FIND_ROUTE);
+
+} /* NbiFindRouteComplete */
+
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+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:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PFILE_FULL_EA_INFORMATION ea;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ if (!(Connection = NbiCreateConnection (Device))) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // 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
+ //
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)Connection;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONNECTION_FILE;
+#ifdef ISN_NT
+ Connection->FileObject = IrpSp->FileObject;
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* NbiOpenConnection */
+
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to stop an active connection.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection to be stopped.
+
+ DisconnectStatus - The reason for the disconnect. One of:
+ STATUS_LINK_FAILED: We timed out trying to probe the remote.
+ STATUS_REMOTE_DISCONNECT: The remote sent a session end.
+ STATUS_LOCAL_DISCONNECT: The local side disconnected.
+ STATUS_CANCELLED: A send or receive on this connection was cancelled.
+ STATUS_INVALID_CONNECTION: The local side closed the connection.
+ STATUS_INVALID_ADDRESS: The local side closed the address.
+
+ LockHandle - The handle which the connection lock was acquired with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST ListenRequest, AcceptRequest, SendRequest, ReceiveRequest,
+ DisconnectWaitRequest, ConnectRequest;
+ PREQUEST Request, TmpRequest;
+ BOOLEAN DerefForPacketize;
+ BOOLEAN DerefForWaitPacket;
+ BOOLEAN DerefForActive;
+ BOOLEAN DerefForWaitCache;
+ BOOLEAN SendSessionEnd;
+ BOOLEAN ActiveReceive;
+ BOOLEAN IndicateToClient;
+ BOOLEAN ConnectionWasActive;
+ PDEVICE Device = NbiDevice;
+ PADDRESS_FILE AddressFile;
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+
+ NB_DEBUG2 (CONNECTION, ("Stop connection %lx (%lx)\n", Connection, DisconnectStatus));
+
+ //
+ // These flags control our actions after we set the state to
+ // DISCONNECT.
+ //
+
+ DerefForPacketize = FALSE;
+ DerefForWaitPacket = FALSE;
+ DerefForActive = FALSE;
+ DerefForWaitCache = FALSE;
+ SendSessionEnd = FALSE;
+ ActiveReceive = FALSE;
+ IndicateToClient = FALSE;
+ ConnectionWasActive = FALSE;
+
+ //
+ // These contain requests or queues of request to complete.
+ //
+
+ ListenRequest = NULL;
+ AcceptRequest = NULL;
+ SendRequest = NULL;
+ ReceiveRequest = NULL;
+ DisconnectWaitRequest = NULL;
+ ConnectRequest = NULL;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ --Device->Statistics.OpenConnections;
+
+ ConnectionWasActive = TRUE;
+
+ Connection->Status = DisconnectStatus;
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_LOCAL_DISCONNECT)) {
+
+ //
+ // Send out session end frames, but fewer if
+ // we timed out.
+ //
+ // BUGBUG: What about STATUS_CANCELLED?
+ //
+
+ Connection->Retries = (DisconnectStatus == STATUS_LOCAL_DISCONNECT) ?
+ Device->ConnectionCount :
+ (Device->ConnectionCount / 2);
+
+ SendSessionEnd = TRUE;
+ Connection->SubState = CONNECTION_SUBSTATE_D_W_ACK;
+
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_TRANSFER) {
+ ActiveReceive = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_DISCONNECT;
+ DerefForActive = TRUE;
+
+ if (Connection->DisconnectWaitRequest != NULL) {
+ DisconnectWaitRequest = Connection->DisconnectWaitRequest;
+ Connection->DisconnectWaitRequest = NULL;
+ }
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_REMOTE_DISCONNECT) ||
+ (DisconnectStatus == STATUS_CANCELLED)) {
+
+ IndicateToClient = TRUE;
+
+ }
+
+ //
+ // If we are inside NbiAssignSequenceAndSend, add
+ // a reference so the connection won't go away during it.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+ *(Connection->NdisSendReference) = TRUE;
+ NB_DEBUG2 (SEND, ("Adding CREF_NDIS_SEND to %lx\n", Connection));
+ NbiReferenceConnectionLock (Connection, CREF_NDIS_SEND);
+ }
+
+ //
+ // Clean up some other stuff.
+ //
+
+ Connection->ReceiveUnaccepted = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ //
+ // Update our counters. BUGBUG: Some of these we
+ // never use.
+ //
+
+ switch (DisconnectStatus) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ ++Device->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ ++Device->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ ++Device->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ ++Device->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ ++Device->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ ++Device->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INVALID_CONNECTION:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INSUFFICIENT_RESOURCES:
+ ++Device->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_REMOTE_NOT_LISTENING:
+ ++Device->Statistics.NotFoundFailures;
+ break;
+ default:
+ CTEAssert(FALSE);
+ break;
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ //
+ // There is a connect in progress. We have to find ourselves
+ // in the pending connect queue if we are there.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) {
+ RemoveEntryList (REQUEST_LINKAGE(Connection->ConnectRequest));
+ DerefForWaitCache = TRUE;
+ }
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) {
+
+ ConnectRequest = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ }
+
+ }
+
+
+ //
+ // If we allocated this memory, free it.
+ //
+
+ if (Connection->SessionInitAckDataLength > 0) {
+
+ NbiFreeMemory(
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ MEMORY_CONNECTION,
+ "SessionInitAckData");
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+
+ }
+
+
+ if (Connection->ListenRequest != NULL) {
+
+ ListenRequest = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(ListenRequest)); // take out of Device->ListenQueue
+
+ }
+
+ if (Connection->AcceptRequest != NULL) {
+
+ AcceptRequest = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ }
+
+
+ //
+ // BUGBUG: Do we need to stop the connection timer?
+ // I don't think so.
+ //
+
+
+
+ //
+ // A lot of this we only have to tear down if we were
+ // active before this, because once we are stopping nothing
+ // new will get started. BUGBUG: Some of the other stuff
+ // can be put inside this if also.
+ //
+
+ if (ConnectionWasActive) {
+
+ //
+ // Stop any receives. If there is one that is actively
+ // transferring we leave it and just run down the rest
+ // of the queue. If not, we queue the rest of the
+ // queue on the back of the current one and run
+ // down them all.
+ //
+
+ if (ActiveReceive) {
+
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+
+ //
+ // Connection->ReceiveRequest will get set to NULL
+ // when the transfer completes.
+ //
+
+ } else {
+
+ ReceiveRequest = Connection->ReceiveRequest;
+ if (ReceiveRequest) {
+ REQUEST_SINGLE_LINKAGE (ReceiveRequest) = Connection->ReceiveQueue.Head;
+ } else {
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+ }
+ Connection->ReceiveRequest = NULL;
+
+ }
+
+ Connection->ReceiveQueue.Head = NULL;
+
+
+ if ((Request = Connection->FirstMessageRequest) != NULL) {
+
+ //
+ // If the current request has some sends outstanding, then
+ // we dequeue it from the queue to let it complete when
+ // the sends complete. In that case we set SendRequest
+ // to be the rest of the queue, which will be aborted.
+ // If the current request has no sends, then we put
+ // queue everything to SendRequest to be aborted below.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ //
+ // NOTE: If this is a multi-request message, then
+ // the linkage of Request will already point to the
+ // send queue head, but we don't bother checking.
+ //
+
+ SendRequest = Request;
+ REQUEST_SINGLE_LINKAGE (Request) = Connection->SendQueue.Head;
+
+ } else {
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->FirstMessageRequest = NULL;
+
+ } else {
+
+ //
+ // This may happen if we were sending a probe when a
+ // send was submitted, and the probe timed out.
+ //
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->SendQueue.Head = NULL;
+
+ }
+
+
+ if (Connection->OnWaitPacketQueue) {
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+ DerefForWaitPacket = TRUE;
+ }
+
+ if (Connection->OnPacketizeQueue) {
+ Connection->OnPacketizeQueue = FALSE;
+ RemoveEntryList (&Connection->PacketizeLinkage);
+ DerefForPacketize = TRUE;
+ }
+
+ //
+ // BUGBUG: Should we check if DataAckPending is TRUE and
+ // send an ack??
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // We can't acquire TimerLock with Lock held, since
+ // we sometimes call ReferenceConnection (which does an
+ // interlocked add using Lock) with TimerLock held.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle3);
+
+ if (Connection->OnShortList) {
+ Connection->OnShortList = FALSE;
+ RemoveEntryList (&Connection->ShortList);
+ }
+
+ if (Connection->OnLongList) {
+ Connection->OnLongList = FALSE;
+ RemoveEntryList (&Connection->LongList);
+ }
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Device->DataAckQueueChanged = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle3);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+
+ if (IndicateToClient) {
+
+ AddressFile = Connection->AddressFile;
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_DISCONNECT]) {
+
+ NB_DEBUG2 (CONNECTION, ("Session end indicated on connection %lx\n", Connection));
+
+ (*AddressFile->DisconnectHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_DISCONNECT],
+ Connection->Context,
+ 0, // DisconnectData
+ NULL,
+ 0, // DisconnectInformation
+ NULL,
+ TDI_DISCONNECT_RELEASE); // DisconnectReason. BUGBUG: Clean it up?
+
+ }
+
+ }
+
+
+ if (DisconnectWaitRequest != NULL) {
+
+ //
+ // Make the TDI tester happy by returning CONNECTION_RESET
+ // here.
+ //
+
+ if (DisconnectStatus == STATUS_REMOTE_DISCONNECT) {
+ REQUEST_STATUS(DisconnectWaitRequest) = STATUS_CONNECTION_RESET;
+ } else {
+ REQUEST_STATUS(DisconnectWaitRequest) = DisconnectStatus;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (DisconnectWaitRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (DisconnectWaitRequest);
+ NbiFreeRequest (Device, DisconnectWaitRequest);
+
+ }
+
+ if (ConnectRequest != NULL) {
+
+ REQUEST_STATUS (ConnectRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ConnectRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION(ListenRequest) = 0;
+ REQUEST_STATUS(ListenRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest(Device, ListenRequest);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ }
+
+ if (AcceptRequest != NULL) {
+
+ REQUEST_INFORMATION(AcceptRequest) = 0;
+ REQUEST_STATUS(AcceptRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest(Device, AcceptRequest);
+
+ NbiDereferenceConnection (Connection, CREF_ACCEPT);
+
+ }
+
+ while (ReceiveRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (ReceiveRequest);
+
+ REQUEST_STATUS (ReceiveRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (ReceiveRequest) = 0;
+
+ NB_DEBUG2 (RECEIVE, ("StopConnection aborting receive %lx\n", ReceiveRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ReceiveRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ReceiveRequest);
+ NbiFreeRequest (Device, ReceiveRequest);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ ReceiveRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ }
+
+ while (SendRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+
+ REQUEST_STATUS (SendRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (SendRequest) = 0;
+
+ NB_DEBUG2 (SEND, ("StopConnection aborting send %lx\n", SendRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+
+ SendRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ if (SendSessionEnd) {
+ NbiSendSessionEnd (Connection);
+ }
+
+ if (DerefForWaitCache) {
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ }
+
+ if (DerefForPacketize) {
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+ }
+
+ if (DerefForWaitPacket) {
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+ }
+
+ if (DerefForActive) {
+ NbiDereferenceConnection (Connection, CREF_ACTIVE);
+ }
+
+} /* NbiStopConnection */
+
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (CONNECTION, ("Close connection %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and some thread has already done cleanup,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ if ( Connection->CanBeDestroyed && ( Connection->ThreadsInHandleConnectionZero == 0 ) ) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDestroyConnection(Connection);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ return Status;
+
+} /* NbiCloseConnection */
+
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and
+ the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject;
+#endif
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
+ CTELockHandle LockHandle;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+
+ //
+ // The request request parameters hold
+ // get a pointer to the address FileObject, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)REQUEST_PARAMETERS(Request);
+
+#ifdef ISN_NT
+
+ Status = ObReferenceObjectByHandle (
+ Parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *)&FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ AddressFile = (PADDRESS_FILE)(FileObject->FsContext);
+
+#else
+
+ //
+ // I don't know how this works in a VxD.
+ //
+
+ AddressFile = (PADDRESS_FILE)(Parameters->AddressHandle);
+
+#endif
+
+ //
+ // Make sure the address file is valid, and reference it.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+
+#ifdef ISN_NT
+ ObDereferenceObject (FileObject);
+#endif
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Associate connection %lx with address file %lx\n",
+ Connection, AddressFile));
+
+
+ //
+ // Now insert the connection into the database of the address.
+ //
+
+ Address = AddressFile->Address;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFile != NULL) {
+
+ //
+ // The connection is already associated with
+ // an address file.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ if (AddressFile->State == ADDRESSFILE_STATE_OPEN) {
+
+ Connection->AddressFile = AddressFile;
+ Connection->AddressFileLinked = TRUE;
+ InsertHeadList (&AddressFile->ConnectionDatabase, &Connection->AddressFileLinkage);
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ }
+
+#ifdef ISN_NT
+
+ //
+ // We don't need the reference to the file object, we just
+ // used it to get from the handle to the object.
+ //
+
+ ObDereferenceObject (FileObject);
+
+#endif
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAssociateAddress */
+
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection
+ and the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Disassociate connection %lx\n", Connection));
+
+
+ //
+ // First check if the connection is still active.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if (Connection->State != CONNECTION_STATE_INACTIVE) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ //
+ // BUGBUG: Keep the sync through the function??
+ //
+
+ NB_END_SYNC (&SyncContext);
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is associated and is not in the
+ // middle of disassociating.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL)) {
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // Because the connection still has a reference to
+ // the address file, we know it is still valid. We
+ // set the connection address file to the temporary
+ // value of -1, which prevents somebody else from
+ // disassociating it and also prevents a new association.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Set this so when the count goes to 0 it will
+ // be disassociated and the request completed.
+ //
+
+ Connection->DisassociatePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisassociateAddress */
+
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine posts a listen on a connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the listen.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_WAITING;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+
+ if (!Request->Cancel) {
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen %lx on %lx\n", Request, Connection));
+ InsertTailList (&Device->ListenQueue, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelListen);
+ Connection->ListenRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_LISTEN);
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen %lx on %lx\n", Request, Connection));
+ Connection->State = CONNECTION_STATE_INACTIVE;
+ Status = STATUS_CANCELLED;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiListen */
+
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection to a remote machine. The
+ connection must previously have completed a listen with
+ the TDI_QUERY_ACCEPT flag on.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the accept.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_ACCEPT, CREF_ACCEPT);
+ Connection->AcceptRequest = Request;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Accept received on %lx\n", Connection));
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Accept received on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAccept */
+
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_CONNECT Parameters;
+#if 0
+ PLARGE_INTEGER RequestedTimeout;
+ LARGE_INTEGER RealTimeout;
+#endif
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteName == NULL) {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ } else {
+
+ NbiReferenceConnectionLock (Connection, CREF_CONNECT);
+ Connection->State = CONNECTION_STATE_CONNECTING;
+ RtlCopyMemory (Connection->RemoteName, RemoteName->NetbiosName, 16);
+
+ Connection->Retries = Device->ConnectionCount;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+ Status = NbiTdiConnectFindName(
+ Device,
+ Request,
+ Connection,
+ CancelLH,
+ LockHandle1,
+ LockHandle2,
+ &bLockFreed);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Connect on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiConnect */
+
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ )
+{
+ NTSTATUS Status;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // See what is up with this Netbios name.
+ //
+
+ Status = CacheFindName(
+ Device,
+ FindNameConnect,
+ Connection->RemoteName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this connect
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_FIND_NAME;
+
+
+ if (!Request->Cancel) {
+
+ InsertTailList( &Device->WaitingConnects, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelConnectFindName);
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_WAIT_CACHE);
+ NB_DEBUG2 (CONNECTION, ("Queueing up connect %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // We don't need to worry about referencing CacheName
+ // because we stop using it before we release the lock.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelConnectWaitResponse);
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, ConnectionLH);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_DEBUG2 (CONNECTION, ("Found connect cached %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NB_FREE_LOCK (&Connection->Lock, ConnectionLH);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ Status = STATUS_PENDING;
+
+ //
+ // This jump is like falling out of the if, except
+ // it skips over freeing the connection lock since
+ // we just did that.
+ //
+
+ *pbLockFreed = TRUE;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We could not find or queue a request for
+ // this remote, fail it. When the refcount
+ // drops the state will go to INACTIVE and
+ // the connection ID will be deassigned.
+ //
+
+ if (Status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ }
+
+ return Status;
+} /* NbiTdiConnectFindName */
+
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ BOOLEAN DisconnectWait;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ CTELockHandle CancelLH;
+
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ DisconnectWait = (BOOLEAN)
+ ((((PTDI_REQUEST_KERNEL_DISCONNECT)(REQUEST_PARAMETERS(Request)))->RequestFlags &
+ TDI_DISCONNECT_WAIT) != 0);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+
+ //
+ // We need to be inside a sync because NbiStopConnection
+ // expects that.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (DisconnectWait) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // This disconnect wait will get completed by
+ // NbiStopConnection.
+ //
+
+ if (Connection->DisconnectWaitRequest == NULL) {
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelDisconnectWait);
+ NB_DEBUG2 (CONNECTION, ("Disconnect wait queued on connection %lx\n", Connection));
+ Connection->DisconnectWaitRequest = Request;
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled disconnect wait on connection %lx\n", Connection));
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We got a second disconnect request and we already
+ // have one pending.
+ //
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, already queued on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait submitted on disconnected connection %lx\n", Connection));
+ Status = Connection->Status;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, bad state on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ } else {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of active connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ //
+ // This call releases the connection lock, sets
+ // the state to DISCONNECTING, and sends out
+ // the first session end.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // There is already a disconnect pending. Queue
+ // this one up so it completes when the refcount
+ // goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of disconnecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ //
+ // We were waiting for an accept, but instead we got
+ // a disconnect. Remove the reference and the teardown
+ // will proceed. The disconnect will complete when the
+ // refcount goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of accept pending connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_W_ACCEPT);
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // We are connecting, and got a disconnect. We call
+ // NbiStopConnection which will handle this case
+ // and abort the connect.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of connecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // This call releases the connection lock and
+ // aborts the connect request.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of invalid connection (%d) %lx\n",
+ Connection->State, Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisconnect */
+
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a connection ID. It picks
+ one whose hash table has the fewest entries.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD. THE CONNECTION IS INSERTED INTO THE CORRECT HASH
+ ENTRY BY THIS CALL.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ TRUE if it could be successfully assigned.
+
+--*/
+
+{
+ UINT Hash;
+ UINT i;
+ USHORT ConnectionId, HashId;
+ PCONNECTION CurConnection;
+
+
+ CTEAssert (Connection->LocalConnectionId == 0xffff);
+
+ //
+ // Find the hash bucket with the fewest entries.
+ //
+
+ Hash = 0;
+ for (i = 1; i < CONNECTION_HASH_COUNT; i++) {
+ if (Device->ConnectionHash[i].ConnectionCount < Device->ConnectionHash[Hash].ConnectionCount) {
+ Hash = i;
+ }
+ }
+
+
+ //
+ // Now find a valid connection ID within that bucket.
+ //
+
+ ConnectionId = Device->ConnectionHash[Hash].NextConnectionId;
+
+ while (TRUE) {
+
+ //
+ // Scan through the list to see if this ID is in use.
+ //
+
+ HashId = (USHORT)(ConnectionId | (Hash << CONNECTION_HASH_SHIFT));
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+
+ while (CurConnection != NULL) {
+ if (CurConnection->LocalConnectionId != HashId) {
+ CurConnection = CurConnection->NextConnection;
+ } else {
+ break;
+ }
+ }
+
+ if (CurConnection == NULL) {
+ break;
+ }
+
+ if (ConnectionId >= CONNECTION_MAXIMUM_ID) {
+ ConnectionId = 1;
+ } else {
+ ++ConnectionId;
+ }
+
+ //
+ // BUGBUG: What if we have 64K-1 sessions and loop forever?
+ //
+ }
+
+ if (Device->ConnectionHash[Hash].NextConnectionId >= CONNECTION_MAXIMUM_ID) {
+ Device->ConnectionHash[Hash].NextConnectionId = 1;
+ } else {
+ ++Device->ConnectionHash[Hash].NextConnectionId;
+ }
+
+ Connection->LocalConnectionId = HashId;
+ Connection->RemoteConnectionId = 0xffff;
+ NB_DEBUG2 (CONNECTION, ("Assigned ID %lx to %x\n", Connection->LocalConnectionId, Connection));
+
+ Connection->NextConnection = Device->ConnectionHash[Hash].Connections;
+ Device->ConnectionHash[Hash].Connections = Connection;
+ ++Device->ConnectionHash[Hash].ConnectionCount;
+
+ return TRUE;
+
+} /* NbiAssignConnectionId */
+
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to deassign a connection ID. It removes
+ the connection from the hash bucket for its ID.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT Hash;
+ PCONNECTION CurConnection;
+ PCONNECTION * PrevConnection;
+
+ //
+ // Make sure the connection has a valid ID.
+ //
+
+ CTEAssert (Connection->LocalConnectionId != 0xffff);
+
+ Hash = (Connection->LocalConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+ PrevConnection = &Device->ConnectionHash[Hash].Connections;
+
+ while (TRUE) {
+
+ CTEAssert (CurConnection != NULL);
+
+ //
+ // We can loop until we find it because it should be
+ // on here.
+ //
+
+ if (CurConnection == Connection) {
+ *PrevConnection = Connection->NextConnection;
+ --Device->ConnectionHash[Hash].ConnectionCount;
+ break;
+ }
+
+ PrevConnection = &CurConnection->NextConnection;
+ CurConnection = CurConnection->NextConnection;
+
+ }
+
+ Connection->LocalConnectionId = 0xffff;
+
+} /* NbiDeassignConnectionId */
+
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection timer expires.
+ This is either because we need to send the next session
+ initialize, or because our listen has timed out.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection = (PCONNECTION)Context;
+ PDEVICE Device = NbiDevice;
+ PREQUEST Request;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (CancelLH)
+
+ //
+ // Take the lock and see what we need to do.
+ //
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (--Connection->Retries == 0) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out session initializes on %lx\n", Connection));
+
+ //
+ // We have just timed out this connect, we fail the
+ // request. When the reference count goes to 0 we
+ // will set the state to INACTIVE and deassign
+ // the connection ID.
+ //
+
+ Request = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_BAD_NETWORK_PATH;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session initialize.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionInitialize (Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ if ((Connection->SubState != CONNECTION_SUBSTATE_D_W_ACK) ||
+ (--Connection->Retries == 0)) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out disconnect of %lx\n", Connection));
+
+ //
+ // Just dereference the connection, that will cause the
+ // disconnect to be completed, the state to be set
+ // to INACTIVE, and our connection ID deassigned.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session end.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionEnd(Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ }
+
+} /* NbiConnectionTimeout */
+
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ listen.
+
+ 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.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_LISTEN));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_WAITING) &&
+ (Connection->ListenRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen on %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel listen on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelListen */
+
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for the name to be found.
+
+ 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.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // Make sure the request is still on the queue
+ // before cancelling it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ for (p = Device->WaitingConnects.Flink;
+ p != &Device->WaitingConnects;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+ break;
+ }
+ }
+
+ if (p != &Device->WaitingConnects) {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled find name connect on %lx\n", Connection));
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ Connection->ConnectRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+#ifdef RASAUTODIAL
+ if (Connection->Flags & CONNECTION_FLAGS_AUTOCONNECTING)
+ fCanceled = NbiCancelTdiConnect(Device, Request, Connection);
+#endif // RASAUTODIAL
+
+ if (fCanceled) {
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect not found on queue %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectFindName */
+
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for a rip or session init response
+ from the remote.
+
+ 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.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN TimerWasStopped = FALSE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled wait response connect on %lx\n", Connection));
+
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectWaitResponse */
+
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ disconnect wait.
+
+ 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.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_DISCONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->DisconnectWaitRequest == Request) {
+
+ Connection->DisconnectWaitRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelDisconnectWait */
+
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a connection based on the context.
+ The connection is assumed to be associated with the
+ specified address file.
+
+Arguments:
+
+ AddressFile - Pointer to an address file.
+
+ ConnectionContext - Connection context to find.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ CTELockHandle LockHandle1, LockHandle2;
+ PLIST_ENTRY p;
+ PADDRESS Address = AddressFile->Address;
+ PCONNECTION Connection;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p=AddressFile->ConnectionDatabase.Flink;
+ p != &AddressFile->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle2);
+
+ //
+ // BUGBUG: Does this spinlock ordering hurt us
+ // somewhere else?
+ //
+
+ if (Connection->Context == ConnectionContext) {
+
+ NbiReferenceConnection (Connection, CREF_BY_CONTEXT);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return Connection;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return NULL;
+
+} /* NbiLookupConnectionByContext */
+
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection and associates it with
+ the specified transport device context. The reference count in the
+ connection is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ connection.
+
+Return Value:
+
+ The newly created connection, or NULL if none can be allocated.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PNB_SEND_RESERVED SendReserved;
+ ULONG ConnectionSize;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION);
+ ConnectionSize = FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) + HeaderLength;
+
+ Connection = (PCONNECTION)NbiAllocateMemory (ConnectionSize, MEMORY_CONNECTION, "Connection");
+ if (Connection == NULL) {
+ NB_DEBUG (CONNECTION, ("Create connection failed\n"));
+ return NULL;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Create connection %lx\n", Connection));
+ RtlZeroMemory (Connection, ConnectionSize);
+
+
+#if defined(NB_OWN_PACKETS)
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+#else // !NB_OWN_PACKETS
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &Connection->SendPacketPoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (CONNECTION, ("Could not allocatee connection packet %lx\n", Status));
+ Connection->SendPacketInUse = TRUE;
+ } else {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+ }
+
+#endif NB_OWN_PACKETS
+
+ Connection->Type = NB_CONNECTION_SIGNATURE;
+ Connection->Size = (USHORT)ConnectionSize;
+
+#if 0
+ Connection->AddressFileLinked = FALSE;
+ Connection->AddressFile = NULL;
+#endif
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+#if 0
+ Connection->SubState = 0;
+ Connection->ReferenceCount = 0;
+#endif
+
+ Connection->CanBeDestroyed = TRUE;
+
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+
+ //
+ // Device->InitialRetransmissionTime is in milliseconds, as is
+ // SHORT_TIMER_DELTA.
+ //
+
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ //
+ // Device->KeepAliveTimeout is in half-seconds, while LONG_TIMER_DELTA
+ // is in milliseconds.
+ //
+
+ Connection->WatchdogTimeout = (Device->KeepAliveTimeout * 500) / LONG_TIMER_DELTA;
+
+
+ Connection->LocalConnectionId = 0xffff;
+
+ //
+ // When the connection becomes active we will replace the
+ // destination address of this header with the correct
+ // information.
+ //
+
+ RtlCopyMemory(&Connection->RemoteHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ Connection->Device = Device;
+ Connection->DeviceLock = &Device->Lock;
+ CTEInitLock (&Connection->Lock.Lock);
+
+ CTEInitTimer (&Connection->Timer);
+
+ InitializeListHead (&Connection->NdisSendQueue);
+#if 0
+ Connection->NdisSendsInProgress = 0;
+ Connection->DisassociatePending = NULL;
+ Connection->ClosePending = NULL;
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+#endif
+ Connection->Flags = 0;
+
+ NbiReferenceDevice (Device, DREF_CONNECTION);
+
+ return Connection;
+
+} /* NbiCreateConnection */
+
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION 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. We reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ Connection - potential pointer to a CONNECTION object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN LockHeld = FALSE;
+
+ try {
+
+ if ((Connection->Size == FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) +
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) &&
+ (Connection->Type == NB_CONNECTION_SIGNATURE)) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+ if (Connection->State != CONNECTION_STATE_CLOSING) {
+
+ NbiReferenceConnectionLock (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx closing\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx bad signature\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyConnection: C %lx exception\n", Connection);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyConnection */
+
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+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 nonpaged system pool.
+
+Arguments:
+
+ Connection - Pointer to a transport connection structure to be destroyed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = Connection->Device;
+#if 0
+ CTELockHandle LockHandle;
+#endif
+
+ NB_DEBUG2 (CONNECTION, ("Destroy connection %lx\n", Connection));
+
+ if (!Connection->SendPacketInUse) {
+ NbiDeinitializeSendPacket (Device, &Connection->SendPacket, Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+#endif
+ }
+
+ NbiFreeMemory (Connection, (ULONG)Connection->Size, MEMORY_CONNECTION, "Connection");
+
+ NbiDereferenceDevice (Device, DREF_CONNECTION);
+
+} /* NbiDestroyConnection */
+
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ (VOID)ExInterlockedAddUlong (
+ &Connection->ReferenceCount,
+ 1,
+ &Connection->DeviceLock->Lock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnection */
+
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when the device lock is already held.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ++Connection->ReferenceCount;
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionLock */
+
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when we are in a sync routine.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ (VOID)NB_ADD_ULONG (
+ &Connection->ReferenceCount,
+ 1,
+ Connection->DeviceLock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionSync */
+
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+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
+ NbiHandleConnectionZero to complete any disconnect, disassociate,
+ or close requests that have pended on the connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( Connection->DeviceLock, &LockHandle );
+ CTEAssert( Connection->ReferenceCount );
+ if ( !(--Connection->ReferenceCount) ) {
+
+ Connection->ThreadsInHandleConnectionZero++;
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+
+ //
+ // If the refcount has dropped to 0, then the connection can
+ // become inactive. We reacquire the spinlock and if it has not
+ // jumped back up then we handle any disassociates and closes
+ // that have pended.
+ //
+
+ NbiHandleConnectionZero (Connection);
+ } else {
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+ }
+
+
+} /* NbiDerefConnection */
+
+
+#endif
+
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a connection's refcount going to 0.
+
+ BUGBUG: If two threads are in this at the same time and
+ the close has already come through, one of them might
+ destroy the connection while the other one is looking
+ at it. We minimize the chance of this by not derefing
+ the connection after calling CloseConnection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST DisconnectPending;
+ PREQUEST DisassociatePending;
+ PREQUEST ClosePending;
+
+
+ Device = Connection->Device;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+#if DBG
+ //
+ // Make sure if our reference count is zero, all the
+ // sub-reference counts are also zero.
+ //
+
+ if (Connection->ReferenceCount == 0) {
+
+ UINT i;
+ for (i = 0; i < CREF_TOTAL; i++) {
+ if (Connection->RefTypes[i] != 0) {
+ DbgPrint ("NBI: Connection reftype mismatch on %lx\n", Connection);
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ //
+ // If the connection was assigned an ID, then remove it
+ // (it is assigned one when it leaves INACTIVE).
+ //
+
+ if (Connection->LocalConnectionId != 0xffff) {
+ NbiDeassignConnectionId (Device, Connection);
+ }
+
+ //
+ // Complete any pending disconnects.
+ //
+
+ if (Connection->DisconnectRequest != NULL) {
+
+ DisconnectPending = Connection->DisconnectRequest;
+ Connection->DisconnectRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_STATUS(DisconnectPending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisconnectPending);
+ NbiFreeRequest (Device, DisconnectPending);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // This should have been completed by NbiStopConnection,
+ // or else not allowed to be queued.
+ //
+
+ CTEAssert (Connection->DisconnectWaitRequest == NULL);
+
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+
+ //
+ // BUGBUG: Make NbiInitializeConnection() to take care of all this.
+ //
+
+ RtlZeroMemory (&Connection->ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+
+ Connection->ConnectionInfo.TransmittedTsdus = 0;
+ Connection->ConnectionInfo.TransmissionErrors = 0;
+ Connection->ConnectionInfo.ReceivedTsdus = 0;
+ Connection->ConnectionInfo.ReceiveErrors = 0;
+
+ //
+ // See if we need to do a disassociate now.
+ //
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->DisassociatePending != NULL)) {
+
+ //
+ // A disassociate pended, now we complete it.
+ //
+
+ DisassociatePending = Connection->DisassociatePending;
+ Connection->DisassociatePending = NULL;
+
+ //
+ // Set this so nobody else tries to disassociate.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ if (DisassociatePending != (PVOID)-1) {
+ REQUEST_STATUS(DisassociatePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisassociatePending);
+ NbiFreeRequest (Device, DisassociatePending);
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+
+ //
+ // If a close was pending, complete that.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->ClosePending)) {
+
+ ClosePending = Connection->ClosePending;
+ Connection->ClosePending = NULL;
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and we just cleaned up everything,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ if (ExInterlockedAddUlong ( &Connection->ThreadsInHandleConnectionZero, (ULONG)-1, &Device->Lock.Lock) == 1) {
+ NbiDestroyConnection(Connection);
+ }
+
+ REQUEST_STATUS(ClosePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (ClosePending);
+ NbiFreeRequest (Device, ClosePending);
+
+ } else {
+
+ if ( Connection->ReferenceCount == 0 ) {
+ Connection->CanBeDestroyed = TRUE;
+ }
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ Connection->ThreadsInHandleConnectionZero--;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiHandleConnectionZero */
+
diff --git a/private/ntos/tdi/isn/nb/datagram.c b/private/ntos/tdi/isn/nb/datagram.c
new file mode 100644
index 000000000..5c599206e
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/datagram.c
@@ -0,0 +1,1089 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ datagram.c
+
+Abstract:
+
+ This module contains the code to handle datagram reception
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles datagram indications.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+ Broadcast - TRUE if the frame was a broadcast datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ NDIS_STATUS NdisStatus;
+ PUCHAR NetbiosName;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+ PDEVICE Device = NbiDevice;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ ULONG DataOffset;
+ UINT BytesTransferred;
+ PNDIS_PACKET Packet;
+ CTELockHandle LockHandle;
+
+
+ //
+ // See if there is an address that might want this.
+ //
+
+ if (Broadcast) {
+ NetbiosName = (PVOID)-1;
+ } else {
+ NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName;
+ if (Device->AddressCounts[NetbiosName[0]] == 0) {
+ return;
+ }
+ }
+
+ DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+#if defined(_PNP_POWER)
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) {
+#else
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) {
+#endif _PNP_POWER
+
+ NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize));
+ return;
+ }
+
+ Address = NbiFindAddress (Device, NetbiosName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // We need to cache the remote name if the packet came across the router.
+ // This allows this machine to get back to the RAS client which might
+ // have sent this datagram. We currently dont allow broadcasts to go out
+ // on the dial-in line.
+ // Dont cache some of the widely used group names, that would be too much
+ // to store in cache.
+ //
+
+#if 0
+ if ( Connectionless->IpxHeader.TransportControl &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+#endif
+ if ( Connectionless->IpxHeader.TransportControl &&
+ ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+
+ PNETBIOS_CACHE CacheName;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ Connectionless->Datagram.SourceName,
+ &CacheName ) != STATUS_SUCCESS ) {
+
+ CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (CacheName ) {
+ RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16);
+ CacheName->Unique = TRUE;
+ CacheName->ReferenceCount = 1;
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->NetworksAllocated = 1;
+ CacheName->NetworksUsed = 1;
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+ NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n",
+ CacheName, CacheName->NetbiosName));
+
+ CacheName->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ CacheName);
+
+ }
+ } else if ( CacheName->Unique ) {
+ //
+ // We already have an entry for this remote. We should update
+ // the address. This is so that if the ras client dials-out
+ // then dials-in again and gets a new address, we dont end up
+ // caching the old address.
+ //
+ if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) {
+
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+
+ }
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ //
+ // We need to allocate a packet and buffer for the transfer.
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+
+
+ s = NbiPopReceiveBuffer (Device);
+ if (s == NULL) {
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage);
+
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer;
+
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // The indication to the TDI clients will happen at receive
+ // complete time.
+ //
+
+ NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer);
+ ReceiveBuffer->Address = Address;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ TdiCopyLookaheadData(
+ &ReceiveBuffer->RemoteName,
+ Connectionless->Datagram.SourceName,
+ 16,
+ (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + DataOffset,
+ PacketSize - DataOffset,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == PacketSize - DataOffset);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessDatagram */
+
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a datagram to clients on the specified
+ address. It is called from NbiReceiveComplete.
+
+Arguments:
+
+ Address - The address the datagram was sent to.
+
+ RemoteName - The source netbios address of the datagram.
+
+ Data - The data.
+
+ DataLength - The length of the data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p, q;
+ PIRP Irp;
+ ULONG IndicateBytesCopied;
+ PREQUEST Request;
+ TA_NETBIOS_ADDRESS SourceName;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // Update our statistics.
+ //
+
+ ++Device->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ DataLength);
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName);
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = AddressFile->ReceiveDatagramQueue.Flink;
+ q != &AddressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (q);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ RemoteName,
+ DatagramAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ RemoveEntryList (q);
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // Do this deref now, we hold another one so it
+ // will stick around.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Fall past the else to copy the data.
+ //
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No receive datagram requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) {
+
+ IndicateBytesCopied = 0;
+
+ if ((*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ DataLength, // indicated
+ DataLength, // available
+ &IndicateBytesCopied,
+ Data,
+ &Irp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ Request = NbiAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ } else {
+
+ //
+ // The client has nothing posted and no handler,
+ // go on to the next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ }
+
+ //
+ // We have a request; copy the actual user data.
+ //
+ if ( REQUEST_NDIS_BUFFER (Request) ) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl (
+ Data,
+ IndicateBytesCopied,
+ DataLength - IndicateBytesCopied,
+ REQUEST_NDIS_BUFFER (Request),
+ 0,
+ &REQUEST_INFORMATION (Request));
+
+ } else {
+ //
+ // No buffer specified in the request
+ //
+ REQUEST_INFORMATION (Request) = 0;
+ //
+ // If there was any data to be copied, return error o/w success
+ //
+ REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS );
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReturnDatagramInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+} /* NbiIndicateDatagram */
+
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram on an address.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the datagram send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS_FILE AddressFile;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+
+ //
+ // Make sure that the address is valid.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status == STATUS_SUCCESS) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->SendDatagramInformation->RemoteAddress), TRUE);
+
+
+ //
+ // Check that datagram size is less than the maximum allowable
+ // by the adapters. In the worst case this would be
+ // 576 - 64 = 512.
+ //
+
+#if defined(_PNP_POWER)
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumSendSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumSendSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#else
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumPacketSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumPacketSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif _PNP_POWER
+
+ if (RemoteName != NULL) {
+
+ //
+ // Get a packet to use in this send.
+ //
+
+ s = NbiPopSendPacket (Device, FALSE);
+
+ if (s != NULL) {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Check on the cache status of this name.
+ //
+
+ Reserved->u.SR_DG.DatagramRequest = Request;
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.RemoteName = RemoteName;
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength;
+
+ ++Device->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Parameters->SendLength);
+
+ if (Device->Internet) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ (RemoteName == (PVOID)-1) ? NULL : (PUCHAR)RemoteName->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this datagram
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Queueing up datagram %lx on %lx\n",
+ Request, AddressFile));
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ InsertTailList(
+ &Device->WaitingDatagrams,
+ &Reserved->WaitLinkage);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (CONNECTION, ("Found datagram cached %lx on %lx\n",
+ Request, AddressFile));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ //
+ // Only this failure gets passed back up to
+ // the caller, to avoid confusing the browser.
+ //
+
+ if (Status != STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = 0;
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+
+
+
+ }
+
+ } else {
+
+ //
+ // We are not in internet mode, so we do not
+ // need to do the name discovery.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Sending datagram direct %lx on %lx\n",
+ Request, AddressFile));
+
+ Reserved->u.SR_DG.Cache = NULL;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Could not allocate a packet for the datagram.
+ //
+
+ NB_DEBUG (DATAGRAM, ("Couldn't get packet to send DG %lx\n", Request));
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_DEBUG (DATAGRAM, ("No netbios address in DG %lx\n", Request));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NB_DEBUG (DATAGRAM, ("Invalid address file for DG %lx\n", Request));
+
+ }
+
+ return Status;
+
+} /* NbiTdiSendDatagram */
+
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the next net in the
+ cache entry for the remote name.
+
+Arguments:
+
+ Reserved - The reserved section of the packet that has
+ been allocated for this send. Reserved->u.SR_DG.Cache
+ will be NULL if Internet mode is off, otherwise it
+ will contain the cache entry to use when sending
+ this datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET Packet;
+ PNETBIOS_CACHE CacheName;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DATAGRAM;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ if (CacheName == NULL) {
+
+#if defined(_PNP_POWER)
+ //
+ // IPX will send this on all the Nics.
+ //
+ TempLocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+#else
+ TempLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+
+ } else {
+
+ if (CacheName->Unique) {
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ } else {
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+ }
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+ }
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), HeaderLength);
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiTransmitDatagram */
+
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+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:
+
+ Request - Describes this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+ CTELockHandle CancelLH;
+
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status != STATUS_SUCCESS) {
+ return Status;
+ }
+
+ Address = AddressFile->Address;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ if (Request->Cancel) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_CANCELLED;
+ }
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, NbiCancelReceiveDatagram);
+
+ NB_DEBUG2 (DATAGRAM, ("RDG posted on %lx\n", AddressFile));
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_RCV_DGRAM);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ return STATUS_PENDING;
+
+} /* NbiTdiReceiveDatagram */
+
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ 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.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NB_DEBUG (DATAGRAM, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest((PDEVICE)DeviceObject, Request);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* NbiCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/isn/nb/device.c b/private/ntos/tdi/isn/nb/device.c
new file mode 100644
index 000000000..d1a9af781
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/device.c
@@ -0,0 +1,461 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE 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 "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiCreateDevice)
+#endif
+
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Device->ReferenceCount);
+
+} /* NbiRefDevice */
+
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+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:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ NbiDestroyDevice (Device);
+ }
+
+} /* NbiDerefDevice */
+
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - 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 Device;
+ ULONG DeviceSize;
+ UINT 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) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ NB_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject;
+
+ NB_DEBUG2 (DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer, Device));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(Device+1);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "NDC1", 4);
+ RtlCopyMemory(Device->Signature2, "NDC2", 4);
+#endif
+
+ //
+ // BETABUGBUG: Clean this up a bit.
+ //
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 65535;
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.MaxDatagramSize = 500;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTION_MODE | TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_MULTICAST_SUPPORTED | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_DELAYED_ACCEPTANCE | TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_MESSAGE_MODE;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.MaximumLookaheadData = 1500;
+ Device->Information.NumberOfResources = 0;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+ Device->Statistics.MaximumSendWindow = 4;
+ Device->Statistics.AverageSendWindow = 4;
+
+ //
+ // Set this so we won't ignore the broadcast name.
+ //
+
+ Device->AddressCounts['*'] = 1;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock.Lock);
+ CTEInitLock (&Device->Lock.Lock);
+
+ CTEInitTimer (&Device->FindNameTimer);
+
+ Device->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+
+ InitializeListHead (&Device->AddressDatabase);
+#if defined(_PNP_POWER)
+ InitializeListHead (&Device->AdapterAddressDatabase);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingFindNames);
+
+ InitializeListHead (&Device->WaitingConnects);
+ InitializeListHead (&Device->WaitingDatagrams);
+
+ InitializeListHead (&Device->WaitingAdapterStatus);
+ InitializeListHead (&Device->ActiveAdapterStatus);
+
+ InitializeListHead (&Device->WaitingNetbiosFindName);
+
+ InitializeListHead (&Device->ReceiveDatagrams);
+ InitializeListHead (&Device->ConnectIndicationInProgress);
+
+ InitializeListHead (&Device->ListenQueue);
+
+ InitializeListHead (&Device->ReceiveCompletionQueue);
+
+ InitializeListHead (&Device->WaitPacketConnections);
+ InitializeListHead (&Device->PacketizeConnections);
+ InitializeListHead (&Device->DataAckConnections);
+
+ Device->MemoryUsage = 0;
+
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+ InitializeListHead (&Device->ReceiveBufferPoolList);
+
+ ExInitializeSListHead( &Device->SendPacketList );
+ ExInitializeSListHead( &Device->ReceivePacketList );
+ Device->ReceiveBufferList.Next = NULL;
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+ Device->ConnectionHash[i].Connections = NULL;
+ Device->ConnectionHash[i].ConnectionCount = 0;
+ Device->ConnectionHash[i].NextConnectionId = 1;
+ }
+
+ KeQuerySystemTime (&Device->NbiStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+
+ Device->Type = NB_DEVICE_SIGNATURE;
+ Device->Size - sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* NbiCreateDevice */
+
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNB_SEND_POOL SendPool;
+ PNB_SEND_PACKET SendPacket;
+ UINT SendPoolSize;
+ PNB_RECEIVE_POOL ReceivePool;
+ PNB_RECEIVE_PACKET ReceivePacket;
+ UINT ReceivePoolSize;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ ULONG HeaderLength;
+ UINT i;
+
+ NB_DEBUG2 (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the connectionless packets out of its pools.
+ //
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, NB_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ NbiDeinitializeSendPacket (Device, SendPacket, HeaderLength);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", SendPool));
+
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(SendPool->PoolHandle);
+#endif
+
+ NbiFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, NB_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ NbiDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", ReceivePool));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(ReceivePool->PoolHandle);
+#endif
+ NbiFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+
+#if defined(_PNP_POWER)
+ NbiDestroyReceiveBufferPools( Device );
+
+ //
+ // Destroy adapter address list.
+ //
+ while(!IsListEmpty( &Device->AdapterAddressDatabase ) ){
+ PADAPTER_ADDRESS AdapterAddress;
+ AdapterAddress = CONTAINING_RECORD( Device->AdapterAddressDatabase.Flink, ADAPTER_ADDRESS, Linkage );
+ NbiDestroyAdapterAddress( AdapterAddress, NULL );
+ }
+#else
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (Device->Bind.LineInfo.MaximumPacketSize * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Device->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+#endif _PNP_POWER
+
+ NB_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (NbiMemoryTag[i].BytesAllocated != 0) {
+ NB_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, NbiMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+ }
+
+} /* NbiDestroyDevice */
+
diff --git a/private/ntos/tdi/isn/nb/dirs b/private/ntos/tdi/isn/nb/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isn/nb/driver.c b/private/ntos/tdi/isn/nb/driver.c
new file mode 100644
index 000000000..a22e48a53
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/driver.c
@@ -0,0 +1,1794 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE NbiDevice = NULL;
+DEFINE_LOCK_STRUCTURE(NbiGlobalPoolInterlock);
+
+#ifdef RSRC_TIMEOUT_DBG
+
+ULONG NbiGlobalDebugResTimeout = 1;
+LARGE_INTEGER NbiGlobalMaxResTimeout;
+ // the packet is allocated from ndis pool.
+NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+UCHAR NbiGlobalDeathPacketHeader[100];
+
+VOID
+NbiInitDeathPacket()
+{
+
+ NDIS_HANDLE PoolHandle; // poolhandle for sendpacket below when
+ NTSTATUS Status;
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &PoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+ } else {
+
+ if (NbiInitializeSendPacket(
+ NbiDevice,
+ PoolHandle,
+ &NbiGlobalDeathPacket,
+ NbiGlobalDeathPacketHeader,
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) != STATUS_SUCCESS) {
+
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(PoolHandle);
+ }
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+#if DBG
+
+ULONG NbiDebug = 0xffffffff;
+ULONG NbiDebug2 = 0x00000000;
+ULONG NbiMemoryDebug = 0x0002482c;
+
+UCHAR NbiTempDebugBuffer[150];
+UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+PUCHAR NbiDebugMemoryLoc = NbiDebugMemory[0];
+PUCHAR NbiDebugMemoryEnd = NbiDebugMemory[NB_MEMORY_LOG_SIZE];
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (NbiTempDebugBuffer, 150);
+ ArgLen = vsprintf(NbiTempDebugBuffer,FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (NbiDebugMemoryLoc, 64);
+ RtlCopyMemory( NbiDebugMemoryLoc, NbiTempDebugBuffer, ArgLen );
+
+ NbiDebugMemoryLoc += 64;
+ if (NbiDebugMemoryLoc >= NbiDebugMemoryEnd) {
+ NbiDebugMemoryLoc = NbiDebugMemory[0];
+ }
+ }
+
+} /* NbiDebugMemoryLog */
+
+
+DEFINE_LOCK_STRUCTURE(NbiMemoryInterlock);
+MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+DEFINE_LOCK_STRUCTURE(NbiGlobalInterlock);
+
+
+#ifdef RASAUTODIAL
+VOID
+NbiAcdBind();
+
+VOID
+NbiAcdUnbind();
+#endif
+
+#ifdef NB_PACKET_LOG
+
+ULONG NbiPacketLogDebug = NB_PACKET_LOG_RCV_OTHER | NB_PACKET_LOG_SEND_OTHER;
+USHORT NbiPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(NbiPacketLogLock);
+NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+PNB_PACKET_LOG_ENTRY NbiPacketLogLoc = NbiPacketLog;
+PNB_PACKET_LOG_ENTRY NbiPacketLogEnd = &NbiPacketLog[NB_PACKET_LOG_LENGTH];
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PNB_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&NbiPacketLogLock, &LockHandle);
+
+ PacketLog = NbiPacketLogLoc;
+
+ ++NbiPacketLogLoc;
+ if (NbiPacketLogLoc >= NbiPacketLogEnd) {
+ NbiPacketLogLoc = NbiPacketLog;
+ }
+ *(UNALIGNED ULONG *)NbiPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&NbiPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(NB_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* NbiLogPacket */
+
+#endif // NB_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+
+//
+// These two are used in various places in the driver.
+//
+
+#if defined(_PNP_POWER)
+IPX_LOCAL_TARGET BroadcastTarget = { {ITERATIVE_NIC_ID}, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif _PNP_POWER
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+UCHAR NetbiosBroadcastName[16] = { '*', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ULONG NbiFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the Netbios ISN module.
+ 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 Netbios's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("Netbios/IPX Transport");
+ PDEVICE Device;
+ PIPX_HEADER IpxHeader;
+ CTELockHandle LockHandle;
+
+ PCONFIG Config = NULL;
+
+#if 0
+ DbgPrint ("NBI: FailLoad at %lx\n", &NbiFailLoad);
+ DbgBreakPoint();
+
+ if (NbiFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+ NB_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&NbiGlobalInterlock);
+ CTEInitLock (&NbiMemoryInterlock);
+ {
+ UINT i;
+ for (i = 0; i < MEMORY_MAX; i++) {
+ NbiMemoryTag[i].Tag = i;
+ NbiMemoryTag[i].BytesAllocated = 0;
+ }
+ }
+#endif
+#ifdef NB_PACKET_LOG
+ CTEInitLock (&NbiPacketLogLock);
+#endif
+
+#if defined(NB_OWN_PACKETS)
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ NB_DEBUG2 (DEVICE, ("ISN Netbios loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = NbiGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n");
+ return status;
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbiDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
+
+ DriverObject->DriverUnload = NbiUnload;
+
+
+ //
+ // Create the device object which exports our name.
+ //
+
+ status = NbiCreateDevice (DriverObject, &Config->DeviceName, &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ NbiFreeConfiguration(Config);
+ return status;
+ }
+
+ NbiDevice = Device;
+
+ //
+ // Initialize the global pool interlock
+ //
+ CTEInitLock (&NbiGlobalPoolInterlock);
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->AckDelayTime = (Config->Parameters[CONFIG_ACK_DELAY_TIME] / SHORT_TIMER_DELTA) + 1;
+ Device->AckWindow = Config->Parameters[CONFIG_ACK_WINDOW];
+ Device->AckWindowThreshold = Config->Parameters[CONFIG_ACK_WINDOW_THRESHOLD];
+ Device->EnablePiggyBackAck = Config->Parameters[CONFIG_ENABLE_PIGGYBACK_ACK];
+ Device->Extensions = Config->Parameters[CONFIG_EXTENSIONS];
+ Device->RcvWindowMax = Config->Parameters[CONFIG_RCV_WINDOW_MAX];
+ Device->BroadcastCount = Config->Parameters[CONFIG_BROADCAST_COUNT];
+ Device->BroadcastTimeout = Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500;
+ Device->ConnectionCount = Config->Parameters[CONFIG_CONNECTION_COUNT];
+ Device->ConnectionTimeout = Config->Parameters[CONFIG_CONNECTION_TIMEOUT] * 500;
+ Device->InitPackets = Config->Parameters[CONFIG_INIT_PACKETS];
+ Device->MaxPackets = Config->Parameters[CONFIG_MAX_PACKETS];
+ Device->InitialRetransmissionTime = Config->Parameters[CONFIG_INIT_RETRANSMIT_TIME];
+ Device->Internet = Config->Parameters[CONFIG_INTERNET];
+ Device->KeepAliveCount = Config->Parameters[CONFIG_KEEP_ALIVE_COUNT];
+ Device->KeepAliveTimeout = Config->Parameters[CONFIG_KEEP_ALIVE_TIMEOUT];
+ Device->RetransmitMax = Config->Parameters[CONFIG_RETRANSMIT_MAX];
+ Device->RouterMtu = Config->Parameters[CONFIG_ROUTER_MTU];
+
+ Device->FindNameTimeout =
+ ((Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500) + (FIND_NAME_GRANULARITY/2)) /
+ FIND_NAME_GRANULARITY;
+
+ Device->MaxReceiveBuffers = 20; // BUGBUG: Make it configurable?
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+
+ NbiInitializeTimers (Device);
+#endif _PNP_POWER
+
+ //
+ // Now bind to IPX via the internal interface.
+ //
+
+ status = NbiBind (Device, Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ NbiInitDeathPacket();
+ // NbiGlobalMaxResTimeout.QuadPart = 50; // 1*1000*10000;
+ NbiGlobalMaxResTimeout.QuadPart = 20*60*1000;
+ NbiGlobalMaxResTimeout.QuadPart *= 10000;
+#endif // RSRC_TIMEOUT_DBG
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Create Hash Table to store netbios cache entries
+ // For server create a big table, for workstation a small one
+ //
+
+ if ( MmIsThisAnNtAsSystem() ) {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_LARGE );
+ } else {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_SMALL );
+ }
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+ //
+ // Allocate our initial connectionless packet pool.
+ //
+
+ NbiAllocateSendPool (Device);
+
+ //
+ // Allocate our initial receive packet pool.
+ //
+
+ NbiAllocateReceivePool (Device);
+
+ //
+ // Allocate our initial receive buffer pool.
+ //
+ //
+#if !defined(_PNP_POWER)
+ NbiAllocateReceiveBufferPool (Device);
+#endif !_PNP_POWER
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == Device->State ) {
+ Device->State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#if !defined(_PNP_POWER)
+ //
+ // Start the timer system.
+ //
+
+ NbiInitializeTimers (Device);
+#endif !_PNP_POWER
+
+
+ //
+ // Fill in the default connnectionless header.
+ //
+
+ IpxHeader = &Device->ConnectionlessHeader;
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = 0;
+ IpxHeader->PacketLength[1] = 0;
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = 0;
+ *(UNALIGNED ULONG *)(IpxHeader->DestinationNetwork) = 0;
+ RtlCopyMemory(IpxHeader->DestinationNode, BroadcastAddress, 6);
+ IpxHeader->DestinationSocket = NB_SOCKET;
+ IpxHeader->SourceSocket = NB_SOCKET;
+#if !defined(_PNP_POWER)
+ RtlCopyMemory(IpxHeader->SourceNetwork, Device->Bind.Network, 4);
+ RtlCopyMemory(IpxHeader->SourceNode, Device->Bind.Node, 6);
+
+ Device->State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+
+ NbiFreeConfiguration(Config);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbiAcdBind();
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* DriverEntry */
+
+VOID
+NbiUnload(
+ 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 Netbios open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbiAcdUnbind();
+#endif
+
+ Device->State = DEVICE_STATE_STOPPING;
+
+ //
+ // Free the cache of netbios names.
+ //
+
+ DestroyNetbiosCacheTable( Device->NameCache );
+
+ //
+ // Cancel the long timer.
+ //
+
+ if (CTEStopTimer (&Device->LongTimer)) {
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+ //
+ // Unbind from the IPX driver.
+ //
+
+ NbiUnbind (Device);
+
+ //
+ // This event will get set when the reference count
+ // drops to 0.
+ //
+
+ KeInitializeEvent(
+ &Device->UnloadEvent,
+ NotificationEvent,
+ FALSE);
+ Device->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ NbiDereferenceDevice (Device, DREF_LOADED);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &Device->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} /* NbiUnload */
+
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to clean up the data structures associated
+ with a given Device. When this routine exits, the Device
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ Device - Pointer to the Device we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if 0
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+#endif
+
+
+#if 0
+ //
+ // Clean up packet pool.
+ //
+
+ while ( Device->PacketPool.Next != NULL ) {
+ s = PopEntryList( &Device->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbiDeallocateSendPacket (Device, packet);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( Device->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&Device->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbiDeallocateReceivePacket (Device, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( Device->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &Device->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbiDeallocateReceiveBuffer (Device, BufferTag);
+ }
+
+#endif
+
+} /* NbiFreeResources */
+
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPXNB 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.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ UINT i;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+#if !defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // 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 (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenConnection (Device, Request);
+ break;
+ }
+
+ } else {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier);
+ ++Device->ControlChannelIdentifier;
+ if (Device->ControlChannelIdentifier == 0) {
+ Device->ControlChannelIdentifier = 1;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONTROL_CHANNEL_FILE;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // 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)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbiCloseAddressFile (Device, Request);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // We don't call VerifyConnection because the I/O
+ // system should only give us one close and the file
+ // object should be valid. This helps avoid a window
+ // where two threads call HandleConnectionZero at the
+ // same time.
+ //
+
+ Status = NbiCloseConnection (Device, Request);
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // 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)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbiStopAddressFile (AddressFile, AddressFile->Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection(Connection);
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_CONNECTION
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchOpenClose */
+
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ 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 Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // 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.
+ //
+
+ Status = NbiDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+
+ return Status;
+
+} /* NbiDeviceControl */
+
+
+NB_TDI_DISPATCH_ROUTINE NbiDispatchInternalTable[] = {
+ NbiTdiAssociateAddress,
+ NbiTdiDisassociateAddress,
+ NbiTdiConnect,
+ NbiTdiListen,
+ NbiTdiAccept,
+ NbiTdiDisconnect,
+ NbiTdiSend,
+ NbiTdiReceive,
+ NbiTdiSendDatagram,
+ NbiTdiReceiveDatagram,
+ NbiTdiSetEventHandler,
+ NbiTdiQueryInformation,
+ NbiTdiSetInformation,
+ NbiTdiAction
+ };
+
+
+NTSTATUS
+NbiDispatchInternal(
+ 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 Device = (PDEVICE)DeviceObject;
+ PREQUEST Request;
+ UCHAR MinorFunction;
+
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+
+ //
+ // Branch to the appropriate request handler.
+ //
+
+ MinorFunction = REQUEST_MINOR_FUNCTION(Request) - 1;
+
+ if (MinorFunction <= (TDI_ACTION-1)) {
+
+ Status = (*NbiDispatchInternalTable[MinorFunction]) (
+ Device,
+ Request);
+
+ } else {
+
+ NB_DEBUG (DRIVER, ("Unsupported minor code %d\n", MinorFunction+1));
+ if ((MinorFunction+1) == TDI_DISCONNECT) {
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchInternal */
+
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = NbiDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ NbiPrint1 ("Nbi: Could not allocate %d: limit\n", BytesNeeded);
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' IBN');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ NbiPrint1("Nbi: Could not allocate %d: no pool\n", BytesNeeded);
+
+ if (ChargeDevice) {
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+
+} /* NbipAllocateMemory */
+
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* NbipFreeMemory */
+
+#if DBG
+
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = NbipAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &NbiMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* NbipAllocateTaggedMemory */
+
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &NbiMemoryInterlock);
+
+ NbipFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* NbipFreeTaggedMemory */
+
+#endif
+
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - 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";
+ INT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ 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, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteResourceErrorLog */
+
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ 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:
+
+ Device - 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[8] = L"NwlnkNb";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (Device->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->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)Device,
+ 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 (Device->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteGeneralErrorLog */
+
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ 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:
+
+ Device - 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";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ 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, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteOidErrorLog */
+
diff --git a/private/ntos/tdi/isn/nb/event.c b/private/ntos/tdi/isn/nb/event.c
new file mode 100644
index 000000000..f6cff7105
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/event.c
@@ -0,0 +1,117 @@
+/*++
+
+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 "precomp.h"
+#pragma hdrstop
+
+PVOID TdiDefaultHandlers[6] = {
+ TdiDefaultConnectHandler,
+ TdiDefaultDisconnectHandler,
+ TdiDefaultErrorHandler,
+ TdiDefaultReceiveHandler,
+ TdiDefaultRcvDatagramHandler,
+ TdiDefaultRcvExpeditedHandler
+ };
+
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+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:
+
+ Device - The netbios device object.
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+ UINT EventType;
+
+ UNREFERENCED_PARAMETER (Device);
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+ EventType = (UINT)(Parameters->EventType);
+
+ if (Parameters->EventType > TDI_EVENT_RECEIVE_EXPEDITED) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } else {
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->RegisteredHandler[EventType] = FALSE;
+ AddressFile->Handlers[EventType] = TdiDefaultHandlers[EventType];
+ AddressFile->HandlerContexts[EventType] = NULL;
+ } else {
+ AddressFile->Handlers[EventType] = Parameters->EventHandler;
+ AddressFile->HandlerContexts[EventType] = Parameters->EventContext;
+ AddressFile->RegisteredHandler[EventType] = TRUE;
+ }
+
+ }
+
+ NB_FREE_LOCK (&AddressFile->Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isn/nb/frame.c b/private/ntos/tdi/isn/nb/frame.c
new file mode 100644
index 000000000..49846a177
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/frame.c
@@ -0,0 +1,1096 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ frame.c
+
+Abstract:
+
+ This module contains code which creates and sends various
+ types of frames.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ ReqFrame - If specified, the request frame for which this
+ response is being sent. The reqframe contains the
+ destination ipx address and the netbios name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(ReqFrame)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ LocalTarget = &BroadcastTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#else
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ DestAddress - If specified, the destination IPX address to
+ use for the send (if not, it will be broadcast on net 0).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.CurrentNicId = 1;
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ } else {
+ Reserved->u.SR_NF.CurrentNicId = 0;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(DestAddress)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)DestAddress, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : NetbiosBroadcastName,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ TempLocalTarget.NicId = 1; // BUGBUG: What if 1 isn't valid?
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#endif _PNP_POWER
+
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ sizeof(NB_SESSION_INIT));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Device->Extensions) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = 0xffff;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.ReceiveSequence = 0;
+ if (Device->Extensions) {
+ Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitialize */
+
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize ack
+ frame for the specified connection. If extra data was
+ specified in the session initialize frame it is echoed
+ back to the remote.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ ExtraData - Any extra data (after the SESSION_INIT buffer)
+ in the frame.
+
+ ExtraDataLength - THe length of the extra data.
+
+ LockHandle - If specified, indicates the connection lock
+ is held and should be released. This is for cases
+ where the ExtraData is in memory which may be freed
+ once the connection lock is released.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ ULONG SessionInitBufferLength;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+ //
+ // Save the extra data, now we can free the lock.
+ //
+
+ if (ExtraDataLength != 0) {
+ RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
+ }
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ SessionInitBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Connection->NewNetbios) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
+ }
+ CTEAssert (Connection->CurrentSend.SendSequence == 0);
+ CTEAssert (Connection->ReceiveSequence == 1);
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.ReceiveSequence = 1;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + SessionInitBufferLength,
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitAck */
+
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a data ack frame.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ AckType - Indicates if this is a query to the remote,
+ a response to a received probe, or a request to resend.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, try for the connection
+ // packet. If that's not available, that's OK since data
+ // acks are connectionless anyway.
+ //
+
+ if (s == NULL) {
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ } else {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ switch (AckType) {
+ case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
+ case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
+ case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ NbiReferenceConnectionSync(Connection, CREF_FRAME);
+
+ //
+ // Set this so we will accept a probe from a remote without
+ // the send ack bit on. However if we receive such a request
+ // we turn this flag off until we get something else from the
+ // remote.
+ //
+
+ Connection->IgnoreNextDosProbe = FALSE;
+
+ Connection->ReceivesWithoutAck = 0;
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+} /* NbiSendDataAck */
+
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. We don't advance the
+ // send pointer, since it is the last frame of the session
+ // and we want it to stay the same in the case of resends.
+ //
+
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceConnection (Connection, CREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEnd */
+
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame. Generally it is sent on a connection but we
+ are not tied to that, to allow us to respond to
+ session ends from unknown remotes.
+
+Arguments:
+
+ RemoteAddress - The remote IPX address.
+
+ LocalTarget - The local target of the remote.
+
+ SessionEnd - The received session end frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = NULL;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Session.ConnectionControlFlag = 0x00;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
+ Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
+ Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
+ Header->Session.SendSequence = SessionEnd->ReceiveSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ if (SessionEnd->BytesReceived != 0) { // BUGBUG: Will this detect new netbios?
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
+ Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
+ } else {
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence;
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceDevice (Device, DREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEndAck */
+
diff --git a/private/ntos/tdi/isn/nb/isnnb.h b/private/ntos/tdi/isn/nb/isnnb.h
new file mode 100644
index 000000000..2d142e346
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/isnnb.h
@@ -0,0 +1,787 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnnb.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#define NB_MAXIMUM_MAC 40
+
+#define NB_SOCKET 0x5504
+
+#if defined(_PNP_POWER)
+#define NB_NETBIOS_NAME_SIZE 16
+
+#define LOCK_ACQUIRED TRUE
+#define LOCK_NOT_ACQUIRED FALSE
+#endif _PNP_POWER
+
+//
+// Defined granularity of find name timeouts in milliseconds --
+// we make this the same as the spec'ed RIP gap to avoid
+// flooding routers.
+//
+
+#define FIND_NAME_GRANULARITY 55
+
+
+//
+// Defines the number of milliseconds between expirations of the
+// short and long timers.
+//
+
+#define MILLISECONDS 10000 // number of NT time units in one
+
+#define SHORT_TIMER_DELTA 100
+#define LONG_TIMER_DELTA 2000
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of the Netbios header for name frames.
+//
+
+typedef struct _NB_NAME_FRAME {
+ union {
+ struct {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ };
+ UCHAR RoutingInfo[32];
+ };
+ UCHAR NameTypeFlag;
+ UCHAR DataStreamType2;
+ UCHAR Name[16];
+} NB_NAME_FRAME, *PNB_NAME_FRAME;
+
+//
+// Definition of the Netbios header for directed datagrams.
+//
+
+typedef struct _NB_DATAGRAM {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+} NB_DATAGRAM, *PNB_DATAGRAM;
+
+//
+// Definition of the Netbios header for a status query.
+//
+
+typedef struct _NB_STATUS_QUERY {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR Padding[14];
+} NB_STATUS_QUERY, *PNB_STATUS_QUERY;
+
+//
+// Definition of the Netbios header for a status response
+// (this does not include the status buffer itself).
+//
+
+typedef struct _NB_STATUS_RESPONSE {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+} NB_STATUS_RESPONSE, *PNB_STATUS_RESPONSE;
+
+
+//
+// Definition of the general Netbios connectionless header.
+//
+
+typedef struct _NB_CONNECTIONLESS {
+ IPX_HEADER IpxHeader;
+ union {
+ NB_NAME_FRAME NameFrame;
+ NB_DATAGRAM Datagram;
+ NB_STATUS_QUERY StatusQuery;
+ NB_STATUS_RESPONSE StatusResponse;
+ };
+} NB_CONNECTIONLESS, *PNB_CONNECTIONLESS;
+
+
+//
+// Definition of the Netbios session frame.
+//
+
+typedef struct _NB_SESSION {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT SourceConnectionId;
+ USHORT DestConnectionId;
+ USHORT SendSequence;
+ USHORT TotalDataLength;
+ USHORT Offset;
+ USHORT DataLength;
+ USHORT ReceiveSequence;
+ union {
+ USHORT BytesReceived;
+ USHORT ReceiveSequenceMax;
+ };
+} NB_SESSION, *PNB_SESSION;
+
+
+//
+// Definition of the extra fields in a Netbios
+// session frame for session init and session init
+// ack.
+//
+
+typedef struct _NB_SESSION_INIT {
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+ USHORT MaximumDataSize;
+ USHORT MaximumPacketTime;
+ USHORT StartTripTime;
+} NB_SESSION_INIT, *PNB_SESSION_INIT;
+
+
+//
+// Definition of the general Netbios connection-oriented header.
+//
+
+typedef struct _NB_CONNECTION {
+ IPX_HEADER IpxHeader;
+ NB_SESSION Session;
+} NB_CONNECTION, *PNB_CONNECTION;
+
+
+//
+// Definition of a Netbios packet.
+//
+
+typedef union _NB_FRAME {
+ NB_CONNECTIONLESS Connectionless;
+ NB_CONNECTION Connection;
+} NB_FRAME, *PNB_FRAME;
+
+#include <packoff.h>
+
+
+//
+// Definitions for the DataStreamType field, with the
+// format used shown in the comment afterward.
+//
+
+#define NB_CMD_FIND_NAME 0x01 // NAME_FRAME
+#define NB_CMD_NAME_RECOGNIZED 0x02 // NAME_FRAME
+#define NB_CMD_ADD_NAME 0x03 // NAME_FRAME
+#define NB_CMD_NAME_IN_USE 0x04 // NAME_FRAME
+#define NB_CMD_DELETE_NAME 0x05 // NAME_FRAME
+#define NB_CMD_SESSION_DATA 0x06 // SESSION
+#define NB_CMD_SESSION_END 0x07 // SESSION
+#define NB_CMD_SESSION_END_ACK 0x08 // SESSION
+#define NB_CMD_STATUS_QUERY 0x09 // STATUS_QUERY
+#define NB_CMD_STATUS_RESPONSE 0x0a // STATUS_RESPONSE
+#define NB_CMD_DATAGRAM 0x0b // DATAGRAM
+#define NB_CMD_BROADCAST_DATAGRAM 0x0c // BROADCAST_DATAGRAM
+
+#ifdef RSRC_TIMEOUT_DBG
+#define NB_CMD_DEATH_PACKET 0x99 //
+#endif // RSRC_TIMEOUT_DBG
+
+//
+// Bit values in the NameTypeFlag of NB_NAME_FRAME frames.
+//
+
+#define NB_NAME_UNIQUE 0x00
+#define NB_NAME_GROUP 0x80
+#define NB_NAME_USED 0x40
+#define NB_NAME_REGISTERED 0x04
+#define NB_NAME_DUPLICATED 0x02
+#define NB_NAME_DEREGISTERED 0x01
+
+//
+// Bit values in the ConnectionControlFlag.
+//
+
+#define NB_CONTROL_SYSTEM 0x80
+#define NB_CONTROL_SEND_ACK 0x40
+#define NB_CONTROL_ATTENTION 0x20
+#define NB_CONTROL_EOM 0x10
+#define NB_CONTROL_RESEND 0x08
+#define NB_CONTROL_NEW_NB 0x01
+
+
+
+#define NB_DEVICE_SIGNATURE 0x1401
+#if defined(_PNP_POWER)
+#define NB_ADAPTER_ADDRESS_SIGNATURE 0x1403
+#endif _PNP_POWER
+#define NB_ADDRESS_SIGNATURE 0x1404
+#define NB_ADDRESSFILE_SIGNATURE 0x1405
+#define NB_CONNECTION_SIGNATURE 0x1406
+
+
+//
+// Useful in various places.
+//
+#if defined(_PNP_POWER)
+extern IPX_LOCAL_TARGET BroadcastTarget;
+#endif _PNP_POWER
+extern UCHAR BroadcastAddress[6];
+extern UCHAR NetbiosBroadcastName[16];
+
+
+//
+// Contains the default handler for each of the TDI event types
+// that are supported.
+//
+
+extern PVOID TdiDefaultHandlers[6];
+
+
+//
+// Define a structure that can track lock acquire/release.
+//
+
+typedef struct _NB_LOCK {
+ CTELock Lock;
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+} NB_LOCK, *PNB_LOCK;
+
+
+
+#if DBG
+
+extern ULONG NbiDebug;
+extern ULONG NbiDebug2;
+extern ULONG NbiMemoryDebug;
+
+#define NB_MEMORY_LOG_SIZE 128
+extern UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+extern PUCHAR NbiDebugMemoryLoc;
+extern PUCHAR NbiDebugMemoryEnd;
+
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define NB_DEBUG(_Flag, _Print) { \
+ if (NbiDebug & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#define NB_DEBUG2(_Flag, _Print) { \
+ if (NbiDebug2 & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define NB_DEBUG(_Flag, _Print)
+#define NB_DEBUG2(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+typedef struct _REQUEST_LIST_HEAD {
+ PREQUEST Head; // list is empty if this is NULL
+ PREQUEST Tail; // undefined if the list is empty.
+} REQUEST_LIST_HEAD, *PREQUEST_LIST_HEAD;
+
+
+//
+// PREQUEST
+// NbiAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define NbiAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// NbiFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define NbiFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// REQUEST_SINGLE_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Used to access a single list linkage field in the request.
+//
+
+#define REQUEST_SINGLE_LINKAGE(_Request) \
+ (*((PREQUEST *)&((_Request)->Tail.Overlay.ListEntry.Flink)))
+
+
+//
+// ULONG
+// REQUEST_REFCOUNT(
+// IN PREQUEST Request
+// );
+//
+// Used to access a field in the request which can be used for
+// the reference count, as long as it is on a REQUEST_LIST.
+//
+
+#define REQUEST_REFCOUNT(_Request) \
+ (*((PULONG)&((_Request)->Tail.Overlay.ListEntry.Blink)))
+
+
+//
+// VOID
+// REQUEST_LIST_INSERT_TAIL(
+// IN PREQUEST_LIST_HEAD Head,
+// IN PREQUEST Entry
+// );
+//
+// Inserts a request into a single list linkage queue.
+//
+
+#define REQUEST_LIST_INSERT_TAIL(_Head,_Entry) { \
+ if ((_Head)->Head == NULL) { \
+ (_Head)->Head = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } else { \
+ REQUEST_SINGLE_LINKAGE((_Head)->Tail) = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } \
+}
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// NbiCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define NbiCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+//
+// some utility macros.
+
+// Minimum of two
+//
+#define NB_MIN( _a , _b ) ( ( (_a) < (_b) ) ? (_a) : (_b) )
+
+//
+// Swap the _s1 and _s2 of Type _T
+//
+
+#define NB_SWAP(_s1, _s2, _T) { \
+ _T _temp; \
+ _temp = (_s1); \
+ (_s1) = (_s2); \
+ (_s2) = _temp; \
+}
+
+#define NB_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+//
+// Define our own spinlock routines.
+//
+
+#if DBG
+
+#define NB_GET_LOCK(_Lock, _LockHandle) { \
+ CTEGetLock(&(_Lock)->Lock, _LockHandle); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK(_Lock, _LockHandle) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ CTEFreeLock(&(_Lock)->Lock, _LockHandle); \
+}
+
+#define NB_GET_LOCK_DPC(_Lock) { \
+ ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK_DPC(_Lock) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock); \
+}
+
+#else
+
+#define NB_GET_LOCK(_Lock, _LockHandle) CTEGetLock(&(_Lock)->Lock, _LockHandle)
+#define NB_FREE_LOCK(_Lock, _LockHandle) CTEFreeLock(&(_Lock)->Lock, _LockHandle)
+#define NB_GET_LOCK_DPC(_Lock) ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock)
+#define NB_FREE_LOCK_DPC(_Lock) ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock)
+
+#endif
+
+
+#define NB_GET_CANCEL_LOCK( _LockHandle ) IoAcquireCancelSpinLock( _LockHandle )
+
+#define NB_FREE_CANCEL_LOCK( _LockHandle ) IoReleaseCancelSpinLock( _LockHandle )
+
+
+//
+// Routines to optimize for a uni-processor environment.
+//
+
+
+#define NB_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define NB_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define NB_ADD_ULONG(_Pulong, _Ulong, _Lock) ExInterlockedAddUlong(_Pulong, _Ulong, &(_Lock)->Lock)
+
+#define NB_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define NB_BEGIN_SYNC(_SyncContext)
+#define NB_END_SYNC(_SyncContext)
+
+#define NB_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+
+//
+// BUGBUG: Make these be NB_XXX_LOCK_DPC calls -- then the definitions
+// of the NB_SYNC_XXX_LOCK calls can be changed to not need _LockHandle
+// and many of the functions won't need that as a parameter.
+//
+
+#define NB_SYNC_GET_LOCK(_Lock, _LockHandle) NB_GET_LOCK(_Lock, _LockHandle)
+#define NB_SYNC_FREE_LOCK(_Lock, _LockHandle) NB_FREE_LOCK(_Lock, _LockHandle)
+
+#define NB_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, &(_Lock)->Lock)
+#define NB_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define NB_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, &(_Lock)->Lock)
+#define NB_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntryList(_Queue, &(_Lock)->Lock)
+#define NB_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntryList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_LOCK_HANDLE_PARAM(_LockHandle) , IN CTELockHandle _LockHandle
+#define NB_LOCK_HANDLE_ARG(_LockHandle) , (_LockHandle)
+
+#define NB_SYNC_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER (should be
+// called with a spinlock held).
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define NB_DEBUG_DEVICE 0x00000001
+#define NB_DEBUG_ADDRESS 0x00000004
+#define NB_DEBUG_SEND 0x00000008
+#define NB_DEBUG_RECEIVE 0x00000020
+#define NB_DEBUG_CONFIG 0x00000040
+#define NB_DEBUG_PACKET 0x00000080
+#define NB_DEBUG_BIND 0x00000200
+#define NB_DEBUG_ADDRESS_FRAME 0x00000400
+#define NB_DEBUG_CONNECTION 0x00000800
+#define NB_DEBUG_QUERY 0x00001000
+#define NB_DEBUG_DRIVER 0x00002000
+#define NB_DEBUG_CACHE 0x00004000
+#define NB_DEBUG_DATAGRAM 0x00008000
+#define NB_DEBUG_TIMER 0x00010000
+#define NB_DEBUG_SEND_WINDOW 0x00020000
+
+
+
+//
+// NB_GET_NBHDR_BUFF - gets the nb header in the packet. It is always the
+// second buffer.
+//
+#define NB_GET_NBHDR_BUFF(Packet) (NDIS_BUFFER_LINKAGE((Packet)->Private.Head))
+
+
diff --git a/private/ntos/tdi/isn/nb/mp/makefile b/private/ntos/tdi/isn/nb/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/mp/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/isn/nb/mp/sources b/private/ntos/tdi/isn/nb/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/mp/sources
@@ -0,0 +1,29 @@
+!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
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isn/nb/nbcount/makefile b/private/ntos/tdi/isn/nb/nbcount/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/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/isn/nb/nbcount/nbcount.c b/private/ntos/tdi/isn/nb/nbcount/nbcount.c
new file mode 100644
index 000000000..74a656f16
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/nbcount.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT
+*
+* Module: ipx/route/ipxroute.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <ntstapi.h>
+#include <sys/stropts.h>
+#include <windows.h>
+#include "errno.h"
+#include "tdi.h"
+#include "isnkrnl.h"
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+HANDLE isnnbfd;
+wchar_t isnnbname[] = L"\\Device\\NwlnkNb";
+char pgmname[] = "NBCOUNT";
+
+/** **/
+
+#define INVALID_HANDLE (HANDLE)(-1)
+
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen);
+
+/*page*************************************************************
+ m a i n
+
+ This is the main routine that gets executed when a NET START
+ happens.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void _CRTAPI1 main(int argc, char **argv)
+{
+ UNICODE_STRING FileString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ NB_ACTION_GET_COUNTS GetCounts;
+ int rc;
+ int i;
+
+ /** Open the nwlnknb driver **/
+
+ RtlInitUnicodeString (&FileString, isnnbname);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnnbfd,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnnbfd = INVALID_HANDLE;
+ printf("Could not open transport\n");
+ }
+
+ if (isnnbfd == INVALID_HANDLE) {
+ exit(1);
+ }
+
+ rc = do_isnnbioctl(isnnbfd, (I_MIPX | 351), (char *)&GetCounts, sizeof(NB_ACTION_GET_COUNTS));
+ if (rc == 0) {
+
+ printf("NB NIC count: %d\n", GetCounts.MaximumNicId);
+ for (i = 1; i <= GetCounts.MaximumNicId; i++) {
+ printf("NIC %d: %d sessions\n", i, GetCounts.NicIdCounts[i]);
+ }
+ }
+}
+
+
+/*page***************************************************************
+ d o _ i s n i p x i o c t l
+
+ Do the equivalent of a stream ioctl to isnnb
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen)
+{
+ NTSTATUS Status;
+ UCHAR buffer[300];
+ PNWLINK_ACTION action;
+ IO_STATUS_BLOCK IoStatusBlock;
+ int rc;
+
+ /** Fill out the structure **/
+
+ action = (PNWLINK_ACTION)buffer;
+
+ action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
+ action->OptionType = NWLINK_OPTION_CONTROL;
+ action->BufferLength = sizeof(ULONG) + dlen;
+ action->Option = cmd;
+ RtlMoveMemory(action->Data, datap, dlen);
+
+ /** Issue the ioctl **/
+
+ Status = NtDeviceIoControlFile(
+ fd,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ action,
+ FIELD_OFFSET(NWLINK_ACTION,Data) + dlen);
+
+ if (Status != STATUS_SUCCESS) {
+ if (Status == STATUS_INVALID_PARAMETER) {
+ rc = ERANGE;
+ } else {
+ rc = EINVAL;
+ }
+ } else {
+ if (dlen > 0) {
+ RtlMoveMemory (datap, action->Data, dlen);
+ }
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
diff --git a/private/ntos/tdi/isn/nb/nbcount/nbcount.rc b/private/ntos/tdi/isn/nb/nbcount/nbcount.rc
new file mode 100644
index 000000000..ada219b24
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/nbcount.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLink Netbios Session Count Application"
+#define VER_INTERNALNAME_STR "nbcount.exe"
+#define VER_ORIGINALFILENAME_STR "nbcount.exe"
+
+#include "common.ver"
diff --git a/private/ntos/tdi/isn/nb/nbcount/sources b/private/ntos/tdi/isn/nb/nbcount/sources
new file mode 100644
index 000000000..f9dfe3561
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbcount/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=nbcount
+
+TARGETNAME=nbcount
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=UMAPPL_NOLIB
+
+USE_CRTDLL=1
+
+C_DEFINES=$(C_DEFINES)
+
+!IF 0
+INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc
+!ENDIF
+
+SOURCES= nbcount.c nbcount.rc
+
+UMTYPE=console
+UMAPPL=$(TARGETNAME)
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+
diff --git a/private/ntos/tdi/isn/nb/nbiprocs.h b/private/ntos/tdi/isn/nb/nbiprocs.h
new file mode 100644
index 000000000..64fd8f3a6
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbiprocs.h
@@ -0,0 +1,1533 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbiprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbiPrint0(fmt) DbgPrint(fmt)
+#define NbiPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbiPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbiPrint0(fmt)
+#define NbiPrint1(fmt,v0)
+#define NbiPrint2(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define NB_PACKET_LOG 1
+#endif
+
+#ifdef NB_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _NB_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER NbiHeader;
+ UCHAR Data[14];
+} NB_PACKET_LOG_ENTRY, *PNB_PACKET_LOG_ENTRY;
+
+#define NB_PACKET_LOG_LENGTH 128
+extern ULONG NbiPacketLogDebug;
+extern USHORT NbiPacketLogSocket;
+EXTERNAL_LOCK(NbiPacketLogLock);
+extern NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogLoc;
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogEnd;
+
+//
+// Bit fields in NbiPacketLogDebug
+//
+
+#define NB_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to NbiPacketLogSocket
+#define NB_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-NB)
+
+#define NB_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from NbiPacketLogSocket
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (NbiPacketLogDebug & (_Bit))
+
+#else // NB_PACKET_LOG
+
+#define NbiLogPacket(_MacHeader,_Length,_NbiHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // NB_PACKET_LOG
+
+
+#if DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefDevice (_Device)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefDevice (_Device)
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddress (_Address)
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressLock (_Address)
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFile (_AddressFile)
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFileLock (_AddressFile)
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddressFile (_AddressFile)
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+
+#define NbiReferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnection (_Connection)
+
+#define NbiReferenceConnectionLock(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionLock (_Connection)
+
+#define NbiReferenceConnectionSync(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionSync (_Connection)
+
+#define NbiDereferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefConnection (_Connection)
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+#else // DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ NbiDerefDevice (_Device)
+
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ if ( !InterlockedDecrement(&(_AddressFile)->ReferenceCount )) { \
+ NbiDestroyAddressFile (_AddressFile); \
+ }
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+
+#define NbiReferenceConnection(_Connection, _Type) { \
+ (VOID)ExInterlockedAddUlong( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ &(_Connection)->DeviceLock->Lock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionLock(_Connection, _Type) { \
+ ++(_Connection)->ReferenceCount; \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionSync(_Connection, _Type) { \
+ (VOID)NB_ADD_ULONG( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ (_Connection)->DeviceLock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiDereferenceConnection(_Connection, _Type) { \
+ CTELockHandle _LockHandle; \
+ NB_GET_LOCK( (_Connection)->DeviceLock, &_LockHandle ); \
+ if ( !(--(_Connection)->ReferenceCount) ) { \
+ (_Connection)->ThreadsInHandleConnectionZero++; \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ NbiHandleConnectionZero (_Connection); \
+ } else { \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ } \
+}
+
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// Definition of the callback routine where an NdisTransferData
+// call is not needed.
+//
+
+typedef VOID
+(*NB_CALLBACK_NO_TRANSFER) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define NB_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define NB_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+
+//
+// Definition of the routine to handler a particular minor
+// code for an IOCTL_MJ_INTERNAL_DEVICE_CONTROL IRP.
+//
+
+typedef NTSTATUS
+(*NB_TDI_DISPATCH_ROUTINE) (
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ );
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ );
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if !defined(_PNP_POWER)
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+#endif !_PNP_POWER
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ );
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ );
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+#if defined(_PNP_POWER)
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ );
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ );
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ );
+#endif _PNP_POWER
+
+
+//
+// Routines in bind.c
+//
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ );
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ );
+
+VOID
+NbiLineDown(
+ IN USHORT NicId,
+ IN ULONG FwdAdapterCtx
+ );
+
+
+//
+// Routines in cache.c
+//
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+);
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ );
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ );
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ );
+
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ );
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ );
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ );
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ );
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+//
+// Routines in connect.c
+//
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ );
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnectionSync(
+ IN PCONNECTION Connection
+ );
+#endif
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ );
+
+
+//
+// Routines in datagram.c
+//
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ );
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ );
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in frame.c
+//
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+#if defined(_PNP_POWER)
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+#else
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+#endif _PNP_POWER
+ );
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ );
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ );
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ );
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ );
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+#if defined(_PNP_POWER)
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ );
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ );
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+#else
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ );
+#endif _PNP_POWER
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ );
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ );
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ );
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in receive.c
+//
+
+
+BOOLEAN
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+ );
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ );
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in send.c
+//
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ );
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ );
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ );
+
+
+//
+// Routines in session.c
+//
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in timer.c
+//
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#else
+
+#define NbiStopRetransmit(_Connection) \
+ (_Connection)->Retransmit = 0;
+
+#define NbiStopWatchdog(_Connection) \
+ (_Connection)->Watchdog = 0;
+
+#endif
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ );
+
diff --git a/private/ntos/tdi/isn/nb/nbitypes.h b/private/ntos/tdi/isn/nb/nbitypes.h
new file mode 100644
index 000000000..604df5fb5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nbitypes.h
@@ -0,0 +1,1511 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbitypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// For find name requests, defines the current status (SR_FN.Status).
+//
+
+typedef enum {
+ FNStatusNoResponse, // no response has been received
+ FNStatusResponseUnique, // response received, is a unique name
+ FNStatusResponseGroup // response received, is a group name
+};
+
+//
+// Defines the results we can get from sending a series of find
+// names to locate a netbios name.
+//
+
+typedef enum _NETBIOS_NAME_RESULT {
+ NetbiosNameFound, // name was located
+ NetbiosNameNotFoundNormal, // name not found, no response received
+ NetbiosNameNotFoundWanDown // name not found, all lines were down
+} NETBIOS_NAME_RESULT, *PNETBIOS_NAME_RESULT;
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _NB_SEND_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ UCHAR Type; // what to do on completion
+ BOOLEAN OwnedByConnection; // if this is a connection's one packet
+#if defined(_PNP_POWER)
+ PVOID Reserved[SEND_RESERVED_COMMON_SIZE]; // used by ipx for even-padding and local target etc.
+#else
+ PVOID Reserved[2]; // used by ipx for even-padding
+#endif _PNP_POWER
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY WaitLinkage; // when waiting on other queues
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ union {
+ struct {
+ UCHAR NetbiosName[16]; // name being searched for
+ UCHAR StatusAndSentOnUpLine; // low nibble: look at FNStatusXXX enum
+ // high nibble: TRUE if while sending, found lan or up wan line
+ UCHAR RetryCount; // number of times sent
+ USHORT SendTime; // based on Device->FindNameTime
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // current nic id it is being sent on
+ USHORT MaximumNicId; // highest one it will be sent on
+#endif !_PNP_POWER
+ struct _NETBIOS_CACHE * NewCache; // new cache entry for group names
+ } SR_FN;
+ struct {
+ struct _ADDRESS * Address; // that owns this packet, if one does
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // non-zero for frames that go to all
+#endif !_PNP_POWER
+ UCHAR NameTypeFlag; // save these two values for frames
+ UCHAR DataStreamType; // that need to be sent to all nic id's
+ } SR_NF;
+ struct {
+ PREQUEST DatagramRequest; // holds the passed-in request
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName; // will be -1 for broadcast
+ struct _ADDRESS_FILE * AddressFile; // that the datagram was sent on
+ struct _NETBIOS_CACHE * Cache; // how to route to the netbios address
+ ULONG CurrentNetwork; // within the cache entry
+ } SR_DG;
+ struct {
+ struct _CONNECTION * Connection; // that this frame was sent on.
+ PREQUEST Request; // that this frame was sent for.
+ ULONG PacketLength; // total packet length.
+ BOOLEAN NoNdisBuffer; // none allocate for send
+ } SR_CO;
+ struct {
+ ULONG ActualBufferLength; // real length of allocated buffer.
+ } SR_AS;
+ } u;
+ PUCHAR Header; // points to the MAC/IPX/NB header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header
+} NB_SEND_RESERVED, *PNB_SEND_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define SEND_TYPE_NAME_FRAME 1
+#define SEND_TYPE_SESSION_INIT 2
+#define SEND_TYPE_FIND_NAME 3
+#define SEND_TYPE_DATAGRAM 4
+#define SEND_TYPE_SESSION_NO_DATA 5
+#define SEND_TYPE_SESSION_DATA 6
+#define SEND_TYPE_STATUS_QUERY 7
+#define SEND_TYPE_STATUS_RESPONSE 8
+
+#ifdef RSRC_TIMEOUT_DBG
+#define SEND_TYPE_DEATH_PACKET 9
+#endif //RSRC_TIMEOUT_DBG
+
+//
+// Macros to access StatusAndSentOnUpLine.
+//
+
+#define NB_GET_SR_FN_STATUS(_Reserved) \
+ ((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f)
+
+#define NB_SET_SR_FN_STATUS(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) | (_Value));
+
+#define NB_GET_SR_FN_SENT_ON_UP_LINE(_Reserved) \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) != 0)
+
+#define NB_SET_SR_FN_SENT_ON_UP_LINE(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f) | ((_Value) << 4));
+
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _NB_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ UCHAR Type; // what to do on completion
+#if defined(_PNP_POWER)
+ PVOID Pool; // send pool it was allocated from
+#else
+
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+
+#endif _PNP_POWER
+ union {
+ struct {
+ struct _CONNECTION * Connection; // that the transfer is for
+ BOOLEAN EndOfMessage; // this was the last part of a message
+ BOOLEAN CompleteReceive; // receive should be completed
+ BOOLEAN NoNdisBuffer; // user's mdl chain was used
+ BOOLEAN PartialReceive; // (new nb) don't ack this packet
+ } RR_CO;
+ struct {
+ struct _NB_RECEIVE_BUFFER * ReceiveBuffer; // datagram receive buffer
+ } RR_DG;
+ struct {
+ PREQUEST Request; // for this request
+ } RR_AS;
+ } u;
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+} NB_RECEIVE_RESERVED, *PNB_RECEIVE_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define RECEIVE_TYPE_DATAGRAM 1
+#define RECEIVE_TYPE_DATA 2
+#define RECEIVE_TYPE_ADAPTER_STATUS 3
+
+
+
+typedef struct _NB_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#if defined(_PNP_POWER)
+ PVOID Pool; // receive buffer pool was allocated from
+#else
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+#endif _PNP_POWER
+ struct _ADDRESS * Address; // that the datagram is for
+ SINGLE_LIST_ENTRY PoolLinkage; // when in free pool
+ LIST_ENTRY WaitLinkage; // when in ReceiveDatagrams queue
+ PNDIS_BUFFER NdisBuffer; // describes the data
+ UCHAR RemoteName[16]; // datagram was received from
+ ULONG DataLength; // length for current one, not allocated
+ PUCHAR Data; // points to data to hold packet
+} NB_RECEIVE_BUFFER, *PNB_RECEIVE_BUFFER;
+
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+//#define NB_OWN_PACKETS 1
+
+#ifdef NB_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _NB_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_SEND_RESERVED)];
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_RECEIVE_RESERVED)];
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_SendPacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiAllocateReceivePacket(_Device,_PoolHandle, _ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_ReceivePacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet)
+
+#define NbiFreeReceivePacket(_Device,_Packet)
+
+
+#else // NB_OWN_PACKETS
+
+typedef struct _NB_SEND_PACKET {
+ PNDIS_PACKET Packet;
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, _PoolHandle); \
+}
+
+#define NbiAllocateReceivePacket(_Device, _PoolHandle, _ReceivePacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, _PoolHandle); \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#define NbiFreeReceivePacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#endif // NB_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PNB_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PNB_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+
+typedef struct _NB_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+#if defined(_PNP_POWER)
+ UINT BufferDataSize; // allocation size of each buffer data
+#endif _PNP_POWER
+ NB_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} NB_RECEIVE_BUFFER_POOL, *PNB_RECEIVE_BUFFER_POOL;
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_CACHE 4
+#define MEMORY_CONNECTION 5
+#define MEMORY_STATUS 6
+#define MEMORY_QUERY 7
+#if defined(_PNP_POWER)
+#define MEMORY_WORK_ITEM 8
+#define MEMORY_ADAPTER_ADDRESS 9
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+#define MEMORY_MAX 10
+#else
+#define MEMORY_MAX 8
+#endif _PNP_POWER
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(NbiMemoryInterlock);
+extern MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+
+//
+// This structure holds a single remote network which a
+// Netbios name exists on.
+//
+
+typedef struct _NETBIOS_NETWORK {
+ ULONG Network;
+ IPX_LOCAL_TARGET LocalTarget;
+} NETBIOS_NETWORK, *PNETBIOS_NETWORK;
+
+//
+// This defines a netbios cache entry for a given name.
+//
+
+typedef struct _NETBIOS_CACHE {
+ UCHAR NetbiosName[16];
+ BOOLEAN Unique;
+ BOOLEAN FailedOnDownWan; // if NetworksUsed == 0, was it due to down wan lines?
+ USHORT TimeStamp; // in seconds - CacheTimeStamp when inserted
+ ULONG ReferenceCount;
+ LIST_ENTRY Linkage;
+ TDI_ADDRESS_IPX FirstResponse;
+ USHORT NetworksAllocated;
+ USHORT NetworksUsed;
+ NETBIOS_NETWORK Networks[1]; // may be more than one of these
+} NETBIOS_CACHE, *PNETBIOS_CACHE;
+
+typedef struct _NETBIOS_CACHE_TABLE {
+ USHORT MaxHashIndex;
+ USHORT CurrentEntries;
+ LIST_ENTRY Bucket[1];
+} NETBIOS_CACHE_TABLE, *PNETBIOS_CACHE_TABLE;
+
+#define NB_NETBIOS_CACHE_TABLE_LARGE 26 // for server
+#define NB_NETBIOS_CACHE_TABLE_SMALL 8 // for workstation
+#define NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET 8
+
+//
+// This defines the different kind of requests that can be made
+// to CacheFindName().
+//
+
+typedef enum _FIND_NAME_TYPE {
+ FindNameConnect,
+ FindNameNetbiosFindName,
+ FindNameOther
+} FIND_NAME_TYPE, *PFIND_NAME_TYPE;
+
+
+//
+// The number of hash entries in the non-inactive connection
+// database.
+//
+
+#define CONNECTION_HASH_COUNT 8
+
+//
+// Mask and shift to retrieve the hash number from a connection
+// ID.
+//
+
+#define CONNECTION_HASH_MASK 0xe000
+#define CONNECTION_HASH_SHIFT 13
+
+//
+// The maximum connection ID we can assign, not counting the
+// shifted-over hash id (which occupies the top 3 bits of the
+// real id we use on the wire). We can use all the bits except
+// the top one, to prevent an ID of 0xffff being used.
+//
+
+#define CONNECTION_MAXIMUM_ID (USHORT)(~CONNECTION_HASH_MASK & ~1)
+
+//
+// A single connection hash bucket.
+//
+
+typedef struct _CONNECTION_HASH {
+ struct _CONNECTION * Connections;
+ USHORT ConnectionCount;
+ USHORT NextConnectionId;
+} CONNECTION_HASH, *PCONNECTION_HASH;
+
+
+//
+// These are queued in the ConnectIndicationInProgress
+// queue to track indications to TDI clients.
+//
+
+typedef struct _CONNECT_INDICATION {
+ LIST_ENTRY Linkage;
+ UCHAR NetbiosName[16];
+ TDI_ADDRESS_IPX RemoteAddress;
+ USHORT ConnectionId;
+} CONNECT_INDICATION, *PCONNECT_INDICATION;
+
+//
+// This structure defines the per-device structure for NB
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_CONNECTION 4
+#define DREF_FN_TIMER 5
+#define DREF_FIND_NAME 6
+#define DREF_SESSION_INIT 7
+#define DREF_NAME_FRAME 8
+#define DREF_FRAME 9
+#define DREF_SHORT_TIMER 10
+#define DREF_LONG_TIMER 11
+#define DREF_STATUS_QUERY 12
+#define DREF_STATUS_RESPONSE 13
+#define DREF_STATUS_FRAME 14
+#define DREF_NB_FIND_NAME 15
+
+#define DREF_TOTAL 16
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ NB_LOCK Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+ NB_LOCK Lock;
+ LONG ReferenceCount; // activity count/this provider.
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+#if defined(_PNP_POWER)
+ USHORT DeviceNameLength;
+#else
+ ULONG DeviceNameLength;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+ //
+ // All send packet pools are chained on this list.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+ LIST_ENTRY ReceiveBufferPoolList;
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ SINGLE_LIST_ENTRY ReceiveBufferList;
+
+ //
+ // Receive requests waiting to be completed.
+ //
+
+ LIST_ENTRY ReceiveCompletionQueue;
+
+ //
+ // Connections waiting for send packets.
+ //
+
+ LIST_ENTRY WaitPacketConnections;
+
+ //
+ // Connections waiting to packetize.
+ //
+
+ LIST_ENTRY PacketizeConnections;
+
+ //
+ // Connections waiting to send a data ack.
+ //
+
+ LIST_ENTRY DataAckConnections;
+
+ //
+ // The list changed while we were processing it.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // Information to manage the Netbios name cache.
+ //
+
+ LIST_ENTRY WaitingConnects; // connect requests waiting for a name
+ LIST_ENTRY WaitingDatagrams; // datagram requests waiting for a name
+ LIST_ENTRY WaitingAdapterStatus; // adapter status requests waiting for a name
+ LIST_ENTRY WaitingNetbiosFindName; // netbios find name requests waiting for a name
+
+ //
+ // Holds adapter status request which have a name and
+ // are waiting for a response. The long timeout aborts
+ // these after a couple of expirations (BUGBUG: currently we
+ // do not do resends).
+ //
+
+ LIST_ENTRY ActiveAdapterStatus;
+
+ //
+ // Receive datagrams waiting to be indicated.
+ //
+
+ LIST_ENTRY ReceiveDatagrams;
+
+ //
+ // In-progress connect indications (used to make
+ // sure we don't indicate the same packet twice).
+ //
+
+ LIST_ENTRY ConnectIndicationInProgress;
+
+ //
+ // Listens that have been posted to connections.
+ //
+
+ LIST_ENTRY ListenQueue;
+
+ UCHAR State;
+
+ //
+ // The following fields control the timer system.
+ // The short timer is used for retransmission and
+ // delayed acks, and the long timer is used for
+ // watchdog timeouts.
+ //
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckActive; // DataAckConnections is not empty.
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+#if defined(_PNP_POWER)
+ BOOLEAN LongTimerRunning; // True if the long timer is running.
+#endif _PNP_POWER
+ LARGE_INTEGER ShortTimerStart; // tick count when the short timer was set.
+ CTETimer ShortTimer; // controls the short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ CTETimer LongTimer; // kernel DPC object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ NB_LOCK TimerLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of waiting connections
+ LIST_ENTRY LongList; // list of waiting connections
+
+
+ //
+ // Hash table of non-inactive connections.
+ //
+
+ CONNECTION_HASH ConnectionHash[CONNECTION_HASH_COUNT];
+
+ //
+ // Control the queue of waiting find names.
+ //
+
+ USHORT FindNameTime; // incremented each time the timer runs
+ BOOLEAN FindNameTimerActive; // TRUE if the timer is queued
+ CTETimer FindNameTimer; // runs every FIND_NAME_GRANULARITY
+ ULONG FindNameTimeout; // the retry count in timer ticks
+
+ ULONG FindNamePacketCount; // Count of packets on the queue
+ LIST_ENTRY WaitingFindNames; // FIND_NAME frames waiting to go out
+
+ //
+ // The cache of NETBIOS_CACHE entries.
+ //
+
+ PNETBIOS_CACHE_TABLE NameCache;
+
+ //
+ // The current time stamp, incremented every second.
+ //
+
+ USHORT CacheTimeStamp;
+
+ //
+ // Maximum valid NIC ID we can use.
+ //
+
+ USHORT MaximumNicId;
+
+
+ //
+ // Handle for our binding to the IPX driver.
+ //
+
+ HANDLE BindHandle;
+
+ //
+ // Holds the output from binding to IPX.
+ //
+ union {
+ IPX_INTERNAL_BIND_OUTPUT Bind;
+ IPX_INTERNAL_BIND_INPUT BindInput;
+ };
+
+ //
+ // Holds our reserved netbios name, which is 10 bytes
+ // of zeros followed by our node address.
+ //
+#if !defined(_PNP_POWER)
+ UCHAR ReservedNetbiosName[16];
+#endif !_PNP_POWER
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many packets have been allocated.
+ //
+
+ ULONG AllocatedSendPackets;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedReceiveBuffers;
+
+#if defined(_PNP_POWER)
+ //
+ // This is the size of each buffer in the receive buffer pool.
+ // We reallocate buffer pool when the LineInfo.MaxPacketSize changes(increases)
+ // from IPX because of a new adapter. The LineInfo.MaxPacketSize could
+ // also change(decrease) when a adapter disappears but our buffer pool size
+ // will stay at this value.
+ //
+ ULONG CurMaxReceiveBufferSize;
+#endif _PNP_POWER
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG AckDelayTime; // converted to short timeouts, rounded up
+ ULONG AckWindow;
+ ULONG AckWindowThreshold;
+ ULONG EnablePiggyBackAck;
+ ULONG Extensions;
+ ULONG RcvWindowMax;
+ ULONG BroadcastCount;
+ ULONG BroadcastTimeout;
+ ULONG ConnectionCount;
+ ULONG ConnectionTimeout;
+ ULONG InitPackets;
+ ULONG MaxPackets;
+ ULONG InitialRetransmissionTime;
+ ULONG Internet;
+ ULONG KeepAliveCount;
+ ULONG KeepAliveTimeout;
+ ULONG RetransmitMax;
+ ULONG RouterMtu;
+
+ ULONG MaxReceiveBuffers;
+
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // The following field is a head of a list of 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.
+#if defined(_PNP_POWER)
+ LIST_ENTRY AdapterAddressDatabase; // list of netbios names made from adapter addresses.
+#endif _PNP_POWER
+
+ ULONG AddressCount; // number of addresses in the database.
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // This structure holds a pre-built IPX header which is used
+ // to quickly fill in common fields of outgoing connectionless
+ // frames.
+ //
+
+ IPX_HEADER ConnectionlessHeader;
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+#if defined(_PNP_POWER)
+ HANDLE TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ //
+ // Counters for most of the statistics that NB maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempFrameBytesSent;
+ ULONG TempFramesSent;
+ ULONG TempFrameBytesReceived;
+ ULONG TempFramesReceived;
+
+
+ //
+ // 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;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbiStartTime;
+
+ //
+ // This array is used to quickly dismiss connectionless frames
+ // that are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // 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, * PDEVICE;
+
+
+extern PDEVICE NbiDevice;
+EXTERNAL_LOCK(NbiGlobalPoolInterlock);
+
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+
+EXTERNAL_LOCK(NbiGlobalInterlock);
+
+
+//
+// device state definitions
+//
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+#define NB_TDI_RESOURCES 9
+
+
+//
+// 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 an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+#define AFREF_TIMEOUT 5
+#define AFREF_CONNECTION 6
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ PNB_LOCK AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST OpenRequest; // the request used for open
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ LIST_ENTRY ConnectionDatabase; // associated with this address.
+
+ LIST_ENTRY ReceiveDatagramQueue; // posted by the client.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // 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 RegisteredHandler[6];
+
+ //
+ // This is a list of handlers for a given event. They can be
+ // accessed using the explicit names for type-checking, or the
+ // array (indexed by the event type) for speed.
+ //
+
+ union {
+ struct {
+ PTDI_IND_CONNECT ConnectionHandler;
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PTDI_IND_ERROR ErrorHandler;
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ };
+ PVOID Handlers[6];
+ };
+
+ PVOID HandlerContexts[6];
+
+} ADDRESS_FILE, *PADDRESS_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 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.
+//
+
+typedef struct _NBI_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[16];
+ USHORT NetbiosNameType;
+ BOOLEAN Broadcast;
+} NBI_NETBIOS_ADDRESS, *PNBI_NETBIOS_ADDRESS;
+
+//
+// This structure defines an 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.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+#define AREF_NAME_FRAME 3
+#define AREF_TIMER 4
+#define AREF_FIND 5
+
+#define AREF_TOTAL 8
+
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ NB_LOCK Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ UCHAR NameTypeFlag; // NB_NAME_UNIQUE or NB_NAME_GROUP
+
+ NBI_NETBIOS_ADDRESS NetbiosAddress; // our netbios name.
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ ULONG State; // current state of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ PNB_LOCK DeviceLock;
+
+ //
+ // 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 AddressFileDatabase; // list of defined address file objects
+
+ UCHAR SendPacketHeader[NB_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+ //
+ // This timer is used for registering the name.
+ //
+
+ CTETimer RegistrationTimer;
+
+ //
+ // Number of times an add name frame has been sent.
+ //
+
+ ULONG RegistrationCount;
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbiDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+//
+// Values for Flags
+//
+
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000002
+#if defined(_PNP_POWER)
+#define ADDRESS_FLAGS_CONFLICT 0x00000010
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// this booleans are passed to nbiverifyaddressfile calls.
+//
+#define CONFLICT_IS_OK TRUE
+#define CONFLICT_IS_NOT_OK FALSE
+#endif _PNP_POWER
+
+//
+// Values for State
+//
+
+#define ADDRESS_STATE_REGISTERING 1
+#define ADDRESS_STATE_OPEN 2
+#define ADDRESS_STATE_STOPPING 3
+
+#if defined(_PNP_POWER)
+//
+// This holds the adapters names i.e netbios names which are
+// created from adater node address to support adapter status
+// queries using adapter node addresses.
+//
+typedef struct _ADAPTER_ADDRESS {
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ NIC_HANDLE NicHandle; // NicHandle corresponding to this address.
+ UCHAR NetbiosName[16];
+} ADAPTER_ADDRESS, *PADAPTER_ADDRESS;
+#endif _PNP_POWER
+
+//
+// This defines the types of probe packets we can send.
+//
+
+typedef enum _NB_ACK_TYPE {
+ NbiAckQuery,
+ NbiAckResponse,
+ NbiAckResend
+} NB_ACK_TYPE, *PNB_ACK_TYPE;
+
+
+//
+// This defines the a packetizing location in a
+// send.
+//
+
+typedef struct _SEND_POINTER {
+ ULONG MessageOffset; // up count, bytes sent this message.
+ PREQUEST Request; // current send request in chain.
+ PNDIS_BUFFER Buffer; // current buffer in send chain.
+ ULONG BufferOffset; // current byte offset in current buffer.
+ USHORT SendSequence;
+} SEND_POINTER, *PSEND_POINTER;
+
+//
+// This defines the current location in a receive.
+//
+
+typedef struct _RECEIVE_POINTER {
+ ULONG MessageOffset; // up count, bytes received this message.
+ ULONG Offset; // up count, bytes received this request.
+ PNDIS_BUFFER Buffer; // current buffer in receive request.
+ ULONG BufferOffset; // current byte offset in current buffer.
+} RECEIVE_POINTER, *PRECEIVE_POINTER;
+
+
+//
+// This structure defines a connection, which controls a
+// session with a remote.
+//
+
+#define CREF_VERIFY 0
+#define CREF_LISTEN 1
+#define CREF_CONNECT 2
+#define CREF_WAIT_CACHE 3
+#define CREF_TIMER 4
+#define CREF_INDICATE 5
+#define CREF_ACTIVE 6
+#define CREF_FRAME 7
+#define CREF_BY_CONTEXT 8
+#define CREF_W_ACCEPT 9
+#define CREF_SEND 10
+#define CREF_RECEIVE 11
+#define CREF_PACKETIZE 12
+#define CREF_DISASSOC 13
+#define CREF_W_PACKET 14
+#define CREF_CANCEL 15
+#define CREF_NDIS_SEND 16
+#define CREF_SHORT_D_ACK 17
+#define CREF_LONG_D_ACK 18
+#define CREF_FIND_ROUTE 19
+#define CREF_ACCEPT 20
+
+#define CREF_TOTAL 24
+
+typedef struct _CONNECTION {
+
+#if DBG
+ ULONG RefTypes[CREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ NB_LOCK Lock;
+ PNB_LOCK DeviceLock;
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ ULONG State;
+ ULONG SubState;
+ ULONG ReceiveState; // SubState tracks sends when active.
+ ULONG NewNetbios; // 1 if we negotiated this.
+
+ REQUEST_LIST_HEAD SendQueue;
+ REQUEST_LIST_HEAD ReceiveQueue;
+
+ USHORT ReceiveSequence;
+
+ USHORT LocalRcvSequenceMax; // we advertise to him (will be near SendSequence)
+ USHORT RemoteRcvSequenceMax; // he advertises to us (will be near ReceiveSequence)
+ USHORT SendWindowSequenceLimit; // when this send window ends (may send past it however)
+
+ //
+ // RemoteRcvSequenceMax is the largest frame number that he expects to
+ // receive, while SendWindowSequenceLimit is one more than the max
+ // we can send. I.e. if he is advertising a window of 4 and we think
+ // the window should be 2, and the current send sequence is 7,
+ // RemoteRcvSequenceMax is 10 and SendWindowSequenceLimit is 9.
+ //
+
+ USHORT ReceiveWindowSize; // when it is open, how big to make it
+ USHORT SendWindowSize; // what we'll send, may be less than what he advertises
+ USHORT MaxSendWindowSize; // maximum we allow it to grow to
+
+ USHORT IncreaseWindowFailures; // how many windows after increase have had retransmits
+ BOOLEAN RetransmitThisWindow; // we had to retransmit in this send window
+ BOOLEAN SendWindowIncrease; // send window was just increased.
+ BOOLEAN ResponseTimeout; // we hit timeout in SEND_W or REMOTE_W
+
+ BOOLEAN SendBufferInUse; // current send's already queued on packet
+
+ ULONG Retries;
+
+ //
+ // Tracks the current send.
+ //
+
+ SEND_POINTER CurrentSend;
+
+ //
+ // Tracks the unacked point in the send.
+ //
+
+ SEND_POINTER UnAckedSend;
+
+ PREQUEST FirstMessageRequest; // first one in the message.
+ PREQUEST LastMessageRequest; // last one in the message.
+
+ ULONG CurrentMessageLength; // total length of current message.
+
+ //
+ // Tracks the current receive.
+ //
+
+ RECEIVE_POINTER CurrentReceive; // where to receive next data
+ RECEIVE_POINTER PreviousReceive; // stores it while transfer in progress
+
+ PREQUEST ReceiveRequest; // current one; not in ReceiveQueue
+ ULONG ReceiveLength; // length of ReceiveRequest
+
+ ULONG ReceiveUnaccepted; // by client...only indicate when == 0
+
+ ULONG CurrentIndicateOffset; // if previous frame was partially accepted.
+
+ IPX_LINE_INFO LineInfo; // for the adapter this connect is on.
+ ULONG MaximumPacketSize; // as negotiated during session init/ack
+
+ //
+ // Links us in the non-inactive connection hash bucket.
+ //
+
+ struct _CONNECTION * NextConnection;
+
+ //
+ // These are used to determine when to piggyback and when not to.
+ //
+
+ BOOLEAN NoPiggybackHeuristic; // we have reason to assume it would be bad.
+ BOOLEAN PiggybackAckTimeout; // we got a timeout last time we tried.
+ ULONG ReceivesWithoutAck; // used to do an auto ack.
+
+ //
+ // The following field is used as linkage in the device's
+ // PacketizeConnections queue.
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // WaitPacketConnections queue.
+ //
+
+ LIST_ENTRY WaitPacketLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // DataAckConnections queue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if we are on these queues.
+ //
+
+ BOOLEAN OnPacketizeQueue;
+ BOOLEAN OnWaitPacketQueue;
+ BOOLEAN OnDataAckQueue;
+
+ //
+ // TRUE if we have a piggyback ack pending.
+ //
+
+ BOOLEAN DataAckPending;
+
+ //
+ // TRUE if the current receive does not allow piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveNoPiggyback;
+
+ //
+ // Number of short timer expirations with the data ack queued.
+ //
+
+ ULONG DataAckTimeouts;
+
+ //
+ // Used to queue sends so that no two are outstanding at once.
+ //
+
+ ULONG NdisSendsInProgress;
+ LIST_ENTRY NdisSendQueue;
+
+ //
+ // This pointer is valid when NdisSendsInProgress is non-zero;
+ // it holds a pointer to a location on the stack of the thread
+ // which is inside NbiAssignSequenceAndSend. If this location
+ // is set to TRUE, it means the connection was stopped by another
+ // thread and a reference was added to keep the connection around.
+ //
+
+ PBOOLEAN NdisSendReference;
+
+ //
+ // These are used for timeouts.
+ //
+
+ ULONG BaseRetransmitTimeout; // config # of short timeouts we wait.
+ ULONG CurrentRetransmitTimeout; // possibly backed-off number
+ ULONG WatchdogTimeout; // how many long timeouts we wait.
+ ULONG Retransmit; // timer; based on Device->ShortAbsoluteTime
+ ULONG Watchdog; // timer; based on Device->LongAbsoluteTime
+ USHORT TickCount; // 18.21/second, # for 576-byte packet.
+ USHORT HopCount; // As returned by ipx on find route.
+ BOOLEAN OnShortList; // are we inserted in the list
+ BOOLEAN OnLongList; // are we inserted in the list
+ LIST_ENTRY ShortList; // queues us on Device->ShortList
+ LIST_ENTRY LongList; // queues us on Device->LongList
+
+ //
+ // These are valid when we have a connection established;
+ //
+
+ USHORT LocalConnectionId;
+ USHORT RemoteConnectionId;
+
+ PREQUEST DisassociatePending; // guarded by device lock.
+ PREQUEST ClosePending;
+
+ PREQUEST ConnectRequest;
+ PREQUEST ListenRequest;
+ PREQUEST AcceptRequest;
+ PREQUEST DisconnectRequest;
+ PREQUEST DisconnectWaitRequest;
+
+ ULONG CanBeDestroyed; // FALSE if reference is non-zero
+ ULONG ThreadsInHandleConnectionZero; // # of threads in HandleConnectionZero
+
+ //
+ // These are used to hold extra data that was sent on a session
+ // init, for use in sending the ack. Generally will be NULL and 0.
+ //
+
+ PUCHAR SessionInitAckData;
+ ULONG SessionInitAckDataLength;
+
+ IPX_LOCAL_TARGET LocalTarget; // for the remote when active.
+ IPX_HEADER RemoteHeader;
+
+ CTETimer Timer;
+
+ PADDRESS_FILE AddressFile; // guarded by device lock if associated.
+ LIST_ENTRY AddressFileLinkage; // guarded by device lock
+ ULONG AddressFileLinked; // TRUE if queued using AddressFileLinkage
+
+ PDEVICE Device;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+
+ CHAR RemoteName[16]; // for an active connection.
+
+ IPX_FIND_ROUTE_REQUEST FindRouteRequest; // use this to verify route.
+
+ TDI_CONNECTION_INFO ConnectionInfo; // can be queried from above.
+
+ BOOLEAN FindRouteInProgress; // we have a request pending.
+
+ BOOLEAN SendPacketInUse; // put this here to align packet/header.
+ BOOLEAN IgnoreNextDosProbe;
+
+ NTSTATUS Status; // status code for connection rundown.
+
+#ifdef RSRC_TIMEOUT_DBG
+ LARGE_INTEGER FirstMessageRequestTime;
+#endif //RSRC_TIMEOUT_DBG
+
+ NDIS_HANDLE SendPacketPoolHandle; // poolhandle for sendpacket below when
+ // the packet is allocated from ndis pool.
+
+ NB_SEND_PACKET SendPacket; // try to use this first for sends
+
+ ULONG Flags; // miscellaneous connection flags
+
+ UCHAR SendPacketHeader[1]; // connection is extended to include this
+
+ //
+ // NOTE: This is variable length structure!
+ // Do not add fields below this comment.
+ //
+} CONNECTION, *PCONNECTION;
+
+
+#define CONNECTION_STATE_INACTIVE 1
+#define CONNECTION_STATE_CONNECTING 2
+#define CONNECTION_STATE_LISTENING 3
+#define CONNECTION_STATE_ACTIVE 4
+#define CONNECTION_STATE_DISCONNECT 5
+#define CONNECTION_STATE_CLOSING 6
+
+
+#define CONNECTION_SUBSTATE_L_WAITING 1 // queued by a listen
+#define CONNECTION_SUBSTATE_L_W_ACCEPT 2 // waiting for user to accept
+#define CONNECTION_SUBSTATE_L_W_ROUTE 3 // waiting for rip response
+
+#define CONNECTION_SUBSTATE_C_FIND_NAME 1 // waiting for cache response
+#define CONNECTION_SUBSTATE_C_W_ACK 2 // waiting for session init ack
+#define CONNECTION_SUBSTATE_C_W_ROUTE 3 // waiting for rip response
+#define CONNECTION_SUBSTATE_C_DISCONN 4 // disconnect was issued
+
+#define CONNECTION_SUBSTATE_A_IDLE 1 // no sends in progress
+#define CONNECTION_SUBSTATE_A_PACKETIZE 2 // packetizing a send
+#define CONNECTION_SUBSTATE_A_W_ACK 3 // waiting for an ack
+#define CONNECTION_SUBSTATE_A_W_PACKET 4 // waiting for a packet
+#define CONNECTION_SUBSTATE_A_W_EOR 5 // waiting for eor to start packetizing
+#define CONNECTION_SUBSTATE_A_W_PROBE 6 // waiting for a keep-alive response
+#define CONNECTION_SUBSTATE_A_REMOTE_W 7 // remote shut down our window
+
+#define CONNECTION_RECEIVE_IDLE 1 // no receives queued
+#define CONNECTION_RECEIVE_ACTIVE 2 // receive is queued
+#define CONNECTION_RECEIVE_W_RCV 3 // waiting for receive to be posted
+#define CONNECTION_RECEIVE_INDICATE 4 // indication in progress
+#define CONNECTION_RECEIVE_TRANSFER 5 // transfer is in progress
+#define CONNECTION_RECEIVE_PENDING 6 // last request is queued for completion
+
+#define CONNECTION_SUBSTATE_D_W_ACK 1
+#define CONNECTION_SUBSTATE_D_GOT_ACK 2
+
+//
+// Bit values for Flags field in
+// the CONNECTION structure.
+//
+#define CONNECTION_FLAGS_AUTOCONNECTING 0x00000001 // RAS autodial in progress
+#define CONNECTION_FLAGS_AUTOCONNECTED 0x00000002 // RAS autodial connected
+
+#ifdef RSRC_TIMEOUT_DBG
+extern ULONG NbiGlobalDebugResTimeout;
+extern LARGE_INTEGER NbiGlobalMaxResTimeout;
+extern NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+#endif //RSRC_TIMEOUT_DBG
diff --git a/private/ntos/tdi/isn/nb/nwlnknb.ini b/private/ntos/tdi/isn/nb/nwlnknb.ini
new file mode 100644
index 000000000..e2df88f54
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nwlnknb.ini
@@ -0,0 +1,43 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkNb
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnknb.sys
+ DisplayName = NWLINK2 IPX Netbios Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ "NwlnkIpx"
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Export = REG_MULTI_SZ "\Device\NwlnkNb"
+ Route = REG_MULTI_SZ ""NwlnkIpx""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ Parameters
+ AckDelayTime = REG_DWORD 0x000000fa
+ AckWindow = REG_DWORD 0x00000002
+ AckWindowThreshold = REG_DWORD 0x000001f4
+ EnablePiggyBackAck = REG_DWORD 0x00000001
+ Extensions = REG_DWORD 0x00000001
+ RcvWindowMax = REG_DWORD 0x00000004
+ BroadcastCount = REG_DWORD 0x00000003
+ BroadcastTimeout = REG_DWORD 0x00000001
+ ConnectionCount = REG_DWORD 0x00000005
+ ConnectionTimeout = REG_DWORD 0x00000002
+ InitPackets= REG_DWORD 0x00000005
+ MaxPackets = REG_DWORD 0x0000001e
+ InitialRetransmissionTime = REG_DWORD 0x000001f4
+ Internet = REG_DWORD 0x00000001
+ KeepAliveCount = REG_DWORD 0x00000008
+ KeepAliveTimeout = REG_DWORD 0x0000003c
+ RetransmitMax = REG_DWORD 0x00000008
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkNb
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isn/nb/nwlnknb.rc b/private/ntos/tdi/isn/nb/nwlnknb.rc
new file mode 100644
index 000000000..1b0163cf3
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/nwlnknb.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 "NWLINK2 IPX Netbios Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnknb.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnknb.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/nb/packet.c b/private/ntos/tdi/isn/nb/packet.c
new file mode 100644
index 000000000..7e22534a8
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/packet.c
@@ -0,0 +1,1482 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local Function Protos
+//
+#if defined(_PNP_POWER)
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+ HeaderLength - The length of the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisNbBuffer;
+ PNB_SEND_RESERVED Reserved;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ NbiAllocateSendPacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+// DbgPrint("NbiInitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+
+ //
+ // allocate the mac header.
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisBuffer);
+
+// DbgPrint("NbiInitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+ //
+ // Allocate the nb header
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisNbBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MacHeaderNeeded,
+ HeaderLength - MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // DbgPrint("NbiInitializeSendPacket: IPX header address is (%x)\n", NdisNbBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisNbBuffer);
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->SendInProgress = FALSE;
+ Reserved->OwnedByConnection = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisBuffer;
+
+ Reserved->Reserved[0] = NULL;
+ Reserved->Reserved[1] = NULL;
+
+ InsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeSendPacket */
+
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PNB_RECEIVE_RESERVED Reserved;
+
+ NbiAllocateReceivePacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->TransferInProgress = FALSE;
+
+ InsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceivePacket */
+
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ InsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceiveBuffer */
+
+
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+ HeaderLength - The length of the first buffer on the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNB_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ CTEAssert(HeaderLength > MacHeaderNeeded);
+ Reserved = SEND_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Free the mac header
+ //
+ // DbgPrint("NbiDeinitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // Free the nb header
+ //
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: IPX header address is (%x)\n", NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, HeaderLength - MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // free the packet
+ //
+ NbiFreeSendPacket (Device, Packet);
+
+} /* NbiDeinitializeSendPacket */
+
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNB_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeReceivePacket (Device, Packet);
+
+} /* NbiDeinitializeReceivePacket */
+
+
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE SHOULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+#else
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* NbiDeinitializeReceiveBuffer */
+
+
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PNB_SEND_PACKET Packet;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ SendPool = (PNB_SEND_POOL)NbiAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (SendPool, SendPoolSize);
+
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &SendPool->PoolHandle, Device->InitPackets, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( SendPool, SendPoolSize, MEMORY_PACKET, "Send Pool Freed");
+ return;
+ }
+#endif
+
+ NB_DEBUG2 (PACKET, ("Initializing send pool %lx, %d packets, header %d\n",
+ SendPool, Device->InitPackets, HeaderLength));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitPackets]);
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (NbiInitializeSendPacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ SendPool->PoolHandle,
+#endif
+ Packet,
+ Header,
+ HeaderLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->u.SR_NF.Address = NULL;
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += HeaderLength;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedSendPackets += SendPool->PacketCount;
+
+} /* NbiAllocateSendPool */
+
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 5 receive packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PNB_RECEIVE_PACKET Packet;
+ PNB_RECEIVE_RESERVED Reserved;
+ NTSTATUS Status;
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ ReceivePool = (PNB_RECEIVE_POOL)NbiAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceivePool, ReceivePoolSize);
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &ReceivePool->PoolHandle, Device->InitPackets, sizeof(NB_RECEIVE_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( ReceivePool, ReceivePoolSize, MEMORY_PACKET, "Receive Pool Freed");
+ return;
+ }
+#endif NB_OWN_PACKETS
+
+ NB_DEBUG2 (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitPackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (NbiInitializeReceivePacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ ReceivePool->PoolHandle,
+#endif
+ Packet) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+// PushEntryList (&Device->ReceivePacketList, &Reserved->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+} /* NbiAllocateReceivePool */
+
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ DataLength - Max length of the data in each buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PUCHAR Data;
+
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+ ReceiveBufferPool->BufferDataSize = DataLength;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+ Device->CurMaxReceiveBufferSize = DataLength;
+
+} /* NbiAllocateReceiveBufferPool */
+#else
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ UINT DataLength;
+ PUCHAR Data;
+
+ DataLength = Device->Bind.LineInfo.MaximumPacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef NB_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+} /* NbiAllocateReceiveBufferPool */
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ )
+
+/*++
+
+Routine Description:
+
+ This routines destroys all the existing Buffer Pools and creates
+ new one using the larger packet size given to us by IPX because
+ a new card was inserted with a larger packet size.
+
+Arguments:
+
+ WorkItem - The work item that was allocated for this.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK ( &Device->Lock, &LockHandle );
+
+ if ( Device->Bind.LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("Reallocating new pools due to new maxpacketsize\n");
+#endif
+ NbiDestroyReceiveBufferPools( Device );
+ NbiAllocateReceiveBufferPool( Device, Device->Bind.LineInfo.MaximumPacketSize );
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+ NbiFreeMemory( WorkItem, sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buff Work Item freed");
+}
+
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize,i;
+
+ CTEAssert( ReceiveBufferPool->BufferDataSize );
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (ReceiveBufferPool->BufferDataSize * Device->InitPackets);
+
+ //
+ // Check if we can free this pool
+ //
+ CTEAssert(ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree );
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ RemoveEntryList( &ReceiveBufferPool->Linkage );
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+
+}
+
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routines walks the ReceiveBufferPoolList and destroys the
+ pool which does not have any buffer in use.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE COULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine is also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+{
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY Unused;
+
+
+ //
+ // Clean up this list before we call NbiFreeReceiveBufferPool bcoz that will
+ // simply destroy all the buffer which might be queue here on this list.
+ // At the end of this routine we must start with a fresh ReceiveBufferList.
+ //
+ do {
+ Unused = PopEntryList( &Device->ReceiveBufferList );
+ } while( Unused );
+
+ //
+ // Now destroy each individual ReceiveBufferPool.
+ //
+ for ( p = Device->ReceiveBufferPoolList.Flink;
+ p != &Device->ReceiveBufferPoolList;
+ ) {
+
+
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+ p = p->Flink;
+
+ //
+ // This will destroy and unlink this Pool if none of its buffer is
+ // in use currently.
+ //
+
+ if ( ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ } else {
+ //
+ // When the device is stopping we must succeed in freeing the pool.
+ CTEAssert( Device->State != DEVICE_STATE_STOPPING );
+ }
+
+ }
+
+}
+
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the receive buffer back to the free list.
+ It checks the size of this buffer. If it is smaller than the
+ the CurMaxReceiveBufferSize, then it does not return this back
+ to the free list, instead it destroys it and possibly also
+ destroys the pool associated with it. O/w it simply returns this
+ to the free list.
+
+Arguments:
+
+ ReceiveBuffer - Pointer to the buffer to be returned to the free list.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+#if defined(DBG)
+ ULONG BufLen = 0;
+#endif
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+#if defined(DBG)
+ NdisQueryBuffer( ReceiveBuffer->NdisBuffer, NULL, &BufLen );
+ CTEAssert( BufLen == ReceiveBufferPool->BufferDataSize );
+#endif
+
+ //
+ // This is an old buffer which was in use when we changed
+ // the CurMaxReceiveBufferSize due to new adapter. We must not
+ // return this buffer back to free list. Infact, if the pool
+ // associated with this buffer does not have any other buffers
+ // in use, we should free the pool also.
+ CTEAssert( ReceiveBufferPool->BufferFree < ReceiveBufferPool->BufferCount );
+ ReceiveBufferPool->BufferFree++;
+
+ if ( ReceiveBufferPool->BufferDataSize < Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("ReceiveBuffer %lx, not returned to pool %lx( Free %d)\n", ReceiveBuffer, ReceiveBufferPool, ReceiveBufferPool->BufferFree);
+#endif
+
+
+ if ( ReceiveBufferPool->BufferFree == ReceiveBufferPool->BufferCount ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ }
+ } else {
+
+ PushEntryList( &Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage );
+
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+}
+#endif _PNP_POWER
+
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+ LockAcquired - TRUE if Device->Lock is acquired.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (!LockAcquired) {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ }
+
+ if (Device->AllocatedSendPackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateSendPool (Device);
+
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ return s;
+ } else {
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return NULL;
+ }
+
+} /* NbiPopSendPacket */
+
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a packet back to the device context's pool.
+ If there are connections waiting for packets, it removes
+ one from the list and inserts it on the packetize queue.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // BUGBUG: Make this a function. Optimize for
+ // UP by not doing two checks?
+ //
+
+ if (!IsListEmpty (&Device->WaitPacketConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = RemoveHeadList (&Device->WaitPacketConnections);
+
+ //
+ // Take a connection off the WaitPacketQueue and put it
+ // on the PacketizeQueue. We don't worry about if the
+ // connection has stopped, that will get checked when
+ // the PacketizeQueue is run down.
+ //
+ // Since this is in send completion, we may not get
+ // a receive complete. We guard against this by calling
+ // NbiReceiveComplete from the long timer timeout.
+ //
+
+ if (p != &Device->WaitPacketConnections) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, WaitPacketLinkage);
+
+ CTEAssert (Connection->OnWaitPacketQueue);
+ Connection->OnWaitPacketQueue = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPushSendPacket */
+
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if a connection is on the wait packet
+ queue and if so takes it off and queues it to be packetized.
+ It is meant to be called when the connection's packet has
+ been freed.
+
+Arguments:
+
+ Connection - The connection to check.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (Connection->OnWaitPacketQueue) {
+
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ InsertTailList(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage);
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ return;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiCheckForWaitPacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceivePool (Device);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* NbiPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the device context's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ s = PopEntryList( &Device->ReceiveBufferList );
+
+
+ if ( !s ) {
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateReceiveBufferPool (Device, Device->CurMaxReceiveBufferSize );
+ s = PopEntryList(&Device->ReceiveBufferList);
+ }
+ }
+
+ if ( s ) {
+
+
+ //
+ // Decrement the BufferFree count on the corresponding ReceiveBufferPool.
+ // so that we know that
+ ReceiveBuffer = CONTAINING_RECORD( s, NB_RECEIVE_BUFFER, PoolLinkage );
+
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+
+ CTEAssert( ReceiveBufferPool->BufferFree && ( ReceiveBufferPool->BufferFree <= ReceiveBufferPool->BufferCount ) );
+ CTEAssert( ReceiveBufferPool->BufferDataSize == Device->CurMaxReceiveBufferSize );
+
+ ReceiveBufferPool->BufferFree--;
+
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+#else
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntryList(
+ &Device->ReceiveBufferList,
+ &Device->Lock.Lock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceiveBufferPool (Device);
+ s = PopEntryList(&Device->ReceiveBufferList);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+#endif _PNP_POWER
+} /* NbiPopReceiveBuffer */
+
diff --git a/private/ntos/tdi/isn/nb/precomp.h b/private/ntos/tdi/isn/nb/precomp.h
new file mode 100644
index 000000000..a024f2d3d
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/precomp.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnnb.h"
+#include "config.h"
+#include "nbitypes.h"
+#include "nbiprocs.h"
+#include "zwapi.h"
diff --git a/private/ntos/tdi/isn/nb/query.c b/private/ntos/tdi/isn/nb/query.c
new file mode 100644
index 000000000..6ee33adf3
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/query.c
@@ -0,0 +1,1817 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Remove the warning -- this is defined in windef also.
+//
+
+#ifdef FAR
+#undef FAR
+#endif
+
+#include <windef.h>
+#include <nb30.h>
+
+
+//
+// Useful macro to obtain the total length of a buffer chain.
+// BUGBUG: Make this use NDIS macros.
+//
+
+#define NbiGetBufferChainLength(Buffer, Length) { \
+ PNDIS_BUFFER _Buffer = (Buffer); \
+ *(Length) = 0; \
+ while (_Buffer) { \
+ *(Length) += MmGetMdlByteCount(_Buffer); \
+ _Buffer = _Buffer->Next; \
+ } \
+}
+
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ The status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS NbiAddress;
+ } AddressInfo;
+ TA_NETBIOS_ADDRESS BroadcastAddress;
+ TDI_ADDRESS_IPX IpxAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ struct {
+ FIND_NAME_HEADER Header;
+ FIND_NAME_BUFFER Buffer;
+ } FindNameInfo;
+ } TempBuffer;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ PADAPTER_STATUS AdapterStatus;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG TargetBufferLength;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PNETBIOS_CACHE CacheName;
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+ NTSTATUS QueryStatus;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN UsedConnection;
+ UINT i;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (Query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = TRUE;
+
+ AddressFile = Connection->AddressFile;
+
+ } else {
+
+ Status = STATUS_INVALID_ADDRESS;
+ break;
+
+ }
+
+ Address = AddressFile->Address;
+
+ NB_DEBUG2 (QUERY, ("Query address info on %lx\n", AddressFile));
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD (p, ADDRESS_FILE, Linkage)->State == ADDRESSFILE_STATE_OPEN) {
+ ++TempBuffer.AddressInfo.ActivityCount;
+ }
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ TdiBuildNetbiosAddress(
+ AddressFile->Address->NetbiosAddress.NetbiosName,
+ (BOOLEAN)(AddressFile->Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempBuffer.AddressInfo.NbiAddress);
+
+ Status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ if (UsedConnection) {
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // Assume 50 ms of delay for every hop after the
+ // first. The delay is returned as a negative number.
+ //
+
+ if (Connection->HopCount > 1) {
+ Connection->ConnectionInfo.Delay.HighPart = (ULONG)-1;
+ Connection->ConnectionInfo.Delay.LowPart =
+ -((Connection->HopCount-1) * 50 * MILLISECONDS);
+ } else {
+ Connection->ConnectionInfo.Delay.HighPart = 0;
+ Connection->ConnectionInfo.Delay.LowPart = 0;
+ }
+
+ //
+ // We have tick count; to convert to bytes/second we do:
+ //
+ // packet 576 bytes 18.21 ticks
+ // ---------------- * --------- * -----------
+ // tick_count ticks packet seconds
+ //
+ // to get 10489/tick_count = bytes/second. We
+ // double this because routers tend to
+ // overestimate it.
+ //
+ // Since tick_count has such a low granularity,
+ // a tick count of 1 gives us a throughput of
+ // only 84 kbps, which is much too low. In
+ // that case we return twice the link speed
+ // which is in 100 bps units; that corresponds
+ // to about 1/6 of our bandwidth in bytes/sec.
+ //
+
+ if (Connection->TickCount <= Connection->HopCount) {
+
+ Connection->ConnectionInfo.Throughput.QuadPart =
+ UInt32x32To64 (Connection->LineInfo.LinkSpeed, 2);
+
+ } else {
+
+ Connection->ConnectionInfo.Throughput.HighPart = 0;
+ Connection->ConnectionInfo.Throughput.LowPart =
+ 20978 / (Connection->TickCount - Connection->HopCount);
+
+ }
+
+ Connection->ConnectionInfo.Unreliable = FALSE;
+
+ Status = TdiCopyBufferToMdl (
+ &Connection->ConnectionInfo,
+ 0,
+ sizeof(TDI_CONNECTION_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query provider info\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Information,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query broadcast address\n"));
+
+ TempBuffer.BroadcastAddress.TAAddressCount = 1;
+ TempBuffer.BroadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ TempBuffer.BroadcastAddress.Address[0].AddressLength = 0;
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.BroadcastAddress,
+ 0L,
+ sizeof (TempBuffer.BroadcastAddress.TAAddressCount) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressType) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressLength),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ //
+ // Determine if this is a local or remote query.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (Query->RequestConnectionInformation != NULL) {
+
+ RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (RemoteAddress == NULL) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+#if defined(_PNP_POWER)
+ if ( !NbiFindAdapterAddress(
+ RemoteAddress->NetbiosName,
+ LOCK_NOT_ACQUIRED ) ) {
+
+ RemoteAdapterStatus = TRUE;
+ }
+#else
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+#endif _PNP_POWER
+
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // See if we have this name cached.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this status
+ // request and processing will be resumed when
+ // we get a response.
+ //
+ // The status field in the request will hold
+ // the cache entry for the remote. The information
+ // field will hold the remote netbios name while
+ // it is in the WaitingAdapterStatus queue, and
+ // will hold a timeout value while we it is in
+ // the ActiveAdapterStatus queue.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up adapter status %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ InsertTailList(
+ &Device->WaitingAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found adapter status cached %lx\n", Request));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ REQUEST_STATUS(Request) = (NTSTATUS)CacheName;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ InsertTailList(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiSendStatusQuery (Request);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // Local adapter status.
+ //
+
+ NbiGetBufferChainLength (REQUEST_NDIS_BUFFER(Request), &TargetBufferLength);
+
+ Status = NbiStoreAdapterStatus(
+ TargetBufferLength,
+ 1, // NIC ID, was 0, changed to 1 for Bug #18026
+ // because for NicId = 0, Ipx returns virtual
+ // address. Netbios uses that to register the
+ // name (00...01) and fails.
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // This should succeed since we know the length
+ // will fit.
+ //
+
+ (VOID)TdiCopyBufferToMdl(
+ AdapterStatus,
+ 0,
+ ValidStatusLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if ((Query->RequestConnectionInformation == NULL) ||
+ ((RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE)) == NULL)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We assume the entire request buffer is in the first
+ // piece of the MDL chain (BUGBUG: Can we do this?).
+ // Make sure there is room for at least the header.
+ //
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER)) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // See if we have this name cached. We specify that this is
+ // a netbios name query, so this will only succeed if this is a
+ // unique name -- for a group name it will queue up a find
+ // name query and when we get the response we will fill in
+ // the request's buffer based on it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameNetbiosFindName,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this find
+ // name request and processing will be resumed when
+ // we get a response.
+ //
+ // The information field will hold the remote
+ // netbios name while it is in the WaitingNetbiosFindName
+ // queue. The status will hold the current status --
+ // initially failure, then success, then overflow
+ // if the buffer is too small.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up find name %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ FindNameHeader->node_count = 0;
+ FindNameHeader->reserved = 0;
+ FindNameHeader->unique_group = 0;
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ //
+ // Assume it fails, we update the status to
+ // SUCCESS or BUFFER_OVERFLOW if needed.
+ //
+
+ REQUEST_STATUS (Request) = STATUS_IO_TIMEOUT;
+
+ InsertTailList(
+ &Device->WaitingNetbiosFindName,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found find name cached %lx\n", Request));
+
+ //
+ // We don't need to reference the cache entry since
+ // we only use it here with the lock still held.
+ //
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query. Since we
+ // use TempBuffer.IpxAddress for this query, we have
+ // to immediately copy it to its correct place in
+ // TempBuffer.FindNameInfo.Buffer.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicHandle.NicId ));
+
+ goto QueryFindNameFailed;
+ }
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicId,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ RtlMoveMemory (TempBuffer.FindNameInfo.Buffer.destination_addr, TempBuffer.IpxAddress.NodeAddress, 6);
+ TempBuffer.FindNameInfo.Buffer.access_control = 0x10; // standard token-ring values
+ TempBuffer.FindNameInfo.Buffer.frame_control = 0x40;
+ RtlCopyMemory (TempBuffer.FindNameInfo.Buffer.source_addr, CacheName->FirstResponse.NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, CacheName->FirstResponse.NodeAddress, 6);
+
+ QueryStatus = (*Device->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+#else
+ CacheName->Networks[0].LocalTarget.NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(TempBuffer.FindNameInfo.Buffer.routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ TempBuffer.FindNameInfo.Buffer.routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ TempBuffer.FindNameInfo.Buffer.length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ TempBuffer.FindNameInfo.Header.node_count = 1;
+ TempBuffer.FindNameInfo.Header.reserved = 0;
+ TempBuffer.FindNameInfo.Header.unique_group = 0; // unique
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.FindNameInfo,
+ 0,
+ sizeof(FIND_NAME_HEADER) + 33,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+#if defined(_PNP_POWER)
+QueryFindNameFailed:
+#endif _PNP_POWER
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BETABUGBUG: Keep track of more of these.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query provider statistics\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query datagram info\n"));
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ Status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:{
+#if defined(_PNP_POWER)
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS
+ ? IPX_QUERY_DATA_LINK_ADDRESS
+ : IPX_QUERY_NETWORK_ADDRESS ),
+ NULL,
+ Request,
+ 0,
+ NULL);
+#else
+ ULONG TransportAddressAllocSize;
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+// TransportAddress = CTEAllocMem(sizeof(int) + (ElementSize * Device->MaximumNicId));
+ TransportAddressAllocSize = sizeof(int) + ( ElementSize * Device->MaximumNicId);
+ TransportAddress = NbiAllocateMemory( TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ if (TransportAddress == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+
+ for (i = 1; i <= Device->MaximumNicId; i++) {
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ (USHORT)i,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ RtlCopyMemory (CurAddress->Address, TempBuffer.IpxAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &TempBuffer.IpxAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+
+ Status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+// CTEFreeMem (TransportAddress);
+ NbiFreeMemory( TransportAddress, TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ }
+#endif _PNP_POWER
+ break;
+ }
+ default:
+
+ NB_DEBUG (QUERY, ("Invalid query type %d\n", Query->QueryType));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
+
+} /* NbiTdiQueryInformation */
+
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an ADAPTER_STATUS buffer and
+ fills it in. The buffer will be allocated at most
+ MaximumLength size. The caller is responsible for
+ freeing the buffer.
+
+Arguments:
+
+ MaximumLength - The maximum length to allocate.
+
+ NicId - The NIC ID the query was received on, or 0 for
+ a local query.
+
+ StatusBuffer - Returns the allocated buffer.
+
+ StatusBufferLength - Returns the length of the buffer.
+
+ ValidBufferLength - Returns the length of the buffer which
+ contains valid adapter status data.
+
+Return Value:
+
+ STATUS_SUCCESS - The buffer was written successfully.
+ STATUS_BUFFER_OVERFLOW - The buffer was written but not all
+ data could fit in MaximumLength bytes.
+ STATUS_INSUFFICIENT_RESOURCES - The buffer could not be allocated.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus;
+ PNAME_BUFFER NameBuffer;
+ ADAPTER_STATUS TempAdapterStatus;
+#if !defined(_PNP_POWER)
+ TDI_ADDRESS_IPX IpxAddress;
+#endif !_PNP_POWER
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ UCHAR NameCount;
+ ULONG LengthNeeded;
+ ULONG BytesWritten;
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ //
+ // First fill in the basic adapter status structure, to make
+ // it easier to copy over if the target buffer is really short.
+ //
+
+ RtlZeroMemory ((PVOID)&TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+#if defined(_PNP_POWER)
+ RtlCopyMemory (TempAdapterStatus.adapter_address, Device->Bind.Node, 6);
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ RtlCopyMemory (TempAdapterStatus.adapter_address, IpxAddress.NodeAddress, 6);
+#endif _PNP_POWER
+
+
+ //
+ // Some of the fields mean different things for Novell Netbios,
+ // as described in the comments.
+ //
+
+ TempAdapterStatus.rev_major = 0; // Jumpers
+ TempAdapterStatus.reserved0 = 0; // SelfTest
+ TempAdapterStatus.adapter_type = 0; // MajorVersion
+ TempAdapterStatus.rev_minor = 0; // MinorVersion
+
+ TempAdapterStatus.duration = 0; // ReportingPeriod
+ TempAdapterStatus.frmr_recv = 0; // ReceiveCRCErrors
+ TempAdapterStatus.frmr_xmit = 0; // ReceiveAlignErrors
+
+ TempAdapterStatus.iframe_recv_err = 0; // XmitCollisions
+ TempAdapterStatus.xmit_aborts = 0; // XmitAbort
+
+ TempAdapterStatus.xmit_success = Device->Statistics.DataFramesSent; // SuccessfulXmits
+ TempAdapterStatus.recv_success = Device->Statistics.DataFramesReceived; // SuccessfulReceive
+
+ TempAdapterStatus.iframe_xmit_err = (WORD)Device->Statistics.DataFramesResent; // XmitRetries
+ TempAdapterStatus.recv_buff_unavail = (WORD)Device->Statistics.DataFramesRejected; // ExhaustedResource
+
+ // t1_timeouts, ti_timeouts, and reserved1 are unused.
+
+ TempAdapterStatus.free_ncbs = 0xffff; // FreeBlocks
+ TempAdapterStatus.max_cfg_ncbs = 0xffff; // ConfiguredNCB
+ TempAdapterStatus.max_ncbs = 0xffff; // MaxNCB
+
+ // xmit_bug_unavail and max_dgram_size are unused.
+
+ TempAdapterStatus.pending_sess = (WORD)Device->Statistics.OpenConnections; // CurrentSessions
+ TempAdapterStatus.max_cfg_sess = 0xffff; // MaxSessionConfigured
+ TempAdapterStatus.max_sess = 0xffff; // MaxSessionPossible
+ TempAdapterStatus.max_sess_pkt_size =
+ Device->Bind.LineInfo.MaximumSendSize - sizeof(NB_CONNECTION); // MaxSessionPacketSize
+
+ TempAdapterStatus.name_count = 0;
+
+
+ //
+ // Do a quick estimate of how many names we need room for.
+ // This includes stopping addresses and the broadcast
+ // address, for the moment. BUGBUG: Fix this?
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LengthNeeded = sizeof(ADAPTER_STATUS) + (Device->AddressCount * sizeof(NAME_BUFFER));
+
+ if (LengthNeeded > MaximumLength) {
+ LengthNeeded = MaximumLength;
+ }
+
+ AdapterStatus = NbiAllocateMemory(LengthNeeded, MEMORY_STATUS, "Adapter Status");
+ if (AdapterStatus == NULL) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *StatusBuffer = AdapterStatus;
+ *StatusBufferLength = LengthNeeded;
+
+ if (LengthNeeded < sizeof(ADAPTER_STATUS)) {
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, LengthNeeded);
+ *ValidBufferLength = LengthNeeded;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+ BytesWritten = sizeof(ADAPTER_STATUS);
+ NameBuffer = (PNAME_BUFFER)(AdapterStatus+1);
+ NameCount = 0;
+
+ //
+ // Scan through the device's address database, filling in
+ // the NAME_BUFFERs.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+#if defined(_PNP_POWER)
+ if ((Address->State != ADDRESS_STATE_OPEN) ||
+ (Address->Flags & ADDRESS_FLAGS_CONFLICT)) {
+ continue;
+ }
+#else
+ if ((Address->State != ADDRESS_STATE_OPEN) != 0) {
+ continue;
+ }
+#endif _PNP_POWER
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (Address->NetbiosAddress.Broadcast) {
+ continue;
+ }
+
+ //
+ // Ignore our reserved address.
+ //
+#if defined(_PNP_POWER)
+ if ( NbiFindAdapterAddress(
+ Address->NetbiosAddress.NetbiosName,
+ LOCK_ACQUIRED
+ )) {
+ continue;
+ }
+#else
+ if (RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+ continue;
+ }
+
+#endif _PNP_POWER
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > LengthNeeded) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ ++NameCount;
+ NameBuffer->name_num = NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (Address->NameTypeFlag == NB_NAME_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ //
+ // BUGBUG: name_flags should be done more accurately.
+ //
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ AdapterStatus->name_count = (WORD)NameCount;
+ *ValidBufferLength = BytesWritten;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Status;
+
+} /* NbiStoreAdapterStatus */
+
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the find name request with the
+ new information received. It updates the status in
+ the request if needed.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+ NicId - The NIC ID the response was received on.
+
+ RemoteIpxAddress - The IPX address of the remote.
+
+ Unique - TRUE if the name is unique.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ FIND_NAME_BUFFER UNALIGNED * FindNameBuffer;
+ UINT FindNameBufferLength;
+ TDI_ADDRESS_IPX LocalIpxAddress;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ NTSTATUS QueryStatus;
+ UINT i;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // Scan through the names saved so far and see if this one
+ // is there.
+ //
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)(FindNameHeader+1);
+
+ for (i = 0; i < FindNameHeader->node_count; i++) {
+
+ if (RtlEqualMemory(
+ FindNameBuffer->source_addr,
+ RemoteIpxAddress->NodeAddress,
+ 6)) {
+
+ //
+ // This remote already responded, ignore it.
+ //
+
+ return;
+
+ }
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)
+ (((PUCHAR)FindNameBuffer) + 33);
+
+ }
+
+ //
+ // Make sure there is room for this new node. 33 is
+ // sizeof(FIND_NAME_BUFFER) without padding.
+ //
+
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER) + ((FindNameHeader->node_count+1) * 33)) {
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query.
+ //
+
+#if defined(_PNP_POWER)
+ if( (*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicHandle,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Ignore this response if the query fails. maybe the NicHandle
+ // is bad or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ NicHandle->NicId ));
+ return;
+ }
+#else
+ (VOID)(*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ FindNameBuffer->access_control = 0x10; // standard token-ring values
+ FindNameBuffer->frame_control = 0x40;
+ RtlMoveMemory (FindNameBuffer->destination_addr, LocalIpxAddress.NodeAddress, 6);
+ RtlCopyMemory (FindNameBuffer->source_addr, RemoteIpxAddress->NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, RemoteIpxAddress->NodeAddress, 6);
+
+ QueryStatus = (*NbiDevice->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ NicHandle,
+#else
+ NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(FindNameBuffer->routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ FindNameBuffer->routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ FindNameBuffer->length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ ++FindNameHeader->node_count;
+ if (!Unique) {
+ FindNameHeader->unique_group = 1; // group
+ }
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+} /* NbiUpdateNetbiosFindName */
+
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the REQUEST_INFORMATION field to the right
+ value based on the number of responses recorded in the netbios
+ find name request's buffer.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ REQUEST_INFORMATION(Request) = sizeof(FIND_NAME_HEADER) + (FindNameHeader->node_count * 33);
+
+} /* NbiSetNetbiosFindNameInformation */
+
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbiTdiSetInformation */
+
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LINE_INFO LineInfo;
+ ULONG ResponseSize;
+ NTSTATUS Status;
+ PNDIS_BUFFER AdapterStatusBuffer;
+ PADAPTER_STATUS AdapterStatus;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+
+
+ //
+ // The old stack does not include the 14 bytes of padding in
+ // the 802.3 or IPX length of the packet.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + 2)) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ &RemoteAddress->NicHandle,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Bad NicHandle or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicHandle.NicId ));
+
+ return;
+ }
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+#else
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicId,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+#endif _PNP_POWER
+
+ ResponseSize = LineInfo.MaximumSendSize - sizeof(IPX_HEADER) - sizeof(NB_STATUS_RESPONSE);
+
+ //
+ // Get the local adapter status (this allocates a buffer).
+ //
+
+ Status = NbiStoreAdapterStatus(
+ ResponseSize,
+#if defined(_PNP_POWER)
+ RemoteAddress->NicHandle.NicId,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &AdapterStatusBuffer,
+ Device->NdisBufferPoolHandle,
+ AdapterStatus,
+ ValidStatusLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Reply to AdapterStatus from %lx %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(UNALIGNED ULONG *)Connectionless->IpxHeader.SourceNetwork,
+ Connectionless->IpxHeader.SourceNode[0],
+ Connectionless->IpxHeader.SourceNode[1],
+ Connectionless->IpxHeader.SourceNode[2],
+ Connectionless->IpxHeader.SourceNode[3],
+ Connectionless->IpxHeader.SourceNode[4],
+ Connectionless->IpxHeader.SourceNode[5]));
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_RESPONSE;
+ Reserved->u.SR_AS.ActualBufferLength = AdapterStatusLength;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, Connectionless->IpxHeader.SourceNetwork, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_RESPONSE;
+
+ NbiReferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ NdisChainBufferAtBack (Packet, AdapterStatusBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ RemoteAddress,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + ValidStatusLength,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ Request - Holds the request describing the remote adapter
+ status query. REQUEST_STATUS(Request) points
+ to the netbios cache entry for the remote name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNETBIOS_CACHE CacheName;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_QUERY;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(Request);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ LocalTarget = &CacheName->Networks[0].LocalTarget;
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_QUERY;
+
+ NbiReferenceDevice (Device, DREF_STATUS_FRAME);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY),
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_RESPONSE frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ PREQUEST AdapterStatusRequest;
+ PNETBIOS_CACHE CacheName;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNDIS_BUFFER TargetBuffer;
+ ULONG TargetBufferLength, BytesToTransfer;
+ ULONG BytesTransferred;
+ NDIS_STATUS NdisStatus;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ BOOLEAN Found;
+ PNAME_BUFFER NameBuffer;
+ UINT i,NameCount = 0;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) {
+ return;
+ }
+
+ //
+ // Find out how many names are there.
+ //
+ NameBuffer = (PNAME_BUFFER)(LookaheadBuffer + sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS));
+ if ( LookaheadBufferSize > sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS) ) {
+ NameCount = (LookaheadBufferSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS)) ) /
+ sizeof(NAME_BUFFER);
+ }
+ //
+ // Find a request queued to this remote. If there are
+ // multiple requests outstanding for the same name we
+ // should get multiple responses, so we only need to
+ // find one.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Found = FALSE;
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if ( CacheName->Unique ) {
+ if (RtlEqualMemory(
+ &CacheName->FirstResponse,
+ Connectionless->IpxHeader.SourceNetwork,
+ 12)) {
+ Found = TRUE;
+ break;
+ }
+ } else if ( RtlEqualMemory( CacheName->NetbiosName,NetbiosBroadcastName,16)){
+ //
+ // It's a broadcast name. Any response is fine.
+ //
+ Found = TRUE;
+ break;
+ } else {
+ //
+ // It's group name. Make sure that this remote
+ // has this group name registered with him.
+ //
+ for (i =0;i<NameCount;i++) {
+ if ( (RtlEqualMemory(
+ CacheName->NetbiosName,
+ NameBuffer[i].name,
+ 16)) &&
+
+ (NameBuffer[i].name_flags & GROUP_NAME) ) {
+
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!Found) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Got response to AdapterStatus %lx\n", AdapterStatusRequest));
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+ REQUEST_STATUS (AdapterStatusRequest) = STATUS_INSUFFICIENT_RESOURCES;
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->Type = RECEIVE_TYPE_ADAPTER_STATUS;
+ ReceiveReserved->u.RR_AS.Request = AdapterStatusRequest;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_SUCCESS;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // We will complete the request when the transfer completes.
+ //
+
+ TargetBuffer = REQUEST_NDIS_BUFFER (AdapterStatusRequest);
+
+ NdisChainBufferAtFront (Packet, TargetBuffer);
+
+ NbiGetBufferChainLength (TargetBuffer, &TargetBufferLength);
+ BytesToTransfer = PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if (TargetBufferLength < BytesToTransfer) {
+ BytesToTransfer = TargetBufferLength;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_BUFFER_OVERFLOW;
+ }
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE)),
+ BytesToTransfer,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessStatusResponse */
+
diff --git a/private/ntos/tdi/isn/nb/receive.c b/private/ntos/tdi/isn/nb/receive.c
new file mode 100644
index 000000000..721209d68
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/receive.c
@@ -0,0 +1,1307 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains the code to handle receive indication
+ and posted receives for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This routine is a no-op to put in the NbiCallbacks table so
+// we can avoid checking for runt session frames (this is because
+// of how the if is structure below).
+//
+
+VOID
+NbiProcessSessionRunt(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+{
+ return;
+}
+
+NB_CALLBACK_NO_TRANSFER NbiCallbacksNoTransfer[] = {
+ NbiProcessFindName,
+ NbiProcessNameRecognized,
+ NbiProcessAddName,
+ NbiProcessAddName, // processes name in use frames also
+ NbiProcessDeleteName,
+ NbiProcessSessionRunt, // in case get a short session packet
+ NbiProcessSessionEnd,
+ NbiProcessSessionEndAck,
+ NbiProcessStatusQuery
+ };
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiProcessDeathPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ DbgPrint("******Received death packet - connid %x\n",Sess->DestConnectionId);
+
+ if ( !NbiGlobalDebugResTimeout ) {
+ return;
+ }
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ DbgPrint("********No Connection found with %x id\n",Sess->DestConnectionId);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ DbgPrint("******Received death packet on conn %lx from <%.16s>\n",Connection,Connection->RemoteName);
+ DbgBreakPoint();
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+BOOLEAN
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN ULONG FwdAdapterCtx,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN PMDL pMdl
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive indications from IPX.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ TRUE - receivepacket taken, will return later with NdisReturnPacket.
+ Currently, we always return FALSE.
+
+--*/
+
+{
+ PNB_FRAME NbFrame = (PNB_FRAME)LookaheadBuffer;
+ UCHAR DataStreamType;
+
+ //
+ // We know that this is a frame with a valid IPX header
+ // because IPX would not give it to use otherwise. However,
+ // it does not check the source socket.
+ //
+
+ if (NbFrame->Connectionless.IpxHeader.SourceSocket != NB_SOCKET) {
+ return FALSE;
+ }
+
+ ++NbiDevice->Statistics.PacketsReceived;
+
+ // First assume that the DataStreamType is at the normal place i.e 2nd byte
+ //
+
+ // Now see if this is a name frame.
+ //
+ if ( PacketSize == sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME) ) {
+ // In the internet mode, the DataStreamType2 becomes DataStreamType
+ if (NbFrame->Connectionless.IpxHeader.PacketType == 0x14 ) {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType2;
+ } else {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ }
+
+ // Is this a name frame?
+ // NB_CMD_FIND_NAME = 1 .... NB_CMD_DELETE_NAME = 5
+ //
+ if ((DataStreamType >= NB_CMD_FIND_NAME) && (DataStreamType <= NB_CMD_DELETE_NAME)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+ return FALSE;
+ }
+
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_DEATH_PACKET)) {
+
+ NbiProcessDeathPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_SESSION_DATA)) {
+
+ NbiProcessSessionData(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else {
+
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ // Handle NB_CMD_SESSION_END = 7 ... NB_CMD_STATUS_QUERY = 9
+ //
+ if ((DataStreamType >= NB_CMD_SESSION_END ) && (DataStreamType <= NB_CMD_STATUS_QUERY)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+
+ } else if (DataStreamType == NB_CMD_STATUS_RESPONSE) {
+
+ NbiProcessStatusResponse(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else if ((DataStreamType == NB_CMD_DATAGRAM) ||
+ (DataStreamType == NB_CMD_BROADCAST_DATAGRAM)) {
+
+ NbiProcessDatagram(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize,
+ (BOOLEAN)(DataStreamType == NB_CMD_BROADCAST_DATAGRAM));
+
+ }
+
+ }
+
+ return FALSE;
+} /* NbiReceive */
+
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive complete indications from IPX.
+
+Arguments:
+
+ NicId - The NIC ID on which a receive was previously indicated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ PREQUEST Request;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PDEVICE Device = NbiDevice;
+ LIST_ENTRY LocalList;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ //
+ // Complete any pending receive requests.
+ //
+
+
+ if (!IsListEmpty (&Device->ReceiveCompletionQueue)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveCompletionQueue, p)) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ //
+ // BUGBUG: Cache the connection somewhere easier
+ // to retrieve?
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ }
+
+ }
+
+
+ //
+ // Indicate any datagrams to clients.
+ //
+
+ if (!IsListEmpty (&Device->ReceiveDatagrams)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveDatagrams, p)) {
+
+ ReceiveBuffer = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER, WaitLinkage);
+ Address = ReceiveBuffer->Address;
+
+ NbiIndicateDatagram(
+ Address,
+ ReceiveBuffer->RemoteName,
+ ReceiveBuffer->Data,
+ ReceiveBuffer->DataLength);
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ }
+ }
+
+
+ //
+ // Start packetizing connections.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Check again because it may just have become
+ // empty, and the code below depends on it being
+ // non-empty.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ //
+ // We copy the list locally, in case someone gets
+ // put back on it. We have to hack the end so
+ // it points to LocalList instead of PacketizeConnections.
+ //
+
+ LocalList = Device->PacketizeConnections;
+ LocalList.Flink->Blink = &LocalList;
+ LocalList.Blink->Flink = &LocalList;
+
+ InitializeListHead (&Device->PacketizeConnections);
+
+ //
+ // Set all these connections to not be on the list, so
+ // NbiStopConnection won't try to take them off.
+ //
+
+ for (p = LocalList.Flink; p != &LocalList; p = p->Flink) {
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ CTEAssert (Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = FALSE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&LocalList);
+ if (p == &LocalList) {
+ break;
+ }
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ }
+
+} /* NbiReceiveComplete */
+
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a transfer data complete indication from
+ IPX, indicating that a previously issued NdisTransferData
+ call has completed.
+
+Arguments:
+
+ Packet - The packet associated with the transfer.
+
+ Status - The status of the transfer.
+
+ BytesTransferred - The number of bytes transferred.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PREQUEST AdapterStatusRequest;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ ReceiveReserved = (PNB_RECEIVE_RESERVED)(Packet->ProtocolReserved);
+
+ switch (ReceiveReserved->Type) {
+
+ case RECEIVE_TYPE_DATA:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ Connection = ReceiveReserved->u.RR_CO.Connection;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive = Connection->PreviousReceive;
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // BUGBUG: Send a resend ack?
+ //
+
+ } else {
+
+ //
+ // This aborts the current receive and
+ // releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ } else {
+
+
+ Connection->CurrentReceive.Offset += BytesTransferred;
+ Connection->CurrentReceive.MessageOffset += BytesTransferred;
+
+ if (ReceiveReserved->u.RR_CO.CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (ReceiveReserved->u.RR_CO.EndOfMessage) {
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (ReceiveReserved->u.RR_CO.PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesTransferred;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ }
+
+ //
+ // Free the NDIS buffer chain if we allocated one.
+ //
+
+ if (!ReceiveReserved->u.RR_CO.NoNdisBuffer) {
+
+ NdisQueryPacket (Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ break;
+
+ case RECEIVE_TYPE_DATAGRAM:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ ReceiveBuffer = ReceiveReserved->u.RR_DG.ReceiveBuffer;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = NULL;
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // If it succeeded then queue it for indication,
+ // otherwise free the receive buffer also.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ ReceiveBuffer->DataLength = BytesTransferred;
+ NB_INSERT_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &ReceiveBuffer->WaitLinkage,
+ &Device->Lock);
+
+ } else {
+
+ Address = ReceiveBuffer->Address;
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ break;
+
+ case RECEIVE_TYPE_ADAPTER_STATUS:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ AdapterStatusRequest = ReceiveReserved->u.RR_AS.Request;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // Complete the request.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // REQUEST_STATUS() is already to set to SUCCESS or
+ // BUFFER_OVERFLOW based on whether the buffer was
+ // big enough.
+ //
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = BytesTransferred;
+
+ } else {
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_UNEXPECTED_NETWORK_ERROR;
+
+ }
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ break;
+
+ }
+
+} /* NbiTransferDataComplete */
+
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a receive needs to be acked to
+ the remote. It either sends a data ack or queues up a piggyback
+ ack request.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // CurrentReceiveNoPiggyback is based on the bits he
+ // set in his frame, NoPiggybackHeuristic is based on
+ // guesses about the traffic pattern, it is set to
+ // TRUE if we think we should not piggyback.
+ //
+
+ if ((!Device->EnablePiggyBackAck) ||
+ (Connection->CurrentReceiveNoPiggyback) ||
+ (Connection->PiggybackAckTimeout) ||
+ (Connection->NoPiggybackHeuristic)) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (!Connection->DataAckPending) {
+
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ //
+ // Some stacks can have multiple messages
+ // outstanding, so we may already have an
+ // ack queued.
+ //
+
+ Connection->DataAckTimeouts = 0;
+ Connection->DataAckPending = TRUE;
+
+ ++Device->Statistics.PiggybackAckQueued;
+
+ if (!Connection->OnDataAckQueue) {
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle1);
+
+ if (!Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ }
+
+ if (!Device->DataAckActive) {
+ NbiStartShortTimer (Device);
+ Device->DataAckActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle1);
+ }
+
+ //
+ // Clear this, since a message ack resets the count.
+ //
+
+ Connection->ReceivesWithoutAck = 0;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+}
+
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have filled up a receive request
+ and need to complete it.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+ THIS ROUTINE ALSO HOLDS CANCEL SPIN LOCK WHEN IT IS CALLED
+ AND RELEASES IT WHEN IT RETURNS.
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ EndOfMessage - BOOLEAN set to true if the message end was received.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Complete the current receive request. If the connection
+ // has shut down then we complete it right here, otherwise
+ // we queue it for completion in the receive complete
+ // handler.
+ //
+
+ Request = Connection->ReceiveRequest;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveRequest = NULL; // StopConnection won't do this
+
+ REQUEST_STATUS(Request) = Connection->Status;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = Connection->CurrentReceive.Offset;
+
+ if (EndOfMessage) {
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveUnaccepted) {
+ NB_DEBUG2 (RECEIVE, ("Moving Unaccepted %d down by %d\n",
+ Connection->ReceiveUnaccepted, Connection->CurrentReceive.Offset));
+ if (Connection->CurrentReceive.Offset >= Connection->ReceiveUnaccepted) {
+ Connection->ReceiveUnaccepted = 0;
+ } else {
+ Connection->ReceiveUnaccepted -= Connection->CurrentReceive.Offset;
+ }
+ }
+
+ //
+ // BUGBUG: Check whether to activate another receive?
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_PENDING;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (EndOfMessage) {
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (Connection->CurrentIndicateOffset != 0) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ EndOfMessage ? NbiAckResponse : NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // This will complete the request inside ReceiveComplete,
+ // dereference the connection, and set the state to IDLE.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ReceiveCompletionQueue,
+ REQUEST_LINKAGE (Request),
+ &Device->Lock);
+
+ }
+
+} /* NbiCompleteReceive */
+
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a receive on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the receive.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelReceive);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ //
+ // Insert this in our queue, then see if we need
+ // to wake up the remote.
+ //
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->ReceiveQueue, Request);
+
+ if (Connection->ReceiveState != CONNECTION_RECEIVE_W_RCV) {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx idle\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx awakened\n", Request, Connection));
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax = (USHORT)
+ (Connection->ReceiveSequence + Connection->ReceiveWindowSize - 1);
+
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Receive connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiReceive */
+
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The request is found on the connection's receive queue.
+
+ 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.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+
+ //
+ // Just stop the connection, that will tear down any
+ // receives.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // receives without stopping the connection??
+ //
+ // BUGBUG: This routine is the same as NbiCancelSend,
+ // so if we don't make it more specific, merge the two.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelReceive */
+
diff --git a/private/ntos/tdi/isn/nb/send.c b/private/ntos/tdi/isn/nb/send.c
new file mode 100644
index 000000000..a4443c73c
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/send.c
@@ -0,0 +1,2886 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains the send routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+)
+
+/*++
+
+Routine Description:
+
+ This routine handles a send completion call from IPX.
+
+Arguments:
+
+ Packet - The packet which has been completed.
+
+ Status - The status of the send.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+
+{
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST DatagramRequest;
+ PREQUEST SendRequest, TmpRequest;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PNETBIOS_CACHE CacheName;
+ PNDIS_BUFFER SecondBuffer;
+ PVOID SecondBufferMemory;
+ UINT SecondBufferLength;
+ ULONG oldvalue;
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ CTELockHandle CancelLH;
+#if defined(_PNP_POWER)
+ CTELockHandle LockHandle;
+#endif _PNP_POWER
+
+ //
+ // We jump back here if we re-call send from inside this
+ // function and it doesn't pend (to avoid stack overflow).
+ //
+
+FunctionStart:;
+
+ ++Device->Statistics.PacketsSent;
+
+ switch (Reserved->Type) {
+
+ case SEND_TYPE_SESSION_DATA:
+
+ //
+ // This was a send on a session. This references the
+ // IRP.
+ //
+
+ NB_DEBUG2 (SEND, ("Complete NDIS packet %lx\n", Reserved));
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+ SendRequest = Reserved->u.SR_CO.Request;
+
+ if (!Reserved->u.SR_CO.NoNdisBuffer) {
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ //
+ // If NoNdisBuffer is TRUE, then we could set
+ // Connection->SendBufferInUse to FALSE here. The
+ // problem is that a new send might be in progress
+ // by the time this completes and it may have
+ // used the user buffer, then if we need to
+ // retransmit that packet we would use the buffer
+ // twice. We instead rely on the fact that whenever
+ // we make a new send active we set SendBufferInUse
+ // to FALSE. The net effect is that the user's buffer
+ // can be used the first time a send is packetize
+ // but not on resends.
+ //
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+#if DBG
+ if (REQUEST_REFCOUNT(SendRequest) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, SendRequest);
+ DbgBreakPoint();
+ }
+#endif
+
+#if defined(__PNP)
+ NB_GET_LOCK( &Connection->Lock, &LockHandle );
+ oldvalue = REQUEST_REFCOUNT(SendRequest)--;
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == Status ) {
+ Connection->LocalTarget = Reserved->LocalTarget;
+ }
+ NB_FREE_LOCK( &Connection->Lock, LockHandle );
+#else
+ oldvalue = NB_ADD_ULONG(
+ &REQUEST_REFCOUNT (SendRequest),
+ (ULONG)-1,
+ &Connection->Lock);
+#endif __PNP
+
+ if (oldvalue == 1) {
+
+ //
+ // If the refcount on this request is now zero then
+ // we already got the ack for it, which means
+ // that the ack-processing code has unlinked the
+ // request from Connection->SendQueue. So we
+ // can just run the queue of connections here
+ // and complete them.
+ //
+ // We dereference the connection for all but one
+ // of the requests, we hang on to that until a bit
+ // later so everything stays around.
+ //
+
+ while (TRUE) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+ NB_DEBUG2 (SEND, ("Completing request %lx from send complete\n", SendRequest));
+ REQUEST_STATUS (SendRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ SendRequest = TmpRequest;
+
+ if (SendRequest == NULL) {
+ break;
+ }
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ }
+
+ if (Reserved->OwnedByConnection) {
+
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (oldvalue == 1) {
+ NbiDereferenceConnection (Connection, CREF_SEND);
+ }
+
+ break;
+
+ case SEND_TYPE_NAME_FRAME:
+
+ //
+ // The frame is an add name/delete name; put it back in
+ // the pool and deref the address.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+
+ Address = Reserved->u.SR_NF.Address;
+
+#if !defined(_PNP_POWER)
+ if ((Reserved->u.SR_NF.CurrentNicId) &&
+ (Reserved->u.SR_NF.CurrentNicId < Device->MaximumNicId)) {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ IPX_LOCAL_TARGET TempLocalTarget;
+
+ //
+ // This is a name frame being sent to every address, so
+ // resent it to the next NIC ID. We hold the address
+ // reference through this send.
+ //
+
+ CTEAssert (Address != NULL);
+
+ ++Reserved->u.SR_NF.CurrentNicId;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = Reserved->u.SR_NF.DataStreamType;
+ Header->NameFrame.NameTypeFlag = Reserved->u.SR_NF.NameTypeFlag;
+
+ //
+ // This is not a name in use frame so DataStreamType2
+ // is the same as DataStreamType.
+ //
+
+ Header->NameFrame.DataStreamType2 = Reserved->u.SR_NF.DataStreamType;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ TempLocalTarget.NicId = Reserved->u.SR_NF.CurrentNicId;
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME));
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ &TempLocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ goto FunctionStart;
+
+ }
+
+ return;
+
+ }
+#endif !_PNP_POWER
+
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ if (Address) {
+ NbiDereferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_SESSION_INIT:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+ CTEAssert (SecondBufferLength == sizeof(NB_SESSION_INIT));
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_SESSION_INIT);
+
+ break;
+
+ case SEND_TYPE_SESSION_NO_DATA:
+
+ //
+ // This is a frame which was sent on a connection but
+ // has no data (ack, session end, session end ack).
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+
+ if (Reserved->OwnedByConnection) {
+
+ CTEAssert (Connection != NULL);
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (Connection != NULL) {
+ NbiDereferenceConnection (Connection, CREF_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_FIND_NAME:
+
+ //
+ // The frame is a find name; just set SendInProgress to
+ // FALSE and FindNameTimeout will clean it up.
+ //
+#if defined(_PNP_POWER)
+ NB_GET_LOCK( &Device->Lock, &LockHandle);
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+ if ( STATUS_SUCCESS == Status ) {
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ } else {
+ NB_DEBUG( CACHE, ("Send complete of find name with failure %lx\n",Status ));
+ }
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+#else
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+#endif _PNP_POWER
+ break;
+
+ case SEND_TYPE_DATAGRAM:
+
+ //
+ // If there are any more networks to send this on then
+ // do so, otherwise put it back in the pool and complete
+ // the request.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ if ((Reserved->u.SR_DG.Cache == NULL) ||
+ (++Reserved->u.SR_DG.CurrentNetwork >=
+ Reserved->u.SR_DG.Cache->NetworksUsed)) {
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Completing datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // Remove any user buffers chained on this packet.
+ //
+
+ NdisReinitializePacket (Packet);
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisChainBufferAtFront (Packet, Reserved->HeaderBuffer);
+
+ //
+ // Complete the request.
+ //
+
+ REQUEST_STATUS(DatagramRequest) = Status;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+ NbiPushSendPacket (Reserved);
+
+ //
+ // Since we are no longer referencing the cache
+ // name, see if we should delete it (this will
+ // happen if the cache entry was aged out while
+ // the datagram was being processed).
+ //
+
+ if (CacheName != NULL) {
+
+ oldvalue = NB_ADD_ULONG(
+ &CacheName->ReferenceCount,
+ (ULONG)-1,
+ &Device->Lock);
+
+ if (oldvalue == 1) {
+
+ NB_DEBUG2 (CACHE, ("Free aged cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free old cache");
+
+ }
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ } else {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PIPX_LOCAL_TARGET LocalTarget;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+
+ // send the datagram on the next net.
+ CTEAssert (!Reserved->u.SR_DG.Cache->Unique);
+ Reserved->SendInProgress = TRUE;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ goto FunctionStart;
+ }
+
+ }
+
+ break;
+
+ case SEND_TYPE_STATUS_QUERY:
+
+ //
+ // This is an adapter status query, which is a simple
+ // packet.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_FRAME);
+
+ break;
+
+ case SEND_TYPE_STATUS_RESPONSE:
+
+ //
+ // This is an adapter status response, we have to free the
+ // second buffer.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, Reserved->u.SR_AS.ActualBufferLength, MEMORY_STATUS, "Adapter Status");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ break;
+
+#ifdef RSRC_TIMEOUT_DBG
+ case SEND_TYPE_DEATH_PACKET:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ DbgPrint("********Death packet send completed status %lx\n",Status);
+ DbgBreakPoint();
+ break;
+#endif //RSRC_TIMEOUT_DBG
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+} /* NbiSendComplete */
+
+#if 0
+ULONG NbiLoudSendQueue = 1;
+#endif
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of the lower-level
+ send handler; 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 CONNECTION LOCK HELD, AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection the send is on.
+
+ Packet - The packet to send.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNB_SEND_RESERVED Reserved;
+ PLIST_ENTRY p;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN NdisSendReference;
+ ULONG result;
+
+
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ CTEAssert (Connection->State == CONNECTION_STATE_ACTIVE);
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+
+ NB_DEBUG2 (SEND, ("Queueing send packet %lx on %lx\n", Reserved, Connection));
+ InsertTailList (&Connection->NdisSendQueue, &Reserved->WaitLinkage);
+ ++Connection->NdisSendsInProgress;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence fields in the packet.
+ //
+
+ Connection->NdisSendsInProgress = 1;
+ NdisSendReference = FALSE;
+ Connection->NdisSendReference = &NdisSendReference;
+
+ while (TRUE) {
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+ }
+
+ //
+ // Since we are acking as much as we know, we can clear
+ // this flag. The connection will eventually get removed
+ // from the queue by the long timeout.
+ //
+
+ Connection->DataAckPending = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ NdisStatus = (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ Reserved->u.SR_CO.PacketLength,
+ sizeof(NB_CONNECTION));
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = NB_ADD_ULONG(
+ &Connection->NdisSendsInProgress,
+ (ULONG)-1,
+ &Connection->Lock);
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit. If the connection was stopped while we were sending,
+ // a special reference was added which we remove (NbiStopConnection
+ // sets NdisSendReference to TRUE, using the pointer saved
+ // in Connection->NdisSendReference).
+ //
+
+ if (result == 1) {
+ if (NdisSendReference) {
+ NB_DEBUG2 (SEND, ("Remove CREF_NDIS_SEND from %lx\n", Connection));
+ NbiDereferenceConnection (Connection, CREF_NDIS_SEND);
+ }
+ return;
+ }
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ p = RemoveHeadList(&Connection->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Connection->NdisSendQueue);
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } // while loop
+
+ //
+ // We should never reach here.
+ //
+
+ CTEAssert (FALSE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiAssignSequenceAndSend */
+
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+
+ //
+ // For old netbios, don't allow sends greater than 64K-1.
+ //
+
+ if ((Connection->NewNetbios) ||
+ (Parameters->SendLength <= 0xffff)) {
+
+ IoSetCancelRoutine (Request, NbiCancelSend);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength; // assume it succeeds.
+
+ REQUEST_REFCOUNT (Request) = 1; // refcount starts at 1.
+ NbiReferenceConnectionSync (Connection, CREF_SEND);
+
+ //
+ // NOTE: The connection send queue is managed such
+ // that the current send being packetized is not on
+ // the queue. For multiple-request messages, the
+ // first one is not on the queue, but its linkage
+ // field points to the next request in the message
+ // (which will be on the head of the queue).
+ //
+
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a final send.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx idle\n", Request, Connection));
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have been collecting partial sends waiting
+ // for a final one, which we have now received,
+ // so start packetizing.
+ //
+ // We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx got eor\n", Request, Connection));
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ //
+ // The state is PACKETIZE, W_ACK, or W_PACKET.
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx busy\n", Request, Connection));
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // This is a partial send. We queue them up without
+ // packetizing until we get a final (this is because
+ // we have to put a correct Connection->CurrentMessageLength
+ // in the frames.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ //
+ // Start collecting partial sends. NOTE: Partial sends
+ // are always inserted in the send queue
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have got another partial send to add to our
+ // list. We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ } else {
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, too long for connection %lx (%d)\n", Request, Connection, Parameters->SendLength));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiSend */
+
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ PNB_SEND_RESERVED Reserved;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTION UNALIGNED * Header;
+ ULONG PacketLength;
+ ULONG PacketSize;
+ ULONG DesiredLength;
+ ULONG ActualLength;
+ NTSTATUS Status;
+ PSINGLE_LIST_ENTRY s;
+ USHORT ThisSendSequence;
+ USHORT ThisOffset;
+ BOOLEAN ExitAfterSend;
+ UCHAR ConnectionControlFlag;
+ CTELockHandle DeviceLockHandle;
+
+ //
+ // We jump back here if we are talking new Netbios and it
+ // is OK to packetize another send.
+ //
+
+SendAnotherPacket:
+
+ //
+ // If we decide to packetize another send after this, we
+ // change ExitAfterSend to FALSE and SubState to PACKETIZE.
+ // Right now we don't change SubState in case it is W_PACKET.
+ //
+
+ ExitAfterSend = TRUE;
+
+ CTEAssert (Connection->CurrentSend.Request != NULL);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // Check that we have send window, both that advertised
+ // by the remote and our own locally-decided window which
+ // may be smaller.
+ //
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence-1) == Connection->RemoteRcvSequenceMax) ||
+ (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize)) {
+
+ //
+ // Keep track of whether we are waiting because of his window
+ // or because of our local window. If it is because of our local
+ // window then we may want to adjust it after this window
+ // is acked.
+ //
+
+ if ((USHORT)(Connection->CurrentSend.SendSequence-1) != Connection->RemoteRcvSequenceMax) {
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+ NB_DEBUG2 (SEND, ("Connection %lx local shut down at %lx, %lx\n", Connection, Connection->CurrentSend.SendSequence, Connection->UnAckedSend.SendSequence));
+ } else {
+ Connection->SubState = CONNECTION_SUBSTATE_A_REMOTE_W;
+ NB_DEBUG2 (SEND, ("Connection %lx remote shut down at %lx\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ //
+ // Start the timer so we will keep bugging him about
+ // this. BUGBUG: What if he doesn't get a receive down
+ // quickly -- but this is better than losing his ack
+ // and then dying. We won't really back off our timer
+ // because we will keep getting acks, and resetting it.
+ //
+
+ NbiStartRetransmit (Connection);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+ }
+
+ Request = Connection->CurrentSend.Request;
+
+ //
+ // If we are in this routine then we know that
+ // we are coming out of IDLE, W_ACK, or W_PACKET
+ // and we still have the lock held. We also know
+ // that there is a send request in progress. If
+ // an ack for none or part of the last packet was
+ // received, then our send pointers have been
+ // adjusted to reflect that.
+ //
+
+ //
+ // First get a packet for the current send.
+ //
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s == NULL) {
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ if (s == NULL) {
+
+ //
+ // It is possible to come in here and already be in
+ // W_PACKET state -- this is because we may packetize
+ // when in that state, and rather than always be
+ // checking that we weren't in W_PACKET, we go
+ // ahead and check again here.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PACKET;
+
+ NB_GET_LOCK (&Device->Lock, &DeviceLockHandle);
+ if (!Connection->OnWaitPacketQueue) {
+
+ NbiReferenceConnectionLock (Connection, CREF_W_PACKET);
+
+ Connection->OnWaitPacketQueue = TRUE;
+
+ InsertTailList(
+ &Device->WaitPacketConnections,
+ &Connection->WaitPacketLinkage
+ );
+
+// NB_INSERT_TAIL_LIST(
+// &Device->WaitPacketConnections,
+// &Connection->WaitPacketLinkage,
+// &Device->Lock);
+
+ }
+ NB_FREE_LOCK (&Device->Lock, DeviceLockHandle);
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ //
+ // Set this now, we will change it later if needed.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+
+
+ //
+ // Save these since they go in this next packet.
+ //
+
+ ThisSendSequence = Connection->CurrentSend.SendSequence;
+ ThisOffset = (USHORT)Connection->CurrentSend.MessageOffset;
+
+
+ //
+ // Now see if we need to copy the buffer chain.
+ //
+
+ PacketSize = Connection->MaximumPacketSize;
+
+ if (Connection->CurrentSend.MessageOffset + PacketSize >= Connection->CurrentMessageLength) {
+
+ PacketSize = Connection->CurrentMessageLength - Connection->CurrentSend.MessageOffset;
+
+ if ((Connection->CurrentSend.MessageOffset == 0) &&
+ (!Connection->SendBufferInUse)) {
+
+ //
+ // If the entire send remaining fits in one packet,
+ // and this is also the first packet in the send,
+ // then the entire send fits in one packet and
+ // we don't need to build a duplicate buffer chain.
+ //
+
+ BufferChain = Connection->CurrentSend.Buffer;
+ Reserved->u.SR_CO.NoNdisBuffer = TRUE;
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->CurrentSend.MessageOffset = Connection->CurrentMessageLength;
+ Connection->CurrentSend.Request = NULL;
+ ++Connection->CurrentSend.SendSequence;
+ Connection->SendBufferInUse = TRUE;
+ if (Connection->NewNetbios) {
+ if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+
+ if (BufferChain != NULL) {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), user buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ NdisChainBufferAtBack (Packet, BufferChain);
+ } else {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ }
+
+ goto GotBufferChain;
+
+ }
+
+ }
+
+ //
+ // We need to build a partial buffer chain. In the case
+ // where the current request is a partial one, we may
+ // build this from the ndis buffer chains of several
+ // requests.
+ //
+
+ if (PacketSize > 0) {
+
+ DesiredLength = PacketSize;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), allocate buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ while (TRUE) {
+
+ Status = NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentSend.Buffer,
+ Connection->CurrentSend.BufferOffset,
+ DesiredLength,
+ &BufferChain,
+ &Connection->CurrentSend.Buffer,
+ &Connection->CurrentSend.BufferOffset,
+ &ActualLength);
+
+ if (Status != STATUS_SUCCESS) {
+
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+
+ NB_DEBUG2 (SEND, ("Allocate buffer chain failed for packet %lx\n", Reserved));
+
+ //
+ // We could not allocate resources for this send.
+ // We'll put the connection on the packetize
+ // queue and hope we get more resources later.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ //
+ // Connection->CurrentSend can stay where it is.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Free any buffers we have allocated on previous calls
+ // to BuildBufferChain inside this same while(TRUE) loop,
+ // then free the packet.
+ //
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+ if (Reserved->OwnedByConnection) {
+ Connection->SendPacketInUse = FALSE;
+ } else {
+ NbiPushSendPacket(Reserved);
+ }
+
+ return;
+
+ }
+
+ NdisChainBufferAtBack (Packet, BufferChain);
+ Connection->CurrentSend.MessageOffset += ActualLength;
+
+ DesiredLength -= ActualLength;
+
+ if (DesiredLength == 0) {
+
+ //
+ // We have gotten enough data for our packet.
+ //
+
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ Connection->CurrentSend.Request = NULL;
+ }
+ break;
+ }
+
+ //
+ // We ran out of buffer chain on this send, which means
+ // that we must have another one behind it (since we
+ // don't start packetizing partial sends until all of
+ // them are queued).
+ //
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+ if (Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+
+ }
+
+ } else {
+
+ //
+ // This is a zero-length send (in general we will go
+ // through the code before the if that uses the user's
+ // buffer, but not on a resend).
+ //
+
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ CTEAssert (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength);
+ Connection->CurrentSend.Request = NULL;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no alloc buf\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ }
+
+ Reserved->u.SR_CO.NoNdisBuffer = FALSE;
+
+ if (Connection->NewNetbios) {
+
+ ++Connection->CurrentSend.SendSequence;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+
+ } else if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else if (ThisSendSequence == Connection->RemoteRcvSequenceMax) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = 0;
+ ExitAfterSend = FALSE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ }
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ ++Connection->CurrentSend.SendSequence;
+ }
+ }
+
+GotBufferChain:
+
+ //
+ // We have a packet and a buffer chain, there are
+ // no other resources required for a send so we can
+ // fill in the header and go.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.Request = Connection->FirstMessageRequest;
+
+ PacketLength = PacketSize + sizeof(NB_CONNECTION);
+ Reserved->u.SR_CO.PacketLength = PacketLength;
+
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. BUGBUG: Put this in
+ // a contiguous buffer in the connection.
+ //
+
+ Header->Session.ConnectionControlFlag = ConnectionControlFlag;
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = ThisSendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentMessageLength;
+ Header->Session.Offset = ThisOffset;
+ Header->Session.DataLength = (USHORT)PacketSize;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ //
+ // Reference the request to account for this send.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ ++REQUEST_REFCOUNT (Request);
+
+ ++Device->TempFramesSent;
+ Device->TempFrameBytesSent += PacketSize;
+
+ //
+ // Start the timer.
+ //
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ if (!ExitAfterSend) {
+
+ //
+ // BUGBUG: Did we need to reference the connection until we
+ // get the lock back??
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ //
+ // Jump back to the beginning of the function to
+ // repacketize.
+
+ goto SendAnotherPacket;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPacketizeSend */
+
+
+VOID
+NbiAdjustSendWindow(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adjusts a connection's send window if needed. It is
+ assumed that we just got an ack for a full send window.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Connection->RetransmitThisWindow) {
+
+ //
+ // Move it down. Check if this keeps happening.
+ //
+
+ if (Connection->SendWindowSize > 2) {
+ --Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lower window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased the window.
+ //
+
+ ++Connection->IncreaseWindowFailures;
+ NB_DEBUG2 (SEND_WINDOW, ("%d consecutive increase failues on %lx (%lx)\n", Connection->IncreaseWindowFailures, Connection, Connection->CurrentSend.SendSequence));
+
+ if (Connection->IncreaseWindowFailures >= 2) {
+
+ if (Connection->MaxSendWindowSize > 2) {
+
+ //
+ // Lock ourselves at a smaller window.
+ //
+
+ Connection->MaxSendWindowSize = Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lock send window at %d on %lx (%lx)\n", Connection->MaxSendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ Connection->IncreaseWindowFailures = 0;
+ }
+
+ Connection->SendWindowIncrease = FALSE;
+ }
+
+ } else {
+
+ //
+ // Increase it if allowed, and make a note
+ // in case this increase causes problems in
+ // the next window.
+ //
+
+ if (Connection->SendWindowSize < Connection->MaxSendWindowSize) {
+
+ ++Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Raise window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ Connection->SendWindowIncrease = TRUE;
+
+ } else {
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased it and nothing failed,
+ // which is good.
+ //
+
+ Connection->SendWindowIncrease = FALSE;
+ Connection->IncreaseWindowFailures = 0;
+ NB_DEBUG2 (SEND_WINDOW, ("Raised window OK on %lx (%lx)\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+ }
+ }
+
+
+ //
+ // This controls when we'll check this again.
+ //
+
+ Connection->SendWindowSequenceLimit += Connection->SendWindowSize;
+
+} /* NbiAdjustSendWindow */
+
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have gotten an ack
+ for some data. It completes any sends that have
+ been acked, and if needed modifies the current send
+ pointer and queues the connection for repacketizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ ReceiveSequence - The receive sequence from the remote.
+
+ BytesReceived - The number of bytes received in this message.
+
+ Resend - If it is OK to resend based on this packet.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ PREQUEST RequestToComplete;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+
+
+ //
+ // BUGBUG: We should change to stop the timer
+ // only if we go idle, since otherwise we still
+ // want it running, or will restart it when we
+ // packetize.
+ //
+
+ //
+ // See how much is acked here.
+ //
+
+ if ((Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) &&
+ (ReceiveSequence == (USHORT)(Connection->CurrentSend.SendSequence)) &&
+ (Connection->FirstMessageRequest != NULL)) {
+
+ // Special check for 0 length send which was not accepted by the remote.
+ // In this case it will pass the above 3 conditions yet, nothing
+ // is acked. BUG#10395
+ if (!Connection->CurrentSend.MessageOffset && Connection->CurrentSend.SendSequence == Connection->UnAckedSend.SendSequence ) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // This acks the entire message.
+ //
+
+ NB_DEBUG2 (SEND, ("Got ack for entire message on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ Connection->CurrentSend.MessageOffset = 0; // BUGBUG: Needed?
+ Connection->UnAckedSend.MessageOffset = 0;
+
+ //
+ // We don't adjust the send window since we likely stopped
+ // packetizing before we hit it.
+ //
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ if (Connection->NewNetbios) {
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Request = Connection->FirstMessageRequest;
+
+ //
+ // We dequeue these requests from the connection's
+ // send queue.
+ //
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ RequestToComplete = Request;
+
+ } else {
+
+ //
+ // There are still sends pending, this will get
+ // completed when the last send completes. Since
+ // we have already unlinked the request from the
+ // connection's send queue we can do this without
+ // any locks.
+ //
+
+ RequestToComplete = NULL;
+
+ }
+
+ //
+ // Now see if there is a send to activate.
+ //
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Now complete any requests we need to.
+ //
+
+ while (RequestToComplete != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (RequestToComplete);
+ REQUEST_STATUS (RequestToComplete) = STATUS_SUCCESS;
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ RequestToComplete = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ } else if ((ReceiveSequence == Connection->CurrentSend.SendSequence) &&
+ (Connection->NewNetbios || (BytesReceived == Connection->CurrentSend.MessageOffset)) &&
+ (Connection->CurrentSend.Request != NULL)) {
+
+ //
+ // This acks whatever we sent last time, and we are
+ // not done packetizing this send, so we can repacketize.
+ // BUGBUG: With SendSequence changing as it does now,
+ // don't need the CurrentSend.Request check???
+ //
+
+ NB_DEBUG2 (SEND, ("Got full ack on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // If we are waiting for a window, and this does not open it
+ // anymore, then we don't reset our timers/retries.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) {
+
+ if (Connection->RemoteRcvSequenceMax != BytesReceived) {
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+ }
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ //
+ // We may be on if this ack is duplicated.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if( Connection->FirstMessageRequest ) {
+
+ //
+ // This acked part of the current send. If the
+ // remote is requesting a resend then we advance
+ // the current send location by the amount
+ // acked and resend from there. If he does
+ // not want a resend, just ignore this.
+ //
+ // We repacketize immediately because we have
+ // backed up the pointer, and this would
+ // cause us to ignore an ack for the amount
+ // sent. Since we don't release the lock
+ // until we have packetized, the current
+ // pointer will be advanced past there.
+ //
+ // BUGBUG: If he is acking more than we sent, we
+ // ignore this -- the remote is confused and there
+ // is nothing much we can do.
+ //
+
+ if (Resend) {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RetransmitThisWindow = TRUE;
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else if (!Connection->NewNetbios &&
+ ((ReceiveSequence == Connection->UnAckedSend.SendSequence) &&
+ (BytesReceived <= Connection->CurrentSend.MessageOffset))) {
+
+ ULONG BytesAcked =
+ BytesReceived - Connection->UnAckedSend.MessageOffset;
+
+ //
+ // Old netbios.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ BytesAcked);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, reset the retry count
+ //
+ if ( BytesAcked ) {
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid. We advance
+ // the back of our send window, but we don't repacketize.
+ //
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if ((Connection->CurrentSend.Request != NULL) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ }
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+} /* NbiReframeConnection */
+
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when have gotten an ack for
+ a full message, or received a response to a watchdog
+ probe, and need to check if the connection should
+ start packetizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ ULONG TempCount;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // See if there is a send to activate.
+ //
+
+ if (Connection->SendQueue.Head != NULL) {
+
+ //
+ // Take the first send off the queue and make
+ // it current.
+ //
+
+ Request = Connection->SendQueue.Head;
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Request);
+
+ //
+ // BUGBUG: Cache the information about being EOM
+ // in a more easily accessible location?
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a one-request message.
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ } else {
+
+ //
+ // This is a multiple-request message. We scan
+ // to see if we have the end of message received
+ // yet.
+ //
+
+ TempCount = Parameters->SendLength;
+ TmpRequest = Request;
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ while (Request != NULL) {
+
+ TempCount += Parameters->SendLength;
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ Connection->CurrentSend.Request = TmpRequest;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (TmpRequest);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = TmpRequest;
+ Connection->LastMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = TempCount;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ break;
+
+ }
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ }
+
+ if (Request == NULL) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ }
+
+ }
+
+ } else {
+
+ Connection->FirstMessageRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+
+ NbiStartWatchdog (Connection);
+
+ }
+
+} /* NbiRestartConnection */
+
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer by the specified number of bytes. It
+ assumes that there are enough send requests to
+ handle the number specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+ BytesAcked - The number of bytes acked.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ ULONG CurSendBufferLength;
+ ULONG BytesLeft = BytesAcked;
+ ULONG TempBytes;
+
+ while (BytesLeft > 0) {
+
+ NdisQueryBuffer (Connection->UnAckedSend.Buffer, NULL, &CurSendBufferLength);
+
+ //
+ // See if bytes acked ends within the current buffer.
+ //
+
+ if (Connection->UnAckedSend.BufferOffset + BytesLeft <
+ CurSendBufferLength) {
+
+ Connection->UnAckedSend.BufferOffset += BytesLeft;
+ Connection->UnAckedSend.MessageOffset += BytesLeft;
+ break;
+
+ } else {
+
+ TempBytes = CurSendBufferLength - Connection->UnAckedSend.BufferOffset;
+ BytesLeft -= TempBytes;
+ Connection->UnAckedSend.MessageOffset += TempBytes;
+
+ //
+ // No, so advance the buffer.
+ //
+
+ Connection->UnAckedSend.BufferOffset = 0;
+ Connection->UnAckedSend.Buffer =
+ NDIS_BUFFER_LINKAGE (Connection->UnAckedSend.Buffer);
+
+ //
+ // Is there a next buffer in this request?
+ //
+
+ if (Connection->UnAckedSend.Buffer == NULL) {
+
+ //
+ // No, so advance the request unless we are done.
+ //
+
+ if (BytesLeft == 0) {
+ return;
+ }
+
+ Connection->UnAckedSend.Request =
+ REQUEST_SINGLE_LINKAGE(Connection->UnAckedSend.Request);
+
+ if (Connection->UnAckedSend.Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->UnAckedSend.Buffer =
+ REQUEST_NDIS_BUFFER (Connection->UnAckedSend.Request);
+
+ }
+ }
+ }
+
+} /* NbiAdvanceUnAckedByBytes */
+
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer so that the next packet to send will be
+ the correct one for ReceiveSequence. UnAckedSend
+ must point to a known valid combination. It
+ assumes that there are enough send requests to
+ handle the sequence specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT PacketsAcked;
+
+ //
+ // BUGBUG: Fix this to account for partial sends, where
+ // we might not have used the max. for all packets.
+ //
+
+ PacketsAcked = ReceiveSequence - Connection->UnAckedSend.SendSequence;
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ PacketsAcked * Connection->MaximumPacketSize);
+
+ Connection->UnAckedSend.SendSequence += PacketsAcked;
+
+} /* NbiAdvanceUnAckedBySequence */
+
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send
+ The request is found on the connection's send queue.
+
+ 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.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_SEND));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // Just stop the connection, that will tear down any
+ // sends.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // sends without stopping the connection??
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelSend */
+
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source
+ NDIS_BUFFER 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.
+
+ 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.
+
+Environment:
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentSourceBuffer - Points to the start of the NDIS_BUFFER chain
+ from which to draw the packet.
+
+ CurrentByteOffset - Offset within this NDIS_BUFFER to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ DestinationBuffer - returned pointer to the NDIS_BUFFER chain describing
+ the packet.
+
+ NewSourceBuffer - returned pointer to the NDIS_BUFFER that would
+ be used for the next byte of packet. NULL if the source NDIS_BUFFER
+ chain was exhausted.
+
+ NewByteOffset - returned offset into the NewSourceBuffer for the next byte
+ of packet. NULL if the source NDIS_BUFFER chain was exhausted.
+
+ ActualLength - The actual length of the data copied.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded
+ and was the correct length.
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while
+ building the destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ ULONG CurrentByteCount;
+ ULONG BytesCopied;
+ PNDIS_BUFFER OldNdisBuffer;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+
+ OldNdisBuffer = CurrentSourceBuffer;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ AvailableBytes = CurrentByteCount - CurrentByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ BufferPoolHandle,
+ OldNdisBuffer,
+ CurrentByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *DestinationBuffer = NewNdisBuffer;
+ BytesCopied = AvailableBytes;
+
+ //
+ // Was the first NDIS_BUFFER enough data.
+ //
+
+ if (BytesCopied == DesiredLength) {
+ if (CurrentByteOffset + AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = CurrentSourceBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset + AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ if (CurrentSourceBuffer->Next == NULL) {
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ while (OldNdisBuffer != NULL) {
+
+ AvailableBytes = DesiredLength - BytesCopied;
+ if (AvailableBytes > CurrentByteCount) {
+ AvailableBytes = CurrentByteCount;
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ BufferPoolHandle,
+ OldNdisBuffer,
+ 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 (*DestinationBuffer != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*DestinationBuffer);
+ NdisFreeBuffer (*DestinationBuffer);
+ *DestinationBuffer = NewNdisBuffer;
+ }
+
+ *NewByteOffset = CurrentByteOffset;
+ *NewSourceBuffer = CurrentSourceBuffer;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ BytesCopied += AvailableBytes;
+
+ if (BytesCopied == DesiredLength) {
+ if (AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = OldNdisBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = OldNdisBuffer;
+ *NewByteOffset = AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ }
+
+ //
+ // We ran out of source buffer chain.
+ //
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+} /* NbiBuildBufferChainFromBufferChain */
+
diff --git a/private/ntos/tdi/isn/nb/session.c b/private/ntos/tdi/isn/nb/session.c
new file mode 100644
index 000000000..fe998feb2
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/session.c
@@ -0,0 +1,2450 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ session.c
+
+Abstract:
+
+ This module contains the code to handle session frames
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+NbiNoteNewConnection(
+ PCONNECTION pConnection
+ );
+#endif
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiSendDeathPacket(
+ IN PCONNECTION Connection,
+ IN CTELockHandle LockHandle
+ )
+{
+ PNDIS_PACKET Packet = PACKET(&NbiGlobalDeathPacket);
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ NDIS_STATUS NdisStatus;
+
+ if ( Reserved->SendInProgress ) {
+ DbgPrint("***Could not send death packet - in use\n");
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+ return;
+ }
+
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DEATH_PACKET;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+ Header->Session.ConnectionControlFlag = 0;
+ Header->Session.DataStreamType = NB_CMD_DEATH_PACKET;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+
+ DbgPrint("*****Death packet is being sent for connection %lx, to <%.16s>\n",Connection, Connection->RemoteName);
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ ULONG ReceiveFlags;
+ ULONG IndicateBytesTransferred;
+ ULONG DataAvailable, DataIndicated;
+ ULONG DestBytes, BytesToTransfer;
+ PUCHAR DataHeader;
+ BOOLEAN Last, CompleteReceive, EndOfMessage, PartialReceive, CopyLookahead;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ ULONG NdisBytesTransferred;
+ PIRP ReceiveIrp;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ ULONG BufferChainLength;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ( Connection->FirstMessageRequest && NbiGlobalDebugResTimeout ) {
+ LARGE_INTEGER CurrentTime, ElapsedTime;
+ KeQuerySystemTime(&CurrentTime);
+ ElapsedTime.QuadPart = CurrentTime.QuadPart - Connection->FirstMessageRequestTime.QuadPart;
+// DbgPrint("*****Elapsed %lx.%lx time\n",ElapsedTime.HighPart,ElapsedTime.LowPart);
+ if ( ElapsedTime.QuadPart > NbiGlobalMaxResTimeout.QuadPart ) {
+
+ DbgPrint("*****Connection %lx is not copleting irp %lx for %lx.%lx time\n",Connection, Connection->FirstMessageRequest,
+ ElapsedTime.HighPart,ElapsedTime.LowPart);
+ DbgPrint("************irp arrived at %lx.%lx current time %lx.%lx\n",
+ Connection->FirstMessageRequestTime.HighPart,Connection->FirstMessageRequestTime.LowPart,
+ CurrentTime.HighPart, CurrentTime.LowPart);
+
+ NbiSendDeathPacket( Connection, LockHandle );
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ }
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ //
+ // The connection is up, see if this is data should
+ // be received.
+ //
+
+ if (Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) {
+
+ //
+ // This is an ack. This call releases
+ // the lock. BUGBUG: Does this need to
+ // be a function?
+ //
+
+ NbiProcessDataAck(
+ Connection,
+ Sess,
+ RemoteAddress
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // See if there is any piggyback ack here.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. Even the old netbios sometimes piggyback
+ // acks (and doesn't send the explicit ack).
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if ((Connection->NewNetbios) &&
+ (Connection->CurrentSend.SendSequence != Connection->UnAckedSend.SendSequence)) {
+
+ //
+ // For the new netbios, even if we are not waiting
+ // for an ack he may have acked something with this
+ // send and we should check, since it may allow
+ // us to open our send window.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ }
+
+ //
+ // This is data on the connection. First make sure
+ // it is the data we expect next.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (Sess->SendSequence != Connection->ReceiveSequence) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp data on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving a packet we have already seen, just
+ // send a normal ack, otherwise force a resend. This test
+ // we do is equivalent to
+ // Sess->SendSequence < Connection->ReceiveSequence
+ // but rearranged so it works when the numbers wrap.
+ //
+
+ if ((SHORT)(Sess->SendSequence - Connection->ReceiveSequence) < 0) {
+
+ //
+ // Since this is a resend, check if the local
+ // target has changed.
+ //
+#if defined(_PNP_POWER)
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, sizeof(IPX_LOCAL_TARGET))) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx, (%d,%d)\n", Connection,
+ Connection->LocalTarget.NicHandle.NicId, RemoteAddress->NicHandle.NicId);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#else
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#endif _PNP_POWER
+ AckType = NbiAckResponse;
+
+ } else {
+
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // Old netbios.
+ //
+
+ if ((Sess->SendSequence != Connection->ReceiveSequence) ||
+ (Sess->Offset != Connection->CurrentReceive.MessageOffset)) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving the last packet again, just
+ // send a normal ack, otherwise force a resend.
+ //
+
+ if (((Sess->SendSequence == Connection->ReceiveSequence) &&
+ ((ULONG)(Sess->Offset + Sess->DataLength) == Connection->CurrentReceive.MessageOffset)) ||
+ (Sess->SendSequence == (USHORT)(Connection->ReceiveSequence-1))) {
+ AckType = NbiAckResponse;
+ } else {
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+
+ IndicateBytesTransferred = 0;
+ DataAvailable = PacketSize - sizeof(NB_CONNECTION);
+ DataIndicated = LookaheadBufferSize - sizeof(NB_CONNECTION);
+ DataHeader = LookaheadBuffer + sizeof(NB_CONNECTION);
+
+ ++Device->TempFramesReceived;
+ Device->TempFrameBytesReceived += DataAvailable;
+
+ if (Connection->CurrentIndicateOffset) {
+ CTEAssert (DataAvailable >= Connection->CurrentIndicateOffset);
+ DataAvailable -= Connection->CurrentIndicateOffset;
+ if (DataIndicated >= Connection->CurrentIndicateOffset) {
+ DataIndicated -= Connection->CurrentIndicateOffset;
+ } else {
+ DataIndicated = 0;
+ }
+ DataHeader += Connection->CurrentIndicateOffset;
+ }
+
+ CopyLookahead = (BOOLEAN)(MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA);
+
+ if (Connection->NewNetbios) {
+ Last = (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_EOM) != 0);
+ } else {
+ Last = (BOOLEAN)(Sess->Offset + Sess->DataLength == Sess->TotalDataLength);
+ }
+
+ Connection->CurrentReceiveNoPiggyback =
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) != 0);
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) {
+
+ //
+ // We don't have a receive posted, so see if we can
+ // get one from the queue or our client.
+ //
+
+ if (Connection->ReceiveQueue.Head != NULL) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Request = Connection->ReceiveQueue.Head;
+ Connection->ReceiveQueue.Head = REQUEST_SINGLE_LINKAGE(Request);
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NB_DEBUG2 (RECEIVE, ("Activated receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ if ((Connection->ReceiveUnaccepted == 0) &&
+ (Connection->AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE])) {
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_INDICATE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ Status = (*Connection->AddressFile->ReceiveHandler)(
+ Connection->AddressFile->HandlerContexts[TDI_EVENT_RECEIVE],
+ Connection->Context,
+ ReceiveFlags,
+ DataIndicated,
+ DataAvailable,
+ &IndicateBytesTransferred,
+ DataHeader,
+ &ReceiveIrp);
+
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // We got an IRP, activate it.
+ //
+
+ Request = NbiAllocateRequest (Device, ReceiveIrp);
+
+ IF_NOT_ALLOCATED(Request) {
+
+ ReceiveIrp->IoStatus.Information = 0;
+ ReceiveIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (ReceiveIrp, IO_NETWORK_INCREMENT);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ CTEAssert (REQUEST_OPEN_CONTEXT(Request) == Connection);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ Connection->ReceiveUnaccepted = DataAvailable - IndicateBytesTransferred;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ NB_DEBUG2 (RECEIVE, ("Indicate got receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ //
+ // The connection has been stopped.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // He accepted some or all of the data.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Indicate took receive data %lx (%d)\n", Connection, Connection->ReceiveSequence));
+
+ if ( (IndicateBytesTransferred >= DataAvailable)) {
+
+ CTEAssert (IndicateBytesTransferred == DataAvailable);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentIndicateOffset = 0;
+ if ( Last ) {
+ Connection->CurrentReceive.MessageOffset = 0;
+ } else {
+ Connection->CurrentReceive.MessageOffset+= IndicateBytesTransferred;
+ }
+
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We will do the easiest thing here, which
+ // is to send an ack for the amount he
+ // took, and force a retransmit on the
+ // remote. For net netbios we make a note
+ // of how many bytes were taken and ask
+ // for a resend.
+ //
+ // BUGBUG: Handle this better??
+ //
+
+#if DBG
+ DbgPrint ("NBI: Client took partial indicate data\n");
+#endif
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive.MessageOffset +=
+ IndicateBytesTransferred;
+ Connection->ReceiveUnaccepted =
+ DataAvailable - IndicateBytesTransferred;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+ Connection->CurrentIndicateOffset = IndicateBytesTransferred;
+ //
+ // NOTE: We don't advance ReceiveSequence
+ //
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ Connection->NewNetbios ?
+ NbiAckResend : NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ } else {
+
+ //
+ // No IRP returned.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveUnaccepted = DataAvailable;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_DEBUG (RECEIVE, ("Indicate got no receive on %lx (%lx)\n", Connection, Status));
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // No receive handler.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ if (Connection->ReceiveUnaccepted == 0) {
+ NB_DEBUG (RECEIVE, ("No receive, no handler on %lx\n", Connection));
+ } else {
+ NB_DEBUG (RECEIVE, ("No receive, ReceiveUnaccepted %d on %lx\n",
+ Connection->ReceiveUnaccepted, Connection));
+ }
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+ } else if (Connection->ReceiveState != CONNECTION_RECEIVE_ACTIVE) {
+
+ //
+ // If we have a transfer in progress, or are waiting for
+ // a receive to be posted, then ignore this frame.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Got data on %lx, state %d (%d)\n", Connection, Connection->ReceiveState, Connection->ReceiveSequence));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ //
+ // At this point we have a receive and it is set to
+ // the correct current location.
+ //
+
+ DestBytes = Connection->ReceiveLength - Connection->CurrentReceive.Offset;
+ BytesToTransfer = DataAvailable - IndicateBytesTransferred;
+
+ if (DestBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceive = TRUE;
+ PartialReceive = TRUE;
+ BytesToTransfer = DestBytes;
+
+ } else if (DestBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = TRUE;
+ PartialReceive = FALSE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = Last;
+ PartialReceive = FALSE;
+
+ }
+
+ //
+ // If we can copy the data directly, then update our
+ // pointers, send an ack, and do the copy.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (IndicateBytesTransferred + BytesToTransfer <= DataIndicated)) {
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PNDIS_BUFFER CurBuffer;
+ ULONG CurByteOffset;
+
+ NB_DEBUG2 (RECEIVE, ("Direct copy of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ CurBuffer = Connection->CurrentReceive.Buffer;
+ CurByteOffset = Connection->CurrentReceive.BufferOffset;
+
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurTarget += CurByteOffset;
+ CurTargetLen -= CurByteOffset;
+
+ CurSource = DataHeader + IndicateBytesTransferred;
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurBuffer = CurBuffer->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ CTEAssert (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->CurrentReceive.Buffer = CurBuffer;
+ Connection->CurrentReceive.BufferOffset = CurByteOffset;
+
+ Connection->CurrentReceive.Offset += BytesToTransfer;
+ Connection->CurrentReceive.MessageOffset += BytesToTransfer;
+
+ if (CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (EndOfMessage) {
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesToTransfer;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ // and CANCEL Lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ //
+ // CompleteReceive is FALSE, so EndOfMessage is FALSE.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+
+ //
+ // We have to set up a call to transfer data and send
+ // the ack after it completes (if it succeeds).
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ DataAvailable);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->u.RR_CO.Connection = Connection;
+ ReceiveReserved->u.RR_CO.EndOfMessage = EndOfMessage;
+ ReceiveReserved->u.RR_CO.CompleteReceive = CompleteReceive;
+ ReceiveReserved->u.RR_CO.PartialReceive = PartialReceive;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATA;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("TransferData of 0 bytes %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiTransferDataComplete(
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return;
+ }
+
+ //
+ // If needed, build a buffer chain to describe this
+ // to NDIS.
+ //
+
+ Connection->PreviousReceive = Connection->CurrentReceive;
+
+ if ((Connection->CurrentReceive.Offset == 0) &&
+ CompleteReceive) {
+
+ BufferChain = Connection->CurrentReceive.Buffer;
+ BufferChainLength = BytesToTransfer;
+ Connection->CurrentReceive.Buffer = NULL;
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+
+ } else {
+
+ if (NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentReceive.Buffer,
+ Connection->CurrentReceive.BufferOffset,
+ BytesToTransfer,
+ &BufferChain,
+ &Connection->CurrentReceive.Buffer,
+ &Connection->CurrentReceive.BufferOffset,
+ &BufferChainLength) != NDIS_STATUS_SUCCESS) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("Could not build receive buffer chain %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = FALSE;
+
+ }
+
+
+ NdisChainBufferAtFront (Packet, BufferChain);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("TransferData of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + sizeof(NB_CONNECTION) +
+ Connection->CurrentIndicateOffset + IndicateBytesTransferred,
+ BytesToTransfer,
+ Packet,
+ (PUINT)&NdisBytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (NdisBytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete (
+ Packet,
+ NdisStatus,
+ NdisBytesTransferred);
+
+ }
+
+ return;
+
+ }
+
+ } else if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ //
+ // If this is the ack for the session initialize, then
+ // complete the pending connects. This routine releases
+ // the connection lock.
+ //
+
+ NbiProcessSessionInitAck(
+ Connection,
+ Sess
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ //
+ // This is a session initialize frame.
+ //
+ // BUGBUG: If there is more data than in the lookahead
+ // buffer, we won't be able to echo it back in the
+ // response.
+ //
+
+ NbiProcessSessionInitialize(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+
+ }
+
+} /* NbiProcessSessionData */
+
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an ack on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The session frame.
+
+ RemoteAddress - The local target this packet was received from.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ BOOLEAN Resend;
+
+ //
+ // Make sure we expect an ack right now.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (((Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W)) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We are waiting for an ack (because we completed
+ // packetizing a send, or ran out of receive window).
+ //
+ // This will complete any sends that are acked by
+ // this receive, and if necessary readjust the
+ // send pointer and requeue the connection for
+ // packetizing. It release the connection lock.
+ //
+
+ if (Connection->ResponseTimeout) {
+ Resend = TRUE;
+ Connection->ResponseTimeout = FALSE;
+ } else {
+ Resend = (BOOLEAN)
+ ((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0);
+ }
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ Resend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We had a probe outstanding and got a response. Restart
+ // the connection if needed (a send may have just been
+ // posted while the probe was outstanding).
+ //
+ // BUGBUG: We should check that the response is really
+ // correct.
+ //
+
+ if (Connection->NewNetbios) {
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ }
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ if (Connection->NewNetbios) {
+
+ //
+ // We are packetizing, reframe. In the unlikely
+ // event that this acks everything we may packetize
+ // in this call, but that is OK (the other thread
+ // will exit if we finish up). More normally we
+ // will just advance UnAcked send a bit.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0)
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+#if 0
+
+ //
+ // BUGBUG: Should handle this case (i.e. may be in W_PACKET).
+ //
+
+ } else if ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0) {
+
+ DbgPrint ("NWLNKNB: Ignoring ack, state is %d\n", Connection->SubState);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+#endif
+
+ } else {
+
+ //
+ // We got a probe from the remote. Some old DOS clients
+ // send probes that do not have the send ack bit on,
+ // so we respond to any probe if none of the conditions
+ // above are true. This call releases the lock.
+ //
+ // We use the IgnoreNextDosProbe flag to ignore every
+ // second probe of this nature, to avoid a data ack
+ // war between two machines who each think they are
+ // responding to the other. This flag is set to FALSE
+ // whenever we send an ack or a probe.
+ //
+
+ if (!Connection->IgnoreNextDosProbe) {
+
+ //
+ // Since this is a probe, check if the local
+ // target has changed.
+ //
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+ Connection->IgnoreNextDosProbe = TRUE;
+
+ } else {
+
+ Connection->IgnoreNextDosProbe = FALSE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+} /* NbiProcessDataAck */
+
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION frames which have
+ a remote connection ID of 0xffff -- these are session
+ initialize frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ PacketBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ CONNECT_INDICATION TempConnInd;
+ PCONNECT_INDICATION ConnInd;
+ PCONNECTION Connection;
+ PADDRESS Address;
+ PREQUEST Request, ListenRequest, AcceptRequest;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ ULONG Hash;
+ TA_NETBIOS_ADDRESS SourceName;
+ PIRP AcceptIrp;
+ CONNECTION_CONTEXT ConnectionContext;
+ NTSTATUS AcceptStatus;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_REQUEST_KERNEL_LISTEN ListenParameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+ //
+ // Verify that the whole packet is there.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT))) {
+#if DBG
+ DbgPrint ("NBI: Got short session initialize, %d/%d\n", PacketSize,
+ sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+#endif
+ return;
+ }
+
+ //
+ // Verify that MaximumDataSize that remote can support is > 0
+ // Bug # 19405
+ //
+ if ( SessInit->MaximumDataSize == 0 ) {
+ NB_DEBUG(CONNECTION, ("Connect request with MaximumDataSize == 0\n"
+));
+ return;
+ }
+
+ //
+ // Make sure this is for an address we care about.
+ //
+
+ if (Device->AddressCounts[SessInit->DestinationName[0]] == 0) {
+ return;
+ }
+
+ Address = NbiFindAddress (Device, (PUCHAR)SessInit->DestinationName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // First see if we have a session to this remote. We check
+ // this in case our ack of the session initialize was dropped,
+ // we don't want to reindicate our client.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ for (Hash = 0; Hash < CONNECTION_HASH_COUNT; Hash++) {
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if ((RtlEqualMemory (&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (Connection->RemoteConnectionId == Sess->SourceConnectionId) &&
+ (Connection->State != CONNECTION_STATE_DISCONNECT)) {
+
+ //
+ // Yes, we are talking to this remote, if it is active then
+ // respond, otherwise we are in the process of connecting
+ // and we will respond eventually.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Got connect request on active connection %lx\n", Connection);
+#endif
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ NbiSendSessionInitAck(
+ Connection,
+ (PUCHAR)(SessInit+1),
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT)),
+ NULL); // lock is not held
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ Connection = Connection->NextConnection;
+ }
+ }
+
+
+ TdiBuildNetbiosAddress ((PUCHAR)SessInit->SourceName, FALSE, &SourceName);
+
+ //
+ // Scan the queue of listens to see if there is one that
+ // satisfies this request.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ListenQueue.Flink;
+ p != &Device->ListenQueue;
+ p = p->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->AddressFile->Address != Address) {
+ continue;
+ }
+
+ //
+ // Check that this listen is not specific to a different
+ // netbios name.
+ //
+
+ ListenParameters = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(Request);
+ ListenInformation = ListenParameters->RequestConnectionInformation;
+
+ if (ListenInformation &&
+ (ListenInformation->RemoteAddress) &&
+ (ListenAddress = NbiParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ SessInit->SourceName,
+ ListenAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+
+ //
+ // This connection is valid, so we use it.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen %lx\n", Connection));
+
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ //
+ // Save this information now for whenever we complete the listen.
+ //
+
+ RemoteInformation = ListenParameters->ReturnConnectionInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ if (ListenParameters->RequestFlags & TDI_QUERY_ACCEPT) {
+
+ //
+ // We have to wait for an accept before sending the
+ // session init ack, so we complete the listen and wait.
+ //
+
+ ListenRequest = Request;
+ Connection->ListenRequest = NULL;
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen on %lx awaiting accept\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ACCEPT;
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_W_ACCEPT);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ } else {
+
+ //
+ // We are ready to go, so we send out the find route request
+ // for the remote. We keep the listen alive and the CREF_LISTEN
+ // reference on until this completes.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen on %lx\n", Connection));
+
+ ListenRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ }
+
+ //
+ // Complete the listen if needed.
+ //
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION (ListenRequest) = 0;
+ REQUEST_STATUS (ListenRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK ( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest (Device, ListenRequest);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ return;
+
+ }
+
+ //
+ // We could not find a listen, so we indicate to every
+ // client. Make sure there is no session initialize for this
+ // remote being indicated. If there is not, we insert
+ // ourselves in the queue to block others.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ConnectIndicationInProgress.Flink;
+ p != &Device->ConnectIndicationInProgress;
+ p = p->Flink) {
+
+ ConnInd = CONTAINING_RECORD (p, CONNECT_INDICATION, Linkage);
+
+ if ((RtlEqualMemory(ConnInd->NetbiosName, SessInit->DestinationName, 16)) &&
+ (RtlEqualMemory(&ConnInd->RemoteAddress, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (ConnInd->ConnectionId == Sess->SourceConnectionId)) {
+
+ //
+ // We are processing a request from this remote for
+ // the same ID, to avoid confusion we just exit.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Already processing connect to <%.16s>\n", SessInit->DestinationName);
+#endif
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ }
+
+ RtlCopyMemory (&TempConnInd.RemoteAddress, SessInit->DestinationName, 16);
+ RtlCopyMemory (&TempConnInd.RemoteAddress, Conn->IpxHeader.SourceNetwork, 12);
+ TempConnInd.ConnectionId = Sess->SourceConnectionId;
+
+ InsertTailList (&Device->ConnectIndicationInProgress, &TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+
+ //
+ // Now scan through the address to find someone who has
+ // an indication routine registed and wants this connection.
+ //
+
+
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No posted listen requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_CONNECT]) {
+
+ if ((*AddressFile->ConnectionHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_CONNECT],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0, // user data
+ NULL,
+ 0, // options
+ NULL,
+ &ConnectionContext,
+ &AcceptIrp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+ continue;
+
+ }
+
+ AcceptRequest = NbiAllocateRequest (Device, AcceptIrp);
+
+ IF_NOT_ALLOCATED(AcceptRequest) {
+
+ AcceptStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ //
+ // The client accepted the connect, so activate
+ // the connection and complete the accept.
+ // listen. This lookup references the connection
+ // so we know it will remain valid.
+ //
+
+ Connection = NbiLookupConnectionByContext (
+ AddressFile,
+ ConnectionContext);
+
+ if (Connection != NULL) {
+
+ ASSERT (Connection->AddressFile == AddressFile);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle2);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ NB_DEBUG2 (CONNECTION, ("Indication on %lx returned connection %lx\n", AddressFile, Connection));
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ Connection->Retries = Device->KeepAliveCount;
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_ACCEPT);
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ Connection->AcceptRequest = AcceptRequest;
+ AcceptStatus = STATUS_PENDING;
+
+ //
+ // Take us out of this list now, we will jump to
+ // FoundConnection which is past the removal below.
+ //
+
+ RemoveEntryList (&TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned invalid connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_BY_CONTEXT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned unknown connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+
+ }
+ }
+
+ //
+ // Complete the accept request in the failure case.
+ //
+
+ if (AcceptStatus != STATUS_PENDING) {
+
+ REQUEST_STATUS (AcceptRequest) = AcceptStatus;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest (Device, AcceptRequest);
+
+ } else {
+
+ //
+ // We found a connection, so we break; this is
+ // a jump since the while exit assumes the
+ // address lock is held.
+ //
+
+ goto FoundConnection;
+
+ }
+
+ }
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Take us out of the list that blocks other indications
+ // from this remote to this address.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+ RemoveEntryList (&TempConnInd.Linkage);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+FoundConnection:
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+} /* NbiProcessSessionInitialize */
+
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles session init ack frames.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The netbios header for the received frame.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ BOOLEAN TimerWasStopped = FALSE;
+ CTELockHandle CancelLH;
+
+ if ((Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) &&
+ (Sess->SendSequence == 0x0000) &&
+ (Sess->ReceiveSequence == 0x0001)) {
+
+ NB_DEBUG2 (CONNECTION, ("Completing connect on %lx\n", Connection));
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ if (Connection->Retries == NbiDevice->ConnectionCount) {
+ ++NbiDevice->Statistics.ConnectionsAfterNoRetry;
+ } else {
+ ++NbiDevice->Statistics.ConnectionsAfterRetry;
+ }
+ ++NbiDevice->Statistics.OpenConnections;
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ NbiStartWatchdog (Connection);
+
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 1;
+ Connection->UnAckedSend.SendSequence = 1;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 0;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ if (NbiDevice->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveWindowSize - 1);
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 3;
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ if (Connection->MaximumPacketSize > SessInit->MaximumDataSize) {
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+ }
+
+ Request = Connection->ConnectRequest;
+
+#ifdef RASAUTODIAL
+ //
+ // Check to see if we have to notify
+ // the automatic connection driver about
+ // this connection.
+ //
+ if (fAcdLoadedG) {
+ BOOLEAN fEnabled;
+ CTELockHandle AcdHandle;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &AcdHandle);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, AcdHandle);
+ if (fEnabled)
+ NbiNoteNewConnection(Connection);
+ }
+#endif // RASAUTODIAL
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_SUCCESS;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiTransferReferenceConnection (Connection, CREF_CONNECT, CREF_ACTIVE);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessSessionInitAck */
+
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+
+ //
+ // We reply to any session end, even if we don't know the
+ // connection, to speed up the disconnect on the remote.
+ //
+
+ if (Connection == NULL) {
+
+ NB_DEBUG (CONNECTION, ("Session end received on unknown id %lx\n", Sess->DestConnectionId));
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. We do this in case a full send has been
+ // received by the remote but he did not send an
+ // ack before the session went down -- this will
+ // prevent us from failing a send which actually
+ // succeeded. If we are not in W_ACK this may ack
+ // part of a send, but in that case we don't care
+ // since StopConnection will abort it anyway and
+ // the amount successfully received by the remote
+ // doesn't matter.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Session end at W_ACK, reframing %lx (%d)\n", Connection, Sess->ReceiveSequence));
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle1));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on connection %lx\n", Connection));
+
+ }
+
+ //
+ // This call sets the state to DISCONNECT and
+ // releases the connection lock. It will also
+ // complete a disconnect wait request if one
+ // is pending, and indicate to our client
+ // if needed.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_REMOTE_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on inactive connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEnd */
+
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END_ACK frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // Stop the timer, when the reference goes away it
+ // will shut down. We set the substate so if the
+ // timer is running it will not restart (BUGBUG:
+ // there is a small window here, but it is not
+ // harmful, we will just have to timeout one
+ // more time).
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Got session end ack on %lx\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_D_GOT_ACK;
+ if (CTEStopTimer (&Connection->Timer)) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEndAck */
+
diff --git a/private/ntos/tdi/isn/nb/sources.inc b/private/ntos/tdi/isn/nb/sources.inc
new file mode 100644
index 000000000..f54b4918b
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/sources.inc
@@ -0,0 +1,69 @@
+!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=nwlnknb
+
+TARGETNAME=nwlnknb
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\inc;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1 -DRASAUTODIAL
+#-DRSRC_TIMEOUT_DBG
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\address.c \
+ ..\autodial.c \
+ ..\bind.c \
+ ..\cache.c \
+ ..\config.c \
+ ..\connect.c \
+ ..\datagram.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\frame.c \
+ ..\nwlnknb.rc \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\send.c \
+ ..\session.c \
+ ..\timer.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isn/nb/timer.c b/private/ntos/tdi/isn/nb/timer.c
new file mode 100644
index 000000000..381b120e5
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/timer.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code which implements the timers for
+ netbios.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+ULONG NbiTickIncrement = 0;
+ULONG NbiShortTimerDeltaTicks = 0;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiInitializeTimers)
+#endif
+
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the retransmit timer for the given connection.
+ The connection is inserted on the short list if it isn't on already.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Connection->Retransmit =
+ Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
+
+ if (!Connection->OnShortList) {
+
+ CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnShortList) {
+ Connection->OnShortList = TRUE;
+ InsertTailList (&Device->ShortList, &Connection->ShortList);
+ }
+
+ if (!Device->ShortListActive) {
+ NbiStartShortTimer (Device);
+ Device->ShortListActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartRetransmit */
+
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the watchdog timer for a connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
+
+ if (!Connection->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnLongList) {
+ Connection->OnLongList = TRUE;
+ InsertTailList (&Device->LongList, &Connection->LongList);
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartWatchdog */
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the retransmit timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Retransmit = 0;
+
+} /* NbiStopRetransmit */
+
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the watchdog timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Watchdog = 0;
+
+} /* NbiStopWatchdog */
+#endif
+
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's retransmit timer
+ expires. It is called from NbiShortTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ BOOLEAN SendFindRoute;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ SendFindRoute = FALSE;
+
+ ++Device->Statistics.ResponseTimerExpirations;
+
+ if (!(Connection->NewNetbios) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // Set our current packetize location back to the
+ // spot of the last ack, and start up again.
+ //
+ // BUGBUG: Should we send a probe here?
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ }
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // Set this so we know to retransmit when the ack
+ // is received.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) {
+ Connection->ResponseTimeout = TRUE;
+ }
+
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ if (SendFindRoute) {
+
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireRetansmit */
+
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's watchdog timer
+ expires. It is called from NbiLongTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // If we are not idle, then something else is happening
+ // so the watchdog is unnecessary.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE;
+ NbiStartRetransmit (Connection);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireWatchdog */
+
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the short connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE Device = (PDEVICE)Context;
+ PCONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ Device->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ Device->ShortTimerStart.QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ Device->ShortAbsoluteTime += TickDelta;
+
+ if (Device->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->ShortAbsoluteTime -= 0xe0000000;
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ Timeout = Connection->Retransmit;
+ if (Timeout) {
+ Connection->Retransmit = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ ASSERT (Connection->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Retransmit &&
+ (Device->ShortAbsoluteTime > Connection->Retransmit)) {
+
+ Connection->Retransmit = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireRetransmit (Connection); // no locks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Retransmit == 0) {
+
+ Connection->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Connection->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if (Connection->Retransmit != 0) {
+ InsertTailList(&Device->ShortList, &Connection->ShortList);
+ Connection->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&Device->ShortList)) {
+ Device->ShortListActive = FALSE;
+ }
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for enough times through here,
+ // If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (!Connection->DataAckPending) {
+ continue;
+ }
+
+ ++Connection->DataAckTimeouts;
+
+ if (Connection->DataAckTimeouts < Device->AckDelayTime) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
+
+ Device->DataAckQueueChanged = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->DataAckPending) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ // We set PiggybackAckTimeout to TRUE so that we won't try
+ // to piggyback a response until we get back traffic.
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = TRUE;
+ ++Device->Statistics.AckTimerExpirations;
+ ++Device->Statistics.PiggybackAckTimeouts;
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (Device->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&Device->DataAckConnections)) {
+ Device->DataAckActive = FALSE;
+ }
+
+
+ //
+ // Update the real counters from the temp ones. We have
+ // TimerLock here, which is good enough.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesSent,
+ Device->TempFrameBytesSent);
+ Device->Statistics.DataFramesSent += Device->TempFramesSent;
+
+ Device->TempFrameBytesSent = 0;
+ Device->TempFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesReceived,
+ Device->TempFrameBytesReceived);
+ Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
+
+ Device->TempFrameBytesReceived = 0;
+ Device->TempFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ Device->ProcessingShortTimer = FALSE;
+
+ if ((Device->ShortListActive || Device->DataAckActive) &&
+ (Device->State != DEVICE_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
+
+ }
+
+} /* NbiShortTimeout */
+
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the long connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, nextp;
+ LIST_ENTRY AdapterStatusList;
+ PREQUEST AdapterStatusRequest;
+ PCONNECTION Connection;
+ PNETBIOS_CACHE CacheName;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (++Device->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->LongAbsoluteTime = 0x10000000;
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ Timeout = Connection->Watchdog;
+ if (Timeout) {
+ Connection->Watchdog = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+
+ if ((Device->LongAbsoluteTime % 4) == 0) {
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ ASSERT (Connection->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
+
+ Connection->Watchdog = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireWatchdog (Connection); // no spinlocks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Watchdog == 0) {
+
+ Connection->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Connection->Watchdog != 0) {
+ InsertTailList(&Device->LongList, &Connection->LongList);
+ Connection->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped, and it also might just have
+ // had a data ack queued.
+ //
+
+ if (Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ Device->DataAckQueueChanged = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbiReceiveComplete((USHORT)0);
+
+
+ //
+ // Check if any adapter status queries are getting old.
+ //
+
+ InitializeListHead (&AdapterStatusList);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
+
+ //
+ // BUGBUG: We should resend a certain number of times.
+ //
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // We are going to abort this request, so dereference
+ // the cache entry it used.
+ //
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ } else {
+
+ ++REQUEST_INFORMATION(AdapterStatusRequest);
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ //
+ // See if a minute has passed and we need to check for empty
+ // cache entries to age out. We check for 64 seconds to make
+ // the mod operation faster.
+ //
+
+#if defined(_PNP_POWER)
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+#endif _PNP_POWER
+
+ ++Device->CacheTimeStamp;
+
+ if ((Device->CacheTimeStamp % 64) == 0) {
+
+
+ //
+ // flush all the entries which have been around for ten minutes
+ // (LONG_TIMER_DELTA is in milliseconds).
+ //
+
+ FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
+
+ }
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (Device->State != DEVICE_STATE_STOPPING) {
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ } else {
+#if defined(_PNP_POWER)
+ Device->LongTimerRunning = FALSE;
+#endif _PNP_POWER
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+#if defined(_PNP_POWER)
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+} /* NbiLongTimeout */
+
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ Device - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+
+ if ((!Device->ProcessingShortTimer) &&
+ (!(Device->ShortListActive)) &&
+ (!(Device->DataAckActive))) {
+
+ NbiReferenceDevice (Device, DREF_SHORT_TIMER);
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ }
+
+} /* NbiStartShortTimer */
+
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ Device - Pointer to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // NbiTickIncrement is the number of NT time increments
+ // which pass between each tick. NbiShortTimerDeltaTicks
+ // is the number of ticks which should happen in
+ // SHORT_TIMER_DELTA milliseconds (i.e. between each
+ // expiration of the short timer).
+ //
+
+ NbiTickIncrement = KeQueryTimeIncrement();
+
+ if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) {
+ NbiShortTimerDeltaTicks = 1;
+ } else {
+ NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement;
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ Device->ShortAbsoluteTime = 0x10000000;
+ Device->LongAbsoluteTime = 0x10000000;
+
+ CTEInitTimer (&Device->ShortTimer);
+ CTEInitTimer (&Device->LongTimer);
+
+#if !defined(_PNP_POWER)
+ //
+ // One reference for the long timer.
+ //
+
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+#endif !_PNP_POWER
+
+ Device->TimersInitialized = TRUE;
+ Device->ShortListActive = FALSE;
+ Device->ProcessingShortTimer = FALSE;
+
+ InitializeListHead (&Device->ShortList);
+ InitializeListHead (&Device->LongList);
+
+ CTEInitLock (&Device->TimerLock.Lock);
+
+} /* NbiInitializeTimers */
+
diff --git a/private/ntos/tdi/isn/nb/up/makefile b/private/ntos/tdi/isn/nb/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/up/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/isn/nb/up/sources b/private/ntos/tdi/isn/nb/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/nb/up/sources
@@ -0,0 +1,29 @@
+!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
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc