summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isn/spx
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isn/spx')
-rw-r--r--private/ntos/tdi/isn/spx/dirs22
-rw-r--r--private/ntos/tdi/isn/spx/globals.c87
-rw-r--r--private/ntos/tdi/isn/spx/h/fwddecls.h28
-rw-r--r--private/ntos/tdi/isn/spx/h/globals.h67
-rw-r--r--private/ntos/tdi/isn/spx/h/isnspx.h363
-rw-r--r--private/ntos/tdi/isn/spx/h/spxaddr.h426
-rw-r--r--private/ntos/tdi/isn/spx/h/spxbind.h32
-rw-r--r--private/ntos/tdi/isn/spx/h/spxconn.h1666
-rw-r--r--private/ntos/tdi/isn/spx/h/spxdev.h204
-rw-r--r--private/ntos/tdi/isn/spx/h/spxerror.h246
-rw-r--r--private/ntos/tdi/isn/spx/h/spxmem.h142
-rw-r--r--private/ntos/tdi/isn/spx/h/spxntdef.h72
-rw-r--r--private/ntos/tdi/isn/spx/h/spxpkt.h466
-rw-r--r--private/ntos/tdi/isn/spx/h/spxquery.h54
-rw-r--r--private/ntos/tdi/isn/spx/h/spxrecv.h91
-rw-r--r--private/ntos/tdi/isn/spx/h/spxreg.h65
-rw-r--r--private/ntos/tdi/isn/spx/h/spxsend.h34
-rw-r--r--private/ntos/tdi/isn/spx/h/spxtimer.h101
-rw-r--r--private/ntos/tdi/isn/spx/h/spxutils.h178
-rw-r--r--private/ntos/tdi/isn/spx/mp/makefile6
-rw-r--r--private/ntos/tdi/isn/spx/mp/sources29
-rw-r--r--private/ntos/tdi/isn/spx/nwlnkspx.rc12
-rw-r--r--private/ntos/tdi/isn/spx/precomp.h1
-rw-r--r--private/ntos/tdi/isn/spx/sources.inc65
-rw-r--r--private/ntos/tdi/isn/spx/spxaddr.c1729
-rw-r--r--private/ntos/tdi/isn/spx/spxbind.c602
-rw-r--r--private/ntos/tdi/isn/spx/spxconn.c3851
-rw-r--r--private/ntos/tdi/isn/spx/spxcpkt.c4131
-rw-r--r--private/ntos/tdi/isn/spx/spxcutil.c1736
-rw-r--r--private/ntos/tdi/isn/spx/spxdev.c242
-rw-r--r--private/ntos/tdi/isn/spx/spxdrvr.c1008
-rw-r--r--private/ntos/tdi/isn/spx/spxerror.c316
-rw-r--r--private/ntos/tdi/isn/spx/spxmem.c897
-rw-r--r--private/ntos/tdi/isn/spx/spxpkt.c1594
-rw-r--r--private/ntos/tdi/isn/spx/spxquery.c259
-rw-r--r--private/ntos/tdi/isn/spx/spxrecv.c2839
-rw-r--r--private/ntos/tdi/isn/spx/spxreg.c400
-rw-r--r--private/ntos/tdi/isn/spx/spxsend.c262
-rw-r--r--private/ntos/tdi/isn/spx/spxtimer.c637
-rw-r--r--private/ntos/tdi/isn/spx/spxutils.c484
-rw-r--r--private/ntos/tdi/isn/spx/up/makefile6
-rw-r--r--private/ntos/tdi/isn/spx/up/sources29
42 files changed, 25479 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/spx/dirs b/private/ntos/tdi/isn/spx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/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/spx/globals.c b/private/ntos/tdi/isn/spx/globals.c
new file mode 100644
index 000000000..51fc80803
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/globals.c
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Global values
+PDEVICE SpxDevice = NULL;
+UNICODE_STRING IpxDeviceName = {0};
+HANDLE IpxHandle = NULL;
+
+LARGE_INTEGER Magic100000 = {
+ 0x1b478424,
+ 0xa7c5ac47
+ };
+// Line info
+IPX_LINE_INFO IpxLineInfo = {0};
+USHORT IpxMacHdrNeeded = 0;
+USHORT IpxInclHdrOffset= 0;
+
+// Entry Points into the IPX stack
+IPX_INTERNAL_SEND IpxSendPacket = NULL;
+IPX_INTERNAL_FIND_ROUTE IpxFindRoute = NULL;
+IPX_INTERNAL_QUERY IpxQuery = NULL;
+IPX_INTERNAL_TRANSFER_DATA IpxTransferData = NULL;
+
+#if DBG
+ULONG SpxDebugDump = 0;
+LONG SpxDumpInterval = DBG_DUMP_DEF_INTERVAL;
+ULONG SpxDebugLevel = DBG_LEVEL_ERR;
+ULONG SpxDebugSystems = DBG_COMP_MOST;
+#endif
+
+// Unload event triggered when ref count on device goes to zero.
+KEVENT SpxUnloadEvent = {0};
+
+// Maximum packet size quanta used during packet size negotiation
+ULONG SpxMaxPktSize[] = {
+ 576 - MIN_IPXSPX2_HDRSIZE,
+ 1024 - MIN_IPXSPX2_HDRSIZE,
+ 1474 - MIN_IPXSPX2_HDRSIZE,
+ 1492 - MIN_IPXSPX2_HDRSIZE,
+ 1500 - MIN_IPXSPX2_HDRSIZE,
+ 1954 - MIN_IPXSPX2_HDRSIZE,
+ 4002 - MIN_IPXSPX2_HDRSIZE,
+ 8192 - MIN_IPXSPX2_HDRSIZE,
+ 17314 - MIN_IPXSPX2_HDRSIZE,
+ 65535 - MIN_IPXSPX2_HDRSIZE
+ };
+
+ULONG SpxMaxPktSizeIndex = sizeof(SpxMaxPktSize)/sizeof(ULONG);
+
+
+// Global interlock
+CTELock SpxGlobalInterlock = {0};
+
+// Another one, used only for global queues for addr/conn
+CTELock SpxGlobalQInterlock = {0};
+PSPX_CONN_FILE SpxGlobalConnList = NULL;
+PSPX_ADDR_FILE SpxGlobalAddrList = NULL;
+
+SPX_CONNFILE_LIST SpxPktConnList = {NULL, NULL};
+SPX_CONNFILE_LIST SpxRecvConnList = {NULL, NULL};
+
+// Timer globals
+LONG SpxTimerCurrentTime = 0;
diff --git a/private/ntos/tdi/isn/spx/h/fwddecls.h b/private/ntos/tdi/isn/spx/h/fwddecls.h
new file mode 100644
index 000000000..feda4e76b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/fwddecls.h
@@ -0,0 +1,28 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ fwddecls.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+struct _SPX_ADDR ;
+struct _SPX_ADDR_FILE ;
+struct _SPX_CONN_FILE ;
+struct _SPX_SEND_RESD ;
diff --git a/private/ntos/tdi/isn/spx/h/globals.h b/private/ntos/tdi/isn/spx/h/globals.h
new file mode 100644
index 000000000..e4fcf39a8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/globals.h
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ globals.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+extern PDEVICE SpxDevice;
+extern UNICODE_STRING IpxDeviceName;
+extern HANDLE IpxHandle;
+
+extern LARGE_INTEGER Magic100000;
+
+#if 1 // DBG
+extern ULONG SpxDebugDump;
+extern LONG SpxDumpInterval;
+extern ULONG SpxDebugLevel;
+extern ULONG SpxDebugSystems;
+
+#endif
+
+// More IPX info.
+extern IPX_LINE_INFO IpxLineInfo;
+extern USHORT IpxMacHdrNeeded;
+extern USHORT IpxInclHdrOffset;
+
+// Entry Points into the IPX stack
+extern IPX_INTERNAL_SEND IpxSendPacket;
+extern IPX_INTERNAL_FIND_ROUTE IpxFindRoute;
+extern IPX_INTERNAL_QUERY IpxQuery;
+extern IPX_INTERNAL_TRANSFER_DATA IpxTransferData;
+
+// Unload event
+extern KEVENT SpxUnloadEvent;
+
+extern ULONG SpxMaxPktSize[];
+extern ULONG SpxMaxPktSizeIndex;
+
+extern CTELock SpxGlobalInterlock;
+
+
+extern CTELock SpxGlobalQInterlock;
+extern PSPX_CONN_FILE SpxGlobalConnList;
+extern PSPX_ADDR_FILE SpxGlobalAddrList;
+
+extern SPX_CONNFILE_LIST SpxPktConnList;
+extern SPX_CONNFILE_LIST SpxRecvConnList;
+
+extern LONG SpxTimerCurrentTime;
diff --git a/private/ntos/tdi/isn/spx/h/isnspx.h b/private/ntos/tdi/isn/spx/h/isnspx.h
new file mode 100644
index 000000000..6080b0423
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/isnspx.h
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnspx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#ifndef CTE_TYPEDEFS_DEFINED
+#include <cxport.h>
+#endif
+#include <bind.h>
+
+#include "wsnwlink.h"
+
+#define SPX_DEVICE_SIGNATURE (USHORT)(*(PUSHORT)"SD")
+#define SPX_ADDRESS_SIGNATURE (USHORT)(*(PUSHORT)"AD")
+#define SPX_ADDRESSFILE_SIGNATURE (USHORT)(*(PUSHORT)"AF")
+#define SPX_CONNFILE_SIGNATURE (USHORT)(*(PUSHORT)"CF")
+
+#define SPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+#define SPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+typedef UCHAR BYTE, *PBYTE;
+typedef ULONG DWORD, *PDWORD;
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+//
+// PREQUEST
+// SpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define SpxAllocateRequest(_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
+// SpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define SpxFreeRequest(_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_TDI_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the TDI buffer chain associated with a request.
+//
+
+#define REQUEST_TDI_BUFFER(_Request) \
+ ((PVOID)((_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
+// 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)))
+
+
+//
+// PUNICODE_STRING
+// REQUEST_OPEN_NAME(
+// IN PREQUEST Request
+// );
+//
+// Used to access the RemainingName field of a request.
+//
+
+#define REQUEST_OPEN_NAME(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->FileObject->FileName))
+
+//
+// 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
+// SpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define SpxCompleteRequest(_Request) \
+ { \
+ CTELockHandle _CancelIrql; \
+ DBGPRINT(TDI, INFO, \
+ ("SpxCompleteRequest: Completing %lx with %lx\n", \
+ (_Request), REQUEST_STATUS(_Request))); \
+ \
+ IoAcquireCancelSpinLock( &_CancelIrql ); \
+ (_Request)->CancelRoutine = NULL; \
+ IoReleaseCancelSpinLock( _CancelIrql ); \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT); \
+ }
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+#include "fwddecls.h"
+
+// BUGBUG: This should go in ntddk.h?
+#ifndef _NTIOAPI_
+#include "spxntdef.h"
+#endif
+
+#include "spxreg.h"
+#include "spxdev.h"
+#include "spxbind.h"
+#include "spxtimer.h"
+#include "spxpkt.h"
+#include "spxerror.h"
+#include "spxaddr.h"
+#include "spxconn.h"
+#include "spxrecv.h"
+#include "spxsend.h"
+#include "spxquery.h"
+#include "spxmem.h"
+#include "spxutils.h"
+
+
+// Globals
+#include "globals.h"
+
+
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxaddr.h b/private/ntos/tdi/isn/spx/h/spxaddr.h
new file mode 100644
index 000000000..b49a4791e
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxaddr.h
@@ -0,0 +1,426 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.h
+
+Abstract:
+
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define DYNSKT_RANGE_START 0x4000
+#define DYNSKT_RANGE_END 0x7FFF
+#define SOCKET_UNIQUENESS 1
+
+// 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_VERIFY 1
+#define AFREF_INDICATION 2
+#define AFREF_CONN_ASSOC 3
+
+#define AFREF_TOTAL 4
+
+typedef struct _SPX_ADDR_FILE {
+
+#if DBG
+ ULONG saf_RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT saf_Type;
+ CSHORT saf_Size;
+
+ // number of references to this object.
+ ULONG saf_RefCount;
+
+ // Linkage in address list.
+ struct _SPX_ADDR_FILE * saf_Next;
+ struct _SPX_ADDR_FILE * saf_GlobalNext;
+
+ // List of associated connection/active or otherwise
+ struct _SPX_CONN_FILE * saf_AssocConnList;
+
+ // the current state of the address file structure; this is either open or
+ // closing
+ USHORT saf_Flags;
+
+ // address to which we are bound, pointer to its lock.
+ struct _SPX_ADDR * saf_Addr;
+ CTELock * saf_AddrLock;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT saf_FileObject;
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * saf_Device;
+
+ // This holds the request used to close this address file,
+ // for pended completion.
+ PREQUEST saf_CloseReq;
+
+ // This function pointer points to a connection indication handler for this
+ // Address. Any time a connect request is received on the address, this
+ // routine is invoked.
+ PTDI_IND_CONNECT saf_ConnHandler;
+ PVOID saf_ConnHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_DISCONNECT
+ // handler for the address.
+ PTDI_IND_DISCONNECT saf_DiscHandler;
+ PVOID saf_DiscHandlerCtx;
+
+ // The following function pointer always points to a TDI_IND_RECEIVE
+ // event handler for connections on this address.
+ PTDI_IND_RECEIVE saf_RecvHandler;
+ PVOID saf_RecvHandlerCtx;
+
+ // Send possible handler
+ PTDI_IND_SEND_POSSIBLE saf_SendPossibleHandler;
+ PVOID saf_SendPossibleHandlerCtx;
+
+ // !!!We do not do datagrams or expedited data!!!
+
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address.
+ PTDI_IND_ERROR saf_ErrHandler;
+ PVOID saf_ErrHandlerCtx;
+ PVOID saf_ErrHandlerOwner;
+
+
+} SPX_ADDR_FILE, *PSPX_ADDR_FILE;
+
+#define SPX_ADDRFILE_OPENING 0x0000 // not yet open for business
+#define SPX_ADDRFILE_OPEN 0x0001 // open for business
+#define SPX_ADDRFILE_CLOSING 0x0002 // closing
+#define SPX_ADDRFILE_STREAM 0x0004 // Opened for stream mode operation
+#define SPX_ADDRFILE_CONNIND 0x0008 // Connect ind in progress
+#define SPX_ADDRFILE_SPX2 0x0010 // Attempt SPX2 address file
+#define SPX_ADDRFILE_NOACKWAIT 0x0020 // Dont delay acks on assoc connections
+#define SPX_ADDRFILE_IPXHDR 0x0040 // Pass ipx hdr on all assoc connections
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+// If you are adding any more states to this beyond 0x0080, MAKE SURE to go
+// in code and change statements like (Flags & SPX_***) to
+// ((Flags & SPX_**) != 0)!!! I dont want to make that change that at this stage.
+// ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP*** ***STOP***
+
+// 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.
+
+#define AREF_ADDR_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _SPX_ADDR {
+
+#if DBG
+ ULONG sa_RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT sa_Size;
+ CSHORT sa_Type;
+
+ // number of references to this object.
+ ULONG sa_RefCount;
+
+ // next address/this device object.
+ struct _SPX_ADDR * sa_Next;
+
+ // The following fields are used to maintain state about this address.
+ // attributes of the address.
+ ULONG sa_Flags;
+
+ // Next addressfile for this address
+ struct _SPX_ADDR_FILE * sa_AddrFileList;
+
+ // List of inactive connections and active connections on this address file.
+ struct _SPX_CONN_FILE * sa_InactiveConnList;
+ struct _SPX_CONN_FILE * sa_ActiveConnList;
+
+ // This is the list of connections which have a POST_LISTEN on them. They
+ // do not have a local connection id at this point. But will, when they move
+ // from here to the ActiveConnList, when the listen is satisfied (no matter
+ // if the accept has not been posted yet, in the case of non-autoaccept listens)
+ struct _SPX_CONN_FILE * sa_ListenConnList;
+
+ CTELock sa_Lock;
+
+ // the socket this address corresponds to.
+ USHORT sa_Socket;
+
+ // device context to which we are attached.
+ struct _DEVICE * sa_Device;
+ CTELock * sa_DeviceLock;
+
+#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 sa_ShareAccess;
+
+ // Used for delaying NbfDestroyAddress to a thread so
+ // we can access the security descriptor.
+ WORK_QUEUE_ITEM sa_DestroyAddrQueueItem;
+
+ } u;
+
+ // This structure is used to hold ACLs on the address.
+ PSECURITY_DESCRIPTOR sa_SecurityDescriptor;
+
+#endif
+
+} SPX_ADDR, *PSPX_ADDR;
+
+#define SPX_ADDR_CLOSING 0x00000001
+
+
+// ROUTINE PROTOTYPES
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR Address);
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile);
+
+NTSTATUS
+SpxAddrOpen(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address);
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxAddrFileClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT struct _SPX_CONN_FILE **ppSpxConnFile);
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile);
+
+VOID
+SpxAddrDestroy(
+ IN PVOID Parameter);
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device);
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket);
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile);
+
+#if DBG
+#define SpxAddrReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type],\
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrRef (_Address); \
+ }
+
+#define SpxAddrLockReference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrLockRef (_Address); \
+ }
+
+#define SpxAddrDereference(_Address, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Address)->sa_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }\
+ }
+
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileRef (_AddressFile); \
+ }
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileLockRef (_AddressFile); \
+ }
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxAddrFileDeref (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_AddressFile)->saf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxAddrReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock)
+
+#define SpxAddrLockReference(_Address, _Type) \
+ SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ 1, \
+ (_Address)->sa_DeviceLock);
+
+#define SpxAddrDereference(_Address, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_Address)->sa_RefCount, \
+ (ULONG)-1, \
+ &(_Address)->sa_Lock) == 1) { \
+ SpxAddrDestroy (_Address); \
+ }
+
+#define SpxAddrFileReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock)
+
+#define SpxAddrFileLockReference(_AddressFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ 1, \
+ (_AddressFile)->saf_AddrLock);
+
+#define SpxAddrFileDereference(_AddressFile, _Type) \
+ if (SPX_ADD_ULONG( \
+ &(_AddressFile)->saf_RefCount, \
+ (ULONG)-1, \
+ (_AddressFile)->saf_AddrLock) == 1) { \
+ SpxAddrFileDestroy (_AddressFile); \
+ }
+
+#define SpxAddrFileTransferReference(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
diff --git a/private/ntos/tdi/isn/spx/h/spxbind.h b/private/ntos/tdi/isn/spx/h/spxbind.h
new file mode 100644
index 000000000..81ad6ac58
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxbind.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID);
+
+VOID
+SpxUnbindFromIpx(
+ VOID);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxconn.h b/private/ntos/tdi/isn/spx/h/spxconn.h
new file mode 100644
index 000000000..bb1173432
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxconn.h
@@ -0,0 +1,1666 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+// Minimum value for RTT in ms.
+// BUGBUG: Have these be a derivate of registry values.
+#define SPX_T1_MIN 200
+#define MAX_RETRY_DELAY 5000 // 5 seconds
+#define SPX_DEF_RENEG_RETRYCOUNT 1 // All reneg pkts except min sent once
+
+// Some types
+typedef enum
+{
+ SPX_CALL_RECVLEVEL,
+ SPX_CALL_TDILEVEL
+} SPX_CALL_LEVEL;
+
+typedef enum
+{
+ SPX_REQ_DATA,
+ SPX_REQ_ORDREL,
+ SPX_REQ_DISC
+
+} SPX_SENDREQ_TYPE;
+
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Connection.
+
+#define CFREF_CREATE 0
+#define CFREF_VERIFY 1
+#define CFREF_INDICATION 2
+#define CFREF_BYCTX 3
+#define CFREF_BYID 4
+#define CFREF_ADDR 5
+#define CFREF_REQ 6
+#define CFREF_TIMER 7
+#define CFREF_PKTIZE 8
+#define CFREF_RECV 9
+#define CFREF_ABORTPKT 10
+#define CFREF_ERRORSTATE 11
+#define CFREF_FINDROUTE 12
+
+//
+// New state added to reflect an SPXI connection which is waiting for
+// a local disconnect after having indicated a RELEASE to AFD.
+//
+#define CFREF_DISCWAITSPX 13
+
+#define CFREF_TOTAL 14
+
+#define CFMAX_STATES 20
+
+typedef struct _SPX_CONN_FILE
+{
+
+#if DBG
+ ULONG scf_RefTypes[CFREF_TOTAL];
+
+#if 0
+//
+// Disabled for now - to enable logging of states, move this array *after* the Type/Size;
+// a change in their offset can cause problems since we assume the offset to be less than
+// the size of an AddressFile structure. (see SpxTdiQueryInformation)
+//
+ ULONG scf_StateBuffer[CFMAX_STATES];
+ ULONG scf_NextStatePtr;
+#endif
+
+#endif
+
+ CSHORT scf_Type;
+ CSHORT scf_Size;
+
+ // number of references to this object.
+ ULONG scf_RefCount;
+
+ // Linkage in device address file list. The connection can be on the device
+ // connection list, address inactive/listen/active list.
+ struct _SPX_CONN_FILE * scf_Next;
+ struct _SPX_CONN_FILE * scf_AssocNext;
+ struct _SPX_CONN_FILE * scf_GlobalActiveNext;
+
+ // Queued in a global list, stays here from creation to destroy.
+ struct _SPX_CONN_FILE * scf_GlobalNext;
+ struct _SPX_CONN_FILE * scf_PktNext;
+ struct _SPX_CONN_FILE * scf_ProcessRecvNext;
+
+ // the current state of the connection. One main state and multiple substates.
+ ULONG scf_Flags;
+
+ // More information
+ ULONG scf_Flags2;
+
+#if DBG
+ // Save the state of flags/flags2 before reinit. Overwritten every reinit.
+ ULONG scf_GhostFlags;
+ ULONG scf_GhostFlags2;
+ ULONG scf_GhostRefCount;
+ PREQUEST scf_GhostDiscReq;
+#endif
+
+ // Connection retry counts, or watchdog timer count when the connection goes
+ // active
+ union
+ {
+ LONG scf_CRetryCount;
+ LONG scf_WRetryCount;
+ };
+ LONG scf_RRetryCount;
+ USHORT scf_RRetrySeqNum;
+
+ union
+ {
+ ULONG scf_CTimerId;
+ ULONG scf_RTimerId; // Only after we turn active
+ };
+
+ ULONG scf_WTimerId; // Watchdog timer
+ ULONG scf_TTimerId; // TDI Connect/Disconnect timer
+ ULONG scf_ATimerId; // Ack timer id
+
+ // Variables used to manage the Retry timer tick value
+ // Note our timer subsytem fires at 100ms granularity.
+ int scf_BaseT1;
+ int scf_AveT1;
+ int scf_DevT1;
+
+ // Stored in HOST-ORDER
+ // LOCAL variables
+ USHORT scf_LocalConnId;
+ USHORT scf_SendSeqNum; // Debug dw +9a
+ USHORT scf_SentAllocNum; // dw +9c
+
+ // REMOTE variables
+ USHORT scf_RecvSeqNum; // dw +9e
+ USHORT scf_RecdAckNum; // dw +a0
+ USHORT scf_RecdAllocNum; // dw +a2
+
+ // RETRY sequence number
+ USHORT scf_RetrySeqNum;
+
+ // Saved ack number to be used in building the reneg ack packet.
+ // Note that our RecvSeqNum which we normally use is overwritten
+ // when we receive a renegotiate request.
+ USHORT scf_RenegAckAckNum;
+
+ // Stored in NETWORK-ORDER. scf_RemAckAddr contains the remote address
+ // for a data packet that had the ack bit set, buildAck will use this
+ // address.
+ BYTE scf_RemAddr[12];
+ BYTE scf_RemAckAddr[12];
+ USHORT scf_RemConnId; // Debug dw +be
+
+ // Maximum packet size (or size of first) reneg packet.
+ USHORT scf_RenegMaxPktSize;
+
+ // Local target to use in when sending acks. This is set to received
+ // data's indicated local target.
+ IPX_LOCAL_TARGET scf_AckLocalTarget;
+
+ // Maximum packet size to use for this connection
+ USHORT scf_MaxPktSize;
+ UCHAR scf_DataType;
+
+ // Local target to use in sends, initialized upon connect indication
+ // or when find_route completes
+ IPX_LOCAL_TARGET scf_LocalTarget;
+
+ // Connection lock
+ CTELock scf_Lock;
+
+ // address to which we are bound
+ struct _SPX_ADDR_FILE * scf_AddrFile;
+
+ // Connection context
+ CONNECTION_CONTEXT scf_ConnCtx;
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ PFILE_OBJECT scf_FileObject;
+#endif
+
+ // LIST_ENTRY of disconnect irps waiting for completion. There could be
+ // multiple disconnect inform irps.
+ LIST_ENTRY scf_DiscLinkage;
+
+ // LIST_ENTRY of send requests (intially contains connect/listen/accept also)
+ // on this connection.
+ LIST_ENTRY scf_ReqLinkage;
+
+ // Queue for completed requests awaiting completion
+ LIST_ENTRY scf_ReqDoneLinkage;
+ LIST_ENTRY scf_RecvDoneLinkage;
+
+ // Queue for pending receives
+ LIST_ENTRY scf_RecvLinkage;
+ PREQUEST scf_CurRecvReq;
+ ULONG scf_CurRecvOffset;
+ ULONG scf_CurRecvSize;
+
+ // Current request packetize info
+ PREQUEST scf_ReqPkt;
+ ULONG scf_ReqPktOffset;
+ ULONG scf_ReqPktSize;
+ ULONG scf_ReqPktFlags;
+ SPX_SENDREQ_TYPE scf_ReqPktType;
+
+ // Single linked list of sequenced send/disc packets
+ PSPX_SEND_RESD scf_SendSeqListHead;
+ PSPX_SEND_RESD scf_SendSeqListTail;
+
+ // Single linked list of send (unsequenced) packets
+ PSPX_SEND_RESD scf_SendListHead;
+ PSPX_SEND_RESD scf_SendListTail;
+
+ // Single linked list of buffered recv packets.
+ PSPX_RECV_RESD scf_RecvListHead;
+ PSPX_RECV_RESD scf_RecvListTail;
+
+ // Connect request
+ PREQUEST scf_ConnectReq;
+
+ // This holds the request used to close this address file,
+ // for pended completion. We also pend cleanup requests for connections.
+ PREQUEST scf_CleanupReq;
+ PREQUEST scf_CloseReq;
+
+#if DBG
+
+ // Packet being indicated, seq num, flags/flags2
+ USHORT scf_PktSeqNum;
+ ULONG scf_PktFlags;
+ ULONG scf_PktFlags2;
+
+ ULONG scf_IndBytes;
+ ULONG scf_IndLine;
+#endif
+
+#if DBG_WDW_CLOSE
+
+ // Keep track of how long the window was closed on this connection.
+ ULONG scf_WdwCloseAve;
+ LARGE_INTEGER scf_WdwCloseTime; // Time when wdw was closed
+#endif
+
+ // device to which we are attached.
+ struct _DEVICE * scf_Device;
+
+} SPX_CONN_FILE, *PSPX_CONN_FILE;
+
+
+// Basic states
+// Least significant byte of flags is used.
+// Mutually exclusive states are coded as numbers, others are bit flags.
+// Only main states are currently in form of numbers. Also, send and receive.
+//
+// Once we go active, we need SEND/RECEIVE/DISC substates to be mutually
+// exclusive with each other. As all three could be active at the same time.
+
+// Connection MAIN states. These are all mutually exclusive.
+#define SPX_CONNFILE_MAINMASK 0x00000007
+#define SPX_CONNFILE_ACTIVE 0x00000001
+#define SPX_CONNFILE_CONNECTING 0x00000002
+#define SPX_CONNFILE_LISTENING 0x00000003
+#define SPX_CONNFILE_DISCONN 0x00000004
+
+// Connecting states (VALID when CONNFILE_CONNECTING)
+#define SPX_CONNECT_MASK 0x000000F0
+#define SPX_CONNECT_SENTREQ 0x00000010
+#define SPX_CONNECT_NEG 0x00000020
+#define SPX_CONNECT_W_SETUP 0x00000030
+
+// Listening states (VALID when CONNFILE_LISTENING)
+#define SPX_LISTEN_MASK 0x000000F0
+#define SPX_LISTEN_RECDREQ 0x00000010
+#define SPX_LISTEN_SENTACK 0x00000020
+#define SPX_LISTEN_NEGACK 0x00000030
+#define SPX_LISTEN_SETUP 0x00000040
+
+// Connection SUB states
+// Send machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_SEND_MASK 0x000000F0
+#define SPX_SEND_IDLE 0x00000000
+#define SPX_SEND_PACKETIZE 0x00000010
+#define SPX_SEND_RETRY 0x00000020
+#define SPX_SEND_RETRYWD 0x00000030
+#define SPX_SEND_RENEG 0x00000040
+#define SPX_SEND_RETRY2 0x00000050
+#define SPX_SEND_RETRY3 0x00000060
+#define SPX_SEND_WD 0x00000070 // We dont reneg pkt size on wdog
+ // Also we change to this state only
+ // 2nd time wdog fires w/out ack.
+#define SPX_SEND_NAK_RECD 0x00000080
+
+// Receive machine states (VALID when CONNFILE_ACTIVE)
+#define SPX_RECV_MASK 0x00000F00
+#define SPX_RECV_IDLE 0x00000000
+#define SPX_RECV_POSTED 0x00000100
+#define SPX_RECV_PROCESS_PKTS 0x00000200
+
+// Disconnect states (VALID when CONNFILE_DISCONN/CONNFILE_ACTIVE)
+// These are valid when either ACTIVE/DISCONN is set. We use these when
+// active for a orderly release, i.e. we receive pkt from remote, but we
+// stay active (setting SPX_DISC_RECV_ORDREL) until our client posts a
+// disconnect, which is when we move to disconnecting.
+#define SPX_DISC_MASK 0x0000F000
+#define SPX_DISC_IDLE 0x00000000
+#define SPX_DISC_ABORT 0x00001000
+#define SPX_DISC_SENT_IDISC 0x00002000
+#define SPX_DISC_POST_ORDREL 0x00003000
+#define SPX_DISC_SENT_ORDREL 0x00004000
+#define SPX_DISC_ORDREL_ACKED 0x00005000
+#define SPX_DISC_POST_IDISC 0x00006000
+
+// [SA] bug #14655 added flag to indicate that SpxConnInactivate already called for
+// this disconnecting connection
+//
+#define SPX_DISC_INACTIVATED 0x00007000
+
+// The following are not mutually exclusive.
+#define SPX_CONNFILE_RECVQ 0x00010000 // Process completed receives/pkts
+#define SPX_CONNFILE_RENEG_SIZE 0x00020000 // Size changed in renegotiate pkt
+#define SPX_CONNFILE_ACKQ 0x00040000 // Waiting to piggyback ack queue
+#define SPX_CONNFILE_PKTQ 0x00080000 // Waiting to packetize queue
+
+#define SPX_CONNFILE_ASSOC 0x00100000 // associated
+#define SPX_CONNFILE_NEG 0x00200000 // CR had neg set (for delayed accept)
+#define SPX_CONNFILE_SPX2 0x00400000
+#define SPX_CONNFILE_STREAM 0x00800000
+#define SPX_CONNFILE_R_TIMER 0x01000000 // Retry timer (only after ACTIVE)
+#define SPX_CONNFILE_C_TIMER 0x01000000 // Connect timer
+#define SPX_CONNFILE_W_TIMER 0x02000000 // Watchdog timer
+#define SPX_CONNFILE_T_TIMER 0x04000000 // tdi connect/disc timer specified
+#define SPX_CONNFILE_RENEG_PKT 0x08000000 // Renegotiate changed size, repacketize
+#define SPX_CONNFILE_IND_IDISC 0x10000000 // Indicated abortive disc to afd
+#define SPX_CONNFILE_IND_ODISC 0x20000000 // Indicated orderly release to afd
+
+#define SPX_CONNFILE_STOPPING 0x40000000
+#define SPX_CONNFILE_CLOSING 0x80000000 // closing
+
+#define SPX_CONNFILE2_PKT_NOIND 0x00000001
+#define SPX_CONNFILE2_RENEGRECD 0x00000002 // A renegotiate was received.
+ // scf_RenegAckAckNum set.
+#define SPX_CONNFILE2_PKT 0x00000004
+#define SPX_CONNFILE2_FINDROUTE 0x00000010 // A find route in progress on conn.
+#define SPX_CONNFILE2_NOACKWAIT 0x00000020 // Dont delay acks on connection, option
+#define SPX_CONNFILE2_IMMED_ACK 0x00000040 // Send an immediate ack,no back traffic
+#define SPX_CONNFILE2_IPXHDR 0x00000080 // Pass ipxhdr in receives
+
+//
+// [SA] Saves the IDisc flag passed to AbortiveDisc; this is TRUE only if there was
+// a remote disconnect on an SPX connection (in which case, we indicate TDI_DISCONNECT_RELEASE
+// else we indicate TDI_DISCONNECT_ABORT)
+//
+#define SPX_CONNFILE2_IDISC 0x00000100
+
+//
+// Indicates an SPXI connfile waiting for a local disconnect in response
+// to a TDI_DISCONNECT_RELEASE to AFD.
+//
+#define SPX_CONNFILE2_DISC_WAIT 0x00000200
+
+// FindRoute request structure
+typedef struct _SPX_FIND_ROUTE_REQUEST
+{
+ // !!!!This must be the first element in the structure
+ IPX_FIND_ROUTE_REQUEST fr_FindRouteReq;
+ PVOID fr_Ctx;
+
+} SPX_FIND_ROUTE_REQUEST, *PSPX_FIND_ROUTE_REQUEST;
+
+typedef struct _SPX_CONNFILE_LIST
+{
+ PSPX_CONN_FILE pcl_Head;
+ PSPX_CONN_FILE pcl_Tail;
+
+} SPX_CONNFILE_LIST, *PSPX_CONNFILE_LIST;
+
+// Exported routines
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT pConnCtx,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest);
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT NTSTATUS * pStatus);
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile);
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle);
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn);
+
+#if DBG
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile);
+#endif
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus);
+
+BOOLEAN
+SpxConnDequeuePktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pAckHdr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle);
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt);
+
+// LOCAL functions
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr);
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+USHORT
+spxConnGetId(
+ VOID);
+
+VOID
+spxConnInsertIntoActiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoInactiveList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile);
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnInsertIntoListenList(
+ IN PSPX_ADDR pSpxAddr,
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove);
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt);
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt);
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize);
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size);
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest);
+
+NTSTATUS
+spxConnProcessRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnProcessIndData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnOrderlyDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+NTSTATUS
+spxConnInformedDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN PREQUEST pRequest,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN Flag); // [SA] Bug #15249
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile);
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn);
+
+//
+// MACROS
+//
+#define SHIFT100000 16
+
+#define SPX_CONVERT100NSTOCENTISEC(Li) \
+ RtlExtendedMagicDivide((Li), Magic100000, SHIFT100000)
+
+#define UNSIGNED_BETWEEN_WITH_WRAP(Low, High, Target) \
+ ((Low <= High) ? ((Target >= Low) && (Target <= High)) : \
+ ((Target >= Low) || (Target <= High)))
+
+// This is with the assumption that the window size will never be greater
+// than the difference of 0x8000 and 0x1000. If High is < 1000 and Low
+// is > 8000 then we can assume a wrap happened. Otherwise, we assume no
+// wrap and do a straight compare.
+#define MAX_WINDOW_SIZE 0x6000
+#define DEFAULT_WINDOW_SIZE 8
+
+#define UNSIGNED_GREATER_WITH_WRAP(High, Low) \
+ (((High < 0x1000) && (Low > 0x8000)) ? TRUE : (High > Low))
+
+#define SPX_SET_ACKNUM(pSpxConnFile, RecdAckNum, RecdAllocNum) \
+ { \
+ DBGPRINT(SEND, DBG, \
+ ("SPX_SET_ACKNUM: %lx.%lx = %lx.%lx (%s.%d)\n", \
+ (RecdAckNum), (RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum), \
+ __FILE__, __LINE__)); \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAckNum), \
+ ((pSpxConnFile)->scf_RecdAckNum))) \
+ { \
+ (pSpxConnFile)->scf_RecdAckNum = (RecdAckNum); \
+ } \
+ \
+ if (UNSIGNED_GREATER_WITH_WRAP((RecdAllocNum), \
+ ((pSpxConnFile)->scf_RecdAllocNum)))\
+ { \
+ (pSpxConnFile)->scf_RecdAllocNum = (RecdAllocNum); \
+ } \
+ }
+
+#define BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum) \
+ { \
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT); \
+ }
+
+#define END_PROCESS_PACKET(pSpxConnFile, fBuffered, fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, \
+ (SPX_CONNFILE2_PKT |SPX_CONNFILE2_RENEGRECD)); \
+ if (fSuccess) \
+ { \
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND); \
+ SPX_SET_RECVNUM(pSpxConnFile, fBuffered); \
+ } \
+ }
+
+#define INCREMENT_WINDOW(pSpxConnFile) \
+ ((pSpxConnFile)->scf_SentAllocNum++)
+
+#define ADD_TO_WINDOW(pSpxConnFile, numPkts) \
+ ((pSpxConnFile)->scf_SentAllocNum += (numPkts))
+
+#if DBG_WDW_CLOSE
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ \
+ if (fBuffered && \
+ (UNSIGNED_GREATER_WITH_WRAP( \
+ (pSpxConnFile)->scf_RecvSeqNum, \
+ (pSpxConnFile)->scf_SentAllocNum))) \
+ { \
+ KeQuerySystemTime( \
+ (PLARGE_INTEGER)&pSpxConnFile->scf_WdwCloseTime); \
+ } \
+ }
+#else
+#define SPX_SET_RECVNUM(pSpxConnFile, fBuffered) \
+ { \
+ (pSpxConnFile)->scf_RecvSeqNum++; \
+ if (!fBuffered) \
+ (pSpxConnFile)->scf_SentAllocNum++; \
+ }
+#endif
+
+
+#define SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest) \
+ { \
+ RemoveEntryList(REQUEST_LINKAGE((pRequest))); \
+ pSpxConnFile->scf_CurRecvReq = NULL; \
+ pSpxConnFile->scf_CurRecvOffset = 0; \
+ pSpxConnFile->scf_CurRecvSize = 0; \
+ if (!IsListEmpty(&(pSpxConnFile)->scf_RecvLinkage)) \
+ { \
+ PTDI_REQUEST_KERNEL_RECEIVE _p; \
+ DBGPRINT(RECEIVE, DBG, \
+ ("spxConnProcessRecv: CURRECV %lx\n", pRequest)); \
+ \
+ (pSpxConnFile)->scf_CurRecvReq = \
+ LIST_ENTRY_TO_REQUEST( \
+ (pSpxConnFile)->scf_RecvLinkage.Flink); \
+ \
+ _p = (PTDI_REQUEST_KERNEL_RECEIVE) \
+ REQUEST_PARAMETERS((pSpxConnFile)->scf_CurRecvReq); \
+ \
+ (pSpxConnFile)->scf_CurRecvOffset = 0; \
+ (pSpxConnFile)->scf_CurRecvSize = (_p)->ReceiveLength; \
+ } \
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) || \
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED)) \
+ { \
+ SPX_RECV_SETSTATE( \
+ pSpxConnFile, \
+ (pSpxConnFile->scf_CurRecvReq == NULL) ? \
+ SPX_RECV_IDLE : SPX_RECV_POSTED); \
+ } \
+ }
+
+#define SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ActiveConnList; \
+ (pSpxAddr)->sa_ActiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_INACTIVE(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_InactiveConnList; \
+ (pSpxAddr)->sa_InactiveConnList = pSpxConnFile; \
+ }
+
+#define SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile) \
+ { \
+ (pSpxConnFile)->scf_Next = (pSpxAddr)->sa_ListenConnList; \
+ (pSpxAddr)->sa_ListenConnList = pSpxConnFile; \
+ }
+
+
+//
+// STATE MANIPULATION
+//
+
+#if 0
+//
+// Disabled for now
+//
+#define SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_StateBuffer[(pSpxConnFile)->scf_NextStatePtr++] = \
+ (pSpxConnFile)->scf_Flags; \
+ (pSpxConnFile)->scf_NextStatePtr %= CFMAX_STATES;
+#else
+
+#define SPX_STORE_LAST_STATE(pSpxConnFile)
+
+#endif
+
+#define SPX_MAIN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNFILE_MAINMASK)
+
+// #define SPX_CONN_IDLE(pSpxConnFile) \
+// ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == 0))
+
+#define SPX_CONN_IDLE(pSpxConnFile) \
+ ((BOOLEAN)((SPX_MAIN_STATE(pSpxConnFile) == 0) || \
+ ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) && \
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED))))
+
+#define SPX_CONN_ACTIVE(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE))
+
+#define SPX_CONN_CONNECTING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_CONNECTING))
+
+#define SPX_CONN_LISTENING(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_LISTENING))
+
+#define SPX_CONN_DISC(pSpxConnFile) \
+ ((BOOLEAN)(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN))
+
+#if DBG
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#else
+
+#define SPX_MAIN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNFILE_MAINMASK) | (newState));\
+ }
+
+#endif
+
+#define SPX_CONN_FLAG(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags & (Flag)) != 0))
+
+#define SPX_CONN_FLAG2(pSpxConnFile, Flag) \
+ ((BOOLEAN)(((pSpxConnFile)->scf_Flags2 & (Flag)) != 0))
+
+#if DBG
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+#else
+
+#define SPX_CONN_SETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags |= (Flag))
+
+#endif
+
+#define SPX_CONN_SETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 |= (Flag))
+
+#define SPX_CONN_RESETFLAG(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags &= ~(Flag))
+
+#define SPX_CONN_RESETFLAG2(pSpxConnFile, Flag) \
+ ((pSpxConnFile)->scf_Flags2 &= ~(Flag))
+
+#define SPX2_CONN(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_SPX2))
+
+#define SPX_CONN_STREAM(pSpxConnFile) \
+ (SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_CONN_MSG(pSpxConnFile) \
+ (!SPX_CONN_FLAG((pSpxConnFile), SPX_CONNFILE_STREAM))
+
+#define SPX_LISTEN_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_LISTEN_MASK)
+
+#define SPX_CONNECT_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_CONNECT_MASK)
+
+#define SPX_SEND_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_SEND_MASK)
+
+#define SPX_RECV_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_RECV_MASK)
+
+#define SPX_DISC_STATE(pSpxConnFile) \
+ ((pSpxConnFile)->scf_Flags & SPX_DISC_MASK)
+
+#if DBG
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ SPX_STORE_LAST_STATE(pSpxConnFile) \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+
+#else
+
+#define SPX_LISTEN_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("LISTEN: %x -> %x\n", \
+ SPX_LISTEN_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ pSpxConnFile->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_LISTEN_MASK) | (newState)); \
+ }
+
+#define SPX_CONNECT_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("CONNECT: %x -> %x\n", \
+ SPX_CONNECT_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_CONNECT_MASK) | (newState)); \
+ }
+
+#define SPX_SEND_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("SEND: %x -> %x\n", \
+ SPX_SEND_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_SEND_MASK) | (newState)); \
+ }
+
+#define SPX_RECV_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("RECV: %x -> %x\n", \
+ SPX_RECV_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_RECV_MASK) | (newState)); \
+ }
+
+#define SPX_DISC_SETSTATE(pSpxConnFile, newState) \
+ { \
+ DBGPRINT(STATE, INFO, \
+ ("DISC: %x -> %x\n", \
+ SPX_DISC_STATE(pSpxConnFile), (newState))); \
+ DBGPRINT(STATE, INFO, \
+ ("FILE: %s - %d\n", __FILE__, __LINE__)); \
+ (pSpxConnFile)->scf_Flags = \
+ (((pSpxConnFile)->scf_Flags & ~SPX_DISC_MASK) | (newState)); \
+ }
+#endif //DBG
+#define SpxConnQueueSendPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendListTail->sr_Next = _pSendResd; \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail->sr_Next = _pSendResd;\
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ } \
+ }
+
+#define SpxConnQueueSendSeqPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_SEND_RESD _pSendResd; \
+ _pSendResd = (PSPX_SEND_RESD)((pPkt)->ProtocolReserved); \
+ _pSendResd->sr_Next = NULL; \
+ if ((pSpxConnFile)->scf_SendSeqListTail != NULL) \
+ { \
+ _pSendResd->sr_Next = (pSpxConnFile)->scf_SendSeqListHead;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_SendSeqListTail = _pSendResd; \
+ } \
+ (pSpxConnFile)->scf_SendSeqListHead = _pSendResd; \
+ }
+
+#define SpxConnQueueRecvPktTail(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ (pSpxConnFile)->scf_RecvListTail->rr_Next = _pRecvResd; \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd;\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ } \
+ }
+
+#define SpxConnQueueRecvPktHead(pSpxConnFile, pPkt) \
+ { \
+ PSPX_RECV_RESD _pRecvResd; \
+ _pRecvResd = (PSPX_RECV_RESD)((pPkt)->ProtocolReserved); \
+ _pRecvResd->rr_Next = NULL; \
+ if ((pSpxConnFile)->scf_RecvListTail != NULL) \
+ { \
+ _pRecvResd->rr_Next = (pSpxConnFile)->scf_RecvListHead; \
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_RecvListTail = _pRecvResd; \
+ } \
+ (pSpxConnFile)->scf_RecvListHead = _pRecvResd; \
+ }
+
+#if DBG
+#define SpxConnFileReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileRef (_ConnFile); \
+ }
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileLockRef (_ConnFile); \
+ }
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxConnFileDeref (_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _l; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_l)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, _l); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_NewType], \
+ 1, \
+ &SpxGlobalInterlock); \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_ConnFile)->scf_RefTypes[_OldType], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ }
+
+#else // DBG
+
+#define SpxConnFileReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock)
+
+#define SpxConnFileLockReference(_ConnFile, _Type) \
+ SPX_ADD_ULONG( \
+ &(_ConnFile)->scf_RefCount, \
+ 1, \
+ &(_ConnFile)->scf_Lock);
+
+#define SpxConnFileDereference(_ConnFile, _Type) \
+ { \
+ SpxConnFileDeref(_ConnFile); \
+ }
+
+#define SpxConnFileReferenceByCtx(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock((_pAddrFile)->saf_AddrLock, &(_lockHandle)); \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));\
+ CTEFreeLock((_pAddrFile)->saf_AddrLock, (_lockHandle)); \
+ }
+
+#define SpxConnFileReferenceByCtxLock(_pAddrFile, _Ctx, _ppConnFile, _pStatus) \
+ SpxConnFileRefByCtxLock((_pAddrFile), (_Ctx), (_ppConnFile),(_pStatus));
+
+#define SpxConnFileReferenceById(_ConnId, _ppConnFile, _pStatus) \
+ { \
+ CTELockHandle _lockHandle; \
+ CTEGetLock(&SpxDevice->dev_Lock, &(_lockHandle)); \
+ SpxConnFileRefByIdLock(_ConnId, _ppConnFile, _pStatus); \
+ CTEFreeLock(&SpxDevice->dev_Lock, (_lockHandle)); \
+ }
+
+#define SpxConnFileTransferReference(_ConnFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+// Set the packet size. If we are spx1 or spx2 and !neg, check if we are different
+// nets, set to min then, else use the size indicated by IPX. If we are spx2, just
+// set it to our local max.
+//
+// Also always even out packet size and round down. This solves an issue with
+// data size needing to be even for some novell 802.2 clients.
+//
+// Fix after beta2 for tokring using receive size. Only if spx2 and neg.
+#if defined(_PNP_POWER)
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ &(pSpxConnFile)->scf_LocalTarget.NicHandle, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#else
+#define SPX_MAX_PKT_SIZE(pSpxConnFile, fSpx2Neg, fSpx2, pRemNet) \
+ { \
+ if (!fSpx2 && PARAM(CONFIG_BACKCOMP_SPX)) { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ else { \
+ IPX_LINE_INFO _i; \
+ \
+ (VOID)(*IpxQuery)( \
+ IPX_QUERY_LINE_INFO, \
+ (pSpxConnFile)->scf_LocalTarget.NicId, \
+ &(_i), \
+ sizeof(IPX_LINE_INFO), \
+ NULL); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumPacketSize; \
+ if (!fSpx2Neg) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = (_i).MaximumSendSize; \
+ } \
+ \
+ if ((pSpxConnFile)->scf_MaxPktSize < SPX_MAX_PACKET) \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("%s : %d.%d\n", __FILE__, __LINE__, fSpx2Neg)); \
+ \
+ if ((!fSpx2Neg) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != 0) && \
+ ((*(UNALIGNED ULONG *)SpxDevice->dev_Network) != 0) && \
+ ((*(UNALIGNED ULONG *)(pRemNet)) != \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network)) \
+ { \
+ if (PARAM(CONFIG_ROUTER_MTU) != 0) \
+ { \
+ DBGPRINT(CONNECT, ERR, \
+ ("SPX_MAX_PKT_SIZE: PARAM %lx Max Pkt %lx\n", \
+ PARAM(CONFIG_ROUTER_MTU), \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ \
+ (pSpxConnFile)->scf_MaxPktSize = \
+ (USHORT)(MIN(PARAM(CONFIG_ROUTER_MTU), \
+ (ULONG)((pSpxConnFile)->scf_MaxPktSize)));\
+ } \
+ else \
+ { \
+ (pSpxConnFile)->scf_MaxPktSize = SPX_MAX_PACKET; \
+ } \
+ \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: Nets %lx.%lx Max Pkt %d\n", \
+ (*(UNALIGNED ULONG *)(pRemNet)), \
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: LineInfo Pkt %d\n", \
+ (_i).MaximumSendSize)); \
+ } \
+ } \
+ (pSpxConnFile)->scf_MaxPktSize &= ~((USHORT)1); \
+ DBGPRINT(CONNECT, DBG, \
+ ("SPX_MAX_PKT_SIZE: %lx.%d\n", \
+ (pSpxConnFile)->scf_MaxPktSize, \
+ (pSpxConnFile)->scf_MaxPktSize)); \
+ }
+#endif _PNP_POWER
+
+#if DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ if (_n != NDIS_STATUS_SUCCESS) \
+ { \
+ DBGPRINT(SEND, ERR, \
+ ("SPX_SENDPACKET: Failed with %lx in %s.%lx\n", \
+ _n, __FILE__, __LINE__)); \
+ } \
+ \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#else // DBG
+#define SPX_SENDPACKET(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_LocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+#define SPX_SENDACK(pSpxConnFile, pNdisPkt, pSendResd) \
+ { \
+ NDIS_STATUS _n; \
+ \
+ ++SpxDevice->dev_Stat.PacketsSent; \
+ \
+ _n = (*IpxSendPacket)( \
+ &(pSpxConnFile)->scf_AckLocalTarget, \
+ (pNdisPkt), \
+ (pSendResd)->sr_Len, \
+ (pSendResd)->sr_HdrLen); \
+ \
+ if (_n != NDIS_STATUS_PENDING) \
+ { \
+ SpxSendComplete( \
+ (pNdisPkt), \
+ _n); \
+ } \
+ }
+
+#endif // DBG
+
+#define SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile) \
+ { \
+ if (!SPX_CONN_FLAG( \
+ (pSpxConnFile), \
+ SPX_CONNFILE_RECVQ)) \
+ { \
+ SPX_CONN_SETFLAG((pSpxConnFile), SPX_CONNFILE_RECVQ); \
+ SpxConnFileLockReference(pSpxConnFile, CFREF_RECV); \
+ SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile); \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile) \
+ { \
+ if (SpxPktConnList.pcl_Tail) \
+ { \
+ SpxPktConnList.pcl_Tail->scf_PktNext = pSpxConnFile; \
+ SpxPktConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxPktConnList.pcl_Tail = \
+ SpxPktConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+#define SPX_QUEUE_TAIL_RECVLIST(pSpxConnFile) \
+ { \
+ if (SpxRecvConnList.pcl_Tail) \
+ { \
+ SpxRecvConnList.pcl_Tail->scf_ProcessRecvNext = pSpxConnFile; \
+ SpxRecvConnList.pcl_Tail = pSpxConnFile; \
+ } \
+ else \
+ { \
+ SpxRecvConnList.pcl_Tail = \
+ SpxRecvConnList.pcl_Head = pSpxConnFile; \
+ } \
+ }
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxdev.h b/private/ntos/tdi/isn/spx/h/spxdev.h
new file mode 100644
index 000000000..30c0adae5
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxdev.h
@@ -0,0 +1,204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ SPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+// Hash buckets for SPX_ADDR done using socket number
+#define NUM_SPXADDR_HASH_BUCKETS 8
+#define NUM_SPXADDR_HASH_MASK 7
+#define NUM_SPXCONN_HASH_BUCKETS 8
+#define NUM_SPXCONN_HASH_MASK 7
+
+// This structure defines the per-device structure for SPX
+// (one of these is allocated globally).
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_ORPHAN 4
+
+#define DREF_TOTAL 5
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT dev_DevObj; // the I/O system's device object.
+
+#if DBG
+ ULONG dev_RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT dev_Type; // type of this structure
+ USHORT dev_Size; // size of this structure
+
+#if DBG
+ UCHAR dev_Signature1[4]; // contains "SPX1"
+#endif
+
+ // activity count/this provider.
+ LONG dev_RefCount;
+ UCHAR dev_State;
+
+ // number of adapters IPX is bound to.
+ USHORT dev_Adapters;
+
+ // GLOBAL lock for reference count (used in ExInterlockedXxx calls).
+ CTELock dev_Interlock;
+ CTELock dev_Lock;
+
+ // Hash table of lists of addresses opened on this device
+ struct _SPX_ADDR * dev_AddrHashTable[NUM_SPXADDR_HASH_BUCKETS];
+
+ // List of all active connections, later this be a tree.
+ struct _SPX_CONN_FILE * dev_GlobalActiveConnList[NUM_SPXCONN_HASH_BUCKETS];
+ USHORT dev_NextConnId;
+
+ // Other configuration parameters.
+ // Where the current socket allocation is.
+ USHORT dev_CurrentSocket;
+
+ // Our node and network.
+ UCHAR dev_Network[4];
+ UCHAR dev_Node[6];
+
+ // Pointer to the config information from registry
+ PCONFIG dev_ConfigInfo;
+
+ // Control channel identifier
+ ULONG dev_CcId;
+
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ PWCHAR dev_DeviceName;
+#if defined(_PNP_POWER)
+ USHORT dev_DeviceNameLen;
+#else
+ ULONG dev_DeviceNameLen;
+#endif _PNP_POWER
+
+#if DBG
+ UCHAR dev_Signature2[4]; // contains "SPX2"
+#endif
+
+ // Handle to ndis buffer pool for spx stack.
+ NDIS_HANDLE dev_NdisBufferPoolHandle;
+
+ // registration handle with tdi clients.
+#if defined(_PNP_POWER)
+ HANDLE dev_TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ // This interlock is used to guard access to the statistics
+ // define below.
+ KSPIN_LOCK dev_StatInterlock; // for ULONG quantities
+ KSPIN_LOCK dev_StatSpinLock; // for LARGE_INTEGER quantities
+
+ // Counters for most of the statistics that SPX 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 dev_Stat;
+
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ ERESOURCE dev_AddrResource;
+
+ // 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 dev_ProviderInfo; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+// 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
+
+
+// SPX device name
+#define SPX_DEVICE_NAME L"\\Device\\NwlnkSpx"
+
+#define SPX_TDI_RESOURCES 9
+
+
+// MACROS
+#if DBG
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ 1, \
+ &SpxGlobalInterlock); \
+ \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ { \
+ (VOID)SPX_ADD_ULONG ( \
+ &(_Device)->dev_RefTypes[_Type], \
+ (ULONG)-1, \
+ &SpxGlobalInterlock); \
+ SpxDerefDevice (_Device); \
+ }
+
+#else
+
+#define SpxReferenceDevice(_Device, _Type) \
+ { \
+ (VOID)InterlockedIncrement ( \
+ &(_Device)->dev_RefCount); \
+ }
+
+#define SpxDereferenceDevice(_Device, _Type) \
+ SpxDerefDevice (_Device)
+
+#endif
+
+// EXPORTED ROUTINES
+
+VOID
+SpxDestroyDevice(
+ IN PDEVICE Device);
+
+VOID
+SpxDerefDevice(
+ IN PDEVICE Device);
+
+NTSTATUS
+SpxInitCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr);
diff --git a/private/ntos/tdi/isn/spx/h/spxerror.h b/private/ntos/tdi/isn/spx/h/spxerror.h
new file mode 100644
index 000000000..761342512
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxerror.h
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxerror.h
+
+Abstract:
+
+ This module contains some error definitions for spx.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+
+Notes: Tab stop: 4
+--*/
+
+// Define the modules names for SPX - use the high bits.
+#define SPXDRVR 0x00010000
+#define SPXREG 0x00020000
+#define SPXDEV 0x00030000
+#define SPXBIND 0x00040000
+#define SPXRECV 0x00050000
+#define SPXSEND 0x00060000
+#define SPXTIMER 0x00070000
+#define SPXERROR 0x00080000
+#define SPXPKT 0x00090000
+#define SPXUTILS 0x000a0000
+#define SPXCPKT 0x000b0000
+#define SPXCONN 0x000c0000
+#define SPXADDR 0x000d0000
+#define SPXCUTIL 0x000e0000
+#define SPXINIT 0x000f0000
+#define SPXMEM 0x00100000
+#define SPXQUERY 0x00200000
+
+
+// DEBUGGING SUPPORT:
+// Debugging messages are provided per-subsystem defined here, and within
+// the subsystems, there are 4 levels of messages.
+//
+// The four levels of debug messages are:
+//
+// INFO: Informational messages, eg., entry exit in routines
+// DBG: Used when debugging some msgs are turned from info to dbg
+// WARN: Something went wrong, but its not an error, eg., packet was not ours
+// ERR: Error situations, but we can still run if a retry happens
+// FATAL: In this situation, the driver is not operational
+
+#define DBG_LEVEL_INFO 0x4000
+#define DBG_LEVEL_DBG 0x5000
+#define DBG_LEVEL_DBG1 0x5001
+#define DBG_LEVEL_DBG2 0x5002
+#define DBG_LEVEL_DBG3 0x5003
+#define DBG_LEVEL_WARN 0x6000
+#define DBG_LEVEL_ERR 0x7000
+#define DBG_LEVEL_FATAL 0x8000
+
+// SUBSYSTEMS
+#define DBG_COMP_DEVICE 0x00000001
+#define DBG_COMP_CREATE 0x00000002
+#define DBG_COMP_ADDRESS 0x00000004
+#define DBG_COMP_SEND 0x00000008
+#define DBG_COMP_NDIS 0x00000010
+#define DBG_COMP_RECEIVE 0x00000020
+#define DBG_COMP_CONFIG 0x00000040
+#define DBG_COMP_PACKET 0x00000080
+#define DBG_COMP_RESOURCES 0x00000100
+#define DBG_COMP_BIND 0x00000200
+#define DBG_COMP_UNLOAD 0x00000400
+#define DBG_COMP_DUMP 0x00000800
+#define DBG_COMP_REFCOUNTS 0x00001000
+#define DBG_COMP_SYSTEM 0x00002000
+#define DBG_COMP_CRITSEC 0x00004000
+#define DBG_COMP_UTILS 0x00008000
+#define DBG_COMP_TDI 0x00010000
+#define DBG_COMP_CONNECT 0x00020000
+#define DBG_COMP_DISC 0x00040000
+#define DBG_COMP_ACTION 0x00080000
+#define DBG_COMP_STATE 0x00100000
+
+#define DBG_COMP_MOST (DBG_COMP_DEVICE | \
+ DBG_COMP_CREATE | \
+ DBG_COMP_ADDRESS | \
+ DBG_COMP_SEND | \
+ DBG_COMP_NDIS | \
+ DBG_COMP_RECEIVE | \
+ DBG_COMP_CONFIG | \
+ DBG_COMP_PACKET | \
+ DBG_COMP_RESOURCES | \
+ DBG_COMP_BIND | \
+ DBG_COMP_UNLOAD | \
+ DBG_COMP_DUMP | \
+ DBG_COMP_REFCOUNTS | \
+ DBG_COMP_SYSTEM | \
+ DBG_COMP_CRITSEC | \
+ DBG_COMP_UTILS | \
+ DBG_COMP_TDI | \
+ DBG_COMP_CONNECT | \
+ DBG_COMP_DISC | \
+ DBG_COMP_ACTION | \
+ DBG_COMP_STATE)
+
+
+// More debugging support. These values define the dumping components.
+// There are a max of 32 such components that can be defined. Each of
+// these are associated with a dump routine. It one is specified and
+// enabled, periodically it is called. It is upto that component to
+// decide what it wants to do
+
+#define DBG_DUMP_DEF_INTERVAL 30 // In Seconds
+
+// This defines the number of times an error has to happen consecutively before
+// it gets logged again.
+#define ERROR_CONSEQ_FREQ 200
+#define ERROR_CONSEQ_TIME (60*30) // 30 minutes
+
+#ifdef DBG
+typedef VOID (*DUMP_ROUTINE)(VOID);
+
+extern
+BOOLEAN
+SpxDumpComponents(
+ IN PVOID Context);
+
+#endif
+
+//
+// PROTOTYPES
+//
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+VOID
+SpxWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue);
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
+
+
+//
+// MACROS
+//
+
+#if DBG
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#else
+
+#define LOG_ERROR(Error, NtStatus, SecondString, RawData, RawDataLen) \
+ { \
+ SpxWriteGeneralErrorLog( \
+ SpxDevice, \
+ Error, \
+ FILENUM | __LINE__, \
+ NtStatus, \
+ SecondString, \
+ RawData, \
+ RawDataLen); \
+ }
+
+#define RES_LOG_ERROR(BytesNeeded) \
+ { \
+ SpxWriteResourceErrorLog( \
+ SpxDevice, \
+ BytesNeeded, \
+ FILENUM | __LINE__); \
+ }
+
+#endif
+
+
+#if DBG
+
+#define DBGPRINT(Component, Level, Fmt) \
+ { \
+ if (((DBG_LEVEL_ ## Level) >= SpxDebugLevel) && \
+ (SpxDebugSystems & (DBG_COMP_ ## Component))) \
+ { \
+ DbgPrint("SPX: "); \
+ DbgPrint Fmt; \
+ } \
+ }
+
+#define DBGBRK(Level) \
+ { \
+ if ((DBG_LEVEL_ ## Level) >= SpxDebugLevel) \
+ DbgBreakPoint(); \
+ }
+
+#define TMPLOGERR() \
+ { \
+ DBGPRINT(MOST, ERR, \
+ ("TempErrLog: %s, Line %ld\n", __FILE__, __LINE__)); \
+ }
+
+#else
+#define DBGPRINT(Component, Level, Fmt)
+#define DBGBRK(Level)
+#define TMPLOGERR()
+#endif
+
+extern
+VOID
+SpxWriteErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen);
diff --git a/private/ntos/tdi/isn/spx/h/spxmem.h b/private/ntos/tdi/isn/spx/h/spxmem.h
new file mode 100644
index 000000000..717c69a6b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxmem.h
@@ -0,0 +1,142 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.h
+
+Abstract:
+
+ This module contains memory management routines.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 17-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+#define QWORDSIZEBLOCK(Size) (((Size)+sizeof(LARGE_INTEGER)-1) & ~(sizeof(LARGE_INTEGER)-1))
+#define SPX_MEMORY_SIGNATURE *(PULONG)"SPXM"
+#define ZEROED_MEMORY_TAG 0xF0000000
+#define SPX_TAG *((PULONG)"SPX ")
+
+//
+// Definitions for the block management package
+//
+typedef UCHAR BLKID;
+
+// Add a BLKID_xxx and an entry to atalkBlkSize for every block client
+#define BLKID_TIMERLIST (BLKID)0
+#define BLKID_NDISSEND (BLKID)1
+#define BLKID_NDISRECV (BLKID)2
+#define NUM_BLKIDS (BLKID)3
+
+typedef struct _BLK_CHUNK
+{
+ struct _BLK_CHUNK * bc_Next; // Pointer to next in the link
+ SHORT bc_NumFrees; // Number of free blocks in the chunk
+ UCHAR bc_Age; // Number of invocations since the chunk free
+ BLKID bc_BlkId; // Id of the block
+ struct _BLK_HDR * bc_FreeHead; // Head of the list of free blocks
+
+#ifndef SPX_OWN_PACKETS
+ PVOID bc_ChunkCtx; // Used to store pool header if not own
+ // packets
+#else
+ PVOID bc_Padding; // Keep the header 16 bytes
+#endif
+
+ // This is followed by an array of N blks of size M such that the block header
+ // is exactly spxChunkSize[i]
+
+} BLK_CHUNK, *PBLK_CHUNK;
+
+typedef struct _BLK_HDR
+{
+ union
+ {
+ struct _BLK_HDR * bh_Next; // Valid when it is free
+ struct _BLK_CHUNK * bh_pChunk; // The parent chunk to which this blocks belong
+ // valid when it is allocated
+ };
+ PVOID bh_Padding; // Make the header 8 bytes
+} BLK_HDR, *PBLK_HDR;
+
+#define BC_OVERHEAD (8+8) // LARGE_INTEGER for SpxAllocMemory() header and
+ // POOL_HEADER for ExAllocatePool() header
+
+#define BLOCK_POOL_TIMER 1000 // Check interval (1 sec)
+#define MAX_BLOCK_POOL_AGE 3 // # of timer invocations before free
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown);
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define SpxAllocateMemory(Size) SpxAllocMem((Size), FILENUM | __LINE__)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size,
+ IN ULONG FileLine
+);
+
+extern
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+);
+
+#else
+
+#define SpxAllocateMemory(Size) SpxAllocMem(Size)
+#define SpxTrackMemoryUsage(pMem, Alloc, FileLine)
+
+extern
+PVOID
+SpxAllocMem(
+ IN ULONG Size
+);
+
+#endif // TRACK_MEMORY_USAGE
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf);
+
+#define SpxAllocateZeroedMemory(Size) SpxAllocateMemory((Size) | ZEROED_MEMORY_TAG)
+
+
+extern
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+extern
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice);
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId);
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxntdef.h b/private/ntos/tdi/isn/spx/h/spxntdef.h
new file mode 100644
index 000000000..60f9c9e54
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxntdef.h
@@ -0,0 +1,72 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxntdef.h
+
+Abstract:
+
+ Missing nt definitions in ntddk.h
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+NTSTATUS
+NTAPI
+NtCreateFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength
+ );
+
+NTSTATUS
+NTAPI
+NtClose(
+ IN HANDLE Handle
+ );
+
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+ IN HANDLE FileHandle,
+ IN HANDLE Event OPTIONAL,
+ IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+ IN PVOID ApcContext OPTIONAL,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG IoControlCode,
+ IN PVOID InputBuffer OPTIONAL,
+ IN ULONG InputBufferLength,
+ OUT PVOID OutputBuffer OPTIONAL,
+ IN ULONG OutputBufferLength
+ );
+
+NTSTATUS
+NTAPI
+NtWaitForSingleObject(
+ IN HANDLE Handle,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxpkt.h b/private/ntos/tdi/isn/spx/h/spxpkt.h
new file mode 100644
index 000000000..b643ed95b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxpkt.h
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// Use our own NDIS packets
+#define SPX_OWN_PACKETS 1
+
+// Offsets into the IPX header
+#define IPX_HDRSIZE 30 // Size of the IPX header
+#define IPX_CHECKSUM 0 // Checksum
+#define IPX_LENGTH 2 // Length
+#define IPX_XPORTCTL 4 // Transport Control
+#define IPX_PKTTYPE 5 // Packet Type
+#define IPX_DESTADDR 6 // Dest. Address (Total)
+#define IPX_DESTNET 6 // Dest. Network Address
+#define IPX_DESTNODE 10 // Dest. Node Address
+#define IPX_DESTSOCK 16 // Dest. Socket Number
+#define IPX_SRCADDR 18 // Source Address (Total)
+#define IPX_SRCNET 18 // Source Network Address
+#define IPX_SRCNODE 22 // Source Node Address
+#define IPX_SRCSOCK 28 // Source Socket Number
+
+#define IPX_NET_LEN 4
+#define IPX_NODE_LEN 6
+
+
+#include <packon.h>
+
+// Definition of the IPX/SPX header.
+typedef struct _IPXSPX_HEADER
+{
+ USHORT hdr_CheckSum;
+ USHORT hdr_PktLen;
+ UCHAR hdr_XportCtrl;
+ UCHAR hdr_PktType;
+ UCHAR hdr_DestNet[4];
+ UCHAR hdr_DestNode[6];
+ USHORT hdr_DestSkt;
+ UCHAR hdr_SrcNet[4];
+ UCHAR hdr_SrcNode[6];
+ USHORT hdr_SrcSkt;
+
+ // SPX Header Elements
+ UCHAR hdr_ConnCtrl;
+ UCHAR hdr_DataType;
+ USHORT hdr_SrcConnId;
+ USHORT hdr_DestConnId;
+ USHORT hdr_SeqNum;
+ USHORT hdr_AckNum;
+ USHORT hdr_AllocNum;
+
+ // For non-CR SPXII packets only
+ USHORT hdr_NegSize;
+
+} IPXSPX_HDR, *PIPXSPX_HDR;
+
+#include <packoff.h>
+
+// NDIS Packet size
+#define NDIS_PACKET_SIZE 48
+
+// Minimum header size (doesnt include neg size)
+#define MIN_IPXSPX_HDRSIZE (sizeof(IPXSPX_HDR) - sizeof(USHORT))
+#define MIN_IPXSPX2_HDRSIZE sizeof(IPXSPX_HDR)
+#define SPX_CR_PKTLEN 42
+
+// SPX packet type
+#define SPX_PKT_TYPE 0x5
+
+// Connection control fields
+#define SPX_CC_XHD 0x01
+#define SPX_CC_RES1 0x02
+#define SPX_CC_NEG 0x04
+#define SPX_CC_SPX2 0x08
+#define SPX_CC_EOM 0x10
+#define SPX_CC_ATN 0x20
+#define SPX_CC_ACK 0x40
+#define SPX_CC_SYS 0x80
+
+#define SPX_CC_CR (SPX_CC_ACK | SPX_CC_SYS)
+
+// Data stream types
+#define SPX2_DT_ORDREL 0xFD
+#define SPX2_DT_IDISC 0xFE
+#define SPX2_DT_IDISC_ACK 0xFF
+
+// Negotiation size
+#define SPX_MAX_PACKET 576
+#define SPX_NEG_MIN SPX_MAX_PACKET
+#define SPX_NEG_MAX 65535
+
+// No packet references connection. But if the sends are being aborted, and
+// the packet happens to be owned by ipx at the time, the pkt is dequeued from
+// conn, the ABORT flag is set and conn is referenced for packet.
+//
+// Send packet states
+// ABORT : Used for aborted packet. Calls AbortSendPkt().
+// IPXOWNS : Currently owned by ipx
+// FREEDATA: Frees the data associated with second ndis buffer desc
+// ACKREQ : Only for sequenced packets. Set by retry timer in packets it wants
+// resent (1 for spx1, all pending for spx2) with ack bit set.
+// DESTROY : Only for non-sequenced packets, dequeue packet from list and free.
+// REQ : For both seq/non-seq. A request is associated with the packet
+// SEQ : Packet is a sequenced packet.
+// LASTPKT : Packet is last packet comprising the request, if acked req is done.
+// EOM : Send EOM with the last packet for this request
+// ACKEDPKT: Send completion must only deref req with pkt and complete if zero.
+//
+
+#define SPX_SENDPKT_IDLE 0
+#define SPX_SENDPKT_ABORT 0x0002
+#define SPX_SENDPKT_IPXOWNS 0x0004
+#define SPX_SENDPKT_FREEDATA 0x0008
+#define SPX_SENDPKT_ACKREQ 0x0010
+#define SPX_SENDPKT_DESTROY 0x0020
+#define SPX_SENDPKT_REQ 0x0040
+#define SPX_SENDPKT_SEQ 0x0080
+#define SPX_SENDPKT_LASTPKT 0x0100
+#define SPX_SENDPKT_ACKEDPKT 0x0200
+#define SPX_SENDPKT_EOM 0x0400
+#define SPX_SENDPKT_REXMIT 0x0800
+
+// Packet types
+#define SPX_TYPE_CR 0x01
+#define SPX_TYPE_CRACK 0x02
+#define SPX_TYPE_SN 0x03
+#define SPX_TYPE_SNACK 0x04
+#define SPX_TYPE_SS 0x05
+#define SPX_TYPE_SSACK 0x06
+#define SPX_TYPE_RR 0x07
+#define SPX_TYPE_RRACK 0x08
+#define SPX_TYPE_IDISC 0x09
+#define SPX_TYPE_IDISCACK 0x0a
+#define SPX_TYPE_ORDREL 0x0b
+#define SPX_TYPE_ORDRELACK 0x0c
+#define SPX_TYPE_DATA 0x0d
+#define SPX_TYPE_DATAACK 0x0e
+#define SPX_TYPE_DATANACK 0x0f
+#define SPX_TYPE_PROBE 0x10
+
+// Definition of the protocol reserved field of a send packet.
+// BUGBUG: Make Len/HdrLen USHORTS, move to the end before the
+// sr_SentTime so we dont use padding space.
+typedef struct _SPX_SEND_RESD
+{
+ UCHAR sr_Id; // Set to SPX
+ UCHAR sr_Type; // What kind of packet
+ USHORT sr_State; // State of send packet
+ PVOID sr_Reserved1; // Needed by IPX
+ PVOID sr_Reserved2; // Needed by IPX
+#if defined(_PNP_POWER)
+ PVOID sr_Reserved[SEND_RESERVED_COMMON_SIZE-2]; // needed by IPX for local target
+#endif _PNP_POWER
+ ULONG sr_Len; // Length of packet
+ ULONG sr_HdrLen; // Included header length
+
+ struct _SPX_SEND_RESD * sr_Next; // Points to next packet
+ // in send queue in conn.
+ PREQUEST sr_Request; // request associated
+ ULONG sr_Offset; // Offset in mdl for sends
+
+#ifndef SPX_OWN_PACKETS
+ PVOID sr_FreePtr; // Ptr to use in free chunk
+#endif
+
+ struct _SPX_CONN_FILE * sr_ConnFile; // that this send is on
+ USHORT sr_SeqNum; // Seq num for seq pkts
+
+ // Quad word aligned.
+ LARGE_INTEGER sr_SentTime; // Time packet was sent
+ // Only valid for data pkt
+ // with ACKREQ set.
+
+} SPX_SEND_RESD, *PSPX_SEND_RESD;
+
+
+
+// Recv packet states
+#define SPX_RECVPKT_IDLE 0
+#define SPX_RECVPKT_BUFFERING 0x0001
+#define SPX_RECVPKT_IDISC 0x0002
+#define SPX_RECVPKT_ORD_DISC 0x0004
+#define SPX_RECVPKT_INDICATED 0x0008
+#define SPX_RECVPKT_SENDACK 0x0010
+#define SPX_RECVPKT_EOM 0x0020
+#define SPX_RECVPKT_IMMEDACK 0x0040
+
+#define SPX_RECVPKT_DISCMASK (SPX_RECVPKT_ORD_DISC | SPX_RECVPKT_IDISC)
+
+// Definition of the protocol reserved field of a receive packet.
+typedef struct _SPX_RECV_RESD
+{
+ UCHAR rr_Id; // Set to SPX
+ USHORT rr_State; // State of receive packet
+ struct _SPX_RECV_RESD * rr_Next; // Points to next packet
+ ULONG rr_DataOffset; // To indicate/copy from
+
+#ifndef SPX_OWN_PACKETS
+ PVOID rr_FreePtr; // Ptr to use in free chunk
+#endif
+
+#if DBG
+ USHORT rr_SeqNum; // Seq num of packet
+#endif
+
+ PREQUEST rr_Request; // request waiting on xfer
+ struct _SPX_CONN_FILE * rr_ConnFile; // that this recv is on
+
+} SPX_RECV_RESD, *PSPX_RECV_RESD;
+
+
+// Destination built as an assign of 3 ulongs.
+#define SpxBuildIpxHdr(pIpxSpxHdr, PktLen, pRemAddr, SrcSkt) \
+ { \
+ PBYTE pDestIpxAddr = (PBYTE)pIpxSpxHdr->hdr_DestNet; \
+ (pIpxSpxHdr)->hdr_CheckSum = 0xFFFF; \
+ PUTSHORT2SHORT((PUSHORT)(&(pIpxSpxHdr)->hdr_PktLen), (PktLen)); \
+ (pIpxSpxHdr)->hdr_XportCtrl = 0; \
+ (pIpxSpxHdr)->hdr_PktType = SPX_PKT_TYPE; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNet))= \
+ *((UNALIGNED ULONG *)(SpxDevice->dev_Network)); \
+ *((UNALIGNED ULONG *)((pIpxSpxHdr)->hdr_SrcNode)) = \
+ *((UNALIGNED ULONG *)SpxDevice->dev_Node); \
+ *((UNALIGNED USHORT *)((pIpxSpxHdr)->hdr_SrcNode+4)) = \
+ *((UNALIGNED USHORT *)(SpxDevice->dev_Node+4)); \
+ *((UNALIGNED USHORT *)&((pIpxSpxHdr)->hdr_SrcSkt)) = \
+ SrcSkt; \
+ }
+
+#define SpxCopyIpxAddr(pIpxSpxHdr, pDestIpxAddr) \
+ { \
+ PBYTE pRemAddr = (PBYTE)pIpxSpxHdr->hdr_SrcNet; \
+ *((UNALIGNED ULONG *)pDestIpxAddr) = \
+ *((UNALIGNED ULONG *)pRemAddr); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+4)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+4)); \
+ *((UNALIGNED ULONG *)(pDestIpxAddr+8)) = \
+ *((UNALIGNED ULONG *)(pRemAddr+8)); \
+ }
+
+#ifndef SPX_OWN_PACKETS
+#define SpxAllocSendPacket(_Device,_SendPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_SEND_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket), (_Handle)); \
+ SEND_RESD(_SendPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ NDIS_HANDLE _Handle; \
+ NdisAllocatePacketPool(_Status, &(_Handle),1,sizeof(SPX_RECV_RESD));\
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_RecvPacket), (_Handle)); \
+ RECV_RESD(_RecvPacket)->sr_PoolHandle = (_Handle); \
+ } \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle; \
+ NdisFreePacket(_Packet); \
+ NdisFreePacketPool(_Handle); \
+ }
+
+#define SpxReInitSendPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = SEND_RESD(_Packet)->sr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ SEND_RESD(_Packet)->sr_PoolHandle = (_Handle);
+ }
+
+#define SpxReInitRecvPacket(_Packet)
+ {
+ NDIS_HANDLE _Handle = RECV_RESD(_Packet)->rr_PoolHandle;
+ NdisReInitializePacket(_Packet);
+ RECV_RESD(_Packet)->rr_PoolHandle = (_Handle);
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#else
+
+#define SpxAllocSendPacket(_Device, _SendPacket, _Status) \
+ { \
+ if (*(_SendPacket) = SpxBPAllocBlock(BLKID_NDISSEND)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxAllocRecvPacket(_Device,_RecvPacket,_Status) \
+ { \
+ if (*(_RecvPacket) = SpxBPAllocBlock(BLKID_NDISRECV)) \
+ *(_Status) = NDIS_STATUS_SUCCESS; \
+ else \
+ *(_Status) = NDIS_STATUS_RESOURCES; \
+ }
+
+#define SpxFreeSendPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISSEND); \
+ }
+
+#define SpxFreeRecvPacket(_Device,_Packet) \
+ { \
+ SpxBPFreeBlock(_Packet, BLKID_NDISRECV); \
+ }
+
+#define SpxReInitSendPacket(_Packet) \
+ { \
+ }
+
+#define SpxReInitRecvPacket(_Packet) \
+ { \
+ }
+
+#define SEND_RESD(_Packet) ((PSPX_SEND_RESD)((_Packet)->ProtocolReserved))
+#define RECV_RESD(_Packet) ((PSPX_RECV_RESD)((_Packet)->ProtocolReserved))
+
+#endif
+
+
+//
+// Routine Prototypes
+//
+
+VOID
+SpxPktBuildCr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildCrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN struct _SPX_ADDR * pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildSn(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSs(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSsAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildSnAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRr(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State);
+
+VOID
+SpxPktBuildRrAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize);
+
+VOID
+SpxPktBuildProbe(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2);
+
+VOID
+SpxPktBuildData(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length);
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ );
+
+VOID
+SpxPktBuildAck(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend);
+
+VOID
+SpxPktBuildDisc(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType);
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt);
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt);
diff --git a/private/ntos/tdi/isn/spx/h/spxquery.h b/private/ntos/tdi/isn/spx/h/spxquery.h
new file mode 100644
index 000000000..68e0a1ca8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxquery.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#define SPX_TDI_PROVIDERINFO_VERSION 0x0001
+#define SPX_PINFOSENDSIZE 0xFFFFFFFF
+#define SPX_PINFOMINMAXLOOKAHEAD 128
+
+//
+// Bug #14498: Indicate to AFD that we are capable of orderly disc so AFD can follow
+// these semantics.
+// In order to have SPXI connections work correctly, we OR this bit in at query time.
+// (see SpxTdiQueryInformation)
+//
+#define SPX_PINFOSERVICEFLAGS ( TDI_SERVICE_CONNECTION_MODE | \
+ TDI_SERVICE_DELAYED_ACCEPTANCE | \
+ TDI_SERVICE_MESSAGE_MODE | \
+ TDI_SERVICE_ERROR_FREE_DELIVERY) // | \
+ // TDI_SERVICE_ORDERLY_RELEASE )
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo);
+
+NTSTATUS
+SpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
+NTSTATUS
+SpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxrecv.h b/private/ntos/tdi/isn/spx/h/spxrecv.h
new file mode 100644
index 000000000..ca1572c64
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxrecv.h
@@ -0,0 +1,91 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+BOOLEAN
+SpxReceive(
+ 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
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred);
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId);
+
+VOID
+SpxRecvDataPacket(
+ 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
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize);
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize);
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn);
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxreg.h b/private/ntos/tdi/isn/spx/h/spxreg.h
new file mode 100644
index 000000000..4e0cb469b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxreg.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.h
+
+Abstract:
+
+ Private include file for the ISN SPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+#define HALFSEC_TO_MS_FACTOR 500
+#define IPX_REG_PATH L"NwlnkIpx\\Linkage"
+
+// These are used to index into the Parameters array in CONFIG.
+#define CONFIG_CONNECTION_COUNT 0
+#define CONFIG_CONNECTION_TIMEOUT 1
+#define CONFIG_INIT_PACKETS 2
+#define CONFIG_MAX_PACKETS 3
+#define CONFIG_INITIAL_RETRANSMIT_TIMEOUT 4
+#define CONFIG_KEEPALIVE_COUNT 5
+#define CONFIG_KEEPALIVE_TIMEOUT 6
+#define CONFIG_WINDOW_SIZE 7
+#define CONFIG_SOCKET_RANGE_START 8
+#define CONFIG_SOCKET_RANGE_END 9
+#define CONFIG_SOCKET_UNIQUENESS 10
+#define CONFIG_MAX_PACKET_SIZE 11
+#define CONFIG_REXMIT_COUNT 12
+
+// Hidden parameters
+#define CONFIG_DISABLE_SPX2 13
+#define CONFIG_ROUTER_MTU 14
+#define CONFIG_BACKCOMP_SPX 15
+
+#define CONFIG_PARAMETERS 16
+
+// Main configuration structure.
+typedef struct _CONFIG {
+
+ ULONG cf_Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING cf_DeviceName; // device name exported
+ PWSTR cf_RegistryPathBuffer; // path to config info
+
+} CONFIG, * PCONFIG;
+
+
+#define PARAM(x) (SpxDevice->dev_ConfigInfo->cf_Parameters[(x)])
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr);
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config);
+
diff --git a/private/ntos/tdi/isn/spx/h/spxsend.h b/private/ntos/tdi/isn/spx/h/spxsend.h
new file mode 100644
index 000000000..40ef810ea
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxsend.h
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus);
+
+VOID
+SpxSendPktRelease(
+ IN PNDIS_PACKET pPkt,
+ IN UINT BufCount);
diff --git a/private/ntos/tdi/isn/spx/h/spxtimer.h b/private/ntos/tdi/isn/spx/h/spxtimer.h
new file mode 100644
index 000000000..225037bd2
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxtimer.h
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.h
+
+Abstract:
+
+ This module contains routines to schedule timer events.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+Revision History:
+ 19 Jun 1992 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#define TIMER_DONT_REQUEUE 0
+#define TIMER_REQUEUE_CUR_VALUE 1
+
+typedef ULONG (*TIMER_ROUTINE)(IN PVOID Context, IN BOOLEAN TimerShuttingDown);
+
+extern
+NTSTATUS
+SpxTimerInit(
+ VOID);
+
+extern
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG DeltaTime, // Schedule after this much time
+ IN PVOID pContext); // Context to pass to the routine
+
+extern
+VOID
+SpxTimerFlushAndStop(
+ VOID);
+
+extern
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue);
+
+#define TMR_SIGNATURE *(PULONG)"ATMR"
+#if DBG
+#define VALID_TMR(pTmr) (((pTmr) != NULL) && \
+ ((pTmr)->tmr_Signature == TMR_SIGNATURE))
+#else
+#define VALID_TMR(pTmr) ((pTmr) != NULL)
+#endif
+typedef struct _TimerList
+{
+#if DBG
+ ULONG tmr_Signature;
+#endif
+ struct _TimerList * tmr_Next; // Link to next
+ struct _TimerList ** tmr_Prev; // Link to prev
+ struct _TimerList * tmr_Overflow; // Link to overflow entry in hash table
+ ULONG tmr_AbsTime; // Absolute time, for re-enqueue
+ ULONG tmr_RelDelta; // Relative to the previous entry
+ ULONG tmr_Id; // Unique Id for this event
+ BOOLEAN tmr_Cancelled; // Was the timer cancelled?
+ TIMER_ROUTINE tmr_Worker; // Real Worker
+ PVOID tmr_Context; // Real context
+} TIMERLIST, *PTIMERLIST;
+
+
+#define SpxGetCurrentTime() (SpxTimerCurrentTime/SPX_TIMER_FACTOR)
+#define SpxGetCurrentTick() SpxTimerCurrentTime
+
+// Keep this at a ONE second level.
+#define SPX_TIMER_FACTOR 10 // i.e. 10 ticks per second
+#define SPX_MS_TO_TICKS 100 // Divide ms by this to get ticks
+#define SPX_TIMER_TICK -1000000L // 100ms in 100ns units
+#define SPX_TIMER_WAIT 50 // Time to wait in FlushAndStop in ms
+#define TIMER_HASH_TABLE 32
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2);
+
+VOID
+spxTimerWorker(
+ IN PTIMERLIST pList);
+
+VOID
+spxTimerEnqueue(
+ PTIMERLIST pListNew);
+
+
diff --git a/private/ntos/tdi/isn/spx/h/spxutils.h b/private/ntos/tdi/isn/spx/h/spxutils.h
new file mode 100644
index 000000000..074a1649b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/h/spxutils.h
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+// For PROTO_SPX, i'd return a device name from the dll of the form
+// \Device\NwlnkSpx\SpxStream (for SOCK_STREAM) or
+// \Device\NwlnkSpx\Spx (for SOCK_SEQPKT)
+//
+// and for PROTO_SPXII (the more common case we hope, even if
+// internally we degrade to SPX1 cause of the remote client's
+// limitations)
+// \Device\NwlnkSpx\Stream (for SOCK_STREAM) or
+// \Device\NwlnkSpx (for SOCK_SEQPKT)
+
+#define SOCKET1STREAM_SUFFIX L"\\SpxStream"
+#define SOCKET1_SUFFIX L"\\Spx"
+#define SOCKET2STREAM_SUFFIX L"\\Stream"
+#define SOCKET1_TYPE_SEQPKT 0
+#define SOCKET2_TYPE_SEQPKT 1
+#define SOCKET1_TYPE_STREAM 2
+#define SOCKET2_TYPE_STREAM 3
+
+#define IN_RANGE(_S, _RangeStart, _RangeEnd) \
+ ((_S >= _RangeStart) && (_S <= _RangeEnd))
+
+
+//
+// The following macros deal with on-the-wire integer and long values
+//
+// On the wire format is big-endian i.e. a long value of 0x01020304 is
+// represented as 01 02 03 04. Similarly an int value of 0x0102 is
+// represented as 01 02.
+//
+// The host format is not assumed since it will vary from processor to
+// processor.
+//
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = (USHORT) (*(PBYTE)(SrcPtr))
+
+// Get a byte from on-the-wire format to a short in the host format
+#define GETBYTE2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = (ULONG) (*(PBYTE)(SrcPtr))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a short from on-the-wire format to a dword in the host format
+#define GETSHORT2SHORT(DstPtr, SrcPtr) \
+ *(PUSHORT)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 8) + \
+ (*((PBYTE)(SrcPtr)+1) ))
+
+// Get a dword from on-the-wire format to a dword in the host format
+#define GETULONG2ULONG(DstPtr, SrcPtr) \
+ *(PULONG)(DstPtr) = ((*((PBYTE)(SrcPtr)+0) << 24) + \
+ (*((PBYTE)(SrcPtr)+1) << 16) + \
+ (*((PBYTE)(SrcPtr)+2) << 8) + \
+ (*((PBYTE)(SrcPtr)+3) ))
+
+// Get a dword from on-the-wire format to a dword in the same format but
+// also watch out for alignment
+#define GETULONG2ULONG_NOCONV(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0); \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1); \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2); \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3);
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTBYTE2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2BYTE(DstPtr, Src) \
+ *((PBYTE)(DstPtr)) = ((USHORT)(Src) % 256)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTSHORT2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((USHORT)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE)(Src)
+
+// Put a dword from the host format to a byte to on-the-wire format
+#define PUTULONG2BYTE(DstPtr, Src) \
+ *(PBYTE)(DstPtr) = (BYTE)(Src)
+
+// Put a dword from the host format to a short to on-the-wire format
+#define PUTULONG2SHORT(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) (Src)
+
+// Put a dword from the host format to a dword to on-the-wire format
+#define PUTULONG2ULONG(DstPtr, Src) \
+ *((PBYTE)(DstPtr)+0) = (BYTE) ((ULONG)(Src) >> 24), \
+ *((PBYTE)(DstPtr)+1) = (BYTE) ((ULONG)(Src) >> 16), \
+ *((PBYTE)(DstPtr)+2) = (BYTE) ((ULONG)(Src) >> 8), \
+ *((PBYTE)(DstPtr)+3) = (BYTE) (Src)
+
+// Put a BYTE[4] array into another BYTE4 array.
+#define PUTBYTE42BYTE4(DstPtr, SrcPtr) \
+ *((PBYTE)(DstPtr)+0) = *((PBYTE)(SrcPtr)+0), \
+ *((PBYTE)(DstPtr)+1) = *((PBYTE)(SrcPtr)+1), \
+ *((PBYTE)(DstPtr)+2) = *((PBYTE)(SrcPtr)+2), \
+ *((PBYTE)(DstPtr)+3) = *((PBYTE)(SrcPtr)+3)
+
+// MIN/MAX macros
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+
+
+
+// Exported prototypes
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr);
+
+LONG
+SpxRandomNumber(
+ VOID);
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType);
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs);
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket);
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr);
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress);
+
+BOOLEAN
+SpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength);
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1);
diff --git a/private/ntos/tdi/isn/spx/mp/makefile b/private/ntos/tdi/isn/spx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/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/spx/mp/sources b/private/ntos/tdi/isn/spx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/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/spx/nwlnkspx.rc b/private/ntos/tdi/isn/spx/nwlnkspx.rc
new file mode 100644
index 000000000..02175f21d
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/nwlnkspx.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 SPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkspx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkspx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isn/spx/precomp.h b/private/ntos/tdi/isn/spx/precomp.h
new file mode 100644
index 000000000..d227d02f9
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/precomp.h
@@ -0,0 +1 @@
+#include "isnspx.h"
diff --git a/private/ntos/tdi/isn/spx/sources.inc b/private/ntos/tdi/isn/spx/sources.inc
new file mode 100644
index 000000000..419f580f1
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/sources.inc
@@ -0,0 +1,65 @@
+!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=nwlnkspx
+
+TARGETNAME=nwlnkspx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\h;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=..\spxdrvr.c \
+ ..\spxreg.c \
+ ..\spxdev.c \
+ ..\spxbind.c \
+ ..\spxaddr.c \
+ ..\spxconn.c \
+ ..\spxcutil.c \
+ ..\spxcpkt.c \
+ ..\spxrecv.c \
+ ..\spxsend.c \
+ ..\spxquery.c \
+ ..\spxutils.c \
+ ..\spxmem.c \
+ ..\spxtimer.c \
+ ..\spxpkt.c \
+ ..\globals.c \
+ ..\spxerror.c \
+ ..\nwlnkspx.rc
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/ntos/tdi/isn/spx/spxaddr.c b/private/ntos/tdi/isn/spx/spxaddr.c
new file mode 100644
index 000000000..e9e85dc5c
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxaddr.c
@@ -0,0 +1,1729 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxaddr.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Author:
+
+ Adam Barr (adamba ) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( PAGE, SpxAddrFileCreate)
+#pragma alloc_text( PAGE, SpxAddrFileClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXADDR
+
+// Map all generic accesses to the same one.
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+#define REORDER(_Socket) ((((_Socket) & 0xff00) >> 8) | (((_Socket) & 0x00ff) << 8))
+
+
+
+
+NTSTATUS
+SpxAddrOpen(
+ 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:
+
+ DeviceObject - pointer to the device object describing the ST transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR pAddr;
+ PSPX_ADDR_FILE pAddrFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED * AddressName;
+ USHORT Socket, hostSocket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle, LockHandleAddr;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ int i;
+ BOOLEAN found = FALSE;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // The network name is in the EA, passed in the request.
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no EA\n", Request));
+
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+ AddressName = (PTA_ADDRESS)&name->Address[0];
+
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type IPX.
+ for (i=0;i<name->TAAddressCount;i++)
+ {
+ if (AddressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ Socket =
+ ((TDI_ADDRESS_IPX UNALIGNED *)&AddressName->Address[0])->Socket;
+
+ GETSHORT2SHORT(&hostSocket, &Socket);
+
+ DBGPRINT(CREATE, DBG,
+ ("SpxAddrOpen: Creating socket %lx.h%lx\n",
+ Socket, hostSocket ));
+
+ found = TRUE;
+ }
+ break;
+
+ }
+ else
+ {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+ }
+ }
+
+ if (!found)
+ {
+ DBGPRINT(TDI, ERR,
+ ("OpenAddress: REQUEST %lx has no IPX Address\n", Request));
+
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+#ifdef SOCKET_RANGE_OPEN_LIMITATION_REMOVED
+ // Is the socket in our range if its in the range 0x4000-0x7FFF
+ if (IN_RANGE(hostSocket, DYNSKT_RANGE_START, DYNSKT_RANGE_END))
+ {
+ if (!IN_RANGE(
+ hostSocket,
+ PARAM(CONFIG_SOCKET_RANGE_START),
+ PARAM(CONFIG_SOCKET_RANGE_END)))
+ {
+ return(STATUS_INVALID_ADDRESS);
+ }
+ }
+#endif
+
+ // get an address file structure to represent this address.
+ status = SpxAddrFileCreate(Device, Request, &pAddrFile);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ // We checkfor/create sockets within the critical section.
+ if (Socket == 0)
+ {
+ Socket = SpxAddrAssignSocket(Device);
+
+ if (Socket == 0)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("OpenAddress, no unique socket found\n"));
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+ ExReleaseResource (&Device->dev_AddrResource);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+ }
+
+ pAddr = SpxAddrLookup(Device, Socket);
+
+ if (pAddr == NULL)
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // This address doesn't exist. Create it.
+ // registering it. It also puts a ref of type ADDR_FILE on address.
+ pAddr = SpxAddrCreate(
+ Device,
+ Socket);
+
+ if (pAddr != (PSPX_ADDR)NULL)
+ {
+#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,
+ &pAddr->u.sa_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,
+ &pAddr->sa_SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status))
+ {
+ // Error, return status.
+ IoRemoveShareAccess (IrpSp->FileObject, &pAddr->u.sa_ShareAccess);
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ return status;
+ }
+
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // if the adapter isn't ready, we can't do any of this; get out
+#if defined(_PNP_POWER)
+ if (Device->dev_State != DEVICE_STATE_OPEN)
+#else
+ if (Device->dev_State == DEVICE_STATE_STOPPING)
+#endif _PNP_POWER
+ {
+ SpxAddrDereference (pAddr, AREF_ADDR_FILE);
+
+ SpxAddrFileDestroy(pAddrFile);
+ status = STATUS_DEVICE_NOT_READY;
+ }
+ else
+ {
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ status = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+
+ // If the address could not be created, and is not in the process of
+ // being created, then we can't open up an address.
+
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ }
+ else
+ {
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ DBGPRINT(ADDRESS, ERR,
+ ("Add to address %lx\n", pAddr));
+
+ // 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(
+ pAddr->sa_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)
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ 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,
+ &pAddr->u.sa_ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status))
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ SpxAddrFileDestroy(pAddrFile);
+ }
+ else
+ {
+ ExReleaseResource (&Device->dev_AddrResource);
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEGetLock (&pAddr->sa_Lock, &LockHandleAddr);
+
+ pAddrFile->saf_Addr = pAddr;
+ pAddrFile->saf_AddrLock = &pAddr->sa_Lock;
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = IrpSp->FileObject;
+#endif
+ // Set flags appropriately, note spx/stream flags are set at this
+ // point.
+ pAddrFile->saf_Flags &= ~SPX_ADDRFILE_OPENING;
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_OPEN;
+
+ SpxAddrLockReference (pAddr, AREF_ADDR_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)pAddrFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ // Queue in the address list, removed in destroy.
+ pAddrFile->saf_Next = pAddr->sa_AddrFileList;
+ pAddr->sa_AddrFileList = pAddrFile;
+
+ CTEFreeLock (&pAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+ }
+ }
+
+ // Remove the reference from SpxLookupAddress.
+ SpxAddrDereference (pAddr, AREF_LOOKUP);
+ }
+
+ return status;
+
+} // SpxAddrOpen
+
+
+
+
+NTSTATUS
+SpxAddrSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST pRequest
+ )
+{
+ CTELockHandle lockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PSPX_ADDR_FILE
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ PTDI_REQUEST_KERNEL_SET_EVENT
+ pParam = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(pRequest);
+
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(status);
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ switch (pParam->EventType)
+ {
+
+ case TDI_EVENT_ERROR:
+
+ break;
+
+ case TDI_EVENT_CONNECT:
+
+ pSpxAddrFile->saf_ConnHandler =
+ (PTDI_IND_CONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_ConnHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE:
+
+ pSpxAddrFile->saf_RecvHandler =
+ (PTDI_IND_RECEIVE)(pParam->EventHandler);
+ pSpxAddrFile->saf_RecvHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_DISCONNECT:
+
+ pSpxAddrFile->saf_DiscHandler =
+ (PTDI_IND_DISCONNECT)(pParam->EventHandler);
+ pSpxAddrFile->saf_DiscHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+
+ case TDI_EVENT_SEND_POSSIBLE :
+
+ pSpxAddrFile->saf_SendPossibleHandler =
+ (PTDI_IND_SEND_POSSIBLE)(pParam->EventHandler);
+ pSpxAddrFile->saf_SendPossibleHandlerCtx =
+ pParam->EventContext;
+
+ break;
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+ case TDI_EVENT_RECEIVE_EXPEDITED:
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return(status);
+}
+
+
+
+PSPX_ADDR
+SpxAddrCreate(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ Socket - The socket to assign to this address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PSPX_ADDR pAddr;
+ int index;
+ CTELockHandle lockHandle;
+
+ pAddr = (PSPX_ADDR)SpxAllocateZeroedMemory (sizeof(SPX_ADDR));
+ if (pAddr == NULL)
+ {
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx failed\n", (ULONG)Socket));
+
+ return NULL;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address %lx (%lx)\n", pAddr, (ULONG)Socket));
+
+ pAddr->sa_Type = SPX_ADDRESS_SIGNATURE;
+ pAddr->sa_Size = sizeof (SPX_ADDR);
+ pAddr->sa_Flags = 0;
+
+ pAddr->sa_Device = Device;
+ pAddr->sa_DeviceLock = &Device->dev_Lock;
+ CTEInitLock (&pAddr->sa_Lock);
+
+ // This reference is for the address file that will associated with this addr.
+ pAddr->sa_RefCount = 1;
+
+#if DBG
+ pAddr->sa_RefTypes[AREF_ADDR_FILE] = 1;
+#endif
+
+ pAddr->sa_Socket = Socket;
+
+ // Insert address into the device hash table.
+ index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ CTEGetLock (&Device->dev_Lock, &lockHandle);
+ pAddr->sa_Next = Device->dev_AddrHashTable[index];
+ Device->dev_AddrHashTable[index] = pAddr;
+ CTEFreeLock (&Device->dev_Lock, lockHandle);
+
+ SpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return pAddr;
+
+} // SpxAddrCreate
+
+
+
+
+NTSTATUS
+SpxAddrFileVerify(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+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 SPX_ADDR_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_ADDR Address;
+
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+
+ try
+ {
+ if ((pAddrFile->saf_Size == sizeof (SPX_ADDR_FILE)) &&
+ (pAddrFile->saf_Type == SPX_ADDRESSFILE_SIGNATURE) )
+ {
+ Address = pAddrFile->saf_Addr;
+
+ if ((Address->sa_Size == sizeof (SPX_ADDR)) &&
+ (Address->sa_Type == SPX_ADDRESS_SIGNATURE) )
+ {
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) == 0)
+ {
+ SpxAddrFileLockReference(pAddrFile, AFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx closing\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: A %lx bad signature\n", Address));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pAddrFile));
+
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxAddrFileVerify: AF %lx exception\n", Address));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxAddrFileVerify
+
+
+
+
+VOID
+SpxAddrDestroy(
+ 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 SpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by SpxDerefAddress. 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.
+
+--*/
+
+{
+ PSPX_ADDR pAddr, *ppAddr;
+ CTELockHandle LockHandle;
+
+ PSPX_ADDR Address = (PSPX_ADDR)Parameter;
+ PDEVICE Device = Address->sa_Device;
+ int index = (int)(Address->sa_Socket & NUM_SPXADDR_HASH_MASK);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address %lx\n", Address));
+
+ SeDeassignSecurity (&Address->sa_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.
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ for (ppAddr = &Device->dev_AddrHashTable[index]; (pAddr = *ppAddr) != NULL;)
+ {
+ if (pAddr == Address)
+ {
+ *ppAddr = pAddr->sa_Next;
+ break;
+ }
+
+ ppAddr = &pAddr->sa_Next;
+ }
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ SpxFreeMemory (Address);
+ SpxDereferenceDevice (Device, DREF_ADDRESS);
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrRef(
+ IN PSPX_ADDR 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->sa_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+
+
+
+
+VOID
+SpxAddrLockRef(
+ IN PSPX_ADDR 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->sa_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ 1,
+ Address->sa_DeviceLock);
+}
+#endif
+
+
+
+
+VOID
+SpxAddrDeref(
+ IN PSPX_ADDR 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
+ SpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &Address->sa_RefCount,
+ (ULONG)-1,
+ Address->sa_DeviceLock);
+
+ //
+ // 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 (oldvalue != 0);
+
+ if (oldvalue == 1)
+ {
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.sa_DestroyAddrQueueItem,
+ SpxAddrDestroy,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.sa_DestroyAddrQueueItem, DelayedWorkQueue);
+#else
+ SpxAddrDestroy(Address);
+#endif
+
+ }
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCreate(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ OUT PSPX_ADDR_FILE * ppAddrFile
+ )
+
+/*++
+
+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.
+
+--*/
+
+{
+ NTSTATUS status;
+ BYTE socketType;
+ CTELockHandle LockHandle;
+ PSPX_ADDR_FILE pAddrFile;
+
+ // What is the address file type?
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType)))
+ {
+ return(status);
+ }
+
+ pAddrFile = (PSPX_ADDR_FILE)SpxAllocateZeroedMemory (sizeof(SPX_ADDR_FILE));
+ if (pAddrFile == NULL)
+ {
+ DBGPRINT(ADDRESS, ERR,
+ ("Create address file failed\n"));
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Create address file %lx\n", pAddrFile));
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ pAddrFile->saf_Type = SPX_ADDRESSFILE_SIGNATURE;
+ pAddrFile->saf_Size = sizeof (SPX_ADDR_FILE);
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject = NULL;
+#endif
+
+ pAddrFile->saf_Device = Device;
+ pAddrFile->saf_Flags = SPX_ADDRFILE_OPENING;
+ if ((socketType == SOCKET1_TYPE_SEQPKT) ||
+ (socketType == SOCKET1_TYPE_STREAM))
+ {
+ if (socketType == SOCKET1_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM))
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_SPX2;
+ if (socketType == SOCKET2_TYPE_STREAM)
+ {
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_STREAM;
+ }
+ }
+
+ pAddrFile->saf_RefCount = 1;
+
+#if DBG
+ pAddrFile->saf_RefTypes[AFREF_CREATE] = 1;
+#endif
+
+ pAddrFile->saf_CloseReq = (PREQUEST)NULL;
+
+ // Initialize the request handlers.
+ pAddrFile->saf_ConnHandler =
+ pAddrFile->saf_ConnHandlerCtx = NULL;
+ pAddrFile->saf_DiscHandler =
+ pAddrFile->saf_DiscHandlerCtx = NULL;
+ pAddrFile->saf_RecvHandler =
+ pAddrFile->saf_RecvHandlerCtx = NULL;
+ pAddrFile->saf_ErrHandler =
+ pAddrFile->saf_ErrHandlerCtx = NULL;
+
+ // Release lock
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+
+ // Put in the global list for our reference
+ spxAddrInsertIntoGlobalList(pAddrFile);
+
+ *ppAddrFile = pAddrFile;
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileDestroy(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+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 SpxAddrFileDereference. 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:
+
+ pAddrFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PSPX_ADDR Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ PSPX_ADDR_FILE pRemAddr, *ppRemAddr;
+
+ DBGPRINT(ADDRESS, INFO,
+ ("Destroy address file %lx\n", pAddrFile));
+
+ Address = pAddrFile->saf_Addr;
+ Device = pAddrFile->saf_Device;
+
+ if (Address)
+ {
+ CTEGetLock (&Device->dev_Lock, &LockHandle1);
+
+ // This addressfile was associated with an address.
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ // If the last reference on the address is being removed, set the
+ // closing flag to prevent further references.
+
+ //if (Address->sa_RefCount == 1)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&Address->sa_RefCount, 0, &Address->sa_Lock) == 1) {
+ Address->sa_Flags |= SPX_ADDR_CLOSING;
+ }
+
+ // Dequeue the address file from the address list.
+ for (ppRemAddr = &Address->sa_AddrFileList; (pRemAddr = *ppRemAddr) != NULL;)
+ {
+ if (pRemAddr == pAddrFile)
+ {
+ *ppRemAddr = pRemAddr->saf_Next;
+ break;
+ }
+
+ ppRemAddr = &pRemAddr->saf_Next;
+ }
+
+ pAddrFile->saf_Addr = NULL;
+
+#ifdef ISN_NT
+ pAddrFile->saf_FileObject->FsContext = NULL;
+ pAddrFile->saf_FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ CTEFreeLock (&Device->dev_Lock, LockHandle1);
+
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+ // Now dereference the owning address.
+ SpxAddrDereference(Address, AREF_ADDR_FILE);
+ }
+
+ // Save this for later completion.
+ CloseRequest = pAddrFile->saf_CloseReq;
+
+ // Remove from the global list
+ spxAddrRemoveFromGlobalList(pAddrFile);
+
+ // return the addressFile to the pool of address files
+ SpxFreeMemory (pAddrFile);
+
+ if (CloseRequest != (PREQUEST)NULL)
+ {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ SpxCompleteRequest (CloseRequest);
+ SpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxAddrFileRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+} // SpxRefAddressFile
+
+
+
+
+VOID
+SpxAddrFileLockRef(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pAddrFile->saf_RefCount > 0); // not perfect, but...
+ (VOID)SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ 1,
+ pAddrFile->saf_AddrLock);
+
+}
+#endif
+
+
+
+
+VOID
+SpxAddrFileDeref(
+ IN PSPX_ADDR_FILE pAddrFile
+ )
+
+/*++
+
+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
+ SpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ pAddrFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = SPX_ADD_ULONG (
+ &pAddrFile->saf_RefCount,
+ (ULONG)-1,
+ pAddrFile->saf_AddrLock);
+
+ // 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 (oldvalue > 0);
+
+ if (oldvalue == 1)
+ {
+ SpxAddrFileDestroy(pAddrFile);
+ }
+
+}
+
+
+
+
+PSPX_ADDR
+SpxAddrLookup(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+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.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ SpxAddrLockReference(Address, AREF_LOOKUP);
+ return Address;
+
+ }
+ }
+
+ // The specified address was not found.
+ return NULL;
+
+}
+
+
+
+
+BOOLEAN
+SpxAddrExists(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ Socket - The socket to look up.
+
+Return Value:
+
+ TRUE if so, else FALSE
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ int index = (int)(Socket & NUM_SPXADDR_HASH_MASK);
+
+ for (Address = Device->dev_AddrHashTable[index];
+ Address != NULL;
+ Address = Address->sa_Next)
+ {
+ if ((Address->sa_Flags & SPX_ADDR_CLOSING) != 0)
+ {
+ continue;
+ }
+
+ if (Address->sa_Socket == Socket)
+ {
+ // We found the match
+ return TRUE;
+ }
+ }
+
+ // The specified address was not found.
+ return FALSE;
+
+} // SpxAddrExists
+
+
+
+
+NTSTATUS
+SpxAddrConnByRemoteIdAddrLock(
+ IN PSPX_ADDR pSpxAddr,
+ IN USHORT SrcConnId,
+ IN PBYTE SrcIpxAddr,
+ OUT PSPX_CONN_FILE *ppSpxConnFile
+ )
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ NTSTATUS status = STATUS_INVALID_CONNECTION;
+
+ for (pSpxConnFile = pSpxAddr->sa_ActiveConnList;
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_Next)
+ {
+ if ((pSpxConnFile->scf_RemConnId == SrcConnId) &&
+ (*((UNALIGNED ULONG *)SrcIpxAddr) ==
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+4) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4)) &&
+ (*(UNALIGNED ULONG *)(SrcIpxAddr+8) ==
+ *(UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+8)))
+ {
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ *ppSpxConnFile = pSpxConnFile;
+ status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileStop(
+ IN PSPX_ADDR_FILE pAddrFile,
+ IN PSPX_ADDR Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an pAddrFile 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:
+
+ pAddrFile - 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.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile, pSpxConnFileNext;
+ CTELockHandle LockHandle;
+
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileStop: %lx\n", pAddrFile));
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+
+ if (pAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING)
+ {
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+ }
+
+ pAddrFile->saf_Flags |= SPX_ADDRFILE_CLOSING;
+
+ pSpxConnFileNext = NULL;
+ if (pSpxConnFile = pAddrFile->saf_AssocConnList)
+ {
+ pSpxConnFileNext = pSpxConnFile;
+ SpxConnFileReference(pSpxConnFile, CFREF_ADDR);
+ }
+
+ while (pSpxConnFile)
+ {
+ if (pSpxConnFileNext = pSpxConnFile->scf_AssocNext)
+ {
+ SpxConnFileReference(pSpxConnFileNext, CFREF_ADDR);
+ }
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxAddrFileClose: Assoc conn stop %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ CTEGetLock (&Address->sa_Lock, &LockHandle);
+ pSpxConnFile = pSpxConnFileNext;
+ }
+
+ CTEFreeLock (&Address->sa_Lock, LockHandle);
+ return STATUS_SUCCESS;
+
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+/*++
+
+Routine Description:
+
+
+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.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, INFO,
+ ("SpxAddrFileCleanup: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ SpxAddrFileStop(pSpxAddrFile, Address);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_SUCCESS;
+}
+
+
+
+
+NTSTATUS
+SpxAddrFileClose(
+ 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.
+
+--*/
+
+{
+ PSPX_ADDR Address;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ NTSTATUS status;
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ DBGPRINT(ADDRESS, DBG,
+ ("SpxAddrFileClose: %lx\n", pSpxAddrFile));
+
+ status = SpxAddrFileVerify(pSpxAddrFile);
+
+ if (!NT_SUCCESS (status))
+ {
+ return(status);
+ }
+
+ pSpxAddrFile->saf_CloseReq = Request;
+
+ // We assume that addressFile has already been verified
+ // at this point.
+ Address = pSpxAddrFile->saf_Addr;
+ CTEAssert (Address);
+
+ // Remove us from the access info for this address.
+ ExAcquireResourceExclusive (&Device->dev_AddrResource, TRUE);
+
+#ifdef ISN_NT
+ IoRemoveShareAccess (pSpxAddrFile->saf_FileObject, &Address->u.sa_ShareAccess);
+#endif
+
+ ExReleaseResource (&Device->dev_AddrResource);
+
+
+ SpxAddrFileDereference (pSpxAddrFile, AFREF_CREATE);
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ return STATUS_PENDING;
+
+} // SpxCloseAddressFile
+
+
+
+
+USHORT
+SpxAddrAssignSocket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assigns a socket that is unique within a range
+ of SocketUniqueness.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+Return Value:
+
+ The assigned socket number, or 0 if a unique one cannot
+ be found.
+
+--*/
+
+{
+ BOOLEAN wrapped = FALSE;
+ USHORT temp, Socket;
+
+ // We have to auto-assign a socket.
+ temp = Device->dev_CurrentSocket;
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ while (TRUE)
+ {
+ Device->dev_CurrentSocket += (USHORT)PARAM(CONFIG_SOCKET_UNIQUENESS);
+ if (Device->dev_CurrentSocket > PARAM(CONFIG_SOCKET_RANGE_END))
+ {
+ Device->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+ wrapped = TRUE;
+ }
+
+ if (!SpxAddrExists (Device, Socket))
+ {
+ break;
+ }
+
+ PUTSHORT2SHORT(
+ &Socket,
+ Device->dev_CurrentSocket);
+
+ if (wrapped && (Device->dev_CurrentSocket >= temp))
+ {
+ // If we have checked all possible values given SOCKET_UNIQUENESS...
+ // This may actually return ERROR even if there are
+ // available socket numbers although they may be
+ // implicitly in use due to SOCKET_UNIQUENESS being
+ // > 1. That is the way it is to work.
+
+ Socket = 0;
+ break;
+ }
+ }
+
+ DBGPRINT(ADDRESS, INFO,
+ ("OpenAddress, assigned socket %lx\n", Socket));
+
+ return(Socket);
+}
+
+
+
+
+VOID
+spxAddrInsertIntoGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxAddrFile->saf_GlobalNext = SpxGlobalAddrList;
+ SpxGlobalAddrList = pSpxAddrFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxAddrRemoveFromGlobalList(
+ IN PSPX_ADDR_FILE pSpxAddrFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_ADDR_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalAddrList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxAddrFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxAddrRemoveFromGlobal: %lx\n", pSpxAddrFile));
+
+ // Remove from list
+ *ppC = pC->saf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->saf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_ADDRESS;
+
+ return(status);
+}
+
+
+
+
diff --git a/private/ntos/tdi/isn/spx/spxbind.c b/private/ntos/tdi/isn/spx/spxbind.c
new file mode 100644
index 000000000..ba46eb7a9
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxbind.c
@@ -0,0 +1,602 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxbind.c
+
+Abstract:
+
+ This module contains the code to bind to the IPX transport, as well as the
+ indication routines for the IPX transport not including the send/recv ones.
+
+Author:
+
+ Stefan Solomon (stefans) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXBIND
+
+VOID
+SpxStatus (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry);
+
+VOID
+SpxLineDown (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext);
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData);
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// globals and externs
+//
+extern CTELock spxTimerLock;
+extern LARGE_INTEGER spxTimerTick;
+extern KTIMER spxTimer;
+extern KDPC spxTimerDpc;
+extern BOOLEAN spxTimerStopped;
+#endif _PNP_POWER
+
+NTSTATUS
+SpxInitBindToIpx(
+ VOID
+ )
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK ioStatusBlock;
+ OBJECT_ATTRIBUTES objectAttr;
+ PIPX_INTERNAL_BIND_INPUT pBindInput;
+ PIPX_INTERNAL_BIND_OUTPUT pBindOutput;
+
+ InitializeObjectAttributes(
+ &objectAttr,
+ &IpxDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = NtCreateFile(
+ &IpxHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &objectAttr,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ if ((pBindInput = CTEAllocMem(sizeof(IPX_INTERNAL_BIND_INPUT))) == NULL) {
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Fill in our bind data
+#if defined(_PNP_POWER)
+ pBindInput->Version = ISN_VERSION;
+#else
+ pBindInput->Version = 1;
+#endif _PNP_POWER
+ pBindInput->Identifier = IDENTIFIER_SPX;
+ pBindInput->BroadcastEnable = FALSE;
+ pBindInput->LookaheadRequired = IPX_HDRSIZE;
+ pBindInput->ProtocolOptions = 0;
+ pBindInput->ReceiveHandler = SpxReceive;
+ pBindInput->ReceiveCompleteHandler = SpxReceiveComplete;
+ pBindInput->StatusHandler = SpxStatus;
+ pBindInput->SendCompleteHandler = SpxSendComplete;
+ pBindInput->TransferDataCompleteHandler = SpxTransferDataComplete;
+ pBindInput->FindRouteCompleteHandler = SpxFindRouteComplete;
+ pBindInput->LineUpHandler = SpxLineUp;
+ pBindInput->LineDownHandler = SpxLineDown;
+ pBindInput->ScheduleRouteHandler = SpxScheduleRoute;
+#if defined(_PNP_POWER)
+ pBindInput->PnPHandler = SpxPnPNotification;
+#endif _PNP_POWER
+
+
+ // First get the length for the output buffer.
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ NULL, // Output Buffer
+ 0);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ if ((pBindOutput = CTEAllocMem(ioStatusBlock.Information)) == NULL) {
+ CTEFreeMem(pBindInput);
+ NtClose(IpxHandle);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ status = NtDeviceIoControlFile(
+ IpxHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &ioStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ pBindInput, // Input Buffer
+ sizeof(IPX_INTERNAL_BIND_INPUT), // Input Buffer Length
+ pBindOutput, // Output Buffer
+ ioStatusBlock.Information);
+
+ if (status == STATUS_PENDING) {
+ status = NtWaitForSingleObject(
+ IpxHandle,
+ (BOOLEAN)FALSE,
+ NULL);
+ }
+
+ if (status == STATUS_SUCCESS) {
+
+ // Get all the info from the bind output buffer and save in
+ // appropriate places.
+ IpxLineInfo = pBindOutput->LineInfo;
+ IpxMacHdrNeeded = pBindOutput->MacHeaderNeeded;
+ IpxInclHdrOffset = pBindOutput->IncludedHeaderOffset;
+
+ IpxSendPacket = pBindOutput->SendHandler;
+ IpxFindRoute = pBindOutput->FindRouteHandler;
+ IpxQuery = pBindOutput->QueryHandler;
+ IpxTransferData = pBindOutput->TransferDataHandler;
+
+#if !defined(_PNP_POWER)
+ // Copy over the network node info.
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ pBindOutput->Network,
+ IPX_NET_LEN);
+
+ RtlCopyMemory(
+ SpxDevice->dev_Node,
+ pBindOutput->Node,
+ IPX_NODE_LEN);
+
+
+ DBGPRINT(TDI, INFO,
+ ("SpxInitBindToIpx: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // Find out how many adapters IPX has, if this fails
+ // just assume one.
+ //
+
+ if ((*IpxQuery)(
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ 0,
+ &SpxDevice->dev_Adapters,
+ sizeof(USHORT),
+ NULL) != STATUS_SUCCESS) {
+
+ SpxDevice->dev_Adapters = 1;
+
+ }
+#endif !_PNP_POWER
+ } else {
+
+ NtClose(IpxHandle);
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeMem(pBindInput);
+ CTEFreeMem(pBindOutput);
+
+ return status;
+}
+
+
+
+
+VOID
+SpxUnbindFromIpx(
+ VOID
+ )
+
+{
+ NtClose(IpxHandle);
+ return;
+}
+
+
+
+
+VOID
+SpxStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxStatus: CALLED WITH %lx\n",
+ GeneralStatus));
+
+ return;
+}
+
+
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+{
+ CTELockHandle lockHandle;
+ PSPX_FIND_ROUTE_REQUEST pSpxFrReq = (PSPX_FIND_ROUTE_REQUEST)FindRouteRequest;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)pSpxFrReq->fr_Ctx;
+
+ // This will be on a connection. Grab the lock, check the state and go from
+ // there.
+ if (pSpxConnFile == NULL)
+ {
+ // Should this ever happen?
+ KeBugCheck(0);
+ return;
+ }
+
+ // Check the state. The called routines release the lock, remove the reference.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ // We are doing an active connect!
+ SpxConnConnectFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+ else // For all others call active
+ {
+ SpxConnActiveFindRouteComplete(
+ pSpxConnFile,
+ pSpxFrReq,
+ FoundRoute,
+ lockHandle);
+ }
+
+ // Free the find route request.
+ SpxFreeMemory(pSpxFrReq);
+
+ return;
+}
+
+
+
+
+VOID
+SpxLineUp (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+{
+ // With PnP, our local address is changed when we get PnP
+ // notification.
+#if !defined(_PNP_POWER)
+
+ //
+ // If we get a line up for NicId 0, it means our local
+ // network number has changed, re-query from IPX.
+ //
+
+ if (NicId == 0) {
+
+ TDI_ADDRESS_IPX IpxAddress;
+
+ if ((*IpxQuery)(
+ IPX_QUERY_IPX_ADDRESS,
+ 0,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ RtlCopyMemory(
+ SpxDevice->dev_Network,
+ &IpxAddress.NetworkAddress,
+ IPX_NET_LEN);
+
+ DBGPRINT(TDI, INFO,
+ ("SpxLineUp: Ipx Net %lx\n",
+ *(UNALIGNED ULONG *)SpxDevice->dev_Network));
+
+ //
+ // The node shouldn't change!
+ //
+
+ if (!RtlEqualMemory(
+ SpxDevice->dev_Node,
+ IpxAddress.NodeAddress,
+ IPX_NODE_LEN)) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxLineUp: Node address has changed\n"));
+ }
+ }
+
+ } else {
+
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineUp: CALLED WITH %lx\n",
+ NicId));
+ }
+
+ return;
+#endif !_PNP_POWER
+
+}
+
+
+
+
+VOID
+SpxLineDown (
+ IN USHORT NicId,
+ IN ULONG FwdAdapterContext
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxLineDown: CALLED WITH %lx\n",
+ NicId));
+
+ return;
+}
+
+
+
+
+VOID
+SpxScheduleRoute (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+{
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxScheduleRoute: CALLED WITH %lx\n",
+ RouteEntry));
+
+ return;
+}
+
+#if defined(_PNP_POWER)
+VOID
+SpxPnPNotification(
+ 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.
+
+--*/
+
+{
+
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+ PDEVICE Device = SpxDevice;
+ UNICODE_STRING UnicodeDeviceName;
+
+ DBGPRINT(DEVICE, DBG,("Received a pnp notification, opcode %d\n",OpCode));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ CTELockHandle TimerLockHandle;
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->dev_State != DEVICE_STATE_OPEN );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ //
+ // Start the timer. It is possible that the timer
+ // was still running or we are still in the timer dpc
+ // from the previous ADD_DEVICE - DELETE_DEVICE execution
+ // cycle. But it is ok simply restart this, because
+ // KeSetTimer implicitly cancels the previous Dpc.
+ //
+
+ CTEGetLock(&spxTimerLock, &TimerLockHandle);
+ spxTimerStopped = FALSE;
+ CTEFreeLock(&spxTimerLock, TimerLockHandle);
+ KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+
+ Device->dev_State = DEVICE_STATE_OPEN;
+
+
+ CTEAssert( !Device->dev_Adapters );
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ IpxLineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumPacketSize;
+ // set the provider info
+ SpxDevice->dev_ProviderInfo.MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }else {
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+ }
+
+ Device->dev_Adapters++;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->dev_DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->dev_DeviceNameLen;
+ UnicodeDeviceName.Length = Device->dev_DeviceNameLen - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to register Spx Device with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ CTEAssert( Device->dev_Adapters );
+ Device->dev_Adapters--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->dev_State = DEVICE_STATE_LOADED;
+ Device->dev_Adapters = 0;
+ }
+
+ IpxLineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ CTEFreeLock ( &Device->dev_Lock, LockHandle );
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ SpxTimerFlushAndStop();
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->dev_TdiRegistrationHandle ) )) {
+ DBGPRINT(TDI,ERR, ("Failed to Deregister Spx Device with TDI\n"));
+ }
+ }
+ //
+ // TBD: call ExNotifyCallback
+ //
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ *(UNALIGNED ULONG *)Device->dev_Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->dev_Node, PnPInfo->NodeAddress, 6);
+
+ CTEFreeLock ( &Device->dev_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/spx/spxconn.c b/private/ntos/tdi/isn/spx/spxconn.c
new file mode 100644
index 000000000..0c139fbc7
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxconn.c
@@ -0,0 +1,3851 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxconn.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, SpxConnOpen)
+#pragma alloc_text(PAGE, SpxConnCleanup)
+#pragma alloc_text(PAGE, SpxConnClose)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXCONN
+
+VOID
+SpxFindRouteComplete (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute);
+
+
+NTSTATUS
+SpxConnOpen(
+ IN PDEVICE pDevice,
+ IN CONNECTION_CONTEXT ConnCtx,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create a connection object and associate the
+ passed ConnectionContext with it.
+
+Arguments:
+
+ pConnCtx - The TDI ConnectionContext to be associated with object
+
+Return Value:
+
+ STATUS_SUCCESS if connection was successfully opened
+ Error otherwise.
+
+--*/
+
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PSPX_CONN_FILE pSpxConnFile;
+
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)pRequest;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+
+ // Allocate memory for a connection object
+ if ((pSpxConnFile = SpxAllocateZeroedMemory(sizeof(SPX_CONN_FILE))) == NULL)
+ {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ // Initialize values
+ pSpxConnFile->scf_Flags = 0;
+ pSpxConnFile->scf_Type = SPX_CONNFILE_SIGNATURE;
+ pSpxConnFile->scf_Size = sizeof (SPX_CONN_FILE);
+
+ CTEInitLock (&pSpxConnFile->scf_Lock);
+
+ pSpxConnFile->scf_ConnCtx = ConnCtx;
+ pSpxConnFile->scf_Device = pDevice;
+
+ // Initialize list for requests.
+ InitializeListHead(&pSpxConnFile->scf_ReqLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvLinkage);
+ InitializeListHead(&pSpxConnFile->scf_RecvDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_ReqDoneLinkage);
+ InitializeListHead(&pSpxConnFile->scf_DiscLinkage);
+
+#ifdef ISN_NT
+ // easy backlink to file object.
+ pSpxConnFile->scf_FileObject = IrpSp->FileObject;
+#endif
+
+ // For connections we go from 0->0 with flags indicating if a close
+ // happened.
+ pSpxConnFile->scf_RefCount = 0;
+
+ // Insert into a global connection list.
+ spxConnInsertIntoGlobalList(pSpxConnFile);
+
+#if DBG
+
+ // Initialize this to 0xFFFF so we dont hit assert on first packet.
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+
+#endif
+
+ // Set values in the request.
+ REQUEST_OPEN_CONTEXT(pRequest) = (PVOID)pSpxConnFile;
+ REQUEST_OPEN_TYPE(pRequest) = (PVOID)TDI_CONNECTION_FILE;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnOpen: Opened %lx\n", pSpxConnFile));
+
+ ASSERT(status == STATUS_SUCCESS);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnCleanup(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+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 connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileCleanup: %lx.%lx when %lx\n",
+ pSpxConnFile, Request, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CleanupReq = Request;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // We have a reference, so it wont go to zero until stop returns. Therefore
+ // deref can expect flag to be set.
+ SpxConnStop(pSpxConnFile);
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+
+ //
+ // If this is a connection which is waiting for a local disconnect,
+ // deref it since we dont expect a disconnect after a cleanup.
+ //
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ KdPrint(("Deref for DISCWAIT on connfile: %lx\n", pSpxConnFile));
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_DISCWAITSPX);
+ } else {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+
+ return STATUS_PENDING;
+}
+
+
+
+
+NTSTATUS
+SpxConnClose(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+
+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 connection
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ DBGBRK(FATAL);
+ return (status);
+ }
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileClose: %lx when %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ pSpxConnFile->scf_CloseReq = Request;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ SpxConnFileDereference (pSpxConnFile, CFREF_VERIFY);
+ return STATUS_PENDING;
+}
+
+
+
+
+VOID
+SpxConnStop(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!!Connection must have a reference when this is called!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ CTELockHandle lockHandle;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnFileStop: %lx when %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags));
+
+ // Call disconnect and disassociate
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ }
+ else
+ {
+ // Disassociate if we are associated.
+ spxConnDisAssoc(pSpxConnFile, lockHandle);
+ }
+
+ // Lock released at this point.
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine moves the connection from the device list to the inactive
+ connection list in the address of the address file specified. The address
+ file is pointed to by the connection and is referenced for the associate.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ CTELockHandle lockHandle1, lockHandle2;
+
+ BOOLEAN derefAddr = FALSE, derefConn = FALSE;
+ PFILE_OBJECT pFileObj = NULL;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+ HANDLE AddrObjHandle =
+ ((PTDI_REQUEST_KERNEL_ASSOCIATE)(REQUEST_PARAMETERS(pRequest)))->AddressHandle;
+
+ do
+ {
+ // Get the handle to the address object from the irp and map it to
+ // the corres. file object.
+ status = ObReferenceObjectByHandle(
+ AddrObjHandle,
+ 0,
+ 0,
+ KernelMode,
+ (PVOID *)&pFileObj,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ break;
+
+ pSpxAddrFile = pFileObj->FsContext;
+ ASSERT(pFileObj->FsContext2 == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ // Verify address file/connection file
+ if ((status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ break;
+
+ derefAddr = TRUE;
+
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ break;
+
+ derefConn = TRUE;
+
+ // Grab the addres file lock, then the connection lock for associate.
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ if (!SPX_CONN_FLAG(pSpxConnFile, (SPX_CONNFILE_CLOSING |
+ SPX_CONNFILE_STOPPING |
+ SPX_CONNFILE_ASSOC))
+ &&
+ !(pSpxAddrFile->saf_Flags & SPX_ADDRFILE_CLOSING))
+ {
+ derefAddr = FALSE;
+ SpxAddrFileTransferReference(
+ pSpxAddrFile, AFREF_VERIFY, AFREF_CONN_ASSOC);
+
+ // Queue in the inactive list in the address
+ pSpxConnFile->scf_Next = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxAddrFile->saf_Addr->sa_InactiveConnList = pSpxConnFile;
+
+ // Queue in the assoc list in the address file
+ pSpxConnFile->scf_AssocNext = pSpxAddrFile->saf_AssocConnList;
+ pSpxAddrFile->saf_AssocConnList = pSpxConnFile;
+
+ // Remember the addrfile in the connection
+ pSpxConnFile->scf_AddrFile = pSpxAddrFile;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ status = STATUS_SUCCESS;
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnAssociate: %lx with address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandle1);
+
+ // Dereference the file object corres. to the address object
+ ObDereferenceObject(pFileObj);
+
+ } while (FALSE);
+
+ if (derefAddr)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ if (derefConn)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisAssociate(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Verify connection file
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return (status);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile)
+ ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ SpxConnStop(pSpxConnFile);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnDisAssoc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CTELockHandle lockHandleAddr;
+ PSPX_ADDR_FILE pSpxAddrFile;
+
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Unlink it if ok.
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Check again as we had released the lock
+ if (SPX_CONN_IDLE(pSpxConnFile)
+ &&
+ (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC)))
+ {
+ pSpxConnFile->scf_AddrFile = NULL;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDisAssociate: %lx from address file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ if (NT_SUCCESS(status))
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ BUGBUG:
+ We need to have another timer that will be started on the connection
+ if the tdi client indicated a timeout value. 0 -> we do not start such
+ a timer, -1 implies, we let our connection timeout values do their thing.
+ Any other value will forcibly shutdown the connect process, when the timer
+ fires.
+
+Return Value:
+
+
+--*/
+
+{
+ PTDI_REQUEST_KERNEL_CONNECT pParam;
+ TDI_ADDRESS_IPX UNALIGNED * pTdiAddr;
+ PNDIS_PACKET pCrPkt;
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_ADDR pSpxAddr;
+ BOOLEAN locksHeld = TRUE;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Unpack the connect parameters
+ pParam = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(pRequest);
+ pTdiAddr= SpxParseTdiAddress(
+ pParam->RequestConnectionInformation->RemoteAddress);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: Remote SOCKET %lx on %lx.%lx\n",
+ pTdiAddr->Socket,
+ pSpxConnFile,
+ pRequest));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ do
+ {
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SPX2 requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: SOCK_STREAM requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ if (pFindRouteReq)
+ {
+ SpxFreeMemory(pFindRouteReq);
+ }
+
+ return(status);
+ }
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile) &&
+ ((pSpxConnFile->scf_LocalConnId = spxConnGetId()) != 0))
+ {
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_CONNECTING);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+
+ // Move connection from inactive list to non-inactive list.
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+
+ // Put connection in the non-inactive list. Connection id must be set.
+ SPX_INSERT_ADDR_ACTIVE(
+ pSpxAddr,
+ pSpxConnFile);
+
+ // Insert in the global connection tree on device
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ // Store the remote address in the connection.
+ // !!NOTE!! We get both the network/socket in network form.
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) =
+ *((UNALIGNED ULONG *)(&pTdiAddr->NetworkAddress));
+
+ RtlCopyMemory(
+ pSpxConnFile->scf_RemAddr+4,
+ pTdiAddr->NodeAddress,
+ 6);
+
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10)) =
+ *((UNALIGNED USHORT *)(&pTdiAddr->Socket));
+
+ // Ok, we are all set, build connect packet, queue it into connection
+ // with the connect request. Ndis buffer already describes this memory
+ // Build IPX header.
+
+ pCrPkt = NULL; // so it knows to allocate one.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrPkt,
+ SPX_SENDPKT_IDLE,
+ SPX2_CONN(pSpxConnFile));
+
+ if (pCrPkt != NULL)
+ {
+ // Remember the request in the connection
+ //
+ // Dont queue for the failure case since we complete it in SpxInternalDispatch.
+ //
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrPkt);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pIpxSpxHdr->hdr_DestNode, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNode);
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pIpxSpxHdr->hdr_DestNode+4));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pIpxSpxHdr->hdr_DestNet)));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnConnect: NODE %02x-%02x-%02x-%02x-%02x-%02x\n",
+ pFindRouteReq->fr_FindRouteReq.Node[0], pFindRouteReq->fr_FindRouteReq.Node[1],
+ pFindRouteReq->fr_FindRouteReq.Node[2], pFindRouteReq->fr_FindRouteReq.Node[3],
+ pFindRouteReq->fr_FindRouteReq.Node[4], pFindRouteReq->fr_FindRouteReq.Node[5]));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier = IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // We wont force a rip for every connection. Only if its not
+ // in the IPX database.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ // Reference for the find route. So that abort connect wont
+ // free up the connection until we return from here.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Abort connect attempt.
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ CTEAssert(pSpxConnFile->scf_ConnectReq == NULL);
+
+ locksHeld = FALSE;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // Start off the find route request, We send the packet in completion.
+ // The verify reference is kept until the connect request completes.
+ // If connecting to network 0 we don't do this, proceed to find
+ // route completion which will send the request on very card.
+
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ SpxFindRouteComplete(
+ &pFindRouteReq->fr_FindRouteReq,
+ TRUE);
+
+ } else {
+
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: Failed %lx\n", status));
+
+ SpxFreeMemory(pFindRouteReq);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnListen(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ We assume the connection passed in is already associated with an address.
+ If it is not, we will die! Is that ok?
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle1, lockHandle2;
+ PSPX_ADDR pSpxAddr;
+
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Check if connection is associated, if so, the association cannot
+ // go away until the reference above is removed. So we are safe in
+ // releasing the lock.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_ADDRESS;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_SPX2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnect: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxConnFile->scf_AddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+
+ if (NT_SUCCESS(status))
+ {
+ CTEGetLock(&pSpxAddr->sa_Lock, &lockHandle1);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle2);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_IDLE(pSpxConnFile))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+
+ // Move connection from inactive list to listening list.
+ if (NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile)))
+ {
+ // Put connection in the listening list.
+ SPX_INSERT_ADDR_LISTEN(pSpxAddr, pSpxConnFile);
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // This should never happen!
+ KeBugCheck(0);
+ }
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle2);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle1);
+ }
+
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAccept(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_ADDR pSpxAddr;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: %lx\n", pSpxConnFile));
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return (status);
+ }
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ status = STATUS_SUCCESS;
+ pSpxAddr = pSpxConnFile->scf_AddrFile->saf_Addr;
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (NT_SUCCESS(status))
+ {
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ status = STATUS_INVALID_CONNECTION;
+ if ((SPX_CONN_LISTENING(pSpxConnFile)) &&
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_RECDREQ))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Call acceptcr now.
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnAccept: Accepted\n"));
+
+ status = STATUS_PENDING;
+ }
+ else
+ {
+ // Free all locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+ }
+
+ // Remove reference. Note: Listen reference will exist if ok. And that will
+ // be transferred to the fact that the connection is active when accepted.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnDisconnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+ If active, we do the following.
+ If informative disconnect, just remember the request in the connection.
+ We do not ref for request. Assume it will always be checked for when
+ changing from disconnect to idle.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ SPX_SENDREQ_TYPE reqType;
+ int numDerefs = 0;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ // Deref unless the disc request gets queued in as a send request.
+ numDerefs++;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnDisconnect: %lx On %lx when %lx.%lx %lx Params %lx\n",
+ pRequest, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile),
+ SPX_DISC_STATE(pSpxConnFile),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC),
+ pParam->RequestFlags));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDisconnect: %lx\n", pSpxConnFile));
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+ switch (pParam->RequestFlags)
+ {
+ case TDI_DISCONNECT_WAIT:
+
+ // If informative disconnect, just remember in the connection.
+ status = STATUS_INVALID_CONNECTION;
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ }
+
+ break;
+
+ case TDI_DISCONNECT_ABORT:
+ case TDI_DISCONNECT_RELEASE:
+
+ // NOTE! We don't honor the async disconnect symantics of tdi
+ // but map them to an abortive disconnect.
+ // NOTE! If our send list is not empty but our client tries to
+ // do a orderly release, we just queue the ord rel as a send
+ // data request. In process ack, we check for the next packet
+ // to not be a ord rel before giving up on window closure.
+ // NOTE! For spx1 connection, map TDI_DISCONNECT_RELEASE to
+ // TDI_DISCONNECT_ABORT (Informed disconnect)
+
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ pParam->RequestFlags = TDI_DISCONNECT_ABORT;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // Since we are not a timer disconnect, then we need to keep
+ // retrying the disconnect packet. Change state to DISCONN if this
+ // is not an orderly release or we previously received an orderly
+ // release and are now confirming it.
+ // Retry timer will now keep sending out the disconnect packet.
+
+ reqType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_ORDREL);
+ reqType = SPX_REQ_ORDREL;
+ }
+ else
+ {
+ // Abortive disconnect
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_POST_IDISC);
+ numDerefs++;
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Abort all receives if we are informed disconnect.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ // Since we released the lock, a remote IDISC could have come
+ // in in which case we really don't want to queue in the disc
+ // request. Instead, we set it as the disc request in the
+ // connection if one is not already there.
+ if (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDisconnect: DISC not POST! %lx.%lx\n",
+ pSpxConnFile, SPX_DISC_STATE(pSpxConnFile)));
+
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+ break;
+ }
+ }
+
+ // !NOTE
+ // AbortSends might leave send requests around as packets might
+ // have been with ipx at the time. That is why SendComplete should
+ // never call AbortSends but must call AbortPkt else it may complete
+ // the following disconnect request prematurely.
+
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = reqType;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // Do not deref the connection, it is taken by the pending request
+ numDerefs--;
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandleConn);
+
+ lockHeld = FALSE;
+ }
+
+ status = STATUS_PENDING;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ status = STATUS_SUCCESS;
+ break;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // When we queue in a disconnect as a send request, we expect
+ // to be able to set it into the scf_DiscReq when it is done.
+ // So we don't use scf_DiscReq here. This will be a problem if
+ // the client has a InformDiscReq pending, and a remote disconnect
+ // comes in, *and* the client then does a disc. We will be completing
+ // the request with STATUS_INVALID_CONNECTION.
+ status = STATUS_INVALID_CONNECTION;
+ if (pParam->RequestFlags != TDI_DISCONNECT_RELEASE)
+ {
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ status = STATUS_PENDING;
+
+ //
+ // If this is a disconnect for a connection which was already
+ // disconnected (but AFD's disconnect handler was not called
+ // because the connfile could not be placed in the inactive list),
+ // set this flag so that the disconnect is not called from
+ // ConnInactivate now that the disconnect has occured here.
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC)) {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // If this was an SPXI connection where we indicated TDI_DISCONNECT_RELEASE
+ // to AFD, the ref count was bumped up to indicate a wait for local disconnect
+ // from AFD. Now that we have this disconnect, deref the connection file. Now
+ // we are ready to truly inactivate this connection file.
+ //
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT)) {
+
+ CTEAssert( (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC));
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX]);
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ lockHeld = FALSE;
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_DISCWAITSPX);
+ }
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDisconnect: returning for %lx.%lx\n", pSpxConnFile, status));
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnSend(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_SEND pParam;
+ NTSTATUS status;
+ CTELockHandle lockHandleConn;
+ BOOLEAN lockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSend: %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pRequest, pParam->SendLength, pParam->SendFlags));
+
+
+ // Check if we are in the correct state and associated.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ DBGPRINT(SEND, INFO,
+ ("Send: %lx.%lx.%lx\n",
+ pParam->SendLength, pParam->SendFlags, pRequest));
+
+ status = STATUS_PENDING;
+ do
+ {
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_POST_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED)))
+ {
+ // Creation reference for request.
+ REQUEST_INFORMATION(pRequest) = 1;
+
+ // If we have no current requests, queue it in and
+ // set it to be the current request, else just queue it in.
+ // There may be other pending requests in queue.
+ if (pSpxConnFile->scf_ReqPkt == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("%lx\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+ else
+ {
+ //
+ // [SA] Bug #14655
+ // Return the correct error message in case a send fails due to remote disconnect
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ status = STATUS_REMOTE_DISCONNECT ;
+ }
+ else
+ {
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ break;
+ }
+
+ // We packetize only upto the window we have.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(pSpxConnFile, TRUE, lockHandleConn);
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+
+ if (lockHeld)
+ {
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnRecv(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ CTELockHandle lockHandle;
+ BOOLEAN fLockHeld;
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ // Check if the connection is in a valid state
+ if ((status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ {
+ return(status);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnReceive: %lx.%lx\n", pSpxConnFile, pRequest));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ status = STATUS_INVALID_CONNECTION;
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ !(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)))
+ {
+ status = STATUS_PENDING;
+
+ // This routine adds its own reference.
+ SpxConnQueueRecv(pSpxConnFile, pRequest);
+
+ // If recv pkt queue is non-empty then we have buffered data. Call
+ // process pkts/receives.
+ if ((SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE) ||
+ (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_POSTED))
+ {
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(status);
+}
+
+
+
+
+NTSTATUS
+SpxConnAction(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS Status;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ CTELockHandle lockHandle;
+ PIPX_SPXCONNSTATUS_DATA pGetStats;
+ PSPX_CONN_FILE pSpxConnFile = NULL;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ 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(pRequest);
+ if (NdisBuffer == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer(
+ REQUEST_NDIS_BUFFER(pRequest), (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])))
+ {
+ DBGPRINT(ACTION, ERR,
+ ("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.
+ switch (NwlinkAction->OptionType)
+ {
+ case NWLINK_OPTION_CONNECTION:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_CONNECTION_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not connection file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxConnFileVerify(pSpxConnFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ case NWLINK_OPTION_ADDRESS:
+
+ if (REQUEST_OPEN_TYPE(pRequest) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
+ {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, not address file\n"));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(pRequest);
+
+ if ((Status = SpxAddrFileVerify(pSpxAddrFile)) != STATUS_SUCCESS)
+ return(Status);
+
+ break;
+
+ default:
+
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action failed, option type %d\n",
+ NwlinkAction->OptionType));
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ // 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;
+
+ DBGPRINT(ACTION, INFO,
+ ("SpxConnAction: Option %x\n", NwlinkAction->Option));
+
+ switch (NwlinkAction->Option)
+ {
+
+ //
+ // This first group support the winsock helper dll.
+ // In most cases the corresponding sockopt is shown in
+ // the comment, as well as the contents of the Data
+ // part of the action buffer.
+ //
+
+ case MSPX_SETDATASTREAM:
+
+ if (pSpxConnFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ if (DataLength >= 1)
+ {
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MIPX_SETSENDPTYPE %x\n",
+ pSpxConnFile, NwlinkAction->Data[0]));
+
+ pSpxConnFile->scf_DataType = NwlinkAction->Data[0];
+ }
+ else
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MSPX_SENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_SENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break ;
+
+ case MSPX_NOSENDHEADER:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_NOSENDHEADER\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_IPXHDR;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_GETSTATS:
+
+ DBGPRINT(ACTION, INFO,
+ ("%lx: MSPX_GETSTATS\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ USHORT TempRetryCount;
+
+ //
+ // Status fields are returned in network order.
+ //
+
+ pGetStats = (PIPX_SPXCONNSTATUS_DATA)&NwlinkAction->Data[0];
+
+ switch (SPX_MAIN_STATE(pSpxConnFile)) {
+ case SPX_CONNFILE_LISTENING: pGetStats->ConnectionState = 1; break;
+ case SPX_CONNFILE_CONNECTING: pGetStats->ConnectionState = 2; break;
+ case SPX_CONNFILE_ACTIVE: pGetStats->ConnectionState = 3; break;
+ case SPX_CONNFILE_DISCONN: pGetStats->ConnectionState = 4; break;
+ default: pGetStats->ConnectionState = 0;
+ }
+ pGetStats->WatchDogActive = 1; // Always 1
+ GETSHORT2SHORT( // scf_LocalConnId is in host order
+ &pGetStats->LocalConnectionId,
+ &pSpxConnFile->scf_LocalConnId);
+ pGetStats->RemoteConnectionId = pSpxConnFile->scf_RemConnId;
+
+ GETSHORT2SHORT(&pGetStats->LocalSequenceNumber, &pSpxConnFile->scf_SendSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAckNumber, &pSpxConnFile->scf_RecvSeqNum);
+ GETSHORT2SHORT(&pGetStats->LocalAllocNumber, &pSpxConnFile->scf_SentAllocNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAckNumber, &pSpxConnFile->scf_RecdAckNum);
+ GETSHORT2SHORT(&pGetStats->RemoteAllocNumber, &pSpxConnFile->scf_RecdAllocNum);
+
+ pGetStats->LocalSocket = pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket;
+
+ RtlZeroMemory(pGetStats->ImmediateAddress, 6);
+
+ // Remote network returned in net order.
+ *((ULONG UNALIGNED *)pGetStats->RemoteNetwork) =
+ *((ULONG UNALIGNED *)pSpxConnFile->scf_RemAddr);
+
+ RtlCopyMemory(
+ pGetStats->RemoteNode,
+ &pSpxConnFile->scf_RemAddr[4],
+ 6);
+
+ pGetStats->RemoteSocket = *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+10));
+
+ TempRetryCount = (USHORT)pSpxConnFile->scf_WRetryCount;
+ GETSHORT2SHORT(&pGetStats->RetransmissionCount, &TempRetryCount);
+ GETSHORT2SHORT(&pGetStats->EstimatedRoundTripDelay, &pSpxConnFile->scf_BaseT1);
+ pGetStats->RetransmittedPackets = 0;
+ pGetStats->SuppressedPacket = 0;
+
+ DBGPRINT(ACTION, INFO,
+ ("SSeq %lx RSeq %lx RecdAck %lx RemAllocNum %lx\n",
+ pGetStats->LocalSequenceNumber,
+ pGetStats->LocalAckNumber,
+ pGetStats->RemoteAckNumber,
+ pGetStats->RemoteAllocNumber));
+
+ DBGPRINT(ACTION, INFO,
+ ("LocalSkt %lx RemSkt %lx LocConnId %lx RemConnId %lx\n",
+ pGetStats->LocalSocket,
+ pGetStats->RemoteSocket,
+ pGetStats->LocalConnectionId,
+ pGetStats->RemoteConnectionId));
+ }
+ else
+ {
+ Status = STATUS_INVALID_CONNECTION;
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ break;
+
+ case MSPX_NOACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_NOACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+ case MSPX_ACKWAIT:
+
+ DBGPRINT(ACTION, ERR,
+ ("%lx: MSPX_ACKWAIT\n", pSpxAddrFile));
+
+ if (pSpxAddrFile == NULL)
+ {
+ Status = STATUS_INVALID_HANDLE;
+ break;
+ }
+
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandle);
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_NOACKWAIT;
+ CTEFreeLock(pSpxAddrFile->saf_AddrLock, lockHandle);
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ // The Option was not supported, so fail.
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (Status != STATUS_SUCCESS) {
+ DBGPRINT(ACTION, ERR,
+ ("Nwlink action %lx failed, status %lx\n",
+ NwlinkAction->Option, Status));
+ }
+
+#endif
+
+ if (pSpxConnFile)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ if (pSpxAddrFile)
+ {
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_VERIFY);
+ }
+
+ return Status;
+}
+
+
+
+
+VOID
+SpxConnConnectFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ ULONG Timeout;
+ NTSTATUS status = STATUS_BAD_NETWORK_PATH;
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pCrPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+#if defined(_PNP_POWER)
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+
+ // Here we are going to send on every NIC ID. We adjust the
+ // timeout down so that a full run through all the NIC IDs will
+ // take one normal timeout. We don't adjust the timer below
+ // 100 ms however.
+
+ Timeout = (PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR) / SpxDevice->dev_Adapters;
+ if (Timeout < (HALFSEC_TO_MS_FACTOR/5)) {
+ Timeout = HALFSEC_TO_MS_FACTOR / 5;
+ }
+
+ } else {
+
+ Timeout = PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR;
+ }
+#endif
+
+
+ // Timeout value is in half-seconds
+ if ((FoundRoute) &&
+ ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ Timeout,
+ pSpxConnFile)) != 0))
+ {
+ // Add a reference for the connect timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+#if 0
+ {
+ int i;
+ char *address = pFrReq->fr_FindRouteReq.LocalTarget.MacAddress;
+
+ DbgPrint("FIND ROUTE LOCALTARGET.MAC:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+
+ address = pSpxConnFile->scf_RemAddr+4;
+ DbgPrint("SPX DESTINATION ADDRESS:\n");
+ for (i= 0; i < 6; i++)
+ {
+ UCHAR ch1, ch2;
+
+ ch1 = ((address[i] >> 4) & 0x0F);
+ if (ch1 > 0x9)
+ {
+ ch1 -= 0xa;
+ ch1 += 'a';
+ }
+ else
+ {
+ ch1 += '0';
+ }
+
+ ch2 = (address[i] & 0x0F);
+ if (ch2 > 0x9)
+ {
+ ch2 -= 0xa;
+ ch2 += 'a';
+ }
+ else
+ {
+ ch2 += '0';
+ }
+
+ DbgPrint("%c%c", ch1, ch2);
+ }
+ DbgPrint("\n");
+ }
+
+ DbgPrint("NIC Id %lx\n", pFrReq->fr_FindRouteReq.LocalTarget.NicId);
+#endif
+
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address. Also if this is a connect to network 0 fill
+ // it in with the destination address, and further down we will loop
+ // through all possible NIC IDs.
+ if (((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ ||
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnConnectFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ // We are all set to go ahead with the connect.
+ // Timer is started on connection
+ status = STATUS_SUCCESS;
+
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT) * SpxDevice->dev_Adapters;
+ } else {
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+#endif _PNP_POWER
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_C_TIMER | SPX_CONNECT_SENTREQ));
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ pSpxConnFile->scf_AckLocalTarget= pFrReq->fr_FindRouteReq.LocalTarget;
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#if defined(_PNP_POWER)
+ pSpxConnFile->scf_LocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+ pSpxConnFile->scf_AckLocalTarget.NicHandle.NicId = (USHORT)ITERATIVE_NIC_ID;
+#else
+ pSpxConnFile->scf_LocalTarget.NicId = 1;
+ pSpxConnFile->scf_AckLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ }
+
+ // We will be giving the packet to ipx.
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pCrPkt, pSendResd);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnConnectFindRouteComplete: FAILED on %lx.%d\n",
+ pSpxConnFile, FoundRoute));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ status,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+ }
+
+ // Remove the reference for the call.
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+VOID
+SpxConnActiveFindRouteComplete(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_FIND_ROUTE_REQUEST pFrReq,
+ IN BOOLEAN FoundRoute,
+ IN CTELockHandle LockHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine is called with the connection lock held and the conn refd.
+ It should deal with both.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fDisconnect = TRUE;
+
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnActiveFindRouteComplete: %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // If we are disconnecting, just remove the reference and exit.
+ if (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE)
+ {
+ fDisconnect = FALSE;
+
+ // We are here if either the wdog or the retry timer did a find
+ // route. We need to save the info from the find route if it was
+ // successful and just restart the timers.
+ if (FoundRoute)
+ {
+ // If the mac address in local target is all zeros, fill it with our
+ // destination address.
+ if ((*((UNALIGNED ULONG *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+2)) == (ULONG)0)
+ &&
+ (*((UNALIGNED USHORT *)
+ (pFrReq->fr_FindRouteReq.LocalTarget.MacAddress+4)) == (USHORT)0))
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnActiveFindRouteComplete: LOCAL NET\n"));
+
+ RtlCopyMemory(
+ pFrReq->fr_FindRouteReq.LocalTarget.MacAddress,
+ pSpxConnFile->scf_RemAddr+4,
+ 6);
+ }
+
+ pSpxConnFile->scf_LocalTarget = pFrReq->fr_FindRouteReq.LocalTarget;
+ }
+
+ // Depending on state restart the wdog or retry timer. Add reference
+ // for it.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRY:
+
+ // Set state to SPX_SEND_RETRYWD
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRYWD);
+
+ // Start retry timer.
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Start watchdog timer.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_IDLE:
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing, remove reference and leave.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnActiveFindRouteComplete: DISCONNECT %lx.%lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // Abortive disc will reset the funky state if necessary.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ SPX_CALL_TDILEVEL,
+ LockHandle,
+ FALSE); // [SA] Bug #15249
+ }
+ else
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_FINDROUTE);
+ return;
+}
+
+
+
+
+ULONG
+spxConnConnectTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ We enter this routine during the connection attempt. We could be at any
+ stage of sending either the CR or the SN packet. If we have reached the end of
+ the retry count, we need to know the substate at that point. For a CR, we give
+ up trying to connect, and for a SN we try the next lower packet size or if we
+ have reached the minimum packet size, we give up the connect.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN fAbort = FALSE, locksHeld = FALSE, sendPkt = FALSE;
+ PREQUEST pRequest = NULL;
+
+ // Get all locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnConnectTimer: Entered\n"));
+
+ do
+ {
+ if ((!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER)) ||
+ (!SPX_CONN_CONNECTING(pSpxConnFile) &&
+ !SPX_CONN_LISTENING(pSpxConnFile)))
+ {
+ TimerShuttingDown = TRUE;
+ }
+
+ if (TimerShuttingDown)
+ {
+ break;
+ }
+
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // There should be only one packet in list, the cr.
+ CTEAssert(pSpxConnFile->scf_SendListHead ==
+ pSpxConnFile->scf_SendListTail);
+
+ pSendResd = pSpxConnFile->scf_SendListHead;
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd,
+ NDIS_PACKET,
+ ProtocolReserved);
+
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // No luck, we need to complete connect request with failure
+ ++SpxDevice->dev_Stat.NotFoundFailures;
+ fAbort = TRUE;
+ break;
+ }
+
+ // We need to resend the packet
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ break;
+ }
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+ default:
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: state is W_Setup %lx\n",
+ pSpxConnFile));
+
+ KeBugCheck(0);
+ }
+ }
+ else
+ {
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_SETUP:
+
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try when we come in next.
+ break;
+ }
+
+ // If we have exhausted current retries, try next smaller size.
+ // If this was the smallest size, we abort.
+ if (pSpxConnFile->scf_CRetryCount-- == 0)
+ {
+ // Have we tried the smallest size?
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // Give up! Remove negotiate packet etc. Have an abort
+ // kind of routine.
+ ++SpxDevice->dev_Stat.SessionTimeouts;
+ fAbort = TRUE;
+ break;
+ }
+
+ // Set neg pkt size to new lower size
+ spxConnSetNegSize(
+ pPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ pSpxConnFile->scf_CRetryCount =
+ PARAM(CONFIG_CONNECTION_COUNT);
+ }
+
+ // We need to resend the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+
+ pSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ sendPkt = TRUE;
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+ }
+
+ } while (FALSE);
+
+ if (fAbort)
+ {
+ CTEAssert(!sendPkt);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnConnectTimer: Expired for %lx\n", pSpxConnFile));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_BAD_NETWORK_PATH,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (sendPkt)
+ {
+ CTEAssert(!fAbort);
+
+#if !defined(_PNP_POWER)
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)) {
+
+ // we are sending to all NICs because this is the initial
+ // connect frame and the remote network is 0.
+
+ pSpxConnFile->scf_LocalTarget.NicId = (USHORT)
+ ((pSpxConnFile->scf_LocalTarget.NicId % SpxDevice->dev_Adapters) + 1);
+
+ // we pass this a valid packet in pPkt, so it knows to
+ // just refresh the header and not update the protocol
+ // reserved variables.
+
+ SpxPktBuildCr(
+ pSpxConnFile,
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ &pPkt,
+ 0, // state will not be updated
+ SPX2_CONN(pSpxConnFile));
+
+ }
+#endif !_PNP_POWER
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ if (TimerShuttingDown || fAbort)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+ }
+
+ return(TIMER_REQUEUE_CUR_VALUE);
+}
+
+
+
+
+ULONG
+spxConnWatchdogTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ This is started on a connection right after the CR or the CR ack is received.
+ During the connection establishment phase, it does nothing other than decrement
+ the retry count and upon reaching 0, it aborts the connection. When it goes off
+ and finds the connection is active, it sends a probe.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ PNDIS_PACKET pProbe = NULL;
+ BOOLEAN lockHeld, fSpx2 = SPX2_CONN(pSpxConnFile),
+ fDisconnect = FALSE, fFindRoute = FALSE, fSendProbe = FALSE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnWatchdogTimer: Entered\n"));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ do
+ {
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // If the retry timer is active on this connection, and the watchdog
+ // timer happens to fire, just requeue ourselves for spx2. For spx1,
+ // we go ahead with sending a probe. Retry timer does the same things
+ // watchdog does for spx2.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // Squash the race condition where a disconnect request is never
+ // packetized, because the send state was not IDLE.
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: POST IDISC %lx\n",
+ pSpxConnFile));
+
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: PKT POST IDISC %lx\n",
+ pSpxConnFile));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+ }
+
+ if (!fSpx2)
+ {
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ fSendProbe = TRUE;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+ }
+
+ // SPX2 connection. Watchdog algorithm needs to do lots of goody
+ // stuff. If retry is active, just requeue ourselves.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ break;
+
+ // There is a race between watchdog and retry if its started. Who
+ // ever changes the state first gets to go do its thing.
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Enter WD state only if we fired for the second time witout
+ // an ack. This prevents PACKETIZE from blocking due to being
+ // in a non-idle state.
+ CTEAssert(pSpxConnFile->scf_WRetryCount != 0);
+ if ((pSpxConnFile->scf_WRetryCount)-- !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT))
+ {
+ // We enter the WD state. Build and send a probe.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_WD);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+
+ fSendProbe = TRUE;
+ break;
+
+ case SPX_SEND_PACKETIZE:
+
+ // Do nothing.
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRYWD:
+ case SPX_SEND_RENEG:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ // Do nothing. Send timer got in first.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnWDogTimer: When retry fired %lx\n",
+ pSpxConnFile));
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Decrement count. If not zero, send a probe. If half the
+ // count is reached, stop timer and call find route.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ if (pSpxConnFile->scf_WRetryCount !=
+ (LONG)PARAM(CONFIG_KEEPALIVE_COUNT)/2)
+ {
+ fSendProbe = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network) =
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6);
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4))=
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnWDogTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ }
+ else
+ {
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+
+ if ((SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) ||
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_NEG))
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP)
+ {
+ // Do nothing. Connect timer is active.
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnWDogTimer: CR Timer active %lx\n",
+ pSpxConnFile));
+
+ break;
+ }
+
+ if (!(pSpxConnFile->scf_WRetryCount--))
+ {
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ default:
+
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ } while (FALSE);
+
+ if (fSendProbe)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fDisconnect);
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnWatchdogTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ fSpx2);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ }
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+ CTEAssert(!fSendProbe);
+
+ // Disconnect!
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnWatchdogTimer: Connection %lx.%lx expired\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+
+ // If spx2, check if we need to do anything special.
+ // AbortiveDisc will reset funky state if needed.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandle,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fFindRoute)
+ {
+ CTEAssert(!fSendProbe);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+
+ if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return((TimerShuttingDown ? TIMER_DONT_REQUEUE : TIMER_REQUEUE_CUR_VALUE));
+}
+
+
+
+ULONG
+spxConnRetryTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle lockHandleConn;
+ PIPXSPX_HDR pSendHdr;
+ PNDIS_PACKET pPkt;
+ PNDIS_PACKET pProbe = NULL;
+ PSPX_FIND_ROUTE_REQUEST pFindRouteReq;
+ USHORT reenqueueTime = TIMER_REQUEUE_CUR_VALUE;
+ BOOLEAN lockHeld, fResendPkt = FALSE, fDisconnect = FALSE,
+ fFindRoute = FALSE, fBackoffTimer = FALSE;
+ PREQUEST pRequest = NULL;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnRetryTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ lockHeld = TRUE;
+
+ do
+ {
+ // If timer is not up, no send pkts, just return.
+ if (TimerShuttingDown ||
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL))
+ {
+#if DBG
+ if ((pSendResd = pSpxConnFile->scf_SendSeqListHead) == NULL)
+ {
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ CTEAssert(FALSE);
+ }
+ }
+#endif
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+ break;
+ }
+
+ // In all other cases, reenqueue with potentially modified reenqueue
+ // time.
+ reenqueueTime = pSpxConnFile->scf_BaseT1;
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: BaseT1 %lx on %lx\n",
+ pSpxConnFile->scf_BaseT1, pSpxConnFile));
+
+ // If an ack for a packet was processed while we were out, reset
+ // retry count and return. Or if we are packetizing, return.
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)
+ {
+ break;
+ }
+ else if ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_RetrySeqNum != pSendResd->sr_SeqNum))
+ {
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+ break;
+ }
+
+ // If packet is still with IPX, requeue for next time.
+ if (pSendResd->sr_State & SPX_SENDPKT_IPXOWNS)
+ {
+ break;
+ }
+
+ CTEAssert(pSendResd != NULL);
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_IDLE:
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // Do we backoff the timer?
+ fBackoffTimer =
+ (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_REXMIT) != 0);
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ ++SpxDevice->dev_Stat.ResponseTimerExpirations;
+
+ CTEAssert((ULONG)pSpxConnFile->scf_RRetryCount <=
+ PARAM(CONFIG_REXMIT_COUNT));
+
+ DBGPRINT(SEND, DBG1,
+ ("spxConnRetryTimer: Retry Count %lx on %lx\n",
+ pSpxConnFile->scf_RRetryCount, pSpxConnFile));
+
+ fResendPkt = TRUE;
+ if (pSpxConnFile->scf_RRetryCount-- != 0)
+ {
+ // We dont treat the IDISC packet as a data packet, so none
+ // of the fancy spx2 retry stuff if we are retrying the idisc.
+ if (SPX2_CONN(pSpxConnFile) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_IDISC))
+ {
+ // We enter the RETRY state. Reference conn for this
+ // "funky" state.
+ CTEAssert(SPX2_CONN(pSpxConnFile));
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ERRORSTATE);
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ fResendPkt = FALSE;
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+
+ // When we have reached retry_count/2 limit, start locate route. Do
+ // not queue ourselves. Handle restarting timer in find route
+ // completion. If timer starts successfully in find route comp, then
+ // it will change our state to RETRYWD.
+
+ // Decrement count. If half the count is reached, stop timer and call
+ // find route.
+ if (pSpxConnFile->scf_RRetryCount-- !=
+ (LONG)PARAM(CONFIG_REXMIT_COUNT)/2)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ break;
+ }
+
+ if ((pFindRouteReq =
+ (PSPX_FIND_ROUTE_REQUEST)SpxAllocateMemory(
+ sizeof(SPX_FIND_ROUTE_REQUEST))) == NULL)
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Alloc Mem %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ break;
+ }
+
+ // Remove timer reference/ Add find route request ref
+ fFindRoute = TRUE;
+ TimerShuttingDown = TRUE;
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_FINDROUTE);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_FINDROUTE);
+
+ // Initialize the find route request
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Network)=
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr);
+
+ //
+ // [SA] Bug #15094
+ // We need to also pass in the node number to IPX so that IPX can
+ // compare the node addresses to determine the proper WAN NICid
+ //
+
+ // RtlCopyMemory (pFindRouteReq->fr_FindRouteReq.Node, pSpxConnFile->scf_RemAddr+4, 6) ;
+
+ *((UNALIGNED ULONG *)pFindRouteReq->fr_FindRouteReq.Node)=
+ *((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr+4));
+
+ *((UNALIGNED USHORT *)(pFindRouteReq->fr_FindRouteReq.Node+4)) =
+ *((UNALIGNED USHORT *)(pSpxConnFile->scf_RemAddr+8));
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnRetryTimer: NETWORK %lx\n",
+ *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr)));
+
+ pFindRouteReq->fr_FindRouteReq.Identifier= IDENTIFIER_SPX;
+ pFindRouteReq->fr_Ctx = pSpxConnFile;
+
+ // Make sure we have IPX re-rip.
+ pFindRouteReq->fr_FindRouteReq.Type = IPX_FIND_ROUTE_FORCE_RIP;
+ break;
+
+ case SPX_SEND_RETRYWD:
+
+ // Retry a watchdog packet WCount times (initialize to RETRY_COUNT).
+ // If process ack receives an ack (i.e. actual ack packet) while in
+ // this state, it will transition the state to RENEG.
+ //
+ // If the pending data gets acked while in this state, we go back
+ // to idle.
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnRetryTimer: Send Probe from %lx.%lx\n",
+ pSpxConnFile->scf_LocalConnId, pSpxConnFile));
+
+ // Use watchdog count here.
+ if (pSpxConnFile->scf_WRetryCount-- > 0)
+ {
+ // Build a probe and send it out to the remote end.
+ SpxPktBuildProbe(
+ pSpxConnFile,
+ &pProbe,
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY),
+ TRUE);
+
+ if (pProbe != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pProbe);
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ break;
+ }
+ }
+
+ // Just set state to retry data packet retry_count/2 times.
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY2);
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // Renegotiate size. If we give up, goto RETRY3.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ break;
+ }
+
+ // Send reneg packet, if we get the rr ack, then we resend data
+ // on queue. Note that each time we goto a new negotiate size,
+ // we rebuild the data packets.
+ if (pSpxConnFile->scf_RRetryCount-- == 0)
+ {
+ // Reset count.
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnRetryTimer: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+
+ // Are we at the lowest possible reneg pkt size? If not, try
+ // next lower. When we do this, we free all pending send
+ // packets and reset the packetize queue to the first packet.
+ // Process ack will just do packetize and will not do anything
+ // more other than resetting state to proper value.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG: %lx - CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ if (!spxConnCheckNegSize(&pSpxConnFile->scf_MaxPktSize))
+ {
+ // We tried lowest size and failed to receive ack. Just
+ // retry data packet, and disc if no ack.
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(min), RETRY3: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ break;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: RENEG(!min): %lx - ATTEMPT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_MaxPktSize));
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: %lx.%lx.%lx RENEG SEQNUM %lx ACKNUM %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RRetryCount,
+ pSpxConnFile->scf_MaxPktSize,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Use first unused data packet sequence number.
+ SpxPktBuildRr(
+ pSpxConnFile,
+ &pPkt,
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1),
+ (SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY));
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ fResendPkt = TRUE;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ }
+
+ break;
+
+ case SPX_SEND_RETRY2:
+
+ // Retry the data packet for remaining amount of RRetryCount. If not
+ // acked goto cleanup. If ack received while in this state, goto idle.
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 2nd try Resend on %lx\n",
+ pSpxConnFile));
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_RETRY3:
+
+ // Send data packet for RETRY_COUNT times initialized in RRetryCount
+ // before state changed to this state. If ok, process ack moves us
+ // back to PKT/IDLE. If not, we disconnect.
+ // We are going to resend this packet
+
+ if (pSpxConnFile->scf_RRetryCount-- > 0)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: 3rd try Resend on %lx\n",
+ pSpxConnFile));
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ fBackoffTimer = TRUE;
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: Retry Count over on %lx\n",
+ pSpxConnFile));
+
+ fDisconnect = TRUE;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Do nothing. Watchdog timer has fired, just requeue.
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+ if (fBackoffTimer)
+ {
+ // Increase retransmit timeout by 50% upto maximum indicated by
+ // initial retransmission value.
+
+ reenqueueTime += reenqueueTime/2;
+ if (reenqueueTime > MAX_RETRY_DELAY)
+ reenqueueTime = MAX_RETRY_DELAY;
+
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = reenqueueTime;
+ pSpxConnFile->scf_DevT1 = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Backed retry on %lx.%lx %lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum, reenqueueTime));
+ }
+
+ if (fDisconnect)
+ {
+ CTEAssert(lockHeld);
+
+ // Do not requeue this timer.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ TimerShuttingDown = TRUE;
+
+ // Disconnect the connection.
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LINK_TIMEOUT,
+ SPX_CALL_TDILEVEL,
+ lockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnRetryTimer: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+ else if (fFindRoute)
+ {
+ CTEAssert(!fResendPkt);
+ CTEAssert(!fDisconnect);
+ CTEAssert(TimerShuttingDown);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnRetryTimer: Find route on %lx\n",
+ pSpxConnFile));
+
+ // Start off the find route request
+ (*IpxFindRoute)(
+ &pFindRouteReq->fr_FindRouteReq);
+ }
+ else if (pProbe != NULL)
+ {
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pProbe, pSendResd);
+ }
+
+ if (TimerShuttingDown)
+ {
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ reenqueueTime = TIMER_DONT_REQUEUE;
+ }
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnRetryTimer: Reenqueue time : %lx on %lx\n",
+ reenqueueTime, pSpxConnFile));
+
+ return(reenqueueTime);
+}
+
+
+
+
+ULONG
+spxConnAckTimer(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile = (PSPX_CONN_FILE)Context;
+ CTELockHandle lockHandleConn;
+
+ DBGPRINT(SEND, INFO,
+ ("spxConnAckTimer: Entered\n"));
+
+ // Get lock
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (!TimerShuttingDown &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // We didnt have any back traffic, until we do a send from this
+ // end, send acks immediately. Dont try to piggyback.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ ++SpxDevice->dev_Stat.PiggybackAckTimeouts;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnAckTimer: Send ack on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ SpxConnSendAck(pSpxConnFile, lockHandleConn);
+ }
+ else
+ {
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ }
+
+ // Dereference connection for verify done in connect, for timer. This
+ // should complete any pending disconnects if they had come in in the
+ // meantime.
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ return(TIMER_DONT_REQUEUE);
+}
+
+
+
+//
+// DISCONNECT ROUTINES
+//
+
+
+VOID
+spxConnAbortiveDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn,
+ IN BOOLEAN IDiscFlag // [SA] Bug #15249
+ )
+/*++
+
+Routine Description:
+
+ This is called when:
+ We time out or have insufficient resources -
+ STATUS_LINK_TIMEOUT/STATUS_INSUFFICIENT_RESOURCES
+ - We abort everything. Could be from watchdog or retry. Stop both.
+
+ We receive a informed disconnect packet -
+ STATUS_REMOTE_DISCONNECT
+ - We abort everything. Ack must be sent by caller as an orphan pkt.
+
+ We receive a informed disconnect ack pkt
+ STATUS_SUCCESS
+ - We abort everything
+ - Abort is done with status success (this completes our disc req in
+ the send queue)
+
+ NOTE: CALLED UNDER THE CONNECTION LOCK.
+
+Arguments:
+[SA] Bug #15249: Added IDiscFlag to indicate if this is an Informed Disconnect. If so, indicate
+ TDI_DISCONNECT_RELEASE to AFD so it allows a receive of buffered pkts. This flag is TRUE
+ only if this routine is called from SpxConnProcessIDisc for SPX connections.
+
+Return Value:
+
+
+--*/
+{
+ int numDerefs = 0;
+ PVOID pDiscHandlerCtx=NULL;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ BOOLEAN lockHeld = TRUE;
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: %lx - On %lx when %lx\n",
+ Status, pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ switch (Status) {
+ case STATUS_LINK_TIMEOUT: ++SpxDevice->dev_Stat.LinkFailures; break;
+ case STATUS_INSUFFICIENT_RESOURCES: ++SpxDevice->dev_Stat.LocalResourceFailures; break;
+ case STATUS_REMOTE_DISCONNECT: ++SpxDevice->dev_Stat.RemoteDisconnects; break;
+ case STATUS_SUCCESS:
+ case STATUS_LOCAL_DISCONNECT: ++SpxDevice->dev_Stat.LocalDisconnects; break;
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_ACTIVE:
+
+ // For transition from active to disconn.
+ numDerefs++;
+
+ case SPX_CONNFILE_DISCONN:
+
+ // If we are in any state other than idle/packetize,
+ // remove the reference for the funky state, and reset the send state to be
+ // idle.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE))
+ {
+#if DBG
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnAbortiveDisc: When DISC STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(CONNECT, DBG1,
+ ("spxConnAbortiveDisc: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // This can be called when a idisc is received, or if a timer
+ // disconnect is happening, or if we sent a idisc/ordrel, but the retries
+ // timed out and we are aborting the connection.
+ // So if we are already aborting, never mind.
+
+ //
+ // [SA] Bug #15249
+ // SPX_DISC_INACTIVATED indicates a DISC_ABORT'ing connection that has been
+ // inactivated (connfile removed from active conn. list)
+ //
+
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ ((SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT) ||
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)))
+ {
+ break;
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ABORT);
+
+ // Stop all timers.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_RTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+#if 0
+ //
+ // [SA] We need to call AFD after aborting sends since this connection
+ // becomes a candidate for re-use as soon as the disconnect handler is
+ // called.
+ // We call the disconnect handler when the refcount falls to 0 and the
+ // connection transitions to the inactive list.
+ //
+
+ // NOTE! We indicate disconnect to afd *before* aborting sends to avoid
+ // afd from calling us again with a disconnect.
+ // Get disconnect handler if we have one. And we have not indicated
+ // abortive disconnect on this connection to afd.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+#endif
+ //
+ // [SA] Save the IDiscFlag in the Connection.
+ //
+ (IDiscFlag) ?
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC) :
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnAbortiveDisc: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+
+ if (!IDiscFlag)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_ABORT);
+ }
+ else
+ {
+ //
+ // [SA] bug #15249
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ spxConnAbortSends(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn);
+
+ lockHeld = FALSE;
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ lockHeld = FALSE;
+
+ {
+ CTELockHandle lockHandleAddr, lockHandleDev;
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ // Ensure we are still in connecting/listening, else call abortive
+ // again.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CONN/LIST Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ Status,
+ lockHandleDev,
+ lockHandleAddr,
+ LockHandleConn);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortiveDisc: CHG ACT Disc2 On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ Status,
+ CallLevel,
+ LockHandleConn,
+ FALSE); // [SA] Bug #15249
+
+ break;
+
+ default:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock(
+ pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(
+ &SpxDevice->dev_Lock, lockHandleDev);
+
+ break;
+ }
+ }
+
+ default:
+
+ // Already disconnected.
+ break;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxcpkt.c b/private/ntos/tdi/isn/spx/spxcpkt.c
new file mode 100644
index 000000000..0c606ab0a
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxcpkt.c
@@ -0,0 +1,4131 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcpkt.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXCPKT
+
+VOID
+spxConnHandleConnReq(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ BOOLEAN fNeg, fSpx2;
+ TA_IPX_ADDRESS srcIpxAddr;
+ PTDI_IND_CONNECT connHandler;
+ USHORT srcConnId, destConnId, destSkt,
+ pktLen, seqNum, ackNum, allocNum;
+ PVOID connHandlerCtx;
+ PREQUEST pListenReq;
+ PSPX_SEND_RESD pSendResd;
+ NTSTATUS status;
+ CTELockHandle lockHandle, lockHandleDev, lockHandleConn;
+ CONNECTION_CONTEXT connCtx;
+ PIRP acceptIrp;
+ PSPX_ADDR pSpxAddr;
+ PSPX_ADDR_FILE pSpxAddrFile, pSpxRefFile;
+ PSPX_CONN_FILE pSpxConnFile;
+ PNDIS_PACKET pCrAckPkt;
+ BOOLEAN connectAccepted = FALSE, delayAccept = FALSE,
+ addrLock = FALSE, tdiListen = FALSE;
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // Verify Connect Request
+ if (((pIpxSpxHdr->hdr_ConnCtrl & (SPX_CC_ACK | SPX_CC_SYS)) !=
+ (SPX_CC_ACK | SPX_CC_SYS)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId != 0xFFFF))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifyCR Failed %lx.%lx\n",
+ srcConnId, destConnId));
+ return;
+ }
+
+ // Get the destination socket from the header
+ destSkt = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_DestSkt;
+
+ SpxBuildTdiAddress(
+ &srcIpxAddr,
+ sizeof(srcIpxAddr),
+ (PBYTE)pIpxSpxHdr->hdr_SrcNet,
+ pIpxSpxHdr->hdr_SrcNode,
+ pIpxSpxHdr->hdr_SrcSkt);
+
+ // Ok, get the address object this is destined for.
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ pSpxAddr = SpxAddrLookup(SpxDevice, destSkt);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ if (pSpxAddr == NULL)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceive: No addr for %lx\n", destSkt));
+
+ return;
+ }
+
+ fSpx2 = ((PARAM(CONFIG_DISABLE_SPX2) == 0) &&
+ (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2));
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Received connect req! %d.%d\n",
+ fSpx2, fNeg));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+
+ // We use a bit setting in the flag to prevent reentering
+ // per address file.
+ //
+ // We first search the list of non-inactive connections on the address
+ // this packet came in on to see if it is a duplicate. If it is, we just
+ // resend ack. Note we dont need to scan the global connection list.
+ status = SpxAddrConnByRemoteIdAddrLock(
+ pSpxAddr, srcConnId, pIpxSpxHdr->hdr_SrcNet, &pSpxConnFile);
+
+ if (NT_SUCCESS(status))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Received duplicate connect req! %lx\n",
+ pSpxConnFile));
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile) ||
+ (SPX_CONN_LISTENING(pSpxConnFile) &&
+ ((SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK) ||
+ (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SETUP))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: Sending Duplicate CR - ACK! %lx\n",
+ pSpxConnFile));
+
+ // Build and send an ack
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG),
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2));
+
+ if (pCrAckPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ // Send the CR Ack packet!
+ if (pCrAckPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+ }
+ }
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // We should return in this if, else addrLock should be set to
+ // FALSE.
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_ADDR);
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+ }
+
+ do
+ {
+ // New connection request:
+ // Assume we will be able to accept it and allocate a packet for the ack.
+ // Walk list of listening connections if any.
+
+ pSpxRefFile = NULL;
+ if ((pSpxConnFile = pSpxAddr->sa_ListenConnList) != NULL)
+ {
+ PTDI_REQUEST_KERNEL_LISTEN pParam;
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnIndicate: Listen available!\n"));
+
+ // dequeue connection
+ pSpxAddr->sa_ListenConnList = pSpxConnFile->scf_Next;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ pListenReq = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ pParam = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(pListenReq);
+
+ // if autoaccept, acceptIrp = listenIrp, get connection id and
+ // process as we do for an indication. As the connection has a
+ // listen posted on it, it must have a reference for it.
+ //
+ // if !autoaccept, we need to complete the listen irp.
+ delayAccept = (BOOLEAN)((pParam->RequestFlags & TDI_QUERY_ACCEPT) != 0);
+ if (delayAccept)
+ {
+ // Remove the listen irp and prepare for completion.
+ // NOTE!! Here we do not remove the listen reference. This will
+ // be removed if disconnect happens, or if accept
+ // happens, it is transferred to being ref for connection
+ // being active.
+ RemoveEntryList(REQUEST_LINKAGE(pListenReq));
+ REQUEST_STATUS(pListenReq) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pListenReq) = 0;
+ }
+
+ // Are we ok with spx2?
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2)) ||
+ !fSpx2)
+ {
+ // We better use spx only.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ fSpx2 = fNeg = FALSE;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ connectAccepted = TRUE;
+ tdiListen = TRUE;
+ }
+ else
+ {
+ // No listens available. Check for connect handlers.
+ // Walk list of address files indicating to each until accepted.
+ for (pSpxAddrFile = pSpxAddr->sa_AddrFileList;
+ pSpxAddrFile != NULL;
+ pSpxAddrFile = pSpxAddrFile->saf_Next)
+ {
+ if ((pSpxAddrFile->saf_Flags & (SPX_ADDRFILE_CLOSING |
+ SPX_ADDRFILE_CONNIND)) ||
+ ((connHandler = pSpxAddrFile->saf_ConnHandler) == NULL))
+ {
+ continue;
+ }
+
+ // Connect indication in progress, drop all subsequent.
+ pSpxAddrFile->saf_Flags |= SPX_ADDRFILE_CONNIND;
+
+ connHandlerCtx = pSpxAddrFile->saf_ConnHandlerCtx;
+ SpxAddrFileLockReference(pSpxAddrFile, AFREF_INDICATION);
+ CTEFreeLock(&pSpxAddr->sa_Lock, lockHandle);
+ addrLock = FALSE;
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ // Make the indication. We are always returned an accept irp on
+ // indication. Else we fail to accept the connection.
+ status = (*connHandler)(
+ connHandlerCtx,
+ sizeof(srcIpxAddr),
+ (PVOID)&srcIpxAddr,
+ 0, // User data length
+ NULL, // User data
+ 0, // Option length
+ NULL, // Options
+ &connCtx,
+ &acceptIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConn: indicate status %lx.%lx\n",
+ status, acceptIrp));
+
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ addrLock = TRUE;
+ pSpxAddrFile->saf_Flags &= ~SPX_ADDRFILE_CONNIND;
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+ CTEAssert(acceptIrp != NULL);
+
+ // Find the connection and accept the connection using that
+ // connection object.
+ SpxConnFileReferenceByCtxLock(
+ pSpxAddrFile,
+ connCtx,
+ &pSpxConnFile,
+ &status);
+
+ if (!NT_SUCCESS(status))
+ {
+ // The connection object is closing, or is not found
+ // in our list. The accept irp must have had the same
+ // connection object. AFD isnt behaving well.
+ KeBugCheck(0);
+ }
+
+ // Only for debugging.
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_BYCTX,
+ CFREF_VERIFY);
+
+ pListenReq = SpxAllocateRequest(
+ SpxDevice,
+ acceptIrp);
+
+ IF_NOT_ALLOCATED(pListenReq)
+ {
+ acceptIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (acceptIrp, IO_NETWORK_INCREMENT);
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ break;
+ }
+
+ InsertTailList(
+ &pSpxConnFile->scf_ReqLinkage,
+ REQUEST_LINKAGE(pListenReq));
+
+ // Setup for dereference
+ pSpxRefFile = pSpxAddrFile;
+ connectAccepted = TRUE;
+
+ // See if this connection is to be a spx2 connection.
+ SPX_CONN_RESETFLAG(pSpxConnFile,
+ (SPX_CONNFILE_SPX2 |
+ SPX_CONNFILE_NEG |
+ SPX_CONNFILE_STREAM));
+
+ if ((pSpxAddrFile->saf_Flags & SPX_ADDRFILE_SPX2) && fSpx2)
+ {
+ SPX_CONN_SETFLAG(
+ pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+ }
+ else
+ {
+ fSpx2 = fNeg = FALSE;
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_STREAM)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_STREAM);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_NOACKWAIT)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: NOACKWAIT requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT);
+ }
+
+ if (pSpxAddrFile->saf_Flags & SPX_ADDRFILE_IPXHDR)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleConnReq: IPXHDR requested %lx\n",
+ pSpxConnFile));
+
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR);
+ }
+
+ break;
+ }
+ else
+ {
+ // We are not going to accept the connection on this address.
+ // Try next one.
+ pSpxRefFile = pSpxAddrFile;
+ continue;
+ }
+ }
+ }
+
+ } while (FALSE);
+
+ if (addrLock)
+ {
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ // No need for flag from this point on.
+ // addrLock = FALSE;
+ }
+
+ if (pSpxRefFile)
+ {
+ SpxAddrFileDereference(pSpxRefFile, AFREF_INDICATION);
+ pSpxRefFile = NULL;
+ }
+
+ if (connectAccepted)
+ {
+ CTEGetLock (&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock (&pSpxAddr->sa_Lock, &lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ if (((USHORT)PARAM(CONFIG_WINDOW_SIZE) == 0) ||
+ ((USHORT)PARAM(CONFIG_WINDOW_SIZE) > MAX_WINDOW_SIZE))
+ {
+ PARAM(CONFIG_WINDOW_SIZE) = DEFAULT_WINDOW_SIZE;
+ }
+
+ pSpxConnFile->scf_LocalConnId = spxConnGetId();
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RetrySeqNum = 0;
+ pSpxConnFile->scf_SentAllocNum = (USHORT)(PARAM(CONFIG_WINDOW_SIZE) - 1);
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleConnReq: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Set max packet size in connection
+ SPX_MAX_PKT_SIZE(pSpxConnFile, (fSpx2 && fNeg), fSpx2, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleConnReq: Accept connect req on %lx.%lx..%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ // Aborts must now deal with the lists. Need this as Accept has to
+ // deal with it.
+ // Put in non-inactive list. All processing now is equivalent to
+ // that when a listen is completed on a connection.
+ if ((!tdiListen) && (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxAddr->sa_InactiveConnList,
+ pSpxConnFile))))
+ {
+ // Should never happen!
+ KeBugCheck(0);
+ }
+
+ SPX_INSERT_ADDR_ACTIVE(pSpxAddr, pSpxConnFile);
+
+ // Insert in the global connection tree on device.
+ spxConnInsertIntoGlobalActiveList(
+ pSpxConnFile);
+
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fNeg ? SPX_CONNFILE_NEG : 0) |
+ (fSpx2 ? SPX_CONNFILE_SPX2: 0)));
+
+ //
+ // If this was a post-inactivated file, clear the disconnect flags
+ //
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ }
+#if 0
+ //
+ // Make sure that this connection got a local disconnect if it was an SPXI
+ // connection earlier, in response to a TDI_DISCONNECT_RELEASE.
+ //
+
+ CTEAssert(pSpxConnFile->scf_RefTypes[CFREF_DISCWAITSPX] == 0);
+#endif
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_LISTENING);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, (delayAccept ? SPX_LISTEN_RECDREQ : 0));
+
+ if (!delayAccept)
+ {
+ spxConnAcceptCr(
+ pSpxConnFile,
+ pSpxAddr,
+ lockHandleDev,
+ lockHandle,
+ lockHandleConn);
+ }
+ else
+ {
+ // Release the locks.
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, lockHandle);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ // Complete the listen irp. Note reference is not removed. Done when
+ // accept is posted.
+ SpxCompleteRequest(pListenReq);
+ }
+ } else {
+ ++SpxDevice->dev_Stat.NoListenFailures;
+ }
+
+ // Deref the address
+ SpxAddrDereference (pSpxAddr, AREF_LOOKUP);
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromClient(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the client side of the connection.
+ Handles:
+ Session Negotiate
+ Sends Session Setup, when recd, handles SS Ack
+
+ STATE MACHINE:
+
+ RR
+ / \
+ / \ ReceivedAck(SPX1Connection)
+ / \
+ / \--------> ACTIVE
+ / ^
+ Send / |
+ ACK / |
+ / |
+ / RecvNeg/NoNeg |
+ / SendSS |
+ SA--------->SS---------------+
+ ^ | SSAckRecv
+ | |
+ +-----+
+ RecvNeg
+
+ RR - Received Connect Request
+ SA - Sent CR Ack
+ SS - Sent Session Setup
+
+ We move from SA to SS when connection is not negotiatiable and we
+ immediately send the SS, or when we receive negotiate packet and send the neg
+ ack and the session setup.
+
+ Note we could receive a negotiate packet when in SS, as our ack to the
+ negotiate could have been dropped. We deal with this.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PNDIS_PACKET pSnAckPkt, pSsPkt = NULL;
+ PSPX_SEND_RESD pSendResd, pSsSendResd;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN locksHeld = FALSE;
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromClient: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_LISTEN_STATE(pSpxConnFile))
+ {
+ case SPX_LISTEN_RECDREQ:
+
+ // Do nothing.
+ break;
+
+ case SPX_LISTEN_SETUP:
+
+ // Is this a setup ack? If so, yippee. Our ack to a negotiate packet
+ // could have been dropped, and so we could also get a negotiate packet
+ // in that case. If that happens, fall through.
+ // Verify Ss Ack
+ if (!SPX2_CONN(pSpxConnFile) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: VerifySSACK Failed Checking SN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ // Fall through to see if this is a neg packet
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG)))
+ {
+ break;
+ }
+ }
+ else
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Recd SSACK %lx\n",
+ pSpxConnFile));
+
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ case SPX_LISTEN_SENTACK:
+
+ // We expect a negotiate packet.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify Sn
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySN Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ CTEAssert(negSize > 0);
+
+ // Build sn ack, abort if we fail
+ SpxPktBuildSnAck(
+ pSpxConnFile,
+ &pSnAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY);
+
+ if (pSnAckPkt == NULL)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SNACK %lx\n",
+ pSpxConnFile));
+
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnAckPkt);
+
+ // The session packet should already be on queue.
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SS,
+ FALSE,
+ &pSsPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromClient: Sending SS %lx\n",
+ pSpxConnFile));
+
+ pSsSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+
+ // We need to resend the packet
+ if ((pSsSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Try next time.
+ pSsPkt = NULL;
+ }
+ else
+ {
+ // Set the size to the neg size indicated in connection.
+ // This could be lower than the size the packet was build
+ // with originally. But will never be higher.
+ pSsSendResd->sr_State |= SPX_SENDPKT_IPXOWNS;
+ spxConnSetNegSize(
+ pSsPkt,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+ }
+
+ // If we are actually LISTEN_SETUP, then send the ss packet also.
+ // We need to start the connect timer to resend the ss pkt.
+ if (SPX_LISTEN_STATE(pSpxConnFile) == SPX_LISTEN_SENTACK)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ SPX_LISTEN_SETSTATE(pSpxConnFile, SPX_LISTEN_SETUP);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSnAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnAckPkt, pSendResd);
+
+ // If we have to send the session setup packet, send that too.
+ if (pSsPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnHandleSessPktFromSrv(
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ Packet received from the server side of the connection. This will both
+ release the lock and dereference the connection as it sees fit.
+
+ STATE MACHINE:
+
+ SR--CTimerExpires-->IDLE
+ /| \
+ / | \ ReceivedAck(SPX1Connection)
+ / | \
+ / | \--------> ACTIVE
+ (Neg) / | ^
+ Send / |RecvAck |
+ SN / |NoNeg |
+ / | |
+ / | |
+ / v |
+ SN--------->WS---------------+
+ RecvSNAck RecvSS
+
+ SR - Sent Connect request
+ SN - Sent Session Negotiate
+ WS - Waiting for session setup packet
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN fNeg, fSpx2;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, negSize, ackNum, allocNum;
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ BOOLEAN cTimerCancelled = FALSE, fAbort = FALSE, locksHeld = FALSE;
+ PNDIS_PACKET pSsAckPkt, pSnPkt, pPkt = NULL;
+
+ // We should get a CR Ack, or if our substate is sent session neg
+ // we should get a session neg ack, or if we are waiting for session
+ // setup, we should get one of those.
+
+ fSpx2 = (BOOLEAN)(pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2);
+ fNeg = (BOOLEAN)(fSpx2 && (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_NEG));
+
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ // If spx2 we convert neg size field too
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2)
+ {
+ GETSHORT2SHORT(&negSize, &pIpxSpxHdr->hdr_NegSize);
+ CTEAssert(negSize > 0);
+ }
+
+ // Grab all three locks
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ locksHeld = TRUE;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx\n", pSpxConnFile));
+
+ // Check substate
+ switch (SPX_CONNECT_STATE(pSpxConnFile))
+ {
+ case SPX_CONNECT_SENTREQ:
+
+ // Check if this qualifies as the ack.
+ // Verify CR Ack
+ if ((pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (seqNum != 0) ||
+ (ackNum != 0) ||
+ ((pktLen != MIN_IPXSPX_HDRSIZE) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen != MIN_IPXSPX2_HDRSIZE))) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX))))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnHandleSessPktFromSrv: CRAck Invalid %lx %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pktLen, negSize, pIpxSpxHdr->hdr_ConnCtrl));
+
+ break;
+ }
+
+ // !!!BUGBUG!!!
+ // From current spx code base:
+ // Do we need to send an ack to this ack? In case of SPX only?
+ // What if this ack is dropped? We need to send an ack, if in future
+ // we get CONNECT REQ Acks, until we reach active?
+ // * If they want an ack schedule it. The normal case is for this not
+ // * to happen, but some Novell mainframe front ends insist on having
+ // * this. And technically, it is OK for them to do this.
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: Recd CRACK %lx\n", pSpxConnFile));
+
+ // Grab the remote alloc num/conn id (in net format)
+ pSpxConnFile->scf_SendSeqNum = 0;
+ pSpxConnFile->scf_RecvSeqNum = 0;
+ pSpxConnFile->scf_RecdAckNum = 0;
+ pSpxConnFile->scf_RemConnId = srcConnId;
+ pSpxConnFile->scf_RecdAllocNum = allocNum;
+
+ // If we have been looking for network 0, which means the
+ // packets were sent on all NIC IDs, update our local
+ // target now that we have received a response.
+
+#if defined(_PNP_POWER)
+ if (pSpxConnFile->scf_LocalTarget.NicHandle.NicId == (USHORT)ITERATIVE_NIC_ID) {
+#else
+ if (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0) {
+#endif _PNP_POWER
+ pSpxConnFile->scf_LocalTarget = *pRemoteAddr;
+ pSpxConnFile->scf_AckLocalTarget= *pRemoteAddr;
+ }
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnHandleSessPktFromSrv: %lx CONN L.R %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RemConnId));
+
+ if (!fSpx2 || !fNeg)
+ {
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference transferred to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // Set max packet size, assume not spx2 or !neg, so pass in FALSE
+ SPX_MAX_PKT_SIZE(pSpxConnFile, FALSE, FALSE, pIpxSpxHdr->hdr_SrcNet);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPSrv: Accept connect req on %lx.%lx.%lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_LocalConnId,
+ pSpxConnFile->scf_RecdAllocNum, pSpxConnFile->scf_MaxPktSize));
+
+ if (!fSpx2)
+ {
+ // Reset spx2 flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG));
+
+ // Complete connect request, this free the lock.
+ // Cancels tdi timer too. Sets all necessary flags.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ break;
+ }
+
+ if (!fNeg)
+ {
+ // Goto W_SETUP
+ // Reset all connect related flags, also spx2/neg flags.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ break;
+ }
+
+ // Reset max packet size. SPX2 and NEG.
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, pIpxSpxHdr->hdr_SrcNet);
+
+ CTEAssert(negSize > 0);
+ CTEAssert(pSpxConnFile->scf_MaxPktSize > 0);
+ pSpxConnFile->scf_MaxPktSize =
+ MIN(negSize, pSpxConnFile->scf_MaxPktSize);
+
+ pSpxConnFile->scf_MaxPktSize = (USHORT)
+ MIN(pSpxConnFile->scf_MaxPktSize, PARAM(CONFIG_MAX_PACKET_SIZE));
+
+ // For SPX2 with negotiation, we set up sneg packet and move to
+ // SPX_CONNECT_NEG.
+ SpxPktBuildSn(
+ pSpxConnFile,
+ &pSnPkt,
+ SPX_SENDPKT_IPXOWNS);
+
+ if (pSnPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ // Queue in packet
+ SpxConnQueueSendPktTail(pSpxConnFile, pSnPkt);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SN %lx\n",
+ pSpxConnFile));
+
+ // Reset retry count for connect timer
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Change state.
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_NEG);
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ locksHeld = FALSE;
+
+ // Send the packet
+ pSendResd = (PSPX_SEND_RESD)(pSnPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSnPkt, pSendResd);
+ break;
+
+ case SPX_CONNECT_NEG:
+
+ // We expect a session neg ack.
+ // We should have asked for SPX2/NEG to begin with.
+ // Verify SN Ack
+ if (((pSpxConnFile->scf_Flags & (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) !=
+ (SPX_CONNFILE_SPX2 | SPX_CONNFILE_NEG)) ||
+ (pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) !=
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySNACK Failed %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SNACK %lx %lx.%lx\n",
+ pSpxConnFile, negSize, pSpxConnFile->scf_MaxPktSize));
+
+ if (negSize > pSpxConnFile->scf_MaxPktSize)
+ negSize = pSpxConnFile->scf_MaxPktSize;
+
+ // Get the size to use
+ if (negSize <= pSpxConnFile->scf_MaxPktSize)
+ {
+ pSpxConnFile->scf_MaxPktSize = negSize;
+ if (!spxConnGetPktByType(
+ pSpxConnFile,
+ SPX_TYPE_SN,
+ FALSE,
+ &pPkt))
+ {
+ KeBugCheck(0);
+ }
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0)
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ else
+ {
+ // Free the negotiate packet
+ SpxPktSendRelease(pPkt);
+ }
+
+ CTEAssert(pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER);
+ cTimerCancelled = SpxTimerCancelEvent(
+ pSpxConnFile->scf_CTimerId, FALSE);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+
+ // Start the watchdog timer, if fail, we abort.
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) == 0)
+ {
+ // Complete cr with error.
+ fAbort = TRUE;
+ break;
+ }
+
+ // Reference goes to watchdog timer.
+ if (cTimerCancelled)
+ {
+ cTimerCancelled = FALSE;
+ }
+ else
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ // We move to the W_SETUP state.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+
+ SPX_CONNECT_SETSTATE(pSpxConnFile, SPX_CONNECT_W_SETUP);
+ }
+
+ break;
+
+ case SPX_CONNECT_W_SETUP:
+
+ // Does this qualify as a session setup packet?
+ // Verify SS
+ if (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)) ||
+ (pIpxSpxHdr->hdr_DataType != 0) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ (seqNum != 0) ||
+ ((negSize < SPX_NEG_MIN) ||
+ (negSize > SPX_NEG_MAX)))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: VerifySS Failed %lx.%lx, %lx %lx.%lx\n",
+ srcConnId, destConnId, negSize,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ (SPX_CC_ACK | SPX_CC_SYS | SPX_CC_SPX2)));
+
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Recd SS %lx\n", pSpxConnFile));
+
+ // Copy remote address over into connection (socket could change)
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+
+ // Remember max packet size in connection.
+ pSpxConnFile->scf_MaxPktSize = negSize;
+
+ // Build ss ack, abort if we fail
+ SpxPktBuildSsAck(
+ pSpxConnFile,
+ &pSsAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT);
+
+ if (pSsAckPkt == NULL)
+ {
+ fAbort = TRUE;
+ break;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnHandleSessPktFromSrv: Sending SSACK %lx\n",
+ pSpxConnFile));
+
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+
+ // We dont queue in the pkt as its already marked as abort.
+ // Queue in the packet.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pSsAckPkt);
+
+ // Complete connect, this releases lock.
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+
+ // Send ack packet
+ pSendResd = (PSPX_SEND_RESD)(pSsAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsAckPkt, pSendResd);
+ break;
+
+ default:
+
+ // Ignore
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnSysPacket: UNKNOWN %lx.%lx\n",
+ srcConnId, destConnId));
+
+ break;
+ }
+
+ if (fAbort)
+ {
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ lockHandleDev,
+ lockHandleAddr,
+ lockHandleConn);
+
+ locksHeld = FALSE;
+ }
+
+ if (locksHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock(pSpxConnFile->scf_AddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock(&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (cTimerCancelled)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine abort a connection (both client and server side) in the middle
+ of a connection establishment.
+
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest = NULL;
+ int numDerefs = 0;
+
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAbortConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ KeBugCheck(0);
+ }
+#endif
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) { // others should be counted elsewhere
+ ++SpxDevice->dev_Stat.LocalResourceFailures;
+ }
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel all timers
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_WTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ }
+
+ // We could be called from disconnect for an accept in which case there
+ // will be no queued request. But we need to remove the reference if there
+ // is no request (an accept/listen irp) and listen state is on.
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // Save req in conn for deref to complete.
+ pSpxConnFile->scf_ConnectReq = pRequest;
+
+ numDerefs++;
+ }
+ else if (SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ numDerefs++;
+ }
+
+ // Bug #20999
+ // Race condition was an abort came in from timer, but the connect state
+ // was left unchanged. Due to an extra ref on the connection from the
+ // aborted cr, the state remained so, and then the cr ack came in, and
+ // a session neg was built and queued on the connection. Although it should
+ // not have been. And we hit the assert in deref where the connection is
+ // being reinitialized. Since this can be called for both listening and
+ // connecting connections, do the below.
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ if (SPX_CONN_CONNECTING(pSpxConnFile))
+ {
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+spxConnCompleteConnect(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This routine completes a connection (both client and server side)
+ !!! Called with connection lock held, releases lock before return !!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCompleteConnect: %lx\n", pSpxConnFile));
+
+#if DBG
+ if (!SPX_CONN_CONNECTING(pSpxConnFile) && !SPX_CONN_LISTENING(pSpxConnFile))
+ {
+ DBGBRK(FATAL);
+ }
+#endif
+
+ // Free up all the packets
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+
+ // Cancel tdi connect timer if we are connecting.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_TTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_T_TIMER);
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER))
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ if (pSpxConnFile->scf_CRetryCount == (LONG)(PARAM(CONFIG_CONNECTION_COUNT))) {
+ ++SpxDevice->dev_Stat.ConnectionsAfterNoRetry;
+ } else {
+ ++SpxDevice->dev_Stat.ConnectionsAfterRetry;
+ }
+
+ // Reset all connect related flags
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_CONNECT_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ if (pSpxConnFile->scf_Flags & SPX_CONNFILE_C_TIMER)
+ {
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_CTimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_LISTEN_SETSTATE(pSpxConnFile, 0);
+ break;
+
+ default:
+
+ KeBugCheck(0);
+
+ }
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_ACTIVE);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_IDLE);
+
+ ++SpxDevice->dev_Stat.OpenConnections;
+
+ // Initialize timer values
+ pSpxConnFile->scf_BaseT1 =
+ pSpxConnFile->scf_AveT1 = PARAM(CONFIG_INITIAL_RETRANSMIT_TIMEOUT);
+ pSpxConnFile->scf_DevT1 = 0;
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ pRequest = LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqLinkage.Flink);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ // When we complete the request, we essentially transfer the reference
+ // to the fact that the connection is active. This will be taken away
+ // when a Disconnect happens on the connection and we transition from
+ // ACTIVE to DISCONN.
+ // numDerefs++;
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (pSpxConnFile->scf_AddrFile->saf_AddrLock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+
+ // Complete request
+ SpxCompleteRequest(pRequest);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+spxConnAcceptCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN CTELockHandle LockHandleDev,
+ IN CTELockHandle LockHandleAddr,
+ IN CTELockHandle LockHandleConn
+ )
+{
+ PNDIS_PACKET pSsPkt, pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+
+ BOOLEAN fNeg = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG);
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnAcceptCr: %lx.%d.%d\n",
+ pSpxConnFile, fSpx2, fNeg));
+
+ // Build and queue in packet.
+ SpxPktBuildCrAck(
+ pSpxConnFile,
+ pSpxAddr,
+ &pCrAckPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ fNeg,
+ fSpx2);
+
+ if ((pCrAckPkt != NULL) &&
+ (pSpxConnFile->scf_LocalConnId != 0))
+ {
+ // Queue in the packet.
+ SpxConnQueueSendPktTail(pSpxConnFile, pCrAckPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // Start the timer
+ if ((pSpxConnFile->scf_WTimerId =
+ SpxTimerScheduleEvent(
+ spxConnWatchdogTimer,
+ PARAM(CONFIG_KEEPALIVE_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER);
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+
+ // We start the connect timer for retrying ss which we send out now
+ // if we are not negotiating.
+ if (fSpx2)
+ {
+ // Build the session setup packet also for spx2.
+ SpxPktBuildSs(
+ pSpxConnFile,
+ &pSsPkt,
+ (USHORT)(fNeg ? 0 : SPX_SENDPKT_IPXOWNS));
+
+ if (pSsPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pSsPkt);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+
+ if (!fNeg)
+ {
+ if ((pSpxConnFile->scf_CTimerId =
+ SpxTimerScheduleEvent(
+ spxConnConnectTimer,
+ PARAM(CONFIG_CONNECTION_TIMEOUT) * HALFSEC_TO_MS_FACTOR,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_C_TIMER);
+ pSpxConnFile->scf_CRetryCount = PARAM(CONFIG_CONNECTION_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ goto AbortConnect;
+ }
+ }
+ }
+
+ CTEAssert((fNeg && fSpx2) || (!fSpx2 && !fNeg));
+
+ // For a SPX connection, we immediately become active. This happens
+ // in the completeConnect routine. !!Dont change it here!!
+ if (!fSpx2)
+ {
+ spxConnCompleteConnect(
+ pSpxConnFile,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+ }
+ else
+ {
+ SPX_LISTEN_SETSTATE(
+ pSpxConnFile, (fNeg ? SPX_LISTEN_SENTACK : SPX_LISTEN_SETUP));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ CTEFreeLock (&pSpxAddr->sa_Lock, LockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, LockHandleDev);
+ }
+
+ // Send the CR Ack packet!
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pCrAckPkt, pSendResd);
+
+ if (fSpx2 && !fNeg)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pSsPkt->ProtocolReserved);
+ SPX_SENDPACKET(pSpxConnFile, pSsPkt, pSendResd);
+ }
+
+ return(TRUE);
+
+
+AbortConnect:
+
+ spxConnAbortConnect(
+ pSpxConnFile,
+ STATUS_INSUFFICIENT_RESOURCES,
+ LockHandleDev,
+ LockHandleAddr,
+ LockHandleConn);
+
+ return (FALSE);
+}
+
+
+
+BOOLEAN
+SpxConnPacketize(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN BOOLEAN fNormalState,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ The caller needs to set the state to packetize before calling this
+ routine. This can be called when SEND state is RENEG also.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+ fNormalState - If true, it will assume it can release lock to send,
+ else, it just builds pkts without releasing lock and
+ releases lock at end. Used after reneg changes size.
+
+Return Value:
+
+
+--*/
+{
+ PLIST_ENTRY p;
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT windowSize;
+ ULONG dataLen;
+ USHORT sendFlags;
+ int numDerefs = 0;
+ BOOLEAN fFirstPass = TRUE, fSuccess = TRUE;
+ PREQUEST pRequest;
+
+#if DBG
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ fNormalState)
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ // Build all of the packets. The firsttime flag is used so
+ // that if we get a 0 byte send, we will send it. The firsttime
+ // flag will be set and we will build the packet and send it.
+ //
+ // FOR SPX1, we cannot trust the remote window size. So we only send
+ // stuff if window size is greater than 0 *AND* we do not have any pending
+ // sends. Dont get in here if we are ABORT. Dont want to be handling any
+ // more requests.
+ while((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ABORT) &&
+ ((pRequest = pSpxConnFile->scf_ReqPkt) != NULL) &&
+ ((pSpxConnFile->scf_ReqPktSize > 0) || fFirstPass))
+ {
+ fFirstPass = FALSE;
+ windowSize = pSpxConnFile->scf_RecdAllocNum -
+ pSpxConnFile->scf_SendSeqNum + 1;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: WINDOW %lx for %lx\n",
+ windowSize, pSpxConnFile));
+
+
+ DBGPRINT(SEND, DBG,
+ ("REMALLOC %lx SENDSEQ %lx\n",
+ pSpxConnFile->scf_RecdAllocNum,
+ pSpxConnFile->scf_SendSeqNum));
+
+
+ CTEAssert(windowSize >= 0);
+
+ // Disconnect/Orderly release is not subject to window closure.
+ if ((pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA) &&
+ (((windowSize == 0) && SPX2_CONN(pSpxConnFile)) ||
+ (!SPX2_CONN(pSpxConnFile) &&
+ (pSpxConnFile->scf_SendSeqListHead != NULL))))
+ {
+ break;
+ }
+
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_DATA)
+ {
+ CTEAssert(pRequest == pSpxConnFile->scf_ReqPkt);
+
+ // Get data length
+ dataLen = (ULONG)MIN(pSpxConnFile->scf_ReqPktSize,
+ (pSpxConnFile->scf_MaxPktSize -
+ ((SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE))));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: %lx Sending %lx Size %lx Req %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ dataLen,
+ pSpxConnFile->scf_ReqPkt,
+ pSpxConnFile->scf_ReqPktSize));
+
+ // Build data packet. Handles 0-length for data. Puts in seq num in
+ // send resd section of packet also.
+ sendFlags =
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) |
+ SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ |
+ ((!SPX2_CONN(pSpxConnFile) || (windowSize == 1)) ?
+ SPX_SENDPKT_ACKREQ : 0));
+
+ if (dataLen == pSpxConnFile->scf_ReqPktSize)
+ {
+ // Last packet of send, ask for a ack.
+ sendFlags |= (SPX_SENDPKT_LASTPKT | SPX_SENDPKT_ACKREQ);
+ if ((pSpxConnFile->scf_ReqPktFlags & TDI_SEND_PARTIAL) == 0)
+ sendFlags |= SPX_SENDPKT_EOM;
+ }
+
+ SpxPktBuildData(
+ pSpxConnFile,
+ &pPkt,
+ sendFlags,
+ (USHORT)dataLen);
+ }
+ else
+ {
+ dataLen = 0;
+
+ DBGPRINT(SEND, DBG,
+ ("Building DISC packet on %lx ReqPktSize %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_ReqPktSize));
+
+ // Build informed disc/orderly rel packet, associate with request
+ SpxPktBuildDisc(
+ pSpxConnFile,
+ pRequest,
+ &pPkt,
+ (USHORT)((fNormalState ? SPX_SENDPKT_IPXOWNS : 0) | SPX_SENDPKT_REQ |
+ SPX_SENDPKT_SEQ | SPX_SENDPKT_LASTPKT),
+ (UCHAR)((pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL) ?
+ SPX2_DT_ORDREL : SPX2_DT_IDISC));
+ }
+
+ if (pPkt != NULL)
+ {
+ // If we were waiting to send an ack, we don't have to as we are
+ // piggybacking it now. Cancel ack timer, get out.
+ if (fNormalState && SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Piggyback happening for %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // We are sending data, allow piggybacks to happen.
+ SPX_CONN_RESETFLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK);
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ if (SpxTimerCancelEvent(pSpxConnFile->scf_ATimerId, FALSE))
+ {
+ numDerefs++;
+ }
+ }
+
+ if (pSpxConnFile->scf_ReqPktType != SPX_REQ_DATA)
+ {
+ // For a disconnect set the state
+ if (pSpxConnFile->scf_ReqPktType == SPX_REQ_ORDREL)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ numDerefs++;
+ }
+ else if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_ORDREL)
+ {
+ CTEAssert((SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_ACTIVE) ||
+ (SPX_MAIN_STATE(pSpxConnFile) ==
+ SPX_CONNFILE_DISCONN));
+
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_ORDREL);
+ }
+ else
+ {
+ CTEAssert(
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL));
+ }
+ }
+ else
+ {
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+ CTEAssert(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_POST_IDISC);
+
+ // Note we have send the idisc here.
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_SENT_IDISC);
+ }
+ }
+ }
+ else
+ {
+ fSuccess = FALSE;
+ break;
+ }
+
+
+ // Queue in packet, reference request for the packet
+ SpxConnQueueSendSeqPktTail(pSpxConnFile, pPkt);
+ REQUEST_INFORMATION(pRequest)++;
+
+ pSpxConnFile->scf_ReqPktSize -= dataLen;
+ pSpxConnFile->scf_ReqPktOffset += dataLen;
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx Size after pkt %lx.%lx\n",
+ pSpxConnFile->scf_ReqPkt, pSpxConnFile->scf_ReqPktSize,
+ dataLen));
+
+ // Even if window size if zero, setup next request is current one
+ // is done. We are here only after we have packetized this send req.
+ if (pSpxConnFile->scf_ReqPktSize == 0)
+ {
+ // This request has been fully packetized. Either go on to
+ // next request or we are done packetizing.
+ p = REQUEST_LINKAGE(pRequest);
+ if (p->Flink == &pSpxConnFile->scf_ReqLinkage)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnPacketize: Req %lx done, no more\n",
+ pRequest));
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pRequest = NULL;
+ }
+ else
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p->Flink);
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnPacketize: Req done, setting next %lx.%lx\n",
+ pRequest, pParam->SendLength));
+
+ DBGPRINT(SEND, INFO,
+ ("-%lx-\n",
+ pRequest));
+
+ // Set parameters in connection for another go.
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if ((pSpxConnFile->scf_ReqPktSize = pParam->SendLength) == 0)
+ {
+ // Another zero length send.
+ fFirstPass = TRUE;
+ }
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPkt = pRequest;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ fFirstPass = TRUE;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+ }
+ }
+
+ if (fNormalState)
+ {
+ // Send the packet if we are not at the reneg state
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ ++SpxDevice->dev_Stat.DataFramesSent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesSent,
+ dataLen);
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if retry timer needs to be started.
+ if (!(SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER)))
+ {
+ if ((pSpxConnFile->scf_RTimerId =
+ SpxTimerScheduleEvent(
+ spxConnRetryTimer,
+ pSpxConnFile->scf_BaseT1,
+ pSpxConnFile)) != 0)
+ {
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Reference connection for the timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnPacketize: Failed to start retry timer\n"));
+
+ fSuccess = FALSE;
+ break;
+ }
+ }
+ }
+
+ // Dont overwrite an error state.
+ if (((fNormalState) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3) &&
+ (pSpxConnFile->scf_SendSeqListHead == NULL)))
+ {
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, ERR,
+ ("COULD NOT PACKETIZE AFTER RENEG %lx\n", pSpxConnFile));
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(fSuccess);
+}
+
+
+
+
+VOID
+SpxConnQueueRecv(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PTDI_REQUEST_KERNEL_RECEIVE pParam;
+ NTSTATUS status = STATUS_PENDING;
+
+ if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ pParam = (PTDI_REQUEST_KERNEL_RECEIVE)REQUEST_PARAMETERS(pRequest);
+ pSpxConnFile->scf_CurRecvReq = pRequest;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = pParam->ReceiveLength;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnQueueRecv: %lx.%lx\n", pRequest, pParam->ReceiveLength));
+
+ // Reference connection for this recv.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ InsertTailList(
+ &pSpxConnFile->scf_RecvLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // RECV irps have no creation references.
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+
+ // State to receive_posted if we are idle.
+ if (SPX_RECV_STATE(pSpxConnFile) == SPX_RECV_IDLE)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_POSTED);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnCompletePended(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+{
+ CTELockHandle lockHandleInter;
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+
+ InitializeListHead(&ReqList);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnCompletePended: PENDING RECV REQUESTS IN DONE LIST! %lx\n",
+ pSpxConnFile));
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ p = pSpxConnFile->scf_RecvDoneLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+
+#if DBG
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_RECEIVE)
+ {
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+VOID
+SpxConnQWaitAck(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ // If we are not already in ack queue, queue ourselves in starting
+ // ack timer.
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ACKQ))
+ {
+ // First start ack timer.
+ if ((pSpxConnFile->scf_ATimerId =
+ SpxTimerScheduleEvent(
+ spxConnAckTimer,
+ 100,
+ pSpxConnFile)) != 0)
+ {
+ // Reference connection for timer
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_ACKQ);
+ ++SpxDevice->dev_Stat.PiggybackAckQueued;
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+VOID
+SpxConnSendAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendAck: ACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an ack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnSendNack(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT NumToSend,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("spxConnSendNack: NACKING on %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_RecvSeqNum));
+
+ // Build an nack packet, queue it in non-sequenced queue. Only if we are
+ // active.
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ TRUE,
+ NumToSend);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendAck: Could not allocate!\n"));
+ }
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnSendAck: WHEN NOT ACTIVE STATE@!@\n"));
+ }
+#endif
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Send it.
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+
+BOOLEAN
+SpxConnProcessAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PREQUEST pRequest;
+ PSPX_SEND_RESD pSendResd;
+ CTELockHandle interLockHandle;
+ USHORT seqNum = 0, ackNum;
+ int numDerefs = 0;
+ BOOLEAN fLastPkt, lockHeld = TRUE, fAbort = FALSE,
+ fResetRetryTimer, fResendPkt = FALSE, fResetSendQueue = FALSE;
+
+ if (pIpxSpxHdr != NULL)
+ {
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ // Ack numbers should already be set in connection!
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ switch (SPX_SEND_STATE(pSpxConnFile))
+ {
+ case SPX_SEND_RETRYWD:
+
+ // Did we receive an ack for pending data? If so, we goto
+ // idle and process the ack.
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RETRYWD %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+ else
+ {
+ // Ok, we received an ack for our probe retry, goto
+ // renegotiate packet size.
+ // For this both sides must have negotiated size to begin with.
+ // If they did not, we go on to retrying the data packet.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG))
+ {
+ pSpxConnFile->scf_RRetryCount = SPX_DEF_RENEG_RETRYCOUNT;
+ if ((ULONG)pSpxConnFile->scf_MaxPktSize <=
+ (SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE))
+ {
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx MIN RENEG SIZE\n",
+ pSpxConnFile));
+ }
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+ else
+ {
+ DBGPRINT(SEND, ERR,
+ ("spxConnRetryTimer: NO NEG FLAG SET: %lx - %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_Flags));
+
+ // Reset count to be
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ }
+
+ break;
+
+ case SPX_SEND_RENEG:
+
+ // We better have a data packet in the list.
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead);
+
+#if DBG
+ if ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx.%lx.%lx RENEGACK SEQNUM %lx ACKNUM %lx EXPSEQ %lx\n",
+ pSpxConnFile,
+ pIpxSpxHdr->hdr_ConnCtrl,
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT),
+ seqNum,
+ ackNum,
+ (pSpxConnFile->scf_SendSeqListHead->sr_SeqNum + 1)));
+ }
+#endif
+
+ // Verify we received an RR ack. If so, we set state to
+ // SEND_RETRY3. First repacketize if we need to.
+ if ((SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT)) &&
+ ((pIpxSpxHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2)))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG! NEW %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ // Dont allow anymore reneg packet acks to be looked at.
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RENEG_PKT);
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+
+ // Also set the new send sequence number.
+ pSpxConnFile->scf_SendSeqNum =
+ (USHORT)(pSpxConnFile->scf_SendSeqListTail->sr_SeqNum + 1);
+
+ // Get the max packet size we will really use. Retry timer
+ // could have sent other sizes by now, so we can't depend
+ // on whats set.
+ // Remember max packet size in connection.
+ GETSHORT2SHORT(
+ &pSpxConnFile->scf_MaxPktSize, &pIpxSpxHdr->hdr_NegSize);
+
+ // Basic sanity checking on the max packet size.
+ if (pSpxConnFile->scf_MaxPktSize < SPX_NEG_MIN)
+ pSpxConnFile->scf_MaxPktSize = SPX_NEG_MIN;
+
+ // Get ready to reset the send queue.
+ fResetSendQueue = TRUE;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: RENEG DONE : RETRY3 %lx.%lx MP %lx!\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RETRY3);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: DUPLICATE RENEG ACK %lx!\n",
+ pSpxConnFile));
+ }
+
+ break;
+
+ case SPX_SEND_RETRY:
+ case SPX_SEND_RETRY2:
+ case SPX_SEND_RETRY3:
+
+ if (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Data acked %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+#if DBG
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_RETRY3)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: CONN RESTORED %lx.%lx!\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+ }
+#endif
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ break;
+
+ case SPX_SEND_WD:
+
+ // Ok, we received an ack for our watchdog. Done.
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ break;
+
+ default:
+
+ break;
+ }
+
+#if DBG
+ if (seqNum != 0)
+ {
+ // We have a nack, which contains an implicit ack.
+ // Instead of nack processing, what we do is we resend a
+ // packet left unacked after ack processing. ONLY if we
+ // either enter the loop below (fResetRetryTimer is FALSE)
+ // or if seqNum is non-zero (SPX2 only NACK)
+ }
+#endif
+ }
+ }
+
+ // Once our numbers are updated, we check to see if any of our packets
+ // have been acked.
+ fResetRetryTimer = TRUE;
+ while (((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ ((SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) ||
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_PACKETIZE) ||
+ fResetSendQueue) &&
+ (UNSIGNED_GREATER_WITH_WRAP(
+ pSpxConnFile->scf_RecdAckNum,
+ pSendResd->sr_SeqNum)))
+ {
+ // Reset retry timer
+ if (fResetRetryTimer)
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_R_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_RTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_RRetryCount = PARAM(CONFIG_REXMIT_COUNT);
+ }
+
+ fResetRetryTimer = FALSE;
+ }
+
+ // Update the retry seq num.
+ pSpxConnFile->scf_RetrySeqNum = pSendResd->sr_SeqNum;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pRequest = pSendResd->sr_Request;
+
+#if DBG
+ if (fResetSendQueue)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: Data acked RENEG %lx.%lx!\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+ }
+#endif
+
+ DBGPRINT(SEND, DBG,
+ ("%lx Acked\n", pSendResd->sr_SeqNum));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: %lx Seq %lx Acked Sr %lx Req %lx %lx.%lx\n",
+ pSpxConnFile,
+ pSendResd->sr_SeqNum,
+ pSendResd,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // If this packet is the last one comprising this request, remove request
+ // from queue. Calculate retry time.
+ fLastPkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_LASTPKT) != 0);
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_REXMIT) == 0) &&
+ ((pSendResd->sr_SeqNum + 1) == pSpxConnFile->scf_RecdAckNum))
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ // This is the packet which is being acked. Adjust round trip
+ // timer.
+ li = pSendResd->sr_SentTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new time
+ SpxCalculateNewT1(pSpxConnFile, value);
+ }
+ }
+
+ if (fLastPkt)
+ {
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Remove creation reference
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: LASTSEQ # %lx for Req %lx with %lx.%lx\n",
+ pSendResd->sr_SeqNum,
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ }
+
+ // Dequeue the packet
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0);
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Dereference request for the dequeing of the packet
+ --(REQUEST_INFORMATION(pRequest));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Packet owned by IPX. What do we do now? Set acked pkt so request
+ // gets dereferenced in send completion. Note that the packet is already
+ // off the queue and is floating at this point.
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnProcessAck: IPXOWNS Pkt %lx with %lx.%lx\n",
+ pPkt, pRequest, REQUEST_STATUS(pRequest)));
+
+ pSendResd->sr_State |= SPX_SENDPKT_ACKEDPKT;
+ }
+
+ if (SPX2_CONN(pSpxConnFile) &&
+ (REQUEST_MINOR_FUNCTION(pRequest) == TDI_DISCONNECT) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_ORDREL))
+ {
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_ORDREL_ACKED);
+
+ // If we had received an ordrel in the meantime, we need
+ // to disconnect.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC))
+ {
+ fAbort = TRUE;
+ }
+ }
+
+ // All packets comprising a request have been acked!
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ CTELockHandle lockHandleInter;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+
+ }
+ }
+#if DBG
+ else if (fLastPkt)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: ReqFloating %lx.%lx\n",
+ pSpxConnFile, pRequest));
+ }
+#endif
+ }
+
+ // See if we reset the send queue and repacketize.
+ if (fResetSendQueue)
+ {
+ // Reset send queue and repacketize only if pkts left unacked.
+ if (pSpxConnFile->scf_SendSeqListHead)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resetting send queue %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ spxConnResetSendQueue(pSpxConnFile);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Repacketizing %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SpxConnPacketize(pSpxConnFile, FALSE, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+ else
+ {
+ // We just go back to idle state now.
+ DBGPRINT(SEND, ERR,
+ ("SpxConnProcessAck: All packets acked reneg ack! %lx.%lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_MaxPktSize));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+ numDerefs++;
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+ }
+ }
+
+ // See if we resend a packet.
+ if ((seqNum != 0) &&
+ !fAbort &&
+ ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0))
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ // Set ack bit in packet. pSendResd initialized at beginning.
+ pSendHdr->hdr_ConnCtrl |= SPX_CC_ACK;
+
+ // We are going to resend this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_ACKREQ |
+ SPX_SENDPKT_REXMIT);
+
+ fResendPkt = TRUE;
+ }
+
+ // Push into packetize only if we received an ack. And if there arent any
+ // packets already waiting. Probably retransmit happening.
+ if (!fAbort &&
+ SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE) &&
+ (pSpxConnFile->scf_ReqPkt != NULL) &&
+ (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_PKTQ)) &&
+ ((pSpxConnFile->scf_SendSeqListHead) == NULL) &&
+ (!SPX2_CONN(pSpxConnFile) ||
+ ((SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_ORDREL_ACKED) &&
+ (SPX_DISC_STATE(pSpxConnFile) != SPX_DISC_SENT_ORDREL))))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessAck: Recd ack pktizng\n", pSpxConnFile));
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_PKTIZE);
+
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_TAIL_PKTLIST(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ else if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (fResendPkt)
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: Resend pkt on %lx.%lx\n",
+ pSpxConnFile, pSendResd->sr_SeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesResent;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesResent,
+ pSendResd->sr_Len - (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxConnProcessRenegReq(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ USHORT seqNum, ackNum, allocNum, maxPktSize;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ // The remote sent us a renegotiate request. We need to send an ack back
+ // ONLY if we have not acked a data packet with that same sequence number.
+ // This is guaranteed by the fact that we will not accept the reneg request
+ // if we have already acked a data packet with the same seq num, as our
+ // receive seq number would be incremented already.
+ //
+ // Note that if we have pending send packets we may end up doing a reneg
+ // also.
+
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&maxPktSize, &pIpxSpxHdr->hdr_PktLen);
+
+ // If the received seq num is less than the expected receive sequence number
+ // we ignore this request.
+ if (!UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ (seqNum != pSpxConnFile->scf_RecvSeqNum))
+ {
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx ERROR RENSEQ %lx RECVSEQ %lx %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ return;
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RENSEQ %lx RECVSEQ %lx MAXPKT %lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum, maxPktSize));
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ // Set RenegAckAckNum before calling buildrrack. If a previous reneg
+ // request was received with a greater maxpktsize, send an ack with
+ // that maxpktsize.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD))
+ {
+ pSpxConnFile->scf_RenegAckAckNum = pSpxConnFile->scf_RecvSeqNum;
+ pSpxConnFile->scf_RenegMaxPktSize= maxPktSize;
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_RENEGRECD);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM CURRENT %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+
+ // Adjust sentallocnum now that recvseqnum might have moved up.
+ pSpxConnFile->scf_SentAllocNum +=
+ (seqNum - pSpxConnFile->scf_RenegAckAckNum);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx SENT ALLOC NUM ADJUSTED %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SentAllocNum));
+ }
+
+ // The recvseqnum for the reneg is always >= the renegackacknum.
+ pSpxConnFile->scf_RecvSeqNum = seqNum;
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessRenegReq: %lx RESET RECVSEQ %lx SavedACKACK %lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum));
+
+ // Build and send an ack.
+ SpxPktBuildRrAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY,
+ pSpxConnFile->scf_RenegMaxPktSize);
+
+ if (pPkt != NULL)
+ {
+ SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+ }
+#if DBG
+ else
+ {
+ // Log error
+ DBGPRINT(SEND, ERR,
+ ("SpxConnSendRenegReqAck: Could not allocate!\n"));
+ }
+#endif
+
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessOrdRel(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ int numDerefs = 0;
+ PNDIS_PACKET pPkt = NULL;
+ BOOLEAN lockHeld = TRUE, fAbort = FALSE;
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ if (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ORDREL_ACKED)
+ {
+ fAbort = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this pkt
+ // Update seq numbers and stuff.
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for this. Ordinary spx2 ack.
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // Get disconnect handler if we have one. And have not indicated
+ // abortive disconnect on this connection to afd.
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC))
+ {
+ // Yeah, we set the flag regardless of whether a handler is
+ // present.
+ pDiscHandler =pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx=pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC);
+ }
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL)
+ {
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ TDI_DISCONNECT_RELEASE);
+ }
+
+ // We abort any receives here if !fAbort else we abort conn.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (fAbort)
+ {
+ // Set IDISC flag so Abortive doesnt reindicate.
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Go through and kill all pending requests.
+ spxConnAbortRecvs(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ }
+ }
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxConnProcessIDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle lockHandle
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE CONNECTION LOCK HELD!!!
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pPkt = NULL;
+
+ SPX_SET_RECVNUM(pSpxConnFile, FALSE);
+
+ // Build and send an ack for the idisc. Need to modify data type
+ // and reset sys bit on ack.
+ // BUG #12344 - Fixing this led to the problem where we queue in
+ // the pkt below, but AbortSends could already have been called
+ // => this packet stays on queue without a ref, conn gets freed
+ // underneath, and in the sendcomplete we crash when this send
+ // completes.
+ //
+ // Fix is to setup this pkt as a aborted pkt to start with.
+
+ SpxPktBuildAck(
+ pSpxConnFile,
+ &pPkt,
+ SPX_SENDPKT_IPXOWNS | SPX_SENDPKT_DESTROY | SPX_SENDPKT_ABORT,
+ FALSE,
+ 0);
+
+ if (pPkt != NULL)
+ {
+ PIPXSPX_HDR pSendHdr;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ pSendHdr->hdr_ConnCtrl &= ~SPX_CC_SYS;
+ pSendHdr->hdr_DataType = SPX2_DT_IDISC_ACK;
+
+ // We don't queue this pkt in as we have the ABORT flag set in
+ // the packet, which implies the pkt is already dequeued.
+ // SpxConnQueueSendPktTail(pSpxConnFile, pPkt);
+
+ // Reference conn for the pkt.
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ // We better not have any received pkts, we ignore disconnect
+ // pkts when that happens.
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+#if DBG
+ if (pSpxConnFile->scf_SendSeqListHead != NULL)
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA/DISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_SendListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+ }
+#endif
+
+ // Call abortive disconnect on connection.
+
+ //
+ // [SA] bug #15249
+ // This is an informed disconnect, hence pass DISCONNECT_RELEASE to AFD (TRUE in last param)
+ //
+ //
+ // We pass true only in the case of an SPX connection. SPX2 connections follow the
+ // exact semantics of Informed Disconnect.
+ //
+ if (!SPX2_CONN(pSpxConnFile)) {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ TRUE);
+ } else {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_REMOTE_DISCONNECT,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE);
+ }
+
+ if (pPkt != NULL)
+ {
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+
+ // Send the packet
+ SPX_SENDACK(pSpxConnFile, pPkt, pSendResd);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnResetSendQueue(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ CTEAssert(pSendResd != NULL);
+
+ pRequest = pSendResd->sr_Request;
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = pSendResd->sr_Request;
+ pSpxConnFile->scf_ReqPktOffset = pSendResd->sr_Offset;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(pRequest);
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset SEND Req to %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest, pParam->SendLength));
+
+ // Set parameters in connection for another go. Size parameter is
+ // original size - offset at this point.
+ pSpxConnFile->scf_ReqPktFlags = pParam->SendFlags;
+ pSpxConnFile->scf_ReqPktSize = pParam->SendLength -
+ pSpxConnFile->scf_ReqPktOffset;
+ }
+ else
+ {
+ PTDI_REQUEST_KERNEL_DISCONNECT pParam;
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: %lx.%lx.%lx Reset DISC Req to %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags, pSpxConnFile->scf_Flags2,
+ pRequest));
+
+ DBGPRINT(SEND, ERR,
+ ("spxConnResetSendQueue: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ pParam =
+ (PTDI_REQUEST_KERNEL_DISCONNECT)REQUEST_PARAMETERS(pRequest);
+
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DISC;
+ if (pParam->RequestFlags == TDI_DISCONNECT_RELEASE)
+ {
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_ORDREL;
+ }
+ }
+
+ DBGPRINT(SEND, DBG3,
+ ("spxConnResetSendQueue: Seq Num for %lx is now %lx\n",
+ pSpxConnFile, pSpxConnFile->scf_SendSeqNum));
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ do
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ KeBugCheck(0);
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+
+ } while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSendPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_SEND_RESD pSendResd,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Called to abort either a sequenced or a non-sequenced packet ONLY from
+ send completion.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ if ((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0)
+ {
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0);
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ // BUG #11626 - request is already removed from list.
+ // RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ SpxConnFileDereference(pSpxConnFile, CFREF_ABORTPKT);
+
+ if (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortSends(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PSPX_SEND_RESD pSendResd;
+ PREQUEST pRequest;
+ PNDIS_PACKET pPkt;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN);
+
+ // Reset the current send request values
+ pSpxConnFile->scf_ReqPkt = NULL;
+ pSpxConnFile->scf_ReqPktOffset = 0;
+ pSpxConnFile->scf_ReqPktSize = 0;
+ pSpxConnFile->scf_ReqPktType = SPX_REQ_DATA;
+
+ // First go through the non-seq pkt queue.Just set abort flag if owned by ipx
+ while ((pSendResd = pSpxConnFile->scf_SendListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) == 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // Set abort flag and reference conn for the pkt if its not already.
+ // We only do this check for the non-sequenced packets.
+ // BUG #12344 (see SpxRecvDiscPacket())
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) == 0)
+ {
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+ }
+
+ // When we are trying to abort a pkt and it is in use by ipx, we simply let
+ // it float.
+ while ((pSendResd = pSpxConnFile->scf_SendSeqListHead) != NULL)
+ {
+ pPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSendResd, NDIS_PACKET, ProtocolReserved);
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0);
+ pRequest = pSendResd->sr_Request;
+
+ CTEAssert(REQUEST_INFORMATION(pRequest) != 0);
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pPkt);
+ if ((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) == 0)
+ {
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+ REQUEST_INFORMATION(pRequest) = 0;
+
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+
+ // Free the packet
+ SpxPktSendRelease(pPkt);
+ }
+ else
+ {
+ // We let send completion know that this packet is to be aborted.
+ pSendResd->sr_State |= SPX_SENDPKT_ABORT;
+ SpxConnFileLockReference(pSpxConnFile, CFREF_ABORTPKT);
+ }
+ }
+
+ // If retry timer state is on, then we need to reset and deref.
+ if ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_WD))
+ {
+ DBGPRINT(SEND, DBG1,
+ ("spxConnAbortSends: When SEND ERROR STATE %lx.%lx\n",
+ pSpxConnFile, SPX_SEND_STATE(pSpxConnFile)));
+
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_IDLE);
+
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_ERRORSTATE,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ }
+
+ // Remove creation references on all sends.
+ if (!IsListEmpty(&pSpxConnFile->scf_ReqLinkage))
+ {
+ p = pSpxConnFile->scf_ReqLinkage.Flink;
+ while (p != &pSpxConnFile->scf_ReqLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on. Its complete or abort list for it.
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Aborting Send Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ if (REQUEST_MINOR_FUNCTION(pRequest) != TDI_DISCONNECT)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_ReqDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendComplete: DISC Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ numDerefs++;
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+spxConnAbortRecvs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NTSTATUS Status,
+ IN SPX_CALL_LEVEL CallLevel,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LIST_ENTRY ReqList, *p;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PBYTE pData;
+ ULONG dataLen;
+ int numDerefs = 0;
+
+ InitializeListHead(&ReqList);
+
+ // We better be in disconnect state, abortive/informed/orderly initiate.
+ // Reset the current receive request values
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ // If we have any buffered data, abort it.
+ // Buffered data that is 0 bytes long (only eom) may not have a ndis
+ // buffer associated with it.
+ while ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL)
+ {
+ if ((pSpxConnFile->scf_RecvListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pSpxConnFile->scf_RecvListTail = NULL;
+ }
+
+ pNdisPkt = (PNDIS_PACKET)
+ CONTAINING_RECORD(pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("spxConnAbortRecvs: %lx in bufferlist on %lx\n",
+ pSpxConnFile, pNdisPkt));
+
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ SpxFreeMemory(pData);
+ NdisFreeBuffer(pNdisBuffer);
+ }
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ // Free the ndis packet
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ // If packets are on this queue, they are waiting for transfer data to
+ // complete. Can't do much about that, just go and remove creation refs
+ // on the receives.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ p = pSpxConnFile->scf_RecvLinkage.Flink;
+ while (p != &pSpxConnFile->scf_RecvLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ // Remove request from list its on
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+
+ // Set status
+ REQUEST_STATUS(pRequest) = Status;
+
+ DBGPRINT(RECEIVE, DBG1,
+ ("SpxRecvAbort: Aborting Recv Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvAbort: QForComp Request %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ if (CallLevel == SPX_CALL_RECVLEVEL)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ // If connection is not already in recv queue, put it in
+ // there.
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ else
+ {
+ InsertTailList(
+ &ReqList,
+ REQUEST_LINKAGE(pRequest));
+ }
+ }
+#if DBG
+ else
+ {
+ // Let it float,
+ DBGPRINT(SEND, DBG1,
+ ("SpxSendAbort: %lx Floating Send %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+ }
+ }
+
+ // Release
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ while (!IsListEmpty(&ReqList))
+ {
+ p = RemoveHeadList(&ReqList);
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ numDerefs++;
+
+ SpxCompleteRequest(pRequest);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+#if 0
+
+VOID
+spxConnResendPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ USHORT startSeqNum;
+ BOOLEAN fLockHeld = TRUE, fDone = FALSE;
+
+ pSendResd = pSpxConnFile->scf_SendSeqListHead;
+ if (pSendResd)
+ {
+ startSeqNum = pSendResd->sr_SeqNum;
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: StartSeqNum %lx for resend on %lx\n",
+ startSeqNum, pSpxConnFile));
+
+ while (spxConnGetPktBySeqNum(pSpxConnFile, startSeqNum++, &pPkt))
+ {
+ CTEAssert(pPkt != NULL);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if (!(pSendResd->sr_State & SPX_SENDPKT_IPXOWNS))
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx resent on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+
+ // We are going to send this packet
+ pSendResd->sr_State |= (SPX_SENDPKT_IPXOWNS |
+ SPX_SENDPKT_REXMIT);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("spxConnResendPkts: Pkt %lx.%lx owned by ipx on %lx\n",
+ pPkt, (startSeqNum - 1), pSpxConnFile));
+ break;
+ }
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ fLockHeld = FALSE;
+
+ // If pkt has the ack bit set, we break.
+ fDone = ((pSendResd->sr_State & SPX_SENDPKT_ACKREQ) != 0);
+
+ // Send the packet
+ SPX_SENDPACKET(pSpxConnFile, pPkt, pSendResd);
+ if (fDone)
+ {
+ break;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fLockHeld = TRUE;
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return;
+}
+#endif
diff --git a/private/ntos/tdi/isn/spx/spxcutil.c b/private/ntos/tdi/isn/spx/spxcutil.c
new file mode 100644
index 000000000..fa2105e42
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxcutil.c
@@ -0,0 +1,1736 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxcutil.c
+
+Abstract:
+
+ This module contains code which implements the CONNECTION object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport connection objects.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXCUTIL
+
+//
+// Minor utility routines
+//
+
+
+BOOLEAN
+spxConnCheckNegSize(
+ IN PUSHORT pNegSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ int i;
+
+ // We go thru table and see if this is the minimum size or if it
+ // can go down further. Return true if it is not the minimum size.
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[0]));
+
+ if ((ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE) <= SpxMaxPktSize[0])
+ return(FALSE);
+
+ for (i = SpxMaxPktSizeIndex-1; i > 0; i--)
+ {
+ DBGPRINT(CONNECT, INFO,
+ ("spxConnCheckNegSize: Current %lx Check Val %lx\n",
+ (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE),
+ SpxMaxPktSize[i]));
+
+ if (SpxMaxPktSize[i] < (ULONG)(*pNegSize - MIN_IPXSPX2_HDRSIZE))
+ break;
+ }
+
+ *pNegSize = (USHORT)(SpxMaxPktSize[i] + MIN_IPXSPX2_HDRSIZE);
+
+ DBGPRINT(CONNECT, ERR,
+ ("spxConnCheckNegSize: Trying Size %lx Min size possible %lx\n",
+ *pNegSize, SpxMaxPktSize[0] + MIN_IPXSPX2_HDRSIZE));
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+spxConnSetNegSize(
+ IN OUT PNDIS_PACKET pPkt,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ UINT bufCount;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+
+ CTEAssert(Size > 0);
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ CTEAssert (bufCount == 3);
+
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
+ NdisAdjustBufferLength(pNdisBuffer, Size);
+
+ // Change it in send reserved
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Len = (Size + MIN_IPXSPX2_HDRSIZE);
+
+ // Change in ipx header
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ PUTSHORT2SHORT((PUSHORT)&pIpxSpxHdr->hdr_PktLen, (Size + MIN_IPXSPX2_HDRSIZE));
+
+ // Change in the neg packet field of the header.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ (Size + MIN_IPXSPX2_HDRSIZE));
+
+ DBGPRINT(CONNECT, DBG,
+ ("spxConnSetNegSize: Setting size to %lx Hdr %lx\n",
+ Size, (Size + MIN_IPXSPX2_HDRSIZE)));
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueSendPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, pListHead, pListTail;
+ PSPX_SEND_RESD pSendResd;
+ BOOLEAN removed = TRUE;
+
+ // If we are sequenced or not decides which list we choose.
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pListHead = pSpxConnFile->scf_SendSeqListHead;
+ pListTail = pSpxConnFile->scf_SendSeqListTail;
+ }
+ else
+ {
+ pListHead = pSpxConnFile->scf_SendListHead;
+ pListTail = pSpxConnFile->scf_SendListTail;
+ }
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pSendResd)
+ {
+ if ((pListHead = pSendResd->sr_Next) == NULL)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pSendResd));
+
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pSendResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->sr_Next == pSendResd)
+ {
+ if ((pSr->sr_Next = pSendResd->sr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->sr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ if ((pSendResd->sr_State & SPX_SENDPKT_SEQ) != 0)
+ {
+ pSpxConnFile->scf_SendSeqListHead = pListHead;
+ pSpxConnFile->scf_SendSeqListTail = pListTail;
+ }
+ else
+ {
+ pSpxConnFile->scf_SendListHead = pListHead;
+ pSpxConnFile->scf_SendListTail = pListTail;
+ }
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+SpxConnDequeueRecvPktLock(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PNDIS_PACKET pPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_RECV_RESD pSr, pListHead, pListTail;
+ PSPX_RECV_RESD pRecvResd;
+ BOOLEAN removed = TRUE;
+
+ pRecvResd = (PSPX_RECV_RESD)(pPkt->ProtocolReserved);
+ pListHead = pSpxConnFile->scf_RecvListHead;
+ pListTail = pSpxConnFile->scf_RecvListTail;
+
+ // Most often, we will be at the head of the list.
+ if (pListHead == pRecvResd)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx first in list\n", pRecvResd));
+
+ if ((pListHead = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = NULL;
+ }
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDequeuePktLock: %lx !first in list\n", pRecvResd));
+
+ pSr = pListHead;
+ while (pSr != NULL)
+ {
+ if (pSr->rr_Next == pRecvResd)
+ {
+ if ((pSr->rr_Next = pRecvResd->rr_Next) == NULL)
+ {
+ pListTail = pSr;
+ }
+
+ break;
+ }
+
+ pSr = pSr->rr_Next;
+ }
+
+ if (pSr == NULL)
+ removed = FALSE;
+ }
+
+ if (removed)
+ {
+ pSpxConnFile->scf_RecvListHead = pListHead;
+ pSpxConnFile->scf_RecvListTail = pListTail;
+ }
+
+ return(removed);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktByType(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG PktType,
+ IN BOOLEAN fSeqList,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = (fSeqList ?
+ &pSpxConnFile->scf_SendSeqListHead :
+ &pSpxConnFile->scf_SendListHead);
+
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_Type == PktType)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, INFO,
+ ("SpxConnFindByType: %lx.%lx.%d\n", pSr,*ppPkt, fSeqList));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+BOOLEAN
+spxConnGetPktBySeqNum(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN USHORT SeqNum,
+ IN PNDIS_PACKET * ppPkt
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSr, *ppSr;
+
+ // Most often, we will be at the head of the list.
+ ppSr = &pSpxConnFile->scf_SendSeqListHead;
+ for (; (pSr = *ppSr) != NULL; )
+ {
+ if (pSr->sr_SeqNum == SeqNum)
+ {
+ *ppPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pSr, NDIS_PACKET, ProtocolReserved);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnFindBySeq: %lx.%lx.%d\n", pSr,*ppPkt, SeqNum));
+
+ break;
+ }
+
+ ppSr = &pSr->sr_Next;
+ }
+
+ return(pSr != NULL);
+}
+
+
+
+
+USHORT
+spxConnGetId(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ BOOLEAN wrapped = FALSE;
+ USHORT startConnId, retConnId;
+
+ startConnId = SpxDevice->dev_NextConnId;
+
+ // Search the global active list.
+ do
+ {
+ if ((SpxDevice->dev_NextConnId >= startConnId) && wrapped)
+ {
+ retConnId = 0;
+ break;
+ }
+
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ continue;
+ }
+
+ // BUGBUG: Later this be a tree.
+ for (pSpxConnFile = SpxDevice->dev_GlobalActiveConnList[
+ SpxDevice->dev_NextConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxConnFile != NULL;
+ pSpxConnFile = pSpxConnFile->scf_GlobalActiveNext)
+ {
+ if (pSpxConnFile->scf_LocalConnId == SpxDevice->dev_NextConnId)
+ {
+ break;
+ }
+ }
+
+ // Increment for next time.
+ retConnId = SpxDevice->dev_NextConnId++;
+
+ // Ensure we are still legal. We could return if connfile is null.
+ if (SpxDevice->dev_NextConnId == 0xFFFF)
+ {
+ wrapped = TRUE;
+ SpxDevice->dev_NextConnId = 1;
+ }
+
+ if (pSpxConnFile != NULL)
+ {
+ continue;
+ }
+
+ break;
+
+ } while (TRUE);
+
+ return(retConnId);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_Next;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_Next;
+ }
+
+ if (pRemConn == NULL)
+ {
+ DBGBRK(FATAL);
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromAssocList(
+ IN PSPX_CONN_FILE * ppConnListHead,
+ IN PSPX_CONN_FILE pConnRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the address lock (and the lock of the remove
+ connection will usually also be, but is not needed) held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pRemConn, *ppRemConn;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Dequeue the connection file from the address list. It must be
+ // in the inactive list.
+ for (ppRemConn = ppConnListHead;
+ (pRemConn = *ppRemConn) != NULL;)
+ {
+ if (pRemConn == pConnRemove)
+ {
+ *ppRemConn = pRemConn->scf_AssocNext;
+ break;
+ }
+
+ ppRemConn = &pRemConn->scf_AssocNext;
+ }
+
+ if (pRemConn == NULL)
+ {
+ CTEAssert(0);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+
+ // For now, its just a linear list.
+ pSpxConnFile->scf_GlobalActiveNext =
+ SpxDevice->dev_GlobalActiveConnList[index];
+
+ SpxDevice->dev_GlobalActiveConnList[index] =
+ pSpxConnFile;
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalActiveList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine must be called with the device lock held.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PSPX_CONN_FILE pC, *ppC;
+ int index = (int)(pSpxConnFile->scf_LocalConnId &
+ NUM_SPXCONN_HASH_MASK);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // For now, its just a linear list.
+ for (ppC = &SpxDevice->dev_GlobalActiveConnList[index];
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalActiveNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalActiveNext;
+ }
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+VOID
+spxConnInsertIntoGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_GlobalNext = SpxGlobalConnList;
+ SpxGlobalConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+NTSTATUS
+spxConnRemoveFromGlobalList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+ PSPX_CONN_FILE pC, *ppC;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ for (ppC = &SpxGlobalConnList;
+ (pC = *ppC) != NULL;)
+ {
+ if (pC == pSpxConnFile)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromGlobal: %lx\n", pSpxConnFile));
+
+ // Remove from list
+ *ppC = pC->scf_GlobalNext;
+ break;
+ }
+
+ ppC = &pC->scf_GlobalNext;
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ if (pC == NULL)
+ status = STATUS_INVALID_CONNECTION;
+
+ return(status);
+}
+
+
+
+
+
+
+#if 0
+
+VOID
+spxConnPushIntoPktList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_PktNext = SpxPktConnList;
+ SpxPktConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromPktList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxPktConnList) != NULL)
+ {
+ SpxPktConnList = SpxPktConnList->scf_PktNext;
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+
+
+
+VOID
+spxConnPushIntoRecvList(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ pSpxConnFile->scf_ProcessRecvNext = SpxRecvConnList;
+ SpxRecvConnList = pSpxConnFile;
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+
+ return;
+}
+
+
+
+
+VOID
+spxConnPopFromRecvList(
+ IN PSPX_CONN_FILE * ppSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MACROIZE!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CTELockHandle lockHandle;
+
+ // Get the global q lock
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandle);
+ if ((*ppSpxConnFile = SpxRecvConnList) != NULL)
+ {
+ SpxRecvConnList = SpxRecvConnList->scf_ProcessRecvNext;
+ DBGPRINT(SEND, INFO,
+ ("SpxConnRemoveFromRecv: %lx\n", *ppSpxConnFile));
+ }
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandle);
+ return;
+}
+
+#endif
+
+
+//
+// Reference/Dereference routines
+//
+
+
+#if DBG
+
+VOID
+SpxConnFileRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFile
+
+
+
+
+VOID
+SpxConnFileLockRef(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE CONNECTION LOCK HELD.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (pSpxConnFile->scf_RefCount >= 0); // not perfect, but...
+
+ (VOID)SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ 1,
+ &pSpxConnFile->scf_Lock);
+
+} // SpxRefConnectionFileLock
+
+#endif
+
+
+
+
+VOID
+SpxConnFileRefByIdLock (
+ IN USHORT ConnId,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE DEVICE LOCK HELD!!!
+
+ All active connections should be on the device active list. Later,
+ this data structure will be a tree, caching the last accessed
+ connection.
+
+Arguments:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn =
+ SpxDevice->dev_GlobalActiveConnList[ConnId & NUM_SPXCONN_HASH_MASK];
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_GlobalActiveNext)
+ {
+ if (pSpxChkConn->scf_LocalConnId == ConnId)
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYID);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+
+}
+
+
+
+
+VOID
+SpxConnFileRefByCtxLock(
+ IN PSPX_ADDR_FILE pSpxAddrFile,
+ IN CONNECTION_CONTEXT Ctx,
+ OUT PSPX_CONN_FILE * ppSpxConnFile,
+ OUT PNTSTATUS pStatus
+ )
+/*++
+
+Routine Description:
+
+ !!!MUST BE CALLED WITH THE ADDRESS LOCK HELD!!!
+
+ Returns a referenced connection file with the associated context and
+ address file desired.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxChkConn;
+
+ *pStatus = STATUS_SUCCESS;
+
+ for (pSpxChkConn = pSpxAddrFile->saf_Addr->sa_InactiveConnList;
+ pSpxChkConn != NULL;
+ pSpxChkConn = pSpxChkConn->scf_Next)
+ {
+ if ((pSpxChkConn->scf_ConnCtx == Ctx) &&
+ (pSpxChkConn->scf_AddrFile == pSpxAddrFile))
+ {
+ SpxConnFileReference(pSpxChkConn, CFREF_BYCTX);
+ *ppSpxConnFile = pSpxChkConn;
+ break;
+ }
+ }
+
+ if (pSpxChkConn == NULL)
+ {
+ *pStatus = STATUS_INVALID_CONNECTION;
+ }
+
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxConnFileVerify (
+ IN PSPX_CONN_FILE pConnFile
+ )
+
+/*++
+
+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:
+
+
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ try
+ {
+ if ((pConnFile->scf_Size == sizeof (SPX_CONN_FILE)) &&
+ (pConnFile->scf_Type == SPX_CONNFILE_SIGNATURE))
+ {
+ CTEGetLock (&pConnFile->scf_Lock, &LockHandle);
+ if (!SPX_CONN_FLAG(pConnFile, SPX_CONNFILE_CLOSING))
+ {
+ SpxConnFileLockReference(pConnFile, CFREF_VERIFY);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyConnFile: A %lx closing\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+ CTEFreeLock (&pConnFile->scf_Lock, LockHandle);
+ }
+ else
+ {
+ DBGPRINT(TDI, ERR,
+ ("StVerifyAddressFile: AF %lx bad signature\n", pConnFile));
+
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ DBGPRINT(TDI, ERR,
+ ("SpxVerifyConnFile: AF %lx exception\n", pConnFile));
+
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} // SpxVerifyConnFile
+
+
+
+
+VOID
+SpxConnFileDeref(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+
+/*++
+
+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
+ SpxDestroyConnectionFile to remove it from the system.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ BOOLEAN fDiscNotIndicated = FALSE;
+ BOOLEAN fIDiscFlag = FALSE;
+ BOOLEAN fSpx2;
+
+ CTEAssert(pSpxConnFile->scf_RefCount > 0);
+ oldvalue = SPX_ADD_ULONG (
+ &pSpxConnFile->scf_RefCount,
+ (ULONG)-1,
+ &pSpxConnFile->scf_Lock);
+
+ CTEAssert (oldvalue > 0);
+ if (oldvalue == 1)
+ {
+ CTELockHandle lockHandleConn, lockHandleAddr, lockHandleDev;
+ LIST_ENTRY discReqList, *p;
+ PREQUEST pDiscReq;
+ PSPX_ADDR_FILE pSpxAddrFile = NULL;
+ PREQUEST pCloseReq = NULL,
+ pCleanupReq = NULL,
+ pConnectReq = NULL;
+ BOOLEAN fDisassoc = FALSE;
+
+ InitializeListHead(&discReqList);
+
+ // We may not be associated at this point. Note: When we are active we
+ // always have a reference. So its not like we execute this code very often.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ }
+ else
+ {
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+
+ if (pSpxAddrFile)
+ {
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+
+ //if (pSpxConnFile->scf_RefCount == 0)
+
+ //
+ // ** The lock passed here is a dummy - it is pre-compiled out.
+ //
+ if (SPX_ADD_ULONG(&pSpxConnFile->scf_RefCount, 0, &pSpxConnFile->scf_Lock) == 0)
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn is 0 %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // All pending requests on this connection are done. See if we
+ // need to complete the disconnect phase etc.
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_DISCONN:
+
+ // Disconnect is done. Move connection out of all the lists
+ // it is on, reset states etc.
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn being inactivated %lx\n",
+ pSpxConnFile));
+
+ // Time to complete disc requests if present.
+ // There could be multiple of them.
+ p = pSpxConnFile->scf_DiscLinkage.Flink;
+ while (p != &pSpxConnFile->scf_DiscLinkage)
+ {
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Disc on %lx.%lx\n",
+ pSpxConnFile, pDiscReq));
+
+ RemoveEntryList(REQUEST_LINKAGE(pDiscReq));
+
+ if (REQUEST_STATUS(pDiscReq) == STATUS_PENDING)
+ {
+ REQUEST_STATUS(pDiscReq) = STATUS_SUCCESS;
+ }
+
+ InsertTailList(
+ &discReqList,
+ REQUEST_LINKAGE(pDiscReq));
+ }
+
+ //
+ // Note the state here, and check after the conn has been inactivated.
+ //
+
+ //
+ // Bug #14354 - odisc and idisc cross each other, leading to double disc to AFD
+ //
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_ODISC)) {
+ fDiscNotIndicated = TRUE;
+ }
+
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IDISC)) {
+ fIDiscFlag = TRUE;
+ }
+
+ fSpx2 = (SPX2_CONN(pSpxConnFile)) ? TRUE : FALSE;
+
+ //
+ // [SA] Bug #14655
+ // Do not try to inactivate an already inactivated connection
+ //
+
+ if (!(SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED)) {
+ spxConnInactivate(pSpxConnFile);
+ } else {
+ //
+ // This is an SPXI connection which has got the local disconnect.
+ // Reset the flags now.
+ //
+ CTEAssert(!fDiscNotIndicated);
+
+ SPX_MAIN_SETSTATE(pSpxConnFile, 0);
+ SPX_DISC_SETSTATE(pSpxConnFile, 0);
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+ }
+
+ //
+ // [SA] If we were waiting for sends to be aborted and did not indicate this
+ // disconnect to AFD; and AFD did not call a disconnect on this connection,
+ // then call the disonnect handler now.
+ //
+ if (fDiscNotIndicated) {
+ PVOID pDiscHandlerCtx;
+ PTDI_IND_DISCONNECT pDiscHandler = NULL;
+ ULONG discCode = 0;
+
+ pDiscHandler = pSpxConnFile->scf_AddrFile->saf_DiscHandler;
+ pDiscHandlerCtx = pSpxConnFile->scf_AddrFile->saf_DiscHandlerCtx;
+
+ // Indicate disconnect to afd.
+ if (pDiscHandler != NULL) {
+
+ //
+ // If this was an SPXI connection, the disconnect state is still
+ // DISCONN, so if this routine is re-entered, we need to prevent
+ // a re-indicate to AFD.
+ // Also, we need to wait for a local disconnect from AFD since
+ // we indicated a TDI_DISCONNECT_RELEASE. We bump up the ref count
+ // in this case.
+ //
+ if (!fSpx2) {
+ CTEAssert( (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_INACTIVATED) );
+
+ SPX_CONN_SETFLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC);
+
+ if (fIDiscFlag) {
+ SpxConnFileLockReference(pSpxConnFile, CFREF_DISCWAITSPX);
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_DISC_WAIT);
+ }
+ }
+
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+
+ DBGPRINT(CONNECT, INFO,
+ ("spxDerefConnectionFile: Indicating to afd On %lx when %lx\n",
+ pSpxConnFile, SPX_MAIN_STATE(pSpxConnFile)));
+
+ // First complete all requests waiting for receive completion on
+ // this conn before indicating disconnect.
+ spxConnCompletePended(pSpxConnFile);
+
+ if (fIDiscFlag) {
+ //
+ // Indicate DISCONNECT_RELEASE to AFD so it allows receive of packets
+ // it has buffered before the remote disconnect took place.
+ //
+ discCode = TDI_DISCONNECT_RELEASE;
+ } else {
+ //
+ // [SA] bug #15249
+ // If not Informed disconnect, indicate DISCONNECT_ABORT to AFD
+ //
+ discCode = TDI_DISCONNECT_ABORT;
+ }
+
+ (*pDiscHandler)(
+ pDiscHandlerCtx,
+ pSpxConnFile->scf_ConnCtx,
+ 0, // Disc data
+ NULL,
+ 0, // Disc info
+ NULL,
+ discCode);
+
+ CTEGetLock(&SpxDevice->dev_Lock, &lockHandleDev);
+ CTEGetLock(pSpxAddrFile->saf_AddrLock, &lockHandleAddr);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandleConn);
+ }
+ }
+
+ --SpxDevice->dev_Stat.OpenConnections;
+
+ break;
+
+ case SPX_CONNFILE_CONNECTING:
+ case SPX_CONNFILE_LISTENING:
+
+ // Get connect/accept request if present.
+ pConnectReq = pSpxConnFile->scf_ConnectReq;
+ pSpxConnFile->scf_ConnectReq = NULL;
+
+ spxConnInactivate(pSpxConnFile);
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+
+ KeBugCheck(0);
+
+ default:
+
+ CTEAssert(SPX_MAIN_STATE(pSpxConnFile) == 0);
+ break;
+ }
+
+ // If stopping, disassociate from the address file. Complete
+ // cleanup request.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn cleanup %lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_CleanupReq));
+
+ // Save this for later completion.
+ pCleanupReq = pSpxConnFile->scf_CleanupReq;
+ pSpxConnFile->scf_CleanupReq = NULL;
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_ASSOC))
+ {
+ DBGPRINT(TDI, INFO,
+ ("SpxDerefConnectionFile: Conn stopping %lx\n",
+ pSpxConnFile));
+
+ pSpxAddrFile = pSpxConnFile->scf_AddrFile;
+ SPX_CONN_RESETFLAG(pSpxConnFile,SPX_CONNFILE_ASSOC);
+
+ // Dequeue the connection from the address file
+ spxConnRemoveFromAssocList(
+ &pSpxAddrFile->saf_AssocConnList,
+ pSpxConnFile);
+
+ // Dequeue the connection file from the address list. It must
+ // be in the inactive list.
+ spxConnRemoveFromList(
+ &pSpxAddrFile->saf_Addr->sa_InactiveConnList,
+ pSpxConnFile);
+
+ DBGPRINT(CREATE, INFO,
+ ("SpxConnDerefDisAssociate: %lx from addr file %lx\n",
+ pSpxConnFile, pSpxAddrFile));
+
+ fDisassoc = TRUE;
+ }
+ }
+
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Conn closing %lx\n",
+ pSpxConnFile));
+
+ // Save this for later completion.
+ pCloseReq = pSpxConnFile->scf_CloseReq;
+
+ //
+ // Null this out so on a re-entrant case, we dont try to complete this again.
+ //
+ pSpxConnFile->scf_CloseReq = NULL;
+ CTEAssert(pCloseReq != NULL);
+ }
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ }
+ CTEFreeLock (&pSpxConnFile->scf_Lock, lockHandleConn);
+ CTEFreeLock (pSpxAddrFile->saf_AddrLock, lockHandleAddr);
+ CTEFreeLock (&SpxDevice->dev_Lock, lockHandleDev);
+ }
+
+ if (fDisassoc)
+ {
+ // Remove reference on address for this association.
+ SpxAddrFileDereference(pSpxAddrFile, AFREF_CONN_ASSOC);
+ }
+
+ if (pConnectReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Connect on %lx req %lx\n",
+ pSpxConnFile, pConnectReq));
+
+ // Status will already be set in here. We should be here only if
+ // connect is being aborted.
+ SpxCompleteRequest(pConnectReq);
+ }
+
+ while (!IsListEmpty(&discReqList))
+ {
+ p = RemoveHeadList(&discReqList);
+ pDiscReq = LIST_ENTRY_TO_REQUEST(p);
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnFileDeref: DISC REQ %lx.%lx Completing\n",
+ pSpxConnFile, pDiscReq));
+
+ SpxCompleteRequest(pDiscReq);
+ }
+
+ if (pCleanupReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Cleanup complete %lx req %lx\n",
+ pSpxConnFile, pCleanupReq));
+
+ REQUEST_INFORMATION(pCleanupReq) = 0;
+ REQUEST_STATUS(pCleanupReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCleanupReq);
+ }
+
+ if (pCloseReq != (PREQUEST)NULL)
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxDerefConnectionFile: Freed %lx close req %lx\n",
+ pSpxConnFile, pCloseReq));
+
+ CTEAssert(pSpxConnFile->scf_RefCount == 0);
+
+ // Remove from the global list
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalList(pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Free it up.
+ SpxFreeMemory (pSpxConnFile);
+
+ REQUEST_INFORMATION(pCloseReq) = 0;
+ REQUEST_STATUS(pCloseReq) = STATUS_SUCCESS;
+ SpxCompleteRequest (pCloseReq);
+ }
+ }
+
+ return;
+
+} // SpxDerefConnectionFile
+
+
+
+
+VOID
+spxConnReInit(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ // Reinit all variables.
+ pSpxConnFile->scf_Flags2 = 0;
+
+ pSpxConnFile->scf_GlobalActiveNext = NULL;
+ pSpxConnFile->scf_PktNext = NULL;
+ pSpxConnFile->scf_CRetryCount = 0;
+ pSpxConnFile->scf_WRetryCount = 0;
+ pSpxConnFile->scf_RRetryCount = 0;
+ pSpxConnFile->scf_RRetrySeqNum = 0;
+
+ pSpxConnFile->scf_CTimerId =
+ pSpxConnFile->scf_RTimerId =
+ pSpxConnFile->scf_WTimerId =
+ pSpxConnFile->scf_TTimerId =
+ pSpxConnFile->scf_ATimerId = 0;
+
+ pSpxConnFile->scf_LocalConnId =
+ pSpxConnFile->scf_SendSeqNum =
+ pSpxConnFile->scf_SentAllocNum =
+ pSpxConnFile->scf_RecvSeqNum =
+ pSpxConnFile->scf_RetrySeqNum =
+ pSpxConnFile->scf_RecdAckNum =
+ pSpxConnFile->scf_RemConnId =
+ pSpxConnFile->scf_RecdAllocNum = 0;
+
+#if DBG
+ // Initialize so we dont hit breakpoint on seq 0
+ pSpxConnFile->scf_PktSeqNum = 0xFFFF;
+#endif
+
+ pSpxConnFile->scf_DataType = 0;
+
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_ReqLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_DiscLinkage));
+ CTEAssert(IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_RecvListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendListTail == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListHead == NULL);
+ CTEAssert(pSpxConnFile->scf_SendSeqListTail == NULL);
+ pSpxConnFile->scf_CurRecvReq = NULL;
+ pSpxConnFile->scf_CurRecvOffset = 0;
+ pSpxConnFile->scf_CurRecvSize = 0;
+
+ pSpxConnFile->scf_ReqPkt = NULL;
+
+ return;
+}
+
+
+
+
+VOID
+spxConnInactivate(
+ IN PSPX_CONN_FILE pSpxConnFile
+ )
+/*++
+
+Routine Description:
+
+ !!! Called with dev/addr/connection lock held !!!
+
+Arguments:
+
+ This gets us back to associate SAVING the state of the STOPPING and
+ CLOSING flags so that dereference can go ahead and finish those.
+
+Return Value:
+
+
+--*/
+{
+ BOOLEAN fStopping, fClosing, fAborting;
+
+ fStopping = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING);
+ fClosing = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_CLOSING);
+
+ //
+ // [SA] Bug #14655
+ // Save the disconnect states so that a proper error can be given in the case of
+ // a send after a remote disconnection.
+ //
+
+ //
+ // Bug #17729
+ // Dont retain these flags if a local disconnect has already occured.
+ //
+
+ fAborting = (!SPX2_CONN(pSpxConnFile) &&
+ !SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_IND_IDISC) &&
+ (SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_ABORT));
+
+#if DBG
+ pSpxConnFile->scf_GhostFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_GhostFlags2 = pSpxConnFile->scf_Flags2;
+ pSpxConnFile->scf_GhostRefCount = pSpxConnFile->scf_RefCount;
+#endif
+
+ // Clear all flags, go back to the assoc state. Restore stop/close
+ pSpxConnFile->scf_Flags = SPX_CONNFILE_ASSOC;
+ SPX_CONN_SETFLAG(pSpxConnFile,
+ ((fStopping ? SPX_CONNFILE_STOPPING : 0) |
+ (fClosing ? SPX_CONNFILE_CLOSING : 0)));
+
+ //
+ // [SA] bug #14655
+ // In order to avoid a re-entry, mark connection as SPX_DISC_INACTIVATED
+ //
+ if (fAborting)
+ {
+ SPX_MAIN_SETSTATE(pSpxConnFile, SPX_CONNFILE_DISCONN);
+ SPX_DISC_SETSTATE(pSpxConnFile, SPX_DISC_INACTIVATED);
+ }
+
+ // Remove connection from global list on device
+ if (!NT_SUCCESS(spxConnRemoveFromGlobalActiveList(
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Remove connection from active list on address
+ if (!NT_SUCCESS(spxConnRemoveFromList(
+ &pSpxConnFile->scf_AddrFile->saf_Addr->sa_ActiveConnList,
+ pSpxConnFile)))
+ {
+ KeBugCheck(0);
+ }
+
+ // Put connection in inactive list on address
+ SPX_INSERT_ADDR_INACTIVE(
+ pSpxConnFile->scf_AddrFile->saf_Addr,
+ pSpxConnFile);
+
+ spxConnReInit(pSpxConnFile);
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxdev.c b/private/ntos/tdi/isn/spx/spxdev.c
new file mode 100644
index 000000000..431498686
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxdev.c
@@ -0,0 +1,242 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdev.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDEV
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitCreateDevice)
+#pragma alloc_text(PAGE, SpxDestroyDevice)
+#endif
+
+
+
+
+VOID
+SpxDerefDevice(
+ 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->dev_RefCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0)
+ {
+ // Close binding to IPX
+ SpxUnbindFromIpx();
+
+ // Set unload event.
+ KeSetEvent(&SpxUnloadEvent, IO_NETWORK_INCREMENT, FALSE);
+ }
+
+} // SpxDerefDevice
+
+
+
+
+NTSTATUS
+SpxInitCreateDevice(
+ 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;
+ ULONG DeviceNameOffset;
+
+
+ DBGPRINT(DEVICE, INFO,
+ ("SpxInitCreateDevice - Create device %ws\n", DeviceName->Buffer));
+
+ // 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).
+ 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)) {
+ DBGPRINT(DEVICE, ERR, ("IoCreateDevice failed\n"));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+ Device = (PDEVICE)deviceObject;
+
+ DBGPRINT(DEVICE, INFO, ("IoCreateDevice succeeded %lx\n", Device));
+
+ // Initialize our part of the device context.
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ DeviceNameOffset = sizeof(DEVICE);
+
+ // Copy over the device name.
+ Device->dev_DeviceNameLen = DeviceName->Length + sizeof(WCHAR);
+ Device->dev_DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+
+ RtlCopyMemory(
+ Device->dev_DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+
+ Device->dev_DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ // Initialize the reference count.
+ Device->dev_RefCount = 1;
+
+#if DBG
+ Device->dev_RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->dev_Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->dev_Signature2, "IDC2", 4);
+#endif
+
+ // Set next conn id to be used.
+ Device->dev_NextConnId = (USHORT)SpxRandomNumber();
+ if (Device->dev_NextConnId == 0xFFFF)
+ {
+ Device->dev_NextConnId = 1;
+ }
+
+ DBGPRINT(DEVICE, ERR,
+ ("SpxInitCreateDevice: Start Conn Id %lx\n", Device->dev_NextConnId));
+
+ // Initialize the resource that guards address ACLs.
+ ExInitializeResource (&Device->dev_AddrResource);
+
+ // initialize the various fields in the device context
+ CTEInitLock (&Device->dev_Interlock);
+ CTEInitLock (&Device->dev_Lock);
+ KeInitializeSpinLock (&Device->dev_StatInterlock);
+ KeInitializeSpinLock (&Device->dev_StatSpinLock);
+
+ Device->dev_State = DEVICE_STATE_CLOSED;
+ Device->dev_Type = SPX_DEVICE_SIGNATURE;
+ Device->dev_Size = sizeof (DEVICE);
+
+ Device->dev_Stat.Version = 0x100;
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} // SpxCreateDevice
+
+
+
+
+VOID
+SpxDestroyDevice(
+ 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.
+
+--*/
+
+{
+ ExDeleteResource (&Device->dev_AddrResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} // SpxDestroyDevice
diff --git a/private/ntos/tdi/isn/spx/spxdrvr.c b/private/ntos/tdi/isn/spx/spxdrvr.c
new file mode 100644
index 000000000..0e9935d1a
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxdrvr.c
@@ -0,0 +1,1008 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxdrvr.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the SPX/SPXII module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) Original Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 14-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXDRVR
+
+// Forward declaration of various routines used in this module.
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath);
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject);
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, SpxUnload)
+#pragma alloc_text(PAGE, SpxDispatchOpenClose)
+#pragma alloc_text(PAGE, SpxDispatch)
+#pragma alloc_text(PAGE, SpxDeviceControl)
+#pragma alloc_text(PAGE, SpxUnload)
+#endif
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the SPX 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 ST's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ UNICODE_STRING deviceName;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN BoundToIpx = FALSE;
+
+ // DBGBRK(FATAL);
+
+ // Initialize the Common Transport Environment.
+ if (CTEInitialize() == 0) {
+ return (STATUS_UNSUCCESSFUL);
+ }
+
+ // We have this #define'd. Ugh, but CONTAINING_RECORD has problem owise.
+ CTEAssert(NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+
+ // Create the device object. (IoCreateDevice zeroes the memory
+ // occupied by the object.)
+ RtlInitUnicodeString(&deviceName, SPX_DEVICE_NAME);
+ status = SpxInitCreateDevice(
+ DriverObject,
+ &deviceName,
+ &SpxDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ return(status);
+ }
+
+ do
+ {
+ CTEInitLock (&SpxGlobalInterlock);
+ CTEInitLock (&SpxGlobalQInterlock);
+
+ // Initialize the unload event
+ KeInitializeEvent(
+ &SpxUnloadEvent,
+ NotificationEvent,
+ FALSE);
+
+ // !!!The device is created at this point!!!
+ // Get information from the registry.
+ status = SpxInitGetConfiguration(
+ RegistryPath,
+ &SpxDevice->dev_ConfigInfo);
+
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+
+#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.
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif _PNP_POWER
+
+ // Bind to the IPX transport.
+ if (!NT_SUCCESS(status = SpxInitBindToIpx()))
+ {
+ // BUGBUG: Have ipx name here as second string
+ LOG_ERROR(
+ EVENT_TRANSPORT_BINDING_FAILED,
+ status,
+ NULL,
+ NULL,
+ 0);
+
+ break;
+ }
+
+ BoundToIpx = TRUE;
+
+#if !defined(_PNP_POWER)
+ // Initialize the timer system
+ if (!NT_SUCCESS(status = SpxTimerInit()))
+ {
+ break;
+ }
+#endif !_PNP_POWER
+
+ // Initialize the block manager
+ if (!NT_SUCCESS(status = SpxInitMemorySystem(SpxDevice)))
+ {
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+ break;
+ }
+
+ // Initialize the driver object with this driver's entry points.
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = SpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL]
+ = SpxDispatch;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
+ = SpxDispatchInternal;
+ DriverObject->DriverUnload = SpxUnload;
+
+ // Initialize the provider info
+ SpxQueryInitProviderInfo(&SpxDevice->dev_ProviderInfo);
+ SpxDevice->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
+
+#if !defined(_PNP_POWER)
+ // We are open now.
+ SpxDevice->dev_State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+ // Set the window size in statistics
+ SpxDevice->dev_Stat.MaximumSendWindow =
+ SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
+ IpxLineInfo.MaximumSendSize;
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == SpxDevice->dev_State ) {
+ SpxDevice->dev_State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ } while (FALSE);
+
+ if (!NT_SUCCESS(status) )
+ {
+ // Delete the device and any associated resources created.
+ if( BoundToIpx ) {
+ SpxDerefDevice(SpxDevice);
+ }
+ SpxDestroyDevice(SpxDevice);
+ }
+
+ return (status);
+}
+
+
+
+
+VOID
+SpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver. The I/O system will not
+ call us until nobody above has ST open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ // Stop the timer subsystem
+ SpxTimerFlushAndStop();
+
+ // Remove creation reference count on the IPX device object.
+ SpxDerefDevice(SpxDevice);
+
+ // Wait on the unload event.
+ KeWaitForSingleObject(
+ &SpxUnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL);
+
+ // Release the block memory stuff
+ SpxDeInitMemorySystem(SpxDevice);
+ SpxDestroyDevice(SpxDevice);
+ return;
+}
+
+
+
+NTSTATUS
+SpxDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+
+ if (Device->dev_State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // Make sure status information is consistent every time.
+ IoMarkIrpPending (Irp);
+ Irp->IoStatus.Status = STATUS_PENDING;
+ Irp->IoStatus.Information = 0;
+
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ switch (IrpSp->MajorFunction) {
+
+ case IRP_MJ_DEVICE_CONTROL:
+
+ Status = SpxDeviceControl (DeviceObject, Irp);
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Complete the Irp here instead of below.
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ } // major function switch
+
+ /* Commented out and re-located to the default case above.
+
+ if (Status != STATUS_PENDING) {
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+ */
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatch
+
+VOID
+SpxAssignControlChannelId(
+ IN PDEVICE Device,
+ IN PIRP Request
+ )
+/*++
+
+Routine Description:
+
+ This routine is required to ensure that the Device lock (to protect the ControlChannelId in the Device)
+ is not taken in a pageable routine (SpxDispatchOpenClose).
+
+ NOTE: SPX returns the ControlChannelId in the Request, but never uses it later when it comes down in a
+ close/cleanup. The CCID is a ULONG; in future, if we start using this field (as in IPX which uses these Ids
+ to determine lineup Irps to complete), then we may run out of numbers (since we monotonically increase the CCID);
+ though there is a low chance of that since we will probably run out of memory before that! Anyhow, if that
+ happens, one solution (used in IPX) is to make the CCID into a Large Integer and pack the values into the
+ REQUEST_OPEN_TYPE(Irp) too.
+
+
+Arguments:
+
+ Device - Pointer to the device object for this driver.
+
+ Request - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTELockHandle LockHandle;
+
+ CTEGetLock (&Device->dev_Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->dev_CcId);
+ ++Device->dev_CcId;
+ if (Device->dev_CcId == 0) {
+ Device->dev_CcId = 1;
+ }
+
+ CTEFreeLock (&Device->dev_Lock, LockHandle);
+}
+
+NTSTATUS
+SpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the ST device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ BOOLEAN found;
+ PREQUEST Request;
+ UINT i;
+ PFILE_FULL_EA_INFORMATION openType;
+ CONNECTION_CONTEXT connCtx;
+
+
+#if !defined(_PNP_POWER)
+ if (Device->dev_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 = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // 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->dev_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 = SpxAddrOpen (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) {
+ if (openType->EaValueLength < sizeof(CONNECTION_CONTEXT))
+ {
+
+ DBGPRINT(CREATE, ERR,
+ ("Create: Context size %d\n", openType->EaValueLength));
+
+ Status = STATUS_EA_LIST_INCONSISTENT;
+ break;
+ }
+
+ connCtx =
+ *((CONNECTION_CONTEXT UNALIGNED *)
+ &openType->EaName[openType->EaNameLength+1]);
+
+ Status = SpxConnOpen(
+ Device,
+ connCtx,
+ Request);
+
+ break;
+ }
+
+ } else {
+
+ //
+ // Takes a lock in a Pageable routine - call another (non-paged) function to do that.
+ //
+ SpxAssignControlChannelId(Device, Request);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)SPX_FILE_TYPE_CONTROL;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_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:
+
+ Status = SpxAddrFileClose(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+ Status = SpxConnClose(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_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:
+
+ Status = SpxAddrFileCleanup(Device, Request);
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Status = SpxConnCleanup(Device, Request);
+ break;
+
+ case SPX_FILE_TYPE_CONTROL:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } // major function switch
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchOpenClose
+
+
+
+
+NTSTATUS
+SpxDeviceControl(
+ 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;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ // 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 = SpxDispatchInternal (DeviceObject, Irp);
+
+ //
+ // Return the proper error code here. If SpxDispatchInternal returns an error,
+ // then we used to map it to pending below; this is wrong since the client above
+ // us could wait for ever since the IO subsystem does not set the event if an
+ // error is returned and the Irp is not marked pending.
+ //
+
+ // Status = STATUS_PENDING;
+ } else {
+
+ DBGPRINT(TDI, DBG,
+ ("Unknown Tdi code in Irp: %lx\n", Irp));
+
+ //
+ // Complete the Irp....
+ //
+ IrpSp->Control &= ~SL_PENDING_RETURNED;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ }
+
+ return Status;
+
+} // SpxDeviceControl
+
+
+
+
+NTSTATUS
+SpxDispatchInternal (
+ 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.
+
+--*/
+
+{
+ PREQUEST Request;
+ KIRQL oldIrql;
+ NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+
+
+ if (Device->dev_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 = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ // Make sure status information is consistent every time.
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ // Cancel irp
+ IoAcquireCancelSpinLock(&oldIrql);
+ if (!Irp->Cancel)
+ {
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)SpxTdiCancel);
+ }
+ IoReleaseCancelSpinLock(oldIrql);
+
+ if (Irp->Cancel)
+ return STATUS_CANCELLED;
+
+ // 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 (REQUEST_MINOR_FUNCTION(Request))
+ {
+ case TDI_ACCEPT:
+
+ Status = SpxConnAccept(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+
+ Status = SpxAddrSetEventHandler(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_RECEIVE:
+
+ Status = SpxConnRecv(
+ Device,
+ Request);
+ break;
+
+
+ case TDI_SEND:
+
+ Status = SpxConnSend(
+ Device,
+ Request);
+ break;
+
+ case TDI_ACTION:
+
+ Status = SpxConnAction(
+ Device,
+ Request);
+ break;
+
+ case TDI_ASSOCIATE_ADDRESS:
+
+ Status = SpxConnAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISASSOCIATE_ADDRESS:
+
+ Status = SpxConnDisAssociate(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_CONNECT:
+
+ Status = SpxConnConnect(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_DISCONNECT:
+
+ Status = SpxConnDisconnect(
+ Device,
+ Request);
+ break;
+
+ case TDI_LISTEN:
+
+ Status = SpxConnListen(
+ Device,
+ Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+
+ Status = SpxTdiQueryInformation(
+ Device,
+ Request);
+
+ break;
+
+ case TDI_SET_INFORMATION:
+
+ Status = SpxTdiSetInformation(
+ Device,
+ Request);
+
+ break;
+
+ // Something we don't know about was submitted.
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ if (Status != STATUS_PENDING)
+ {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IoAcquireCancelSpinLock(&oldIrql);
+ IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)NULL);
+ IoReleaseCancelSpinLock(oldIrql);
+ SpxCompleteRequest (Request);
+ SpxFreeRequest (Device, Request);
+ }
+
+ // Return the immediate status code to the caller.
+ return Status;
+
+} // SpxDispatchInternal
+
+
+
+
+VOID
+SpxTdiCancel(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine handles cancellation of IO requests
+
+Arguments:
+
+
+Return Value:
+--*/
+{
+ PREQUEST Request;
+ PSPX_ADDR_FILE pSpxAddrFile;
+ PSPX_ADDR pSpxAddr;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ CTELockHandle connectIrql;
+ CTELockHandle TempIrql;
+ PSPX_CONN_FILE pSpxConnFile;
+
+ Request = SpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request)
+ {
+ return;
+ }
+
+ DBGPRINT(TDI, ERR,
+ ("SpxTdiCancel: Cancel irp called %lx.%lx\n",
+ Irp, REQUEST_OPEN_CONTEXT(Request)));
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request))
+ {
+ case TDI_CONNECTION_FILE:
+ pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &connectIrql);
+
+ //
+ // Swap the irql
+ //
+ TempIrql = connectIrql;
+ connectIrql = Irp->CancelIrql;
+ Irp->CancelIrql = TempIrql;
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
+ {
+ if (!SPX_CONN_IDLE(pSpxConnFile))
+ {
+ //
+ // This releases the lock
+ //
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_LOCAL_DISCONNECT,
+ SPX_CALL_TDILEVEL,
+ connectIrql,
+ FALSE); // [SA] bug #15249
+ }
+ }
+
+// SpxConnStop((PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request));
+ break;
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ pSpxAddr = pSpxAddrFile->saf_Addr;
+ SpxAddrFileStop(pSpxAddrFile, pSpxAddr);
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+}
diff --git a/private/ntos/tdi/isn/spx/spxerror.c b/private/ntos/tdi/isn/spx/spxerror.c
new file mode 100644
index 000000000..7d2cc7444
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxerror.c
@@ -0,0 +1,316 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxerror.c
+
+Abstract:
+
+ This module contains code which provides error logging support.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXERROR
+
+LONG SpxLastRawDataLen = 0;
+NTSTATUS SpxLastUniqueErrorCode = STATUS_SUCCESS;
+NTSTATUS SpxLastNtStatusCode = STATUS_SUCCESS;
+ULONG SpxLastErrorCount = 0;
+LONG SpxLastErrorTime = 0;
+BYTE SpxLastRawData[PORT_MAXIMUM_MESSAGE_LENGTH - \
+ sizeof(IO_ERROR_LOG_PACKET)] = {0};
+
+BOOLEAN
+SpxFilterErrorLogEntry(
+ IN NTSTATUS UniqueErrorCode,
+ IN NTSTATUS NtStatusCode,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+
+ int insertionStringLength = 0;
+
+ // Filter out events such that the same event recurring close together does not
+ // cause errorlog clogging. The scheme is - if the event is same as the last event
+ // and the elapsed time is > THRESHOLD and ERROR_CONSEQ_FREQ simulataneous errors
+ // have happened, then log it else skip
+ if ((UniqueErrorCode == SpxLastUniqueErrorCode) &&
+ (NtStatusCode == SpxLastNtStatusCode))
+ {
+ SpxLastErrorCount++;
+ if ((SpxLastRawDataLen == RawDataLen) &&
+ (RtlEqualMemory(SpxLastRawData, RawDataBuf, RawDataLen)) &&
+ ((SpxLastErrorCount % ERROR_CONSEQ_FREQ) != 0) &&
+ ((SpxGetCurrentTime() - SpxLastErrorTime) < ERROR_CONSEQ_TIME))
+ {
+ return(FALSE);
+ }
+ }
+
+ SpxLastUniqueErrorCode = UniqueErrorCode;
+ SpxLastNtStatusCode = NtStatusCode;
+ SpxLastErrorCount = 0;
+ SpxLastErrorTime = SpxGetCurrentTime();
+ if (RawDataLen != 0)
+ {
+ SpxLastRawDataLen = RawDataLen;
+ RtlCopyMemory(
+ SpxLastRawData,
+ RawDataBuf,
+ RawDataLen);
+ }
+
+ return(TRUE);
+}
+
+
+
+
+VOID
+SpxWriteResourceErrorLog(
+ 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";
+ UINT i;
+
+ if (!SpxFilterErrorLogEntry(
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ STATUS_INSUFFICIENT_RESOURCES,
+ (PVOID)&BytesNeeded,
+ sizeof(BytesNeeded)))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->dev_DeviceNameLen +
+ 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->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ RtlCopyMemory(
+ StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+}
+
+
+
+
+VOID
+SpxWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN PVOID RawDataBuf OPTIONAL,
+ IN LONG RawDataLen
+ )
+
+/*++
+
+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.
+
+ RawDataBuf - The number of ULONGs of dump data.
+
+ RawDataLen - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[4] = L"Spx";
+
+ if (!SpxFilterErrorLogEntry(
+ ErrorCode,
+ FinalStatus,
+ RawDataBuf,
+ RawDataLen))
+ {
+ return;
+ }
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ EntrySize += (UCHAR)Device->dev_DeviceNameLen;
+ }
+ 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)RawDataLen;
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + RawDataLen;
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (RawDataLen != 0)
+ {
+ RtlCopyMemory(errorLogEntry->DumpData, RawDataBuf, RawDataLen);
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->dev_Type == SPX_DEVICE_SIGNATURE)
+ {
+ RtlCopyMemory(
+ StringLoc, Device->dev_DeviceName, Device->dev_DeviceNameLen);
+
+ StringLoc += Device->dev_DeviceNameLen;
+ }
+ else
+ {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+
+ if (SecondString)
+ {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxmem.c b/private/ntos/tdi/isn/spx/spxmem.c
new file mode 100644
index 000000000..9cd400e5b
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxmem.c
@@ -0,0 +1,897 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxmem.c
+
+Abstract:
+
+ This module contains code which implements the memory allocation wrappers.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+ Jameel Hyder (jameelh) Initial Version
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, SpxInitMemorySystem)
+#pragma alloc_text( PAGE, SpxDeInitMemorySystem)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXMEM
+
+// Globals for this module
+// Some block sizes (like NDISSEND/NDISRECV are filled in after binding with IPX)
+USHORT spxBlkSize[NUM_BLKIDS] = // Size of each block
+ {
+ sizeof(BLK_HDR)+sizeof(TIMERLIST), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+USHORT spxChunkSize[NUM_BLKIDS] = // Size of each Chunk
+ {
+ 512-BC_OVERHEAD, // BLKID_TIMERLIST
+ 512-BC_OVERHEAD, // BLKID_NDISSEND
+ 512-BC_OVERHEAD // BLKID_NDISRECV
+ };
+
+
+// Filled in after binding with IPX
+// Reference for below.
+// ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+// (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+USHORT spxNumBlks[NUM_BLKIDS] = // Number of blocks per chunk
+ {
+ ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/
+ (sizeof(BLK_HDR)+sizeof(TIMERLIST)), // BLKID_TIMERLIST
+ 0, // BLKID_NDISSEND
+ 0 // BLKID_NDISRECV
+ };
+
+CTELock spxBPLock[NUM_BLKIDS] = { 0 };
+PBLK_CHUNK spxBPHead[NUM_BLKIDS] = { 0 };
+
+
+
+
+NTSTATUS
+SpxInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+ !!! MUST BE CALLED AFTER BINDING TO IPX!!!
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i;
+ NDIS_STATUS ndisStatus;
+
+ // Try to allocate the ndis buffer pool.
+ NdisAllocateBufferPool(
+ &ndisStatus,
+ &pSpxDevice->dev_NdisBufferPoolHandle,
+ 20);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ return(STATUS_INSUFFICIENT_RESOURCES);
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ CTEInitLock (&spxBPLock[i]);
+
+ // Set the sizes in the block id info arrays.
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ // BUGBUG: Do it.
+ switch (i)
+ {
+ case BLKID_NDISSEND:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_SEND_RESD) +
+ NDIS_PACKET_SIZE +
+ IpxMacHdrNeeded +
+ MIN_IPXSPX2_HDRSIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ case BLKID_NDISRECV:
+
+#ifdef SPX_OWN_PACKETS
+ spxBlkSize[i] = sizeof(BLK_HDR) +
+ sizeof(SPX_RECV_RESD) +
+ NDIS_PACKET_SIZE;
+#else
+ spxBlkSize[i] = sizeof(PNDIS_PACKET);
+#endif
+
+ //
+ // Round the block size up to the next 8-byte boundary.
+ //
+ spxBlkSize[i] = QWORDSIZEBLOCK(spxBlkSize[i]);
+
+ // Set number blocks
+ spxNumBlks[i] = ( 512-BC_OVERHEAD-sizeof(BLK_CHUNK))/spxBlkSize[i];
+ break;
+
+ default:
+
+ break;
+ }
+
+ }
+
+ SpxTimerScheduleEvent((TIMER_ROUTINE)spxBPAgePool,
+ BLOCK_POOL_TIMER,
+ NULL);
+}
+
+
+
+
+VOID
+SpxDeInitMemorySystem(
+ IN PDEVICE pSpxDevice
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LONG i, j, NumBlksPerChunk;
+ PBLK_CHUNK pChunk, pFree;
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ for (pChunk = spxBPHead[i];
+ pChunk != NULL; )
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxInitMemorySystem: Freeing %lx\n", pChunk));
+
+ CTEAssert (pChunk->bc_NumFrees == NumBlksPerChunk);
+
+ if ((pChunk->bc_BlkId == BLKID_NDISSEND) ||
+ (pChunk->bc_BlkId == BLKID_NDISRECV))
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free the Ndis stuff for these guys
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+#ifdef SPX_OWN_PACKETS
+ // Only need to free the ndis buffer.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ //
+ // Free the second MDL also
+ //
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+#else
+ // Need to free both the packet and the buffer.
+ ppNdisPkt = (PNDIS_PACKET *)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+
+ NdisUnchainBufferAtFront(*ppNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer == NULL)
+ {
+ // Something is terribly awry.
+ KeBugCheck(0);
+ }
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ NdisFreePacket(*ppNdisPkt);
+#endif
+ }
+ }
+ pFree = pChunk;
+ pChunk = pChunk->bc_Next;
+
+#ifndef SPX_OWN_PACKETS
+ // Free the ndis packet pool in chunk
+ NdisFreePacketPool((NDIS_HANDLE)pFree->bc_ChunkCtx);
+#endif
+ SpxFreeMemory(pFree);
+ }
+ }
+
+ // Free up the ndis buffer pool
+ NdisFreeBufferPool(
+ pSpxDevice->dev_NdisBufferPoolHandle);
+
+ return;
+}
+
+
+
+
+PVOID
+SpxAllocMem(
+#ifdef TRACK_MEMORY_USAGE
+ IN ULONG Size,
+ IN ULONG FileLine
+#else
+ IN ULONG Size
+#endif // TRACK_MEMORY_USAGE
+ )
+/*++
+
+Routine Description:
+
+ Allocate a block of non-paged memory. This is just a wrapper over ExAllocPool.
+ Allocation failures are error-logged. We always allocate a ULONG more than
+ the specified size to accomodate the size. This is used by SpxFreeMemory
+ to update the statistics.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBYTE pBuf;
+ BOOLEAN zeroed;
+
+ // round up the size so that we can put a signature at the end
+ // that is on a LARGE_INTEGER boundary
+ zeroed = ((Size & ZEROED_MEMORY_TAG) == ZEROED_MEMORY_TAG);
+
+ Size = QWORDSIZEBLOCK(Size & ~ZEROED_MEMORY_TAG);
+
+ // Do the actual memory allocation. Allocate eight extra bytes so
+ // that we can store the size of the allocation for the free routine
+ // and still keep the buffer quadword aligned.
+
+ if ((pBuf = ExAllocatePoolWithTag(NonPagedPool, Size + sizeof(LARGE_INTEGER)
+#if DBG
+ + sizeof(ULONG)
+#endif
+ ,SPX_TAG)) == NULL)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxAllocMemory: failed - size %lx\n", Size));
+
+ TMPLOGERR();
+ return NULL;
+ }
+
+ // Save the size of this block in the four extra bytes we allocated.
+ *((PULONG)pBuf) = (Size + sizeof(LARGE_INTEGER));
+
+ // Return a pointer to the memory after the size longword.
+ pBuf += sizeof(LARGE_INTEGER);
+
+#if DBG
+ *((PULONG)(pBuf+Size)) = SPX_MEMORY_SIGNATURE;
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxAllocMemory: %lx Allocated %lx bytes @%lx\n",
+ *(PULONG)((PBYTE)(&Size) - sizeof(Size)), Size, pBuf));
+#endif
+
+ SpxTrackMemoryUsage((PVOID)(pBuf - sizeof(LARGE_INTEGER)), TRUE, FileLine);
+
+ if (zeroed)
+ RtlZeroMemory(pBuf, Size);
+
+ return (pBuf);
+}
+
+
+
+
+VOID
+SpxFreeMemory(
+ IN PVOID pBuf
+ )
+/*++
+
+Routine Description:
+
+ Free the block of memory allocated via SpxAllocMemory. This is
+ a wrapper around ExFreePool.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PULONG pRealBuffer;
+
+ // Get a pointer to the block allocated by ExAllocatePool --
+ // we allocate a LARGE_INTEGER at the front.
+ pRealBuffer = ((PULONG)pBuf - 2);
+
+ SpxTrackMemoryUsage(pRealBuffer, FALSE, 0);
+
+#if DBG
+ // Check the signature at the end
+ if (*(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer)
+ != SPX_MEMORY_SIGNATURE)
+ {
+ DBGPRINT(RESOURCES, FATAL,
+ ("SpxFreeMemory: Memory overrun on block %lx\n", pRealBuffer));
+
+ DBGBRK(FATAL);
+ }
+
+ *(PULONG)((PCHAR)pRealBuffer + *(PULONG)pRealBuffer) = 0;
+#endif
+
+#if DBG
+ *pRealBuffer = 0;
+#endif
+
+ // Free the pool and return.
+ ExFreePool(pRealBuffer);
+}
+
+
+
+
+#ifdef TRACK_MEMORY_USAGE
+
+#define MAX_PTR_COUNT 4*1024
+#define MAX_MEM_USERS 512
+CTELock spxMemTrackLock = {0};
+CTELockHandle lockHandle = {0};
+struct
+{
+ PVOID mem_Ptr;
+ ULONG mem_FileLine;
+} spxMemPtrs[MAX_PTR_COUNT] = {0};
+
+struct
+{
+ ULONG mem_FL;
+ ULONG mem_Count;
+} spxMemUsage[MAX_MEM_USERS] = {0};
+
+VOID
+SpxTrackMemoryUsage(
+ IN PVOID pMem,
+ IN BOOLEAN Alloc,
+ IN ULONG FileLine
+ )
+/*++
+
+Routine Description:
+
+ Keep track of memory usage by storing and clearing away pointers as and
+ when they are allocated or freed. This helps in keeping track of memory
+ leaks.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ static int i = 0;
+ int j, k;
+
+ CTEGetLock (&spxMemTrackLock, &lockHandle);
+
+ if (Alloc)
+ {
+ for (j = 0; j < MAX_PTR_COUNT; i++, j++)
+ {
+ i = i & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[i].mem_Ptr == NULL)
+ {
+ spxMemPtrs[i].mem_Ptr = pMem;
+ spxMemPtrs[i++].mem_FileLine = FileLine;
+ break;
+ }
+ }
+
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == FileLine)
+ {
+ spxMemUsage[k].mem_Count ++;
+ break;
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ for (k = 0; k < MAX_MEM_USERS; k++)
+ {
+ if (spxMemUsage[k].mem_FL == 0)
+ {
+ spxMemUsage[k].mem_FL = FileLine;
+ spxMemUsage[k].mem_Count = 1;
+ break;
+ }
+ }
+ }
+ if (k == MAX_MEM_USERS)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: Out of space on spxMemUsage !!!\n"));
+
+ DBGBRK(FATAL);
+ }
+ }
+ else
+ {
+ for (j = 0, k = i; j < MAX_PTR_COUNT; j++, k--)
+ {
+ k = k & (MAX_PTR_COUNT-1);
+ if (spxMemPtrs[k].mem_Ptr == pMem)
+ {
+ spxMemPtrs[k].mem_Ptr = 0;
+ spxMemPtrs[k].mem_FileLine = 0;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&spxMemTrackLock, lockHandle);
+
+ if (j == MAX_PTR_COUNT)
+ {
+ DBGPRINT(RESOURCES, ERR,
+ ("SpxTrackMemoryUsage: %s\n", Alloc ? "Table Full" : "Can't find"));
+
+ DBGBRK(FATAL);
+ }
+}
+
+#endif // TRACK_MEMORY_USAGE
+
+
+
+
+PVOID
+SpxBPAllocBlock(
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Alloc a block of memory from the block pool package. This is written to speed up
+ operations where a lot of small fixed size allocations/frees happen. Going to
+ ExAllocPool() in these cases is expensive.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_HDR pBlk = NULL;
+ PBLK_CHUNK pChunk, *ppChunkHead;
+ USHORT BlkSize;
+ CTELockHandle lockHandle;
+ PSPX_SEND_RESD pSendResd;
+ PSPX_RECV_RESD pRecvResd;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PNDIS_BUFFER pNdisIpxSpxBuffer;
+
+
+ CTEAssert (BlockId < NUM_BLKIDS);
+
+ if (BlockId < NUM_BLKIDS)
+ {
+ BlkSize = spxBlkSize[BlockId];
+ ppChunkHead = &spxBPHead[BlockId];
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = *ppChunkHead;
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pChunk->bc_NumFrees > 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Found space in Chunk %lx\n", pChunk));
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPHits);
+#endif
+ break;
+ }
+ }
+
+ if (pChunk == NULL)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Allocating a new chunk for Id %d\n", BlockId));
+
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPMisses);
+#endif
+ pChunk = SpxAllocateMemory(spxChunkSize[BlockId]);
+ if (pChunk != NULL)
+ {
+ LONG i, j;
+ PBLK_HDR pBlkHdr;
+ USHORT NumBlksPerChunk;
+
+ NumBlksPerChunk = spxNumBlks[BlockId];
+ pChunk->bc_NumFrees = NumBlksPerChunk;
+ pChunk->bc_BlkId = BlockId;
+ pChunk->bc_FreeHead = (PBLK_HDR)((PBYTE)pChunk + sizeof(BLK_CHUNK));
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPAllocBlock: Initializing chunk %lx\n", pChunk));
+
+ // Initialize the blocks in the chunk
+ for (i = 0, pBlkHdr = pChunk->bc_FreeHead;
+ i < NumBlksPerChunk;
+ i++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NDIS_STATUS ndisStatus;
+
+ pBlkHdr->bh_Next = (PBLK_HDR)((PBYTE)pBlkHdr + BlkSize);
+ if (BlockId == BLKID_NDISSEND)
+ {
+ PBYTE pHdrMem;
+
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ // Allocate a ndis buffer descriptor describing hdr memory
+ // and queue it in.
+ pHdrMem = (PBYTE)pNdisPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD);
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem,
+ IpxMacHdrNeeded);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+
+
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisIpxSpxBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pHdrMem + IpxMacHdrNeeded,
+ MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisIpxSpxBuffer);
+
+
+
+ pSendResd = (PSPX_SEND_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+
+ // Initialize elements of the protocol reserved structure.
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = SPX_SENDPKT_IDLE;
+ }
+ else if (BlockId == BLKID_NDISRECV)
+ {
+#ifdef SPX_OWN_PACKETS
+ // Point to the ndis packet,initialize it.
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisReinitializePacket(pNdisPkt);
+
+ pRecvResd = (PSPX_RECV_RESD)pNdisPkt->ProtocolReserved;
+
+#else
+ // Allocate a ndis packet pool for this chunk
+ NdisAllocatePacketPool();
+ etc.
+#endif
+
+ // Initialize elements of the protocol reserved structure.
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State = SPX_RECVPKT_IDLE;
+ }
+ }
+
+ if (i != NumBlksPerChunk)
+ {
+ // This has to be a failure from Ndis for send blocks!!!
+ // Undo a bunch of stuff
+ CTEAssert (BlockId == BLKID_NDISSEND);
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < i; j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisBuffer);
+
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR)),
+ &pNdisIpxSpxBuffer);
+
+ if (pNdisIpxSpxBuffer)
+ {
+ NdisFreeBuffer(pNdisIpxSpxBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ pChunk = NULL;
+ }
+ else
+ {
+ // Successfully initialized the chunk, link it in
+ pChunk->bc_Next = *ppChunkHead;
+ *ppChunkHead = pChunk;
+ }
+ }
+ }
+
+ if (pChunk != NULL)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ DBGPRINT(RESOURCES, INFO,
+ ("SpxBPAllocBlock: Allocating a block out of chunk %lx(%d) for Id %d\n",
+ pChunk, pChunk->bc_NumFrees, BlockId));
+
+ pChunk->bc_NumFrees --;
+ pChunk->bc_Age = 0; // Reset age
+ pBlk = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlk->bh_Next;
+ pBlk->bh_pChunk = pChunk;
+
+ // Skip the block header!
+ pBlk++;
+ }
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ }
+
+ return pBlk;
+}
+
+
+
+VOID
+SpxBPFreeBlock(
+ IN PVOID pBlock,
+ IN BLKID BlockId
+ )
+/*++
+
+Routine Description:
+
+ Return a block to its owning chunk.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk;
+ PBLK_HDR pBlkHdr = (PBLK_HDR)((PCHAR)pBlock - sizeof(BLK_HDR));
+ CTELockHandle lockHandle;
+
+ CTEGetLock(&spxBPLock[BlockId], &lockHandle);
+
+ for (pChunk = spxBPHead[BlockId];
+ pChunk != NULL;
+ pChunk = pChunk->bc_Next)
+ {
+ CTEAssert(pChunk->bc_BlkId == BlockId);
+ if (pBlkHdr->bh_pChunk == pChunk)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxBPFreeBlock: Returning Block %lx to chunk %lx for Id %d\n",
+ pBlkHdr, pChunk, BlockId));
+
+ CTEAssert (pChunk->bc_NumFrees < spxNumBlks[BlockId]);
+ pChunk->bc_NumFrees ++;
+ pBlkHdr->bh_Next = pChunk->bc_FreeHead;
+ pChunk->bc_FreeHead = pBlkHdr;
+ break;
+ }
+ }
+ CTEAssert ((pChunk != NULL) && (pChunk->bc_FreeHead == pBlkHdr));
+
+ CTEFreeLock(&spxBPLock[BlockId], lockHandle);
+ return;
+}
+
+
+
+
+ULONG
+spxBPAgePool(
+ IN PVOID Context,
+ IN BOOLEAN TimerShuttingDown
+ )
+/*++
+
+Routine Description:
+
+ Age out the block pool of unused blocks
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PBLK_CHUNK pChunk, *ppChunk, pFree = NULL;
+ LONG i, j, NumBlksPerChunk;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+
+ if (TimerShuttingDown)
+ {
+ return TIMER_DONT_REQUEUE;
+ }
+
+ for (i = 0; i < NUM_BLKIDS; i++)
+ {
+ NumBlksPerChunk = spxNumBlks[i];
+ CTEGetLock(&spxBPLock[i], &lockHandle);
+
+ for (ppChunk = &spxBPHead[i];
+ (pChunk = *ppChunk) != NULL; )
+ {
+ if ((pChunk->bc_NumFrees == NumBlksPerChunk) &&
+ (++(pChunk->bc_Age) >= MAX_BLOCK_POOL_AGE))
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("spxBPAgePool: freeing Chunk %lx, Id %d\n",
+ pChunk, pChunk->bc_BlkId));
+
+ *ppChunk = pChunk->bc_Next;
+#ifdef PROFILING
+ InterlockedIncrement( &SpxStatistics.stat_NumBPAge);
+#endif
+ if (pChunk->bc_BlkId == BLKID_NDISSEND)
+ {
+ PBLK_HDR pBlkHdr;
+
+ // We need to free Ndis stuff for these guys
+ pBlkHdr = pChunk->bc_FreeHead;
+ for (j = 0, pBlkHdr = pChunk->bc_FreeHead;
+ j < NumBlksPerChunk;
+ j++, pBlkHdr = pBlkHdr->bh_Next)
+ {
+ pNdisPkt = (PNDIS_PACKET)((PBYTE)pBlkHdr + sizeof(BLK_HDR));
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ pNdisPkt,
+ &pNdisBuffer);
+
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ SpxFreeMemory(pChunk);
+ }
+ else
+ {
+ ppChunk = &pChunk->bc_Next;
+ }
+ }
+ CTEFreeLock(&spxBPLock[i], lockHandle);
+ }
+
+ return TIMER_REQUEUE_CUR_VALUE;
+}
diff --git a/private/ntos/tdi/isn/spx/spxpkt.c b/private/ntos/tdi/isn/spx/spxpkt.c
new file mode 100644
index 000000000..46b234020
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxpkt.c
@@ -0,0 +1,1594 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxpkt.c
+
+Abstract:
+
+ This module contains code that builds various spx packets.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXPKT
+
+VOID
+SpxPktBuildCr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ IN OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+ NOTE: If *ppPkt is NULL, we allocate a packet. If not, we just
+ recreate the data and don't update the packet's state.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrPkt;
+ PSPX_SEND_RESD pSendResd;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ if (*ppPkt == NULL) {
+
+ SpxAllocSendPacket(SpxDevice, &pCrPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ } else {
+
+ pCrPkt = *ppPkt;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ NdisQueryPacket(pCrPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? (SPX_CC_SPX2 | SPX_CC_NEG) : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = 0xFFFF;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ // Initialize
+
+ if (*ppPkt == NULL) {
+
+ pSendResd = (PSPX_SEND_RESD)(pCrPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX_HDRSIZE;
+
+ *ppPkt = pCrPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildCrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PSPX_ADDR pSpxAddr,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fNeg,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pCrAckPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pCrAckPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnHandleConnReq: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pCrAckPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pCrAckPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxAddr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS |
+ (fSpx2 ? SPX_CC_SPX2 : 0) |
+ (fNeg ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnBuildCrAck: Spx2 packet size %d.%lx\n",
+ pSpxConnFile->scf_MaxPktSize));
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+
+ pSendResd = (PSPX_SEND_RESD)(pCrAckPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_CRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pCrAckPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSn(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSn: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SN;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSnAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SNACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildSs(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+
+ CTEAssert(pSpxConnFile->scf_MaxPktSize != 0);
+ DBGPRINT(SEND, DBG,
+ ("SpxPktBuildSs: Data size %lx\n", pSpxConnFile->scf_MaxPktSize));
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SS;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+ } while (FALSE);
+
+ return;
+}
+
+
+
+VOID
+SpxPktBuildSsAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_SYS | SPX_CC_SPX2 |
+ ((pSpxConnFile->scf_Flags & SPX_CONNFILE_NEG) ? SPX_CC_NEG : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ pIpxSpxHdr->hdr_AckNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_SSACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRr(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT SeqNum,
+ IN USHORT State
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pBuf;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PBYTE pData;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ if ((pData =
+ SpxAllocateMemory(
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE)) == NULL)
+ {
+ SpxPktSendRelease(pPkt);
+ break;
+ }
+
+ // Build ndis buffer desc
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pBuf,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ pSpxConnFile->scf_MaxPktSize - MIN_IPXSPX2_HDRSIZE);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ SpxPktSendRelease(pPkt);
+ SpxFreeMemory(pData);
+ break;
+ }
+
+ // Chain at back.
+ NdisChainBufferAtBack(
+ pPkt,
+ pBuf);
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ pSpxConnFile->scf_MaxPktSize,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = ( SPX_CC_SYS | SPX_CC_ACK |
+ SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ // For a renegotiate request, we use the sequence number of
+ // the first waiting data packet. Passed in.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ SeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+
+ // Init the data part to indicate no neg values
+ *(UNALIGNED ULONG *)pData = 0;
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RR;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = (State | SPX_SENDPKT_FREEDATA);
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_SeqNum = SeqNum;
+ pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+ pSendResd->sr_Len = pSpxConnFile->scf_MaxPktSize;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildRrAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT MaxPktSize
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ PSPX_SEND_RESD pSendResd;
+
+ do
+ {
+ *ppPkt = NULL;
+
+ // Allocate a ndis packet for the cr.
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ MIN_IPXSPX2_HDRSIZE,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_NEG | SPX_CC_SPX2);
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ // For the RrAck, ack number will be the appropriate number
+ // for the last data packet received.
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RenegAckAckNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ MaxPktSize);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxPktBuildRrAck: SEQ %lx ACKNUM %lx ALLOCNUM %lx MAXPKT %lx\n",
+ pSpxConnFile->scf_SendSeqNum,
+ pSpxConnFile->scf_RenegAckAckNum,
+ pSpxConnFile->scf_SentAllocNum,
+ MaxPktSize));
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_RRACK;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = MIN_IPXSPX2_HDRSIZE;
+
+ *ppPkt = pPkt;
+
+ } while (FALSE);
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildDisc(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN PREQUEST pRequest,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN UCHAR DataType
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDiscPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDiscPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDiscPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pDiscPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (SPX_CC_ACK |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0) |
+ ((DataType == SPX2_DT_IDISC) ? 0 : SPX_CC_EOM));
+
+ pIpxSpxHdr->hdr_DataType = DataType;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDiscPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type =
+ ((DataType == SPX2_DT_IDISC) ? SPX_TYPE_IDISC : SPX_TYPE_ORDREL);
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pRequest;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Offset = 0;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pDiscPkt;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildProbe(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fSpx2
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pProbe;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pProbe, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pProbe +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE);
+
+ NdisQueryPacket(pProbe, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | SPX_CC_ACK |
+ (fSpx2 ? SPX_CC_SPX2 : 0));
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pProbe->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = SPX_TYPE_PROBE;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Len =
+ pSendResd->sr_HdrLen = (fSpx2 ? MIN_IPXSPX2_HDRSIZE
+ : MIN_IPXSPX_HDRSIZE);
+
+ *ppPkt = pProbe;
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxPktBuildData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN USHORT Length
+ )
+/*++
+
+Routine Description:
+
+ Handles zero length sends.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_PACKET pDataPkt;
+ NDIS_STATUS ndisStatus;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pDataPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Make a ndis buffer descriptor for the data if present.
+ if (Length > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_ReqPkt),
+ pSpxConnFile->scf_ReqPktOffset,
+ Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the send packet
+ SpxPktSendRelease(pDataPkt);
+ return;
+ }
+
+ // Chain this in the packet
+ NdisChainBufferAtBack(pDataPkt, pNdisBuffer);
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pDataPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ Length += hdrLen;
+
+ NdisQueryPacket(pDataPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ Length,
+ pSpxConnFile->scf_RemAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ // Build SPX Header.
+ pIpxSpxHdr->hdr_ConnCtrl =
+ (((State & SPX_SENDPKT_ACKREQ) ? SPX_CC_ACK : 0) |
+ ((State & SPX_SENDPKT_EOM) ? SPX_CC_EOM : 0) |
+ (SPX2_CONN(pSpxConnFile) ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = pSpxConnFile->scf_DataType;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+ pIpxSpxHdr->hdr_DestConnId =
+ *((UNALIGNED USHORT *)&pSpxConnFile->scf_RemConnId);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ if (SPX2_CONN(pSpxConnFile))
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+
+ pSendResd = (PSPX_SEND_RESD)(pDataPkt->ProtocolReserved);
+
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_State = State;
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_Type = SPX_TYPE_DATA;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Request = pSpxConnFile->scf_ReqPkt;
+ pSendResd->sr_Offset = pSpxConnFile->scf_ReqPktOffset;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_SeqNum = pSpxConnFile->scf_SendSeqNum;
+ pSendResd->sr_Len = Length;
+ pSendResd->sr_HdrLen = hdrLen;
+
+ if (State & SPX_SENDPKT_ACKREQ)
+ {
+ KeQuerySystemTime((PLARGE_INTEGER)&pSendResd->sr_SentTime);
+ }
+
+ CTEAssert(pSendResd->sr_Len <= pSpxConnFile->scf_MaxPktSize);
+ *ppPkt = pDataPkt;
+
+ // Ok, allocation succeeded. Increment send seq.
+ pSpxConnFile->scf_SendSeqNum++;
+ }
+
+ return;
+}
+
+
+VOID
+SpxCopyBufferChain(
+ OUT PNDIS_STATUS Status,
+ OUT PNDIS_BUFFER * TargetChain,
+ IN NDIS_HANDLE PoolHandle,
+ IN PNDIS_BUFFER SourceChain,
+ IN UINT Offset,
+ IN UINT Length
+ )
+/*++
+
+Routine Description:
+
+ Creates a TargetBufferChain from the SourceBufferChain. The copy begins at
+ the 'Offset' location in the source chain. It copies 'Length' bytes. It also
+ handles Length = 0. If we run out of source chain before copying length amount
+ of bytes or run out of memory to create any more buffers for the target chain,
+ we clean up the partial chain created so far.
+
+Arguments:
+
+ Status - Status of the request.
+ TargetChain - Pointer to the allocated buffer descriptor.
+ PoolHandle - Handle that is used to specify the pool.
+ SourceChain - Pointer to the descriptor of the source memory.
+ Offset - The Offset in the sources memory from which the copy is to
+ begin
+ Length - Number of Bytes to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT BytesBeforeCurBuffer = 0;
+ PNDIS_BUFFER CurBuffer = SourceChain;
+ UINT BytesLeft;
+ UINT AvailableBytes;
+ PNDIS_BUFFER NewNdisBuffer, StartTargetChain;
+
+ CTEAssert( SourceChain );
+
+ // First of all find the source buffer that contains data that starts at
+ // Offset.
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( BytesBeforeCurBuffer + AvailableBytes <= Offset ) {
+ BytesBeforeCurBuffer += AvailableBytes;
+ CurBuffer = CurBuffer->Next;
+ if ( CurBuffer ) {
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ } else {
+ break;
+ }
+ }
+
+ if ( ! CurBuffer ) {
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+ }
+
+ //
+ // Copy the first buffer. This takes care of Length = 0.
+ //
+ BytesLeft = Length;
+
+ //
+ // ( Offset - BytesBeforeCurBuffer ) gives us the offset within this buffer.
+ //
+
+ AvailableBytes -= ( Offset - BytesBeforeCurBuffer );
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &NewNdisBuffer,
+ PoolHandle,
+ CurBuffer,
+ Offset - BytesBeforeCurBuffer,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+ return;
+ }
+
+ StartTargetChain = NewNdisBuffer;
+ BytesLeft -= AvailableBytes;
+
+ //
+ // Did the first buffer have enough data. If so, we r done.
+ //
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ //
+ // Now follow the Mdl chain and copy more buffers.
+ //
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ while ( CurBuffer ) {
+
+ if ( AvailableBytes > BytesLeft ) {
+ AvailableBytes = BytesLeft;
+ }
+
+ NdisCopyBuffer(
+ Status,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ PoolHandle,
+ CurBuffer,
+ 0,
+ AvailableBytes);
+
+ if ( *Status != NDIS_STATUS_SUCCESS ) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ return;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+ BytesLeft -= AvailableBytes;
+
+ if ( ! BytesLeft ) {
+ *TargetChain = StartTargetChain;
+ return;
+ }
+
+ CurBuffer = CurBuffer->Next;
+ NdisQueryBuffer( CurBuffer, NULL, &AvailableBytes );
+ }
+
+ //
+ // Ran out of source chain. This should not happen.
+ //
+
+ CTEAssert( FALSE );
+
+ // For Retail build we clean up anyways.
+
+ while ( StartTargetChain != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE( StartTargetChain );
+ NdisFreeBuffer ( StartTargetChain );
+ StartTargetChain = NewNdisBuffer;
+ }
+
+ *Status = STATUS_UNSUCCESSFUL;
+ return;
+}
+
+
+VOID
+SpxPktBuildAck(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ OUT PNDIS_PACKET * ppPkt,
+ IN USHORT State,
+ IN BOOLEAN fBuildNack,
+ IN USHORT NumToResend
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pPkt;
+ PSPX_SEND_RESD pSendResd;
+ PIPXSPX_HDR pIpxSpxHdr;
+ NDIS_STATUS ndisStatus;
+ USHORT hdrLen;
+ PNDIS_BUFFER pNdisMacHdr, pNdisIpxHdr;
+
+ BOOLEAN fSpx2 = SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2);
+
+ *ppPkt = NULL;
+
+ SpxAllocSendPacket(SpxDevice, &pPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, ERR,
+ ("SpxPktBuildAck: Could not allocate ndis packet\n"));
+ return;
+ }
+
+ pIpxSpxHdr = (PIPXSPX_HDR)((PBYTE)pPkt +
+ NDIS_PACKET_SIZE +
+ sizeof(SPX_SEND_RESD) +
+ IpxInclHdrOffset);
+
+ hdrLen = SPX2_CONN(pSpxConnFile) ? MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE;
+ NdisQueryPacket(pPkt, NULL, NULL, &pNdisMacHdr, NULL);
+ pNdisIpxHdr = NDIS_BUFFER_LINKAGE(pNdisMacHdr);
+ if (!fSpx2)
+ {
+ NdisAdjustBufferLength(pNdisIpxHdr, MIN_IPXSPX_HDRSIZE);
+ }
+
+ // Send where data came from
+ SpxBuildIpxHdr(
+ pIpxSpxHdr,
+ hdrLen,
+ pSpxConnFile->scf_RemAckAddr,
+ pSpxConnFile->scf_AddrFile->saf_Addr->sa_Socket);
+
+ pIpxSpxHdr->hdr_ConnCtrl = (SPX_CC_SYS | (fSpx2 ? SPX_CC_SPX2 : 0));
+
+ pIpxSpxHdr->hdr_DataType = 0;
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SrcConnId,
+ pSpxConnFile->scf_LocalConnId);
+
+ pIpxSpxHdr->hdr_DestConnId = pSpxConnFile->scf_RemConnId;
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AckNum,
+ pSpxConnFile->scf_RecvSeqNum);
+
+ if (fSpx2)
+ {
+ pIpxSpxHdr->hdr_SeqNum = 0;
+ if (fBuildNack)
+ {
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ NumToResend);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_NegSize,
+ pSpxConnFile->scf_MaxPktSize);
+ }
+ else
+ {
+ // Put current send seq number in packet for spx1
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_SeqNum,
+ pSpxConnFile->scf_SendSeqNum);
+ }
+
+ PUTSHORT2SHORT(
+ &pIpxSpxHdr->hdr_AllocNum,
+ pSpxConnFile->scf_SentAllocNum);
+
+ pSendResd = (PSPX_SEND_RESD)(pPkt->ProtocolReserved);
+ pSendResd->sr_Id = IDENTIFIER_SPX;
+ pSendResd->sr_Type = (fBuildNack ? SPX_TYPE_DATANACK : SPX_TYPE_DATAACK);
+ pSendResd->sr_Reserved1 = NULL;
+ pSendResd->sr_Reserved2 = NULL;
+ pSendResd->sr_State = State;
+ pSendResd->sr_ConnFile = pSpxConnFile;
+ pSendResd->sr_Request = NULL;
+ pSendResd->sr_Next = NULL;
+ pSendResd->sr_Len = pSendResd->sr_HdrLen = hdrLen;
+
+ *ppPkt = pPkt;
+ return;
+}
+
+
+
+VOID
+SpxPktRecvRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ ((PSPX_RECV_RESD)(pPkt->ProtocolReserved))->rr_State = SPX_RECVPKT_IDLE;
+ SpxFreeRecvPacket(SpxDevice, pPkt);
+ return;
+}
+
+
+
+
+VOID
+SpxPktSendRelease(
+ IN PNDIS_PACKET pPkt
+ )
+{
+ PNDIS_BUFFER pBuf, pIpxSpxBuf, pFreeBuf;
+ UINT bufCount;
+
+ CTEAssert((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_IPXOWNS) == 0);
+
+ NdisQueryPacket(pPkt, NULL, &bufCount, &pBuf, NULL);
+
+ // BufCount == 1 for only the header. That's ok, we just reset the length
+ // and free the packet to the buffer pools. Else we need to free user buffers
+ // before that.
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pBuf);
+
+ NdisUnchainBufferAtFront(
+ pPkt,
+ &pIpxSpxBuf);
+
+ //
+ // Set the header length to the max. that can be needed.
+ //
+ NdisAdjustBufferLength(pIpxSpxBuf, MIN_IPXSPX2_HDRSIZE);
+
+ while (bufCount-- > 2)
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ NdisUnchainBufferAtBack(
+ pPkt,
+ &pFreeBuf);
+
+ // See if we free data associated with the buffer
+ if ((((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State &
+ SPX_SENDPKT_FREEDATA) != 0)
+ {
+ NdisQueryBuffer(pFreeBuf, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ SpxFreeMemory(pData);
+ }
+
+ CTEAssert(pFreeBuf != NULL);
+ NdisFreeBuffer(pFreeBuf);
+ }
+
+ NdisReinitializePacket(pPkt);
+
+ // Initialize elements of the protocol reserved structure.
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Id = IDENTIFIER_SPX;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_State = SPX_SENDPKT_IDLE;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved1= NULL;
+ ((PSPX_SEND_RESD)(pPkt->ProtocolReserved))->sr_Reserved2= NULL;
+
+ NdisChainBufferAtFront(
+ pPkt,
+ pBuf);
+
+ NdisChainBufferAtBack(
+ pPkt,
+ pIpxSpxBuf);
+
+ SpxFreeSendPacket(SpxDevice, pPkt);
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxquery.c b/private/ntos/tdi/isn/spx/spxquery.c
new file mode 100644
index 000000000..047ecabe8
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxquery.c
@@ -0,0 +1,259 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxquery.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Author:
+
+ Adam Barr (adamba) Initial Version
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxQueryInitProviderInfo)
+#endif
+
+// Define module number for event logging entries
+#define FILENUM SPXQUERY
+
+// Useful macro to obtain the total length of an MDL chain.
+#define SpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+VOID
+SpxQueryInitProviderInfo(
+ PTDI_PROVIDER_INFO ProviderInfo
+ )
+{
+ // Initialize to defaults first
+ RtlZeroMemory((PVOID)ProviderInfo, sizeof(TDI_PROVIDER_INFO));
+
+ ProviderInfo->Version = SPX_TDI_PROVIDERINFO_VERSION;
+ KeQuerySystemTime (&ProviderInfo->StartTime);
+ ProviderInfo->MinimumLookaheadData = SPX_PINFOMINMAXLOOKAHEAD;
+ ProviderInfo->MaximumLookaheadData = IpxLineInfo.MaximumPacketSize;
+ ProviderInfo->MaxSendSize = SPX_PINFOSENDSIZE;
+ ProviderInfo->ServiceFlags = SPX_PINFOSERVICEFLAGS;
+ return;
+}
+
+
+
+
+NTSTATUS
+SpxTdiQueryInformation(
+ 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:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PSPX_ADDR_FILE AddressFile;
+ PSPX_CONN_FILE ConnectionFile;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS SpxAddress;
+ } AddressInfo;
+
+
+
+ // what type of status do we want?
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType)
+ {
+ case TDI_QUERY_CONNECTION_INFO:
+
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ // The caller wants the exact address value.
+
+ ConnectionFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
+ status = SpxConnFileVerify(ConnectionFile);
+
+ if (status == STATUS_SUCCESS) {
+ AddressFile = ConnectionFile->scf_AddrFile;
+ SpxConnFileDereference(ConnectionFile, CFREF_VERIFY);
+ } else {
+ AddressFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
+ }
+
+ status = SpxAddrFileVerify(AddressFile);
+
+ if (status == STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxTdiQuery: Net.Socket %lx.%lx\n",
+ *(PULONG)Device->dev_Network,
+ AddressFile->saf_Addr->sa_Socket));
+
+ AddressInfo.ActivityCount = 0;
+ (VOID)SpxBuildTdiAddress(
+ &AddressInfo.SpxAddress,
+ sizeof(TA_IPX_ADDRESS),
+ Device->dev_Network,
+ Device->dev_Node,
+ AddressFile->saf_Addr->sa_Socket);
+
+ status = TdiCopyBufferToMdl(
+ &AddressInfo,
+ 0,
+ sizeof(AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ SpxAddrFileDereference(AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO: {
+ BYTE socketType;
+ TDI_PROVIDER_INFO providerInfo = Device->dev_ProviderInfo;
+
+ //
+ // The device name extension comes down in the Irp
+ //
+ if (!NT_SUCCESS(status = SpxUtilGetSocketType(
+ REQUEST_OPEN_NAME(Request),
+ &socketType))) {
+ DBGPRINT(RECEIVE, ERR, ("TDI_QUERY_PROVIDER_INFO: SpxUtilGetSocketType failed: %lx\n", status));
+ return(status);
+ }
+
+ //
+ // The Catapult folks had a problem where AFD was discarding buffered sends on the NT box when it got a
+ // local disconnect on SPX1. This was because the Orderly release flag was always set in the provider
+ // info. AFD queries this once per device type. We detect the device above and OR in the orderly release
+ // flag if this query came down on an SPX2 endpoint.
+ // This is to make sure that AFD follows the correct disconnect semantics for SPX1 and SPX2 (SPX1 does
+ // only abortive; SPX2 does both abortive and orderly).
+ //
+ // BUGBUG: this will still not solve the problem completely since a connection that starts off as an SPX2
+ // one can still be negotiated to SPX1 if the remote supports only SPX1.
+ //
+ if ((socketType == SOCKET2_TYPE_SEQPKT) ||
+ (socketType == SOCKET2_TYPE_STREAM)) {
+
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX2 socket\n"));
+ providerInfo.ServiceFlags |= TDI_SERVICE_ORDERLY_RELEASE;
+ } else {
+ DBGPRINT(RECEIVE, INFO, ("TDI_QUERY_PROVIDER_INFO: SPX1 socket\n"));
+ }
+
+ status = TdiCopyBufferToMdl (
+ &providerInfo,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+ }
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->dev_Stat,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_TDI_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} // SpxTdiQueryInformation
+
+
+
+NTSTATUS
+SpxTdiSetInformation(
+ 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;
+
+} // SpxTdiSetInformation
+
diff --git a/private/ntos/tdi/isn/spx/spxrecv.c b/private/ntos/tdi/isn/spx/spxrecv.c
new file mode 100644
index 000000000..9dc8b6fe3
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxrecv.c
@@ -0,0 +1,2839 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.c
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXRECV
+
+BOOLEAN
+SpxReceive(
+ 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
+ )
+
+{
+ PIPXSPX_HDR pHdr;
+
+ // We have a separate routine to process SYS packets. DATA packets are
+ // processed within this routine.
+ if (LookaheadBufferSize < MIN_IPXSPX_HDRSIZE)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxReceive: Invalid length %lx\n", LookaheadBufferSize));
+
+ return FALSE;
+ }
+
+ ++SpxDevice->dev_Stat.PacketsReceived;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+ if ((pHdr->hdr_ConnCtrl & SPX_CC_SYS) == 0)
+ {
+ // Check for data packets
+ if ((pHdr->hdr_DataType != SPX2_DT_ORDREL) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) &&
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK))
+ {
+ // HANDLE DATA PACKET
+ SpxRecvDataPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+ else
+ {
+ // The whole packet better be in the lookahead, else we ignore.
+ if (LookaheadBufferSize == PacketSize)
+ {
+ SpxRecvDiscPacket(
+ LookaheadBuffer,
+ RemoteAddress,
+ LookaheadBufferSize);
+ }
+ }
+ }
+ else
+ {
+ SpxRecvSysPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+
+ return FALSE;
+}
+
+
+
+
+VOID
+SpxTransferDataComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PREQUEST pRequest;
+ PSPX_RECV_RESD pRecvResd;
+ CTELockHandle lockHandle;
+ NTSTATUS status;
+ BOOLEAN fAck, fEom, fBuffered, fImmedAck, fLockHeld;
+ PNDIS_BUFFER pNdisBuffer;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: For %lx with status %lx\n", pNdisPkt, NdisStatus));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pSpxConnFile = pRecvResd->rr_ConnFile;
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+
+ fEom = ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+ fImmedAck = ((pRecvResd->rr_State & SPX_RECVPKT_IMMEDACK) != 0);
+ fBuffered = ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ fAck = ((pRecvResd->rr_State & SPX_RECVPKT_SENDACK) != 0);
+
+ // Check if receive is done. If we remove the reference for this
+ // packet and it goes to zero, that means the receive was aborted.
+ // Move to the completion queue.
+ // If receive is filled up, then remove the creation reference
+ // i.e. just complete the receive at this point.
+ // There can be only one packet per receive, we dont support
+ // out of order reception.
+
+ if (!fBuffered)
+ {
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert((pNdisBuffer != NULL) || (BytesTransferred == 0));
+
+ // BUG #11772
+ // On MP-machines scf_CurRecvReq could be set to NULL. Get the req
+ // from the recv packet.
+ // pRequest = pSpxConnFile->scf_CurRecvReq;
+ // CTEAssert(pRequest == pRecvResd->rr_Request);
+ pRequest = pRecvResd->rr_Request;
+
+ // Remove reference for this packet.
+ --(REQUEST_INFORMATION(pRequest));
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ pSpxConnFile->scf_CurRecvOffset += BytesTransferred;
+ pSpxConnFile->scf_CurRecvSize -= BytesTransferred;
+
+#if DBG
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (BytesTransferred != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= BytesTransferred;
+ }
+ }
+#endif
+
+ if (REQUEST_INFORMATION(pRequest) == 0)
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom ||
+ ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL)))
+ {
+ CTELockHandle lockHandleInter;
+
+ // We are done with this receive.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+
+ status = STATUS_SUCCESS;
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ status = STATUS_RECEIVE_PARTIAL;
+ }
+
+ if ((REQUEST_STATUS(pRequest) != STATUS_SUCCESS) &&
+ (REQUEST_STATUS(pRequest) != STATUS_RECEIVE_PARTIAL))
+ {
+ status = REQUEST_STATUS(pRequest);
+ }
+
+ REQUEST_STATUS(pRequest) = status;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferDataComplete: Request %lx ref %lx Cur %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest),
+ REQUEST_STATUS(pRequest),
+ pSpxConnFile->scf_CurRecvSize));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+ }
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+ else
+ {
+ // Buffered receive, queue it in if successful.
+ // BUG #18363
+ // IF WE DISCONNECTED in the meantime, we need to just dump this
+ // packet.
+ if (SPX_CONN_ACTIVE(pSpxConnFile) &&
+ (NdisStatus == NDIS_STATUS_SUCCESS))
+ {
+ // Queue packet in connection. Reference connection for this.
+ SpxConnQueueRecvPktTail(pSpxConnFile, pNdisPkt);
+ SpxConnFileLockReference(pSpxConnFile, CFREF_VERIFY);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxTransferData: Buffering: %lx Pkt %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, BytesTransferred, pRecvResd->rr_State));
+
+ // There could either be queued receives. (This could happen in
+ // a partial receive case. Or if a receive got queued in while we
+ // were processing this packet (Possible on MP)), or a packet was
+ // buffered while we were completing some receives
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead);
+
+ if ((pSpxConnFile->scf_CurRecvReq != NULL) ||
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0))
+ {
+ CTELockHandle interLockHandle;
+
+ // Push this connection into a ProcessRecv queue which will be
+ // dealt with in receive completion.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvTransferData: Queueing for recvp %lx.%lx\n",
+ pSpxConnFile, pSpxConnFile->scf_Flags));
+
+ // Get the global q lock, push into recv list.
+ CTEGetLock(&SpxGlobalQInterlock, &interLockHandle);
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, interLockHandle);
+ }
+ }
+ else
+ {
+ PBYTE pData;
+ ULONG dataLen;
+
+ // Get pointer to the buffer descriptor and its memory.
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+
+ // Free the data, ndis buffer.
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ SpxFreeMemory(pData);
+ }
+
+ // Dont send ack, set status to be failure so we free packet/buffer.
+ fAck = FALSE;
+ NdisStatus = NDIS_STATUS_FAILURE;
+ }
+ }
+
+ END_PROCESS_PACKET(
+ pSpxConnFile, fBuffered, (NdisStatus == NDIS_STATUS_SUCCESS));
+
+ if (fAck)
+ {
+ // Rem ack addr should have been copied in receive.
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (!fBuffered || (NdisStatus != STATUS_SUCCESS))
+ {
+ // Free the ndis packet/buffer
+ SpxPktRecvRelease(pNdisPkt);
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxReceiveComplete(
+ IN USHORT NicId
+ )
+
+{
+ CTELockHandle lockHandleInter, lockHandle;
+ PREQUEST pRequest;
+ BOOLEAN fConnLockHeld, fInterlockHeld;
+ PSPX_CONN_FILE pSpxConnFile;
+ int numDerefs = 0;
+
+ // See if any connections need recv processing. This will also take
+ // care of any acks opening up window so our sends go to the max.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ fInterlockHeld = TRUE;
+
+ while ((pSpxConnFile = SpxRecvConnList.pcl_Head) != NULL)
+ {
+ // Reset for each connection
+ numDerefs = 0;
+
+ if ((SpxRecvConnList.pcl_Head = pSpxConnFile->scf_ProcessRecvNext) == NULL)
+ SpxRecvConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_ProcessRecvNext = NULL;
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromRecv: %lx\n", pSpxConnFile));
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ do
+ {
+ // Complete pending requests.
+ while (!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage))
+ {
+ pRequest =
+ LIST_ENTRY_TO_REQUEST(pSpxConnFile->scf_ReqDoneLinkage.Flink);
+
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert (REQUEST_MINOR_FUNCTION(pRequest) != TDI_RECEIVE);
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+ // Call process pkts if we have any packets or if any receives to
+ // complete. Note this will call even when there are no receives
+ // queued and the first packet has already been indicated.
+ if ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage) ||
+ (pSpxConnFile->scf_RecvListHead != NULL)))
+ {
+ // We have the flag reference on the connection.
+ SpxRecvProcessPkts(pSpxConnFile, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ }
+
+#if DBG
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: RecvDone left %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ // Hmm. This check is rather expensive, and essentially we are doing
+ // it twice. Should look to see if this can be modified safely.
+ } while ((!IsListEmpty(&pSpxConnFile->scf_ReqDoneLinkage)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS) &&
+ ((!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ (SPX_RECVPKT_BUFFERING | SPX_RECVPKT_INDICATED)) ==
+ SPX_RECVPKT_BUFFERING)))));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_RECVQ);
+ SpxConnFileTransferReference(
+ pSpxConnFile,
+ CFREF_RECV,
+ CFREF_VERIFY);
+
+ numDerefs++;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+
+ // First see if we need to packetize.
+ while ((pSpxConnFile = SpxPktConnList.pcl_Head) != NULL)
+ {
+ if ((SpxPktConnList.pcl_Head = pSpxConnFile->scf_PktNext) == NULL)
+ SpxPktConnList.pcl_Tail = NULL;
+
+ // Reset next field to NULL
+ pSpxConnFile->scf_PktNext = NULL;
+
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+
+ DBGPRINT(SEND, DBG,
+ ("SpxConnRemoveFromPkt: %lx\n", pSpxConnFile));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fConnLockHeld = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxReceiveComplete: Packetizing %lx\n", pSpxConnFile));
+
+ SPX_CONN_RESETFLAG(pSpxConnFile, SPX_CONNFILE_PKTQ);
+ if (SPX_SEND_STATE(pSpxConnFile) == SPX_SEND_IDLE)
+ {
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_PACKETIZE);
+ if (SpxConnPacketize(
+ pSpxConnFile,
+ TRUE,
+ lockHandle))
+ {
+ // Done.
+ fConnLockHeld = FALSE;
+ }
+ }
+
+ if (fConnLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_PKTIZE);
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ }
+
+ if (fInterlockHeld)
+ {
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ return;
+}
+
+
+
+
+//
+// PACKET HANDLING ROUTINES
+//
+
+
+VOID
+SpxRecvSysPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming system packet.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld = FALSE;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvSysPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ if ((pktLen == SPX_CR_PKTLEN) &&
+ (destConnId == 0xFFFF) &&
+ (pHdr->hdr_ConnCtrl & SPX_CC_CR))
+ {
+ spxConnHandleConnReq(
+ pHdr,
+ pRemoteAddr);
+
+ return;
+ }
+
+ //
+ // [SA] Bug #14917
+ // Some SPX SYS packets (no extended ack field) may come in with the SPX2 bit set.
+ // Make sure we don't discard these packets.
+ //
+
+ // if ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) && (pktLen < MIN_IPXSPX2_HDRSIZE))
+ // {
+ // return;
+ // }
+
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnSysPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnSysPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Id %lx NOT FOUND\n", destConnId));
+ return;
+ }
+
+ do
+ {
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnSysPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // This could be one of many packets. Connection ack/Session negotiate/
+ // Session setup, Data Ack, Probe/Ack, Renegotiate/Ack. We shunt
+ // off all the packets to different routines but process the data
+ // ack packets here.
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAddr);
+
+ lockHeld = TRUE;
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ switch (SPX_MAIN_STATE(pSpxConnFile))
+ {
+ case SPX_CONNFILE_CONNECTING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromSrv(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_LISTENING:
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ lockHeld = FALSE;
+
+ spxConnHandleSessPktFromClient(
+ pHdr,
+ pRemoteAddr,
+ pSpxConnFile);
+
+ break;
+
+ case SPX_CONNFILE_ACTIVE:
+ case SPX_CONNFILE_DISCONN:
+
+ // NOTE: Our ack to a session setup might get dropped.
+ // But the SS Ack is similar to a normal SPX2 ack.
+ // We dont have to do anything special.
+
+ // Received ack/nack/reneg/reneg ack/disc associated packet.
+ // Disc packets except ordrel ack have non-zero datastream type.
+ if ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2)) ==
+ (SPX_CC_SYS | SPX_CC_ACK | SPX_CC_NEG | SPX_CC_SPX2))
+ {
+ // We received a renegotiate packet. Ignore all ack values
+ // in a reneg req.
+ SpxConnProcessRenegReq(pSpxConnFile, pHdr, pRemoteAddr, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ // Check if we are an ack/nack packet in which case call process
+ // ack. Note that the spx2 orderly release ack is a normal spx2 ack.
+ if (((pHdr->hdr_ConnCtrl & SPX_CC_ACK) == 0) &&
+ (pHdr->hdr_DataType == 0))
+ {
+ SpxConnProcessAck(pSpxConnFile, pHdr, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Just process the numbers we got.
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ // If the remote wants us to send an ack, do it.
+ if (pHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (!lockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+ }
+
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+
+ // Ignore this packet.
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnSysPacket: Ignoring packet, state is not active\n"));
+ break;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDiscPacket(
+ IN PUCHAR LookaheadBuffer,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN UINT LookaheadSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ PSPX_CONN_FILE pSpxConnFile;
+ CTELockHandle lockHandle;
+ BOOLEAN lockHeld;
+
+ pHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (LookaheadSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&ackNum, &pHdr->hdr_AckNum);
+ GETSHORT2SHORT(&allocNum, &pHdr->hdr_AllocNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvDiscPacket: Packet Size %lx\n",
+ pktLen));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format. This maintains the
+ // 0x0 and 0xFFFF to be as in the host format.
+ srcConnId = *(USHORT UNALIGNED *)&pHdr->hdr_SrcConnId;
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDiscPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: packet received dest %lx src %lx\n",
+ pHdr->hdr_DestSkt, pHdr->hdr_SrcSkt));
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDiscPacket: Id %lx NOT FOUND", destConnId));
+
+ return;
+ }
+
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: Id %lx Conn %lx DiscType %lx\n",
+ destConnId, pSpxConnFile, pHdr->hdr_DataType));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+
+ // Unless we are in the active/disconnecting, but send state = idle
+ // and recv state = idle/recv posted, we ignore all disconnect packets.
+ if (((SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_ACTIVE) &&
+ (SPX_MAIN_STATE(pSpxConnFile) != SPX_CONNFILE_DISCONN)) ||
+ ((SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_IDLE) &&
+ (SPX_SEND_STATE(pSpxConnFile) != SPX_SEND_PACKETIZE)) ||
+ ((SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_IDLE) &&
+ (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_POSTED)) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT)))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx, %lx, %lx.%lx, %d.%d\n",
+ pSpxConnFile,
+ SPX_MAIN_STATE(pSpxConnFile),
+ SPX_SEND_STATE(pSpxConnFile), SPX_RECV_STATE(pSpxConnFile),
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)),
+ (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))));
+
+ break;
+ }
+
+ // If we have received a disconnect, process received ack to complete any
+ // pending sends before we allow the disconnect. This ack number will be
+ // the last word on this session.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ switch (pHdr->hdr_DataType)
+ {
+ case SPX2_DT_ORDREL:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: Recd ORDREl!\n"));
+
+ // BUGBUG: Need to deal with all sthe states.
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ // On receive, we do check the seq num for the orderly release, just
+ // like for a data packet.
+ // If this was not already indicated, indicate it now. That is all
+ // we do for an orderly release. When our client does a orderly rel
+ // and we receive the ack for that, call abortive with success.
+
+ // Verify ord rel packet, this checks if seq nums match also.
+ if ((pktLen != MIN_IPXSPX2_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl &
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) !=
+ (SPX_CC_ACK | SPX_CC_EOM | SPX_CC_SPX2)) ||
+ (pHdr->hdr_DataType != SPX2_DT_ORDREL) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: OR Failed/Ignored %lx, %lx.%lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDiscPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ lockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessOrdRel(pSpxConnFile, lockHandle);
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, DBG1,
+ ("SpxConnDiscPacket: DATA ORDREL %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ // Set flag in last recd buffer
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_ORD_DISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC %lx!\n",
+ pSpxConnFile, pSpxConnFile->scf_RefCount));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDiscPacket: SEND %d. RECV %d.%lx!\n",
+ IsListEmpty(&pSpxConnFile->scf_ReqLinkage),
+ IsListEmpty(&pSpxConnFile->scf_RecvLinkage),
+ pSpxConnFile->scf_RecvDoneLinkage));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ !(pHdr->hdr_ConnCtrl & SPX_CC_ACK) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:IDISC Ignored %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, seqNum,
+ pSpxConnFile->scf_RecvSeqNum,
+ pSpxConnFile->scf_RecvListTail));
+ break;
+ }
+
+ // Copy address for when ack is to be sent.
+ SpxCopyIpxAddr(pHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+
+ if (pSpxConnFile->scf_RecvListHead == NULL)
+ {
+ // No received data, go ahead and process now.
+ DBGPRINT(CONNECT, INFO,
+ ("SpxConnDiscPacket: NO RECV DATA IDISC %lx.%lx.%lx\n",
+ pSpxConnFile,
+ pSpxConnFile->scf_RecvListHead,
+ pSpxConnFile->scf_SendSeqListHead));
+
+ SpxConnProcessIDisc(pSpxConnFile, lockHandle);
+
+ lockHeld = FALSE;
+ }
+ else
+ {
+ // Set flag in last recd buffer
+
+ pSpxConnFile->scf_RecvListTail->rr_State |= SPX_RECVPKT_IDISC;
+ }
+
+ break;
+
+ case SPX2_DT_IDISC_ACK:
+
+ // Done with informed disconnect. Call abort connection with
+ // status success. That completes the pending disconnect request
+ // with status_success.
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDiscPacket: %lx Recd IDISC ack!\n", pSpxConnFile));
+
+ if (!((pktLen == MIN_IPXSPX_HDRSIZE) ||
+ ((pHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen == MIN_IPXSPX2_HDRSIZE))) ||
+ (pHdr->hdr_DataType != SPX2_DT_IDISC_ACK) ||
+ (srcConnId == 0) ||
+ (srcConnId == 0xFFFF) ||
+ (srcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId == 0) ||
+ (destConnId == 0xFFFF) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDiscPacket:Ver idisc ack Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+ break;
+ }
+
+ // We should be in the right state to accept this.
+ if ((SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_DISCONN) &&
+ (SPX_DISC_STATE(pSpxConnFile) == SPX_DISC_SENT_IDISC))
+ {
+ spxConnAbortiveDisc(
+ pSpxConnFile,
+ STATUS_SUCCESS,
+ SPX_CALL_RECVLEVEL,
+ lockHandle,
+ FALSE); // [SA] bug #15249
+
+ lockHeld = FALSE;
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ }
+
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Remove reference added on connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvBufferPkt(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT LookaheadOffset,
+ IN PIPXSPX_HDR pIpxSpxHdr,
+ IN UINT PacketSize,
+ IN PIPX_LOCAL_TARGET pRemoteAddr,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG bytesCopied;
+ BOOLEAN fEom;
+ NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
+ PBYTE pData = NULL;
+ PNDIS_BUFFER pNdisBuffer = NULL;
+
+ if (PacketSize > 0)
+ {
+ // Allocate memory for this data.
+ if (pData = (PBYTE)SpxAllocateMemory(PacketSize))
+ {
+ // Describe memory with a ndis buffer descriptor.
+ NdisAllocateBuffer(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ pData,
+ PacketSize);
+ }
+ else
+ {
+ ndisStatus = NDIS_STATUS_RESOURCES;
+ }
+ }
+
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus == NDIS_STATUS_SUCCESS)
+ {
+ // Queue the buffer into the packet if there is one.
+ if (pNdisBuffer)
+ {
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_DataOffset= 0;
+
+#if DBG
+ // Store seq number
+ GETSHORT2SHORT(&pRecvResd->rr_SeqNum , &pIpxSpxHdr->hdr_SeqNum);
+#endif
+
+ pRecvResd->rr_State =
+ (SPX_RECVPKT_BUFFERING |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fEom ? SPX_RECVPKT_EOM : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ? SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *pRemoteAddr;
+ }
+
+ pRecvResd->rr_Request = NULL;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvBufferPkt: %lx Len %lx DataPts %lx F %lx\n",
+ pSpxConnFile, PacketSize, pData, pRecvResd->rr_State));
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ // Call ndis transfer data. Copy ENTIRE packet. copySize has
+ // been modified so use original values.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (PacketSize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadOffset,
+ PacketSize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+
+ // BUG: FDDI returns pending which screws us up here. Stupid bug
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ }
+ }
+
+ // ASSERT: Lock will be freed in the success case.
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxRecvBufferPkt: FAILED!\n"));
+
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, FALSE);
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ if (pData != NULL)
+ {
+ SpxFreeMemory(pData);
+ }
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisFreeBuffer(pNdisBuffer);
+ }
+ }
+
+ return;
+}
+
+
+
+
+VOID
+SpxRecvDataPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadSize,
+ IN UINT LookaheadOffset,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This is called to indicate an incoming connection.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PIPXSPX_HDR pIpxSpxHdr;
+ USHORT srcConnId, destConnId,
+ pktLen, seqNum, ackNum, allocNum;
+ ULONG receiveFlags;
+ PSPX_CONN_FILE pSpxConnFile;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, iOffset, copySize, bytesCopied;
+ CTELockHandle lockHandle;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ NDIS_STATUS ndisStatus;
+ PREQUEST pRequest = NULL;
+ BOOLEAN fEom,
+ fImmedAck = FALSE, fLockHeld = FALSE, fPktDone = FALSE;
+
+ pIpxSpxHdr = (PIPXSPX_HDR)LookaheadBuffer;
+
+ // check minimum length
+ if (PacketSize < MIN_IPXSPX_HDRSIZE)
+ {
+ return;
+ }
+
+ // Convert hdr to host format as needed.
+ GETSHORT2SHORT(&pktLen, &pIpxSpxHdr->hdr_PktLen);
+ GETSHORT2SHORT(&destConnId, &pIpxSpxHdr->hdr_DestConnId);
+ GETSHORT2SHORT(&seqNum, &pIpxSpxHdr->hdr_SeqNum);
+ GETSHORT2SHORT(&allocNum, &pIpxSpxHdr->hdr_AllocNum);
+ GETSHORT2SHORT(&ackNum, &pIpxSpxHdr->hdr_AckNum);
+
+ if ((pktLen < MIN_IPXSPX_HDRSIZE) ||
+ (pktLen > PacketSize) ||
+ (pIpxSpxHdr->hdr_PktType != SPX_PKT_TYPE))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Packet Size %lx.%lx\n",
+ pktLen, PacketSize));
+
+ return;
+ }
+
+ // We keep and use the remote id in the net format.
+ srcConnId = *(USHORT UNALIGNED *)&pIpxSpxHdr->hdr_SrcConnId;
+
+ if ((srcConnId == 0) || (srcConnId == 0xFFFF) || (destConnId == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: Incorrect conn id %lx.%lx\n",
+ srcConnId, destConnId));
+
+ return;
+ }
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: packet received dest %lx src %lx seq %lx\n",
+ pIpxSpxHdr->hdr_DestSkt, pIpxSpxHdr->hdr_SrcSkt, seqNum));
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen < MIN_IPXSPX2_HDRSIZE))
+ {
+ return;
+ }
+
+ // Find the connection this is destined for and reference it.
+ SpxConnFileReferenceById(destConnId, &pSpxConnFile, &status);
+ if (!NT_SUCCESS(status))
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: Id %lx NOT FOUND", destConnId));
+ return;
+ }
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+#if 0
+ //
+ // We have the connection. We should update the dest. sock # in
+ // it in case it changed. Unix machines do do that sometimes.
+ // SCO bug 7676
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAddr);
+#endif
+
+ fLockHeld = TRUE;
+ do
+ {
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: Id %lx Conn %lx\n",
+ destConnId, pSpxConnFile));
+
+ // Restart watchdog timer if started.
+ if (SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_W_TIMER))
+ {
+ // This will either successfully restart or not affect the timer
+ // if it is currently running.
+ SpxTimerCancelEvent(
+ pSpxConnFile->scf_WTimerId,
+ TRUE);
+
+ pSpxConnFile->scf_WRetryCount = PARAM(CONFIG_KEEPALIVE_COUNT);
+ }
+
+ if (SPX_CONN_ACTIVE(pSpxConnFile))
+ {
+ // Verify data packet, this checks if seq nums match also.
+ if ((pIpxSpxHdr->hdr_SrcConnId != pSpxConnFile->scf_RemConnId) ||
+ (destConnId != pSpxConnFile->scf_LocalConnId) ||
+ !((pktLen >= MIN_IPXSPX_HDRSIZE) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_SPX2) &&
+ (pktLen >= MIN_IPXSPX2_HDRSIZE))))
+ {
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Failed %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // If it passed above test, but seq number is incorrect, schedule
+ // to send an ack.
+ if (seqNum != pSpxConnFile->scf_RecvSeqNum)
+ {
+ USHORT NumToResend;
+
+ DBGPRINT(CONNECT, DBG,
+ ("SpxConnDataPacket: Unexpected seq on %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ ++SpxDevice->dev_Stat.DataFramesRejected;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesRejected,
+ pktLen - (SPX2_CONN(pSpxConnFile) ?
+ MIN_IPXSPX2_HDRSIZE : MIN_IPXSPX_HDRSIZE));
+
+ //
+ // Bug #16975: Set the remote ack addr for use in SpxConnSendAck()
+ //
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // Calculate number to be resent. If we expect sequence 1 and receive
+ // 2 for eg., we need to send a nack, else we send an ack.
+ if (SPX2_CONN(pSpxConnFile) &&
+ UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_RecvSeqNum) &&
+ !UNSIGNED_GREATER_WITH_WRAP(
+ seqNum,
+ pSpxConnFile->scf_SentAllocNum))
+ {
+ NumToResend = (USHORT)(seqNum - pSpxConnFile->scf_RecvSeqNum + 1);
+ SpxConnSendNack(pSpxConnFile, NumToResend, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+
+ break;
+ }
+
+ // If we have received an orderly release, we accept no more data
+ // packets.
+ if (SPX_CONN_FLAG(
+ pSpxConnFile,
+ (SPX_CONNFILE_IND_IDISC |
+ SPX_CONNFILE_IND_ODISC))
+
+ ||
+
+ ((pSpxConnFile->scf_RecvListTail != NULL) &&
+ ((pSpxConnFile->scf_RecvListTail->rr_State &
+ SPX_RECVPKT_DISCMASK) != 0)))
+ {
+ DBGPRINT(CONNECT, ERR,
+ ("SpxConnDataPacket: After ord rel %lx, %lx.%lx\n",
+ pSpxConnFile, seqNum, pSpxConnFile->scf_RecvSeqNum));
+
+ break;
+ }
+
+ // We are processing a packet OR a receive is about to complete.
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT))
+ {
+ BEGIN_PROCESS_PACKET(pSpxConnFile, seqNum);
+ }
+ else
+ {
+ // Already processing a packet. Or a receive is waiting to
+ // complete. Get out.
+ break;
+ }
+
+ // Set ack numbers for connection.
+ SPX_SET_ACKNUM(
+ pSpxConnFile, ackNum, allocNum);
+
+ SpxConnProcessAck(pSpxConnFile, NULL, lockHandle);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ iOffset = MIN_IPXSPX2_HDRSIZE;
+ if (!SPX2_CONN(pSpxConnFile))
+ {
+ iOffset = 0;
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR))
+ {
+ iOffset = MIN_IPXSPX_HDRSIZE;
+ }
+ }
+
+ copySize = pktLen - iOffset;
+ fEom = ((SPX_CONN_MSG(pSpxConnFile) &&
+ (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM)) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IPXHDR));
+
+ // Do we attempt to piggyback? If not, fImmedAck is true.
+ // For SPX1 we dont piggyback.
+ // Bug #18253
+ fImmedAck = (!SPX2_CONN(pSpxConnFile) ||
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_EOM) == 0));
+
+ // If we do not have EOM to indicate AND we are a zero-sized packet
+ // then just consume this packet.
+ if (!fEom && (copySize == 0))
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("SpxConnDataPacket: ZERO LENGTH PACKET NO EOM %lx.%lx\n",
+ pSpxConnFile, seqNum));
+
+ fPktDone = TRUE;
+ break;
+ }
+
+ receiveFlags = TDI_RECEIVE_NORMAL;
+ receiveFlags |= ((fEom ? TDI_RECEIVE_ENTIRE_MESSAGE : 0) |
+ (((MacOptions &
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0));
+
+ ++SpxDevice->dev_Stat.DataFramesReceived;
+ ExInterlockedAddLargeStatistic(
+ &SpxDevice->dev_Stat.DataFrameBytesReceived,
+ copySize);
+
+ // Ok, we accept this packet. Depending on our state.
+ switch (SPX_RECV_STATE(pSpxConnFile))
+ {
+ case SPX_RECV_PROCESS_PKTS:
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: recv completions on %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+
+ case SPX_RECV_IDLE:
+
+ // If recv q is non-empty we are buffering data.
+ // Also, if no receive handler goto buffer data. Also, if receives
+ // are being completed, buffer this packet.
+ if ((pSpxConnFile->scf_RecvListHead != NULL) ||
+ !(IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) ||
+ !(pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler))
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: RecvListHead non-null %lx\n",
+ pSpxConnFile));
+
+ goto BufferPacket;
+ }
+
+ if (!SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+
+ // Don't indicate this packet again.
+ SPX_CONN_SETFLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND);
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+
+ //
+ // Comment this out for Buf # 10394. we'r hitting this assert
+ // even when there was no data loss.
+ //
+ // CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != seqNum);
+
+ pSpxConnFile->scf_PktSeqNum = seqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+
+ pSpxConnFile->scf_IndBytes = copySize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+
+#endif
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ receiveFlags,
+ LookaheadSize - iOffset,
+ copySize,
+ &bytesTaken,
+ LookaheadBuffer + iOffset,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: IND Flags %lx.%lx ConnID %lx,\
+ %lx Ctx %lx SEQ %lx Size %lx . %lx .%lx IND Status %lx\n",
+ pIpxSpxHdr->hdr_ConnCtrl,
+ receiveFlags,
+ destConnId,
+ pSpxConnFile,
+ pSpxConnFile->scf_ConnCtx,
+ seqNum,
+ LookaheadSize - iOffset,
+ copySize,
+ bytesTaken,
+ status));
+
+ DBGPRINT(RECEIVE, INFO,
+ ("SpxConnDataPacket: %x %x %x %x %x %x %x %x %x %x %x %x\n",
+ *(LookaheadBuffer+iOffset),
+ *(LookaheadBuffer+iOffset+1),
+ *(LookaheadBuffer+iOffset+2),
+ *(LookaheadBuffer+iOffset+3),
+ *(LookaheadBuffer+iOffset+4),
+ *(LookaheadBuffer+iOffset+5),
+ *(LookaheadBuffer+iOffset+6),
+ *(LookaheadBuffer+iOffset+7),
+ *(LookaheadBuffer+iOffset+8),
+ *(LookaheadBuffer+iOffset+9),
+ *(LookaheadBuffer+iOffset+10),
+ *(LookaheadBuffer+iOffset+11)));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted.
+ CTEAssert((bytesTaken != 0) || fEom);
+ fPktDone = TRUE;
+
+#if DBG
+ // Set this to 0, since we just indicated, there could
+ // not have been other data.
+ pSpxConnFile->scf_IndBytes = 0;
+#endif
+
+ break;
+ }
+
+ if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ // If there was indicated but not received data waiting
+ // (which in this path there will never be, the request
+ // could be completed given the data filled it up, and
+ // the lock released.
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ }
+ else if (IsListEmpty(&pSpxConnFile->scf_RecvLinkage))
+ {
+ // Data was not accepted. Need to buffer data and
+ // reduce window.
+ goto BufferPacket;
+ }
+
+ // Fall through to recv_posted.
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, WARN,
+ ("SpxConnDataPacket: !!!Ignoring %lx Seq %lx\n",
+ pSpxConnFile,
+ seqNum));
+
+ break;
+ }
+
+ case SPX_RECV_POSTED:
+
+ if (pSpxConnFile->scf_RecvListHead != NULL)
+ {
+ // This can happen also. Buffer packet if it does.
+ goto BufferPacket;
+ }
+
+ // If a receive irp is posted, then process the receive irp. If
+ // we fell thru we MAY already will have an irp.
+ if (pRequest == NULL)
+ {
+ CTEAssert(!IsListEmpty(&pSpxConnFile->scf_RecvLinkage));
+ CTEAssert(pSpxConnFile->scf_CurRecvReq != NULL);
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+ }
+
+ // Process receive. Here we do not need to worry about
+ // indicated yet not received data. We just deal with
+ // servicing the current packet.
+ CTEAssert(pRequest == pSpxConnFile->scf_CurRecvReq);
+ if ((LookaheadSize == PacketSize) &&
+ (pSpxConnFile->scf_CurRecvSize >= copySize))
+ {
+ bytesCopied = 0;
+ status = STATUS_SUCCESS;
+ if (copySize > 0)
+ {
+ status = TdiCopyBufferToMdl(
+ LookaheadBuffer,
+ iOffset,
+ copySize,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("BytesCopied %lx CopySize %lx, Recv Size %lx.%lx\n",
+ bytesCopied, copySize,
+ pSpxConnFile->scf_CurRecvSize,
+ pSpxConnFile->scf_CurRecvOffset));
+ }
+
+ // Update current request values and see if this request
+ // is to be completed. Either zero or fEom.
+ pSpxConnFile->scf_CurRecvOffset += bytesCopied;
+ pSpxConnFile->scf_CurRecvSize -= bytesCopied;
+
+#if DBG
+ // Decrement indicated data count
+ if (SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_PKT_NOIND))
+ {
+ if (bytesCopied != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= bytesCopied;
+ }
+ }
+#endif
+
+ if (SPX_CONN_STREAM(pSpxConnFile) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ CTELockHandle lockHandleInter;
+
+ // Set status
+ REQUEST_STATUS(pRequest) = STATUS_SUCCESS;
+ REQUEST_INFORMATION(pRequest)=
+ pSpxConnFile->scf_CurRecvOffset;
+
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom)
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnData: Completing recv %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ // Dequeue this request, Set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ // Request is done. Move to completion list.
+ CTEGetLock(&SpxGlobalQInterlock, &lockHandleInter);
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+
+ SPX_QUEUE_FOR_RECV_COMPLETION(pSpxConnFile);
+ CTEFreeLock(&SpxGlobalQInterlock, lockHandleInter);
+ }
+
+ fPktDone = TRUE;
+ }
+ else
+ {
+ // Need to allocate a ndis receive packet for transfer
+ // data.
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnDataPacket: %lx.%lx Tranfer data needed!\n",
+ copySize, pSpxConnFile->scf_CurRecvSize));
+
+ if (copySize > pSpxConnFile->scf_CurRecvSize)
+ {
+ // Partial receive. Buffer and then deal with it.
+ goto BufferPacket;
+ }
+
+ // Allocate a ndis receive packet.
+ SpxAllocRecvPacket(SpxDevice, &pNdisPkt, &ndisStatus);
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ // Describe the receive irp's data with a ndis buffer
+ // descriptor.
+ if (copySize > 0)
+ {
+ SpxCopyBufferChain(
+ &ndisStatus,
+ &pNdisBuffer,
+ SpxDevice->dev_NdisBufferPoolHandle,
+ REQUEST_TDI_BUFFER(pRequest),
+ pSpxConnFile->scf_CurRecvOffset,
+ copySize);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS)
+ {
+ // Free the recv packet
+ SpxPktRecvRelease(pNdisPkt);
+ break;
+ }
+
+ // Queue the buffer into the packet
+ // Link the buffer descriptor into the packet descriptor
+ NdisChainBufferAtBack(
+ pNdisPkt,
+ pNdisBuffer);
+ }
+
+ // Don't care about whether this is indicated or not here
+ // as it is not a buffering packet.
+ pRecvResd = RECV_RESD(pNdisPkt);
+ pRecvResd->rr_Id = IDENTIFIER_SPX;
+ pRecvResd->rr_State =
+ ((fEom ? SPX_RECVPKT_EOM : 0) |
+ (SPX_CONN_FLAG2(
+ pSpxConnFile, SPX_CONNFILE2_PKT_NOIND) ? SPX_RECVPKT_INDICATED : 0) |
+ (fImmedAck ? SPX_RECVPKT_IMMEDACK : 0) |
+ ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) ?
+ SPX_RECVPKT_SENDACK : 0));
+
+ if (pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK)
+ {
+ // copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+ }
+
+ pRecvResd->rr_Request = pRequest;
+ pRecvResd->rr_ConnFile = pSpxConnFile;
+
+ // reference receive request
+ REQUEST_INFORMATION(pRequest)++;
+
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ fLockHeld = FALSE;
+
+ // Call ndis transfer data.
+ ndisStatus = NDIS_STATUS_SUCCESS;
+ bytesCopied = 0;
+ if (copySize > 0)
+ {
+ (*IpxTransferData)(
+ &ndisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ copySize,
+ pNdisPkt,
+ &bytesCopied);
+ }
+
+ if (ndisStatus != STATUS_PENDING)
+ {
+ SpxTransferDataComplete(
+ pNdisPkt,
+ ndisStatus,
+ bytesCopied);
+ }
+ }
+
+ break;
+
+ default:
+
+ KeBugCheck(0);
+ break;
+ }
+
+ break;
+
+BufferPacket:
+
+ SpxRecvBufferPkt(
+ pSpxConnFile,
+ MacBindingHandle,
+ MacReceiveContext,
+ iOffset + LookaheadOffset,
+ pIpxSpxHdr,
+ copySize,
+ RemoteAddress,
+ lockHandle);
+
+ fLockHeld = FALSE;
+ }
+
+ } while (FALSE);
+
+ // Here we process a received ack.
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // Send an ack if one was asked for. And we are done with this packet.
+ if (fPktDone)
+ {
+ END_PROCESS_PACKET(pSpxConnFile, FALSE, TRUE);
+ }
+
+ if ((pIpxSpxHdr->hdr_ConnCtrl & SPX_CC_ACK) && fPktDone)
+ {
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ fLockHeld = TRUE;
+ }
+
+ // First copy the remote address in connection.
+ SpxCopyIpxAddr(pIpxSpxHdr, pSpxConnFile->scf_RemAckAddr);
+ pSpxConnFile->scf_AckLocalTarget = *RemoteAddress;
+
+ // #17564
+ if (fImmedAck ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_NOACKWAIT) ||
+ SPX_CONN_FLAG2(pSpxConnFile, SPX_CONNFILE2_IMMED_ACK))
+ {
+ SpxConnSendAck(pSpxConnFile, lockHandle);
+ fLockHeld = FALSE;
+ }
+ else
+ {
+ SpxConnQWaitAck(pSpxConnFile);
+ }
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ // Deref the connection
+ SpxConnFileDereference(pSpxConnFile, CFREF_BYID);
+ return;
+}
+
+
+
+
+VOID
+SpxRecvFlushBytes(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN ULONG BytesToFlush,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+
+--*/
+{
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ PBYTE pData;
+ ULONG dataLen, copyLen;
+ BOOLEAN fLockHeld = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numPkts = 0, numDerefs = 0;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Flush %lx\n",
+ pSpxConnFile, BytesToFlush));
+
+ while (((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ ((BytesToFlush > 0) ||
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)))
+ {
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ if ((BytesToFlush == 0) && (dataLen != 0))
+ {
+ // Don't flush this packet.
+ break;
+ }
+
+ // Allow for zero data, eom only packets.
+ copyLen = MIN((dataLen - pRecvResd->rr_DataOffset), BytesToFlush);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: %lx Pkt %lx DataLen %lx Copy %lx Flush %lx\n",
+ pSpxConnFile, pNdisPkt, dataLen, copyLen, BytesToFlush));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ BytesToFlush -= (ULONG)copyLen;
+
+#if DBG
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+#endif
+
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ // Packet consumed. Free it up. Check if disc happened.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ numDerefs++;
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ CTEAssert(pNdisBuffer != NULL);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxRecvFlushBytes: !!!ALL INDICATED on %lx.%lx.%lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pNdisBuffer, pData));
+
+ INCREMENT_WINDOW(pSpxConnFile);
+ fWdwOpen = TRUE;
+ }
+ else
+ {
+ // Took only part of this packet. Get out.
+ break;
+ }
+ }
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxRecvFlushBytes: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxRecvFlushBytes: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
+
+
+
+
+BOOLEAN
+SpxRecvIndicatePendingData(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN - Receive was queued => TRUE
+
+--*/
+{
+ ULONG indicateFlags;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PREQUEST pRequest;
+ PIRP pRecvIrp;
+ ULONG bytesTaken, totalSize, bufSize;
+ PTDI_IND_RECEIVE pRecvHandler;
+ PVOID pRecvCtx;
+ PSPX_RECV_RESD pRecvResd;
+ NTSTATUS status;
+ PBYTE lookaheadData;
+ ULONG lookaheadSize;
+ BOOLEAN fLockHeld = TRUE, fRecvQueued = FALSE;
+
+
+ while ((pRecvHandler = pSpxConnFile->scf_AddrFile->saf_RecvHandler) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL) &&
+ (IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage)) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) == 0))
+ {
+ // Once a receive is queued we better get out.
+ CTEAssert(!fRecvQueued);
+
+ // Initialize lookahead values
+ lookaheadData = NULL;
+ lookaheadSize = 0;
+
+ // We have no indicated but pending data, and there is some data to
+ // indicate. Figure out how much. Indicate upto end of message or as
+ // much as we have.
+
+ // A buffering recv packet will have ATMOST one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &lookaheadData, &lookaheadSize);
+ CTEAssert(lookaheadData != NULL);
+ CTEAssert(lookaheadSize >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ lookaheadSize -= pRecvResd->rr_DataOffset;
+ totalSize = lookaheadSize;
+ lookaheadData += pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((lookaheadSize > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+#if DBG
+ CTEAssert (pSpxConnFile->scf_CurRecvReq == NULL);
+
+ // Debug code to ensure we dont reindicate data/indicate
+ // when previously indicated data waiting with afd.
+ CTEAssert(pSpxConnFile->scf_IndBytes == 0);
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ // Go ahead and walk the list of waiting packets. Get total size.
+ while ((pRecvResd->rr_Next != NULL) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) == 0))
+ {
+ // Check next packet.
+ pRecvResd = pRecvResd->rr_Next;
+
+#if DBG
+ CTEAssert(pSpxConnFile->scf_PktSeqNum != pRecvResd->rr_SeqNum);
+
+ pSpxConnFile->scf_PktSeqNum = pRecvResd->rr_SeqNum;
+ pSpxConnFile->scf_PktFlags = pSpxConnFile->scf_Flags;
+ pSpxConnFile->scf_PktFlags2 = pSpxConnFile->scf_Flags2;
+#endif
+
+ pRecvResd->rr_State |= SPX_RECVPKT_INDICATED;
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, NULL, &bufSize);
+ CTEAssert(bufSize >= 0);
+
+ // Allow for zero data, eom only packets.
+ totalSize += bufSize;
+ }
+
+#if DBG
+ pSpxConnFile->scf_IndBytes = totalSize;
+ pSpxConnFile->scf_IndLine = __LINE__;
+
+ // There better not be any pending receives. If so, we have data
+ // corruption about to happen.
+ if (!IsListEmpty(&pSpxConnFile->scf_RecvDoneLinkage))
+ {
+ DBGBRK(FATAL);
+ KeBugCheck(0);
+ }
+#endif
+
+ indicateFlags = TDI_RECEIVE_NORMAL | TDI_RECEIVE_COPY_LOOKAHEAD;
+ if ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)
+ {
+ indicateFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+
+ pRecvCtx = pSpxConnFile->scf_AddrFile->saf_RecvHandlerCtx;
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ bytesTaken = 0;
+ status = (*pRecvHandler)(
+ pRecvCtx,
+ pSpxConnFile->scf_ConnCtx,
+ indicateFlags,
+ lookaheadSize,
+ totalSize,
+ &bytesTaken,
+ lookaheadData,
+ &pRecvIrp);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("SpxConnIndicatePendingData: IND Flags %lx Size %lx .%lx IND Status %lx\n",
+ indicateFlags,
+ totalSize,
+ bytesTaken,
+ status));
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ if (status == STATUS_SUCCESS)
+ {
+ // Assume all data accepted. Free bytesTaken worth of data packets.
+ // Sometimes AFD returns STATUS_SUCCESS to just flush the data, so
+ // we can't assume it took only one packet (since lookahead only
+ // had that information).
+ CTEAssert(bytesTaken == totalSize);
+ SpxRecvFlushBytes(pSpxConnFile, totalSize, LockHandleConn);
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ continue;
+ }
+ else if (status == STATUS_MORE_PROCESSING_REQUIRED)
+ {
+
+ // Queue irp into connection, change state to receive
+ // posted and fall thru.
+ pRequest = SpxAllocateRequest(
+ SpxDevice,
+ pRecvIrp);
+
+ IF_NOT_ALLOCATED(pRequest)
+ {
+ pRecvIrp->IoStatus.Status =
+ STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (pRecvIrp, IO_NETWORK_INCREMENT);
+ return (FALSE);
+ }
+
+ SpxConnQueueRecv(
+ pSpxConnFile,
+ pRequest);
+
+ fRecvQueued = TRUE;
+ }
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ return fRecvQueued;
+}
+
+
+
+
+VOID
+SpxRecvProcessPkts(
+ IN PSPX_CONN_FILE pSpxConnFile,
+ IN CTELockHandle LockHandleConn
+ )
+/*++
+
+Routine Description:
+
+ Handle buffered data, complete irp if necessary. Set state to idle
+ if list becomes empty.
+
+Arguments:
+
+ pSpxConnFile - Pointer to a transport address file object.
+
+Return Value:
+
+ BOOLEAN: More data left to indicate => TRUE
+
+--*/
+{
+ ULONG remainingDataLen, copyLen, bytesCopied;
+ PREQUEST pRequest;
+ NTSTATUS status;
+ BOOLEAN fEom;
+ PNDIS_PACKET pNdisPkt;
+ PNDIS_BUFFER pNdisBuffer;
+ PSPX_RECV_RESD pRecvResd;
+ ULONG dataLen;
+ PBYTE pData;
+ LIST_ENTRY *p;
+ BOOLEAN fLockHeld = TRUE, fMoreData = TRUE, fWdwOpen = FALSE;
+ USHORT discState = 0;
+ int numDerefs = 0;
+
+ if (SPX_RECV_STATE(pSpxConnFile) != SPX_RECV_PROCESS_PKTS)
+ {
+ SPX_RECV_SETSTATE(pSpxConnFile, SPX_RECV_PROCESS_PKTS);
+
+ProcessReceives:
+
+ while ((pSpxConnFile->scf_CurRecvReq != NULL) &&
+ ((pRecvResd = pSpxConnFile->scf_RecvListHead) != NULL))
+ {
+ // A buffering recv packet will have one ndis buffer descriptor
+ // queued in, which will describe a segment of memory we have
+ // allocated. An offset will also be present indicating the data
+ // to start reading from (or to indicate from to AFD).
+ CTEAssert((pRecvResd->rr_State & SPX_RECVPKT_BUFFERING) != 0);
+
+ pNdisPkt = (PNDIS_PACKET)CONTAINING_RECORD(
+ pRecvResd, NDIS_PACKET, ProtocolReserved);
+
+ NdisQueryPacket(pNdisPkt, NULL, NULL, &pNdisBuffer, NULL);
+
+ // Initialize pData
+ pData = NULL;
+ dataLen = 0;
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisQueryBuffer(pNdisBuffer, &pData, &dataLen);
+ CTEAssert(pData != NULL);
+ CTEAssert(dataLen >= 0);
+ }
+
+ // Allow for zero data, eom only packets.
+ remainingDataLen = dataLen - pRecvResd->rr_DataOffset;
+
+ // If this packet contained data then eom must also have been
+ // indicated at the time all the data was consumed.
+ CTEAssert((remainingDataLen > 0) ||
+ ((pRecvResd->rr_DataOffset == 0) &&
+ ((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0)));
+
+ status = STATUS_SUCCESS;
+ copyLen = 0;
+ if (remainingDataLen > 0)
+ {
+ copyLen = MIN(remainingDataLen, pSpxConnFile->scf_CurRecvSize);
+ status = TdiCopyBufferToMdl(
+ pData,
+ pRecvResd->rr_DataOffset,
+ copyLen,
+ REQUEST_TDI_BUFFER(pSpxConnFile->scf_CurRecvReq),
+ pSpxConnFile->scf_CurRecvOffset,
+ &bytesCopied);
+
+ CTEAssert(NT_SUCCESS(status));
+ if (!NT_SUCCESS(status))
+ {
+ // Abort request with this status. Reset request
+ // queue to next request if one is available.
+ copyLen = pSpxConnFile->scf_CurRecvSize;
+ }
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx Size %lx F %lx\n",
+ pSpxConnFile, pNdisPkt, pData, copyLen, pRecvResd->rr_State));
+
+ // Adjust various values to see whats done whats not
+ pRecvResd->rr_DataOffset += (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvSize -= (USHORT)copyLen;
+ pSpxConnFile->scf_CurRecvOffset += (USHORT)copyLen;
+
+#if DBG
+ // If this packet was part of indicated data count, decrement.
+ if ((pRecvResd->rr_State & SPX_RECVPKT_INDICATED) != 0)
+ {
+ if (copyLen != 0)
+ {
+ CTEAssert (pSpxConnFile->scf_IndBytes != 0);
+ pSpxConnFile->scf_IndBytes -= copyLen;
+ }
+ }
+#endif
+
+ // Set fEom/discState (init to 0) only if all of packet was consumed.
+ fEom = FALSE;
+ if (pRecvResd->rr_DataOffset == dataLen)
+ {
+ fEom = (BOOLEAN)((pRecvResd->rr_State & SPX_RECVPKT_EOM) != 0);
+
+ // Remember if disconnect needed to happen. If set, this better be
+ // last packet received. Again, only if entire pkt was consumed.
+ discState = (pRecvResd->rr_State & SPX_RECVPKT_DISCMASK);
+ CTEAssert((discState == 0) ||
+ (pRecvResd == pSpxConnFile->scf_RecvListTail));
+
+ // Packet consumed. Free it up.
+ numDerefs++;
+
+ SpxConnDequeueRecvPktLock(pSpxConnFile, pNdisPkt);
+ INCREMENT_WINDOW(pSpxConnFile);
+
+ fWdwOpen = TRUE;
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx Data %lx DEQUEUED\n",
+ pSpxConnFile, pNdisPkt, pData));
+
+ if (pNdisBuffer != NULL)
+ {
+ NdisUnchainBufferAtFront(pNdisPkt, &pNdisBuffer);
+ NdisFreeBuffer(pNdisBuffer);
+ SpxFreeMemory(pData);
+ }
+
+ SpxPktRecvRelease(pNdisPkt);
+ }
+ else
+ {
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Pkt %lx PARTIAL USE %lx.%lx\n",
+ pSpxConnFile, pNdisPkt, pRecvResd->rr_DataOffset, dataLen));
+ }
+
+ // Don't complete until we are out of all packets and stream mode or...
+ if (((pSpxConnFile->scf_RecvListHead == NULL) &&
+ SPX_CONN_STREAM(pSpxConnFile)) ||
+ (pSpxConnFile->scf_CurRecvSize == 0) ||
+ fEom)
+ {
+ // Done with receive, move to completion or complete depending on
+ // call level.
+ pRequest = pSpxConnFile->scf_CurRecvReq;
+
+ // Set status. Complete with error from TdiCopy if so.
+ REQUEST_INFORMATION(pRequest) = pSpxConnFile->scf_CurRecvOffset;
+ REQUEST_STATUS(pRequest) = status;
+
+ // Ensure we dont overwrite an error status.
+ if (!SPX_CONN_STREAM(pSpxConnFile) &&
+ (pSpxConnFile->scf_CurRecvSize == 0) &&
+ !fEom &&
+ NT_SUCCESS(status))
+ {
+ REQUEST_STATUS(pRequest) = STATUS_RECEIVE_PARTIAL;
+ }
+
+ // Dequeue this request, set next recv if one exists.
+ SPX_CONN_SETNEXT_CUR_RECV(pSpxConnFile, pRequest);
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: %lx Recv %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ // Request is done. Move to receive completion list. There
+ // could already be previously queued requests in here.
+ InsertTailList(
+ &pSpxConnFile->scf_RecvDoneLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ CTEAssert((discState == 0) ||
+ (pSpxConnFile->scf_RecvListHead == NULL));
+ }
+
+ // Complete any completed receives
+ while ((p = pSpxConnFile->scf_RecvDoneLinkage.Flink) !=
+ &pSpxConnFile->scf_RecvDoneLinkage)
+ {
+ pRequest = LIST_ENTRY_TO_REQUEST(p);
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+
+ DBGPRINT(TDI, DBG,
+ ("SpxConnDiscPkt: PENDING REQ COMP %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+#if DBG
+ if ((REQUEST_STATUS(pRequest) == STATUS_SUCCESS) &&
+ (REQUEST_INFORMATION(pRequest) == 0))
+ {
+ DBGPRINT(TDI, DBG,
+ ("SpxReceiveComplete: Completing %lx with %lx.%lx\n",
+ pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+ }
+#endif
+
+ SpxCompleteRequest(pRequest);
+ numDerefs++;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+
+ while (fMoreData)
+ {
+ // Bug #21036
+ // If there is a receive waiting to be processed, we better not
+ // indicate data before we finish it.
+ if (pSpxConnFile->scf_CurRecvReq != NULL)
+ goto ProcessReceives;
+
+ // If a receive was queued the goto beginning again.
+ if (SpxRecvIndicatePendingData(pSpxConnFile, LockHandleConn))
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ goto ProcessReceives;
+ }
+
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ fMoreData = ((pSpxConnFile->scf_RecvListHead != NULL) &&
+ ((pSpxConnFile->scf_RecvListHead ->rr_State &
+ SPX_RECVPKT_BUFFERING) != 0) &&
+ ((pSpxConnFile->scf_RecvListHead->rr_State &
+ SPX_RECVPKT_INDICATED) == 0));
+ }
+
+ // Set state
+ SPX_RECV_SETSTATE(
+ pSpxConnFile,
+ (pSpxConnFile->scf_CurRecvReq == NULL) ?
+ SPX_RECV_IDLE : SPX_RECV_POSTED);
+ }
+#if DBG
+ else
+ {
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Already processing pkts %lx\n",
+ pSpxConnFile));
+ }
+#endif
+
+ if (fWdwOpen && (pSpxConnFile->scf_RecvListHead == NULL))
+ {
+ // Send an ack as our windows probably opened up. Dont wait to
+ // piggyback here...
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Send ACK %lx\n",
+ pSpxConnFile));
+
+#if DBG_WDW_CLOSE
+ // If packets been indicated we have started buffering. Also
+ // check if window is now zero.
+ {
+ LARGE_INTEGER li, ntTime;
+ int value;
+
+ li = pSpxConnFile->scf_WdwCloseTime;
+ if (li.LowPart && li.HighPart)
+ {
+ KeQuerySystemTime(&ntTime);
+
+ // Get the difference
+ ntTime.QuadPart = ntTime.QuadPart - li.QuadPart;
+
+ // Convert to milliseconds. If the highpart is 0, we
+ // take a shortcut.
+ if (ntTime.HighPart == 0)
+ {
+ value = ntTime.LowPart/10000;
+ }
+ else
+ {
+ ntTime = SPX_CONVERT100NSTOCENTISEC(ntTime);
+ value = ntTime.LowPart << 4;
+ }
+
+ // Set new average close time
+ pSpxConnFile->scf_WdwCloseAve += value;
+ pSpxConnFile->scf_WdwCloseAve /= 2;
+ DBGPRINT(RECEIVE, DBG,
+ ("V %ld AVE %ld\n",
+ value, pSpxConnFile->scf_WdwCloseAve));
+ }
+ }
+#endif
+
+ SpxConnSendAck(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ }
+
+ // Check if disconnect happened
+ switch (discState)
+ {
+ case SPX_RECVPKT_IDISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered IDISC %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case SPX_RECVPKT_ORD_DISC:
+
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, DBG,
+ ("spxConnProcessRecdPkts: Buffered ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessOrdRel(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ case (SPX_RECVPKT_IDISC | SPX_RECVPKT_ORD_DISC):
+
+ // IDISC has more priority.
+ CTEAssert(!fMoreData);
+ CTEAssert(pSpxConnFile->scf_RecvListHead == NULL);
+
+ if (!fLockHeld)
+ {
+ CTEGetLock(&pSpxConnFile->scf_Lock, &LockHandleConn);
+ }
+
+ DBGPRINT(RECEIVE, ERR,
+ ("spxConnProcessRecdPkts: Buffered IDISC *AND* ORDREL %lx\n",
+ pSpxConnFile, fMoreData));
+
+ SpxConnProcessIDisc(pSpxConnFile, LockHandleConn);
+ fLockHeld = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ if (fLockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, LockHandleConn);
+ }
+
+ while (numDerefs-- > 0)
+ {
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+}
diff --git a/private/ntos/tdi/isn/spx/spxreg.c b/private/ntos/tdi/isn/spx/spxreg.c
new file mode 100644
index 000000000..4389dca5f
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxreg.c
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxreg.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXREG
+
+// Local functions used to access the registry.
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID);
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+NTSTATUS
+SpxInitGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxInitGetConfiguration)
+#pragma alloc_text(INIT, SpxInitFreeConfiguration)
+#pragma alloc_text(INIT, SpxInitGetConfigValue)
+#pragma alloc_text(INIT, SpxInitReadIpxDeviceName)
+#pragma alloc_text(INIT, SpxInitSetIpxDeviceName)
+#endif
+
+
+NTSTATUS
+SpxInitGetConfiguration (
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX 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:
+
+ RegistryPath - The name of ST's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ NTSTATUS Status;
+ UINT i;
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+
+ ULONG Zero = 0;
+ ULONG Two = 2;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Twelve = 12;
+ ULONG Fifteen = 15;
+ ULONG Thirty = 30;
+ ULONG FiveHundred = 500;
+ ULONG Hex4000 = 0x4000;
+ ULONG Hex7FFF = 0x7FFF;
+ ULONG FourK = 4096;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"ConnectionCount", &Five },
+ { L"ConnectionTimeout", &Two },
+ { L"InitPackets", &Five },
+ { L"MaxPackets", &Thirty},
+ { L"InitialRetransmissionTime", &FiveHundred},
+ { L"KeepAliveCount", &Eight},
+ { L"KeepAliveTimeout", &Twelve},
+ { L"WindowSize", &Four},
+ { L"SpxSocketRangeStart", &Hex4000},
+ { L"SpxSocketRangeEnd", &Hex7FFF},
+ { L"SpxSocketUniqueness", &Eight},
+ { L"MaxPacketSize", &FourK},
+ { L"RetransmissionCount", &Eight},
+ { L"DisableSpx2", &Zero},
+ { L"RouterMtu", &Zero},
+ { L"BackCompSpx", &Zero}
+ };
+
+ if (!NT_SUCCESS(SpxInitReadIpxDeviceName()))
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Allocate memory for the main config structure.
+ Config = CTEAllocMem (sizeof(CONFIG));
+ if (Config == NULL) {
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->cf_DeviceName.Buffer = NULL;
+
+ // SpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ RegistryPathBuffer = (PWSTR)CTEAllocMem(RegistryPath->Length + sizeof(WCHAR));
+
+ if (RegistryPathBuffer == NULL) {
+
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (
+ RegistryPathBuffer,
+ RegistryPath->Buffer,
+ RegistryPath->Length);
+
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->cf_RegistryPathBuffer = RegistryPathBuffer;
+
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+ // Set up QueryTable to do the following:
+ // 1) Switch to the Parameters key below SPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ // 2-14) Call SpxSetBindingValue for each of the keys we
+ // care about.
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = SpxInitGetConfigValue;
+ 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);
+ }
+
+ // 15) 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->cf_RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ SpxInitFreeConfiguration(Config);
+
+ TMPLOGERR();
+ return Status;
+ }
+
+ CTEFreeMem (RegistryPathBuffer);
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfiguration
+
+
+
+
+VOID
+SpxInitFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by SPX to get free any storage that was allocated
+ by SpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEFreeMem (Config);
+
+} // SpxInitFreeConfig
+
+
+
+
+NTSTATUS
+SpxInitGetConfigValue(
+ 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;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DBGPRINT(CONFIG, INFO,
+ ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+
+ Config->cf_Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+ return STATUS_SUCCESS;
+
+} // SpxInitGetConfigValue
+
+
+
+
+NTSTATUS
+SpxInitReadIpxDeviceName(
+ VOID
+ )
+
+{
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ PWSTR Export = L"Export";
+ PWSTR IpxRegistryPath = IPX_REG_PATH;
+
+ // Set up QueryTable to do the following:
+ //
+ // 1) Call SetIpxDeviceName for the string in "Export"
+ QueryTable[0].QueryRoutine = SpxInitSetIpxDeviceName;
+ QueryTable[0].Flags = 0;
+ QueryTable[0].Name = Export;
+ QueryTable[0].EntryContext = NULL;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ // 2) Stop
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_SERVICES,
+ IpxRegistryPath,
+ QueryTable,
+ NULL,
+ NULL);
+
+ return Status;
+}
+
+
+
+
+NTSTATUS
+SpxInitSetIpxDeviceName(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string and
+ saves the information in a ConfigurationInfo structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - NULL.
+
+ EntryContext - NULL.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ PWSTR fileName;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ fileName = (PWSTR)CTEAllocMem(ValueLength);
+ if (fileName != NULL) {
+ RtlCopyMemory(fileName, ValueData, ValueLength);
+ RtlInitUnicodeString (&IpxDeviceName, fileName);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ return(status);
+}
+
diff --git a/private/ntos/tdi/isn/spx/spxsend.c b/private/ntos/tdi/isn/spx/spxsend.c
new file mode 100644
index 000000000..6b856953d
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxsend.c
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxsend.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ SPX transport provider.
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+// Define module number for event logging entries
+#define FILENUM SPXSEND
+
+VOID
+SpxSendComplete(
+ IN PNDIS_PACKET pNdisPkt,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ ProtocolBindingContext - The ADAPTER structure for this binding.
+
+ NdisPacket/RequestHandle - A pointer to the NDIS_PACKET that we sent.
+
+ NdisStatus - the completion status of the send.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PSPX_CONN_FILE pSpxConnFile;
+ PSPX_SEND_RESD pSendResd;
+ PNDIS_BUFFER pNdisBuffer;
+ CTELockHandle lockHandle;
+ UINT bufCount;
+ PREQUEST pRequest = NULL;
+ BOOLEAN completeReq = FALSE, freePkt = FALSE,
+ orphaned = FALSE, lockHeld = FALSE;
+
+ pSendResd = (PSPX_SEND_RESD)(pNdisPkt->ProtocolReserved);
+
+#if DBG
+ if (NdisStatus != NDIS_STATUS_SUCCESS)
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: For %lx with status **%lx**\n",
+ pNdisPkt, NdisStatus));
+ }
+#endif
+
+ // IPX changes the length set for the first ndis buffer descriptor.
+ // Change it back to its original value here.
+ NdisQueryPacket(pNdisPkt, NULL, &bufCount, &pNdisBuffer, NULL);
+ NdisAdjustBufferLength(pNdisBuffer, IpxMacHdrNeeded + MIN_IPXSPX2_HDRSIZE);
+
+ do
+ {
+ pSpxConnFile = pSendResd->sr_ConnFile;
+ CTEGetLock(&pSpxConnFile->scf_Lock, &lockHandle);
+ lockHeld = TRUE;
+#if defined(__PNP)
+ //
+ // if IPX gave us a new LocalTarget, use for our next send.
+ //
+ // But if we are sending connect requests by iterating over NicIds,
+ // dont update the local target bcoz that will screw up our iteration
+ // logic.
+ //
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == NdisStatus
+ &&
+ !(
+ SPX_CONN_CONNECTING(pSpxConnFile) &&
+ (SPX_CONNECT_STATE(pSpxConnFile) == SPX_CONNECT_SENTREQ) &&
+ (*((UNALIGNED ULONG *)(pSpxConnFile->scf_RemAddr)) == 0)
+ ) ) {
+
+ pSpxConnFile->scf_LocalTarget = pSendResd->LocalTarget;
+
+ //
+ // Renegotiate the max packet size if we have an active SPX2
+ // session going on and we negotiated the max size originally.
+ //
+ if ( SPX_MAIN_STATE(pSpxConnFile) == SPX_CONNFILE_ACTIVE &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_SPX2) &&
+ SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_NEG) ) {
+
+ //
+ // this call will get the local max size on this new local target
+ // from IPX.
+ //
+ SPX_MAX_PKT_SIZE(pSpxConnFile, TRUE, TRUE, *((UNALIGNED ULONG *)pSpxConnFile->scf_RemAddr );
+ SPX_SEND_SETSTATE(pSpxConnFile, SPX_SEND_RENEG);
+
+ DBGPRINT(SEND, DBG3,
+ ("SpxConnProcessAck: %lx CONNECTION ENTERING RENEG\n",
+ pSpxConnFile));
+ }
+
+ }
+#endif __PNP
+
+ CTEAssert((pSendResd->sr_State & SPX_SENDPKT_IPXOWNS) != 0);
+
+ // IPX dont own this packet nomore.
+ pSendResd->sr_State &= ~SPX_SENDPKT_IPXOWNS;
+
+ // If a send packet has been aborted, then we need to call
+ // abort send to go ahead and free up this packet, and deref associated
+ // request, if there is one, potentially completing it.
+ if ((pSendResd->sr_State & SPX_SENDPKT_ABORT) != 0)
+ {
+ spxConnAbortSendPkt(
+ pSpxConnFile,
+ pSendResd,
+ SPX_CALL_TDILEVEL,
+ lockHandle);
+
+ lockHeld = FALSE;
+ break;
+ }
+
+ // If there is an associated request, remove reference on it. BUT for a
+ // sequenced packet only if it has been acked and is waiting for the request
+ // to be dereferenced. It is already dequeued from queue, just free it up.
+ if ((((pSendResd->sr_State & SPX_SENDPKT_REQ) != 0) &&
+ ((pSendResd->sr_State & SPX_SENDPKT_SEQ) == 0)) ||
+ ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0))
+ {
+ freePkt = (BOOLEAN)((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) != 0);
+
+ pRequest = pSendResd->sr_Request;
+ CTEAssert(pRequest != NULL);
+
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: ReqRef before dec %lx.%lx\n",
+ pRequest, REQUEST_INFORMATION(pRequest)));
+
+ // Deref the request and see if we complete it now. We always have our
+ // own reference on the request.
+ // !!! Status should already have been set in request...!!!
+ if (--(REQUEST_INFORMATION(pRequest)) == 0)
+ {
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+
+ completeReq = TRUE;
+
+ // If this is acked already, request is not on list.
+ // BUG #11626
+ if ((pSendResd->sr_State & SPX_SENDPKT_ACKEDPKT) == 0)
+ {
+ RemoveEntryList(REQUEST_LINKAGE(pRequest));
+ }
+ }
+ }
+
+ // Do we destroy this packet?
+ if ((pSendResd->sr_State & SPX_SENDPKT_DESTROY) != 0)
+ {
+ // Remove this packet from the send list in the connection.
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: destroy packet...\n"));
+
+ SpxConnDequeueSendPktLock(pSpxConnFile, pNdisPkt);
+ freePkt = TRUE;
+ }
+
+ } while (FALSE);
+
+ if (lockHeld)
+ {
+ CTEFreeLock(&pSpxConnFile->scf_Lock, lockHandle);
+ }
+
+ if (freePkt)
+ {
+ DBGPRINT(SEND, INFO,
+ ("IpxSendComplete: free packet...\n"));
+
+ SpxPktSendRelease(pNdisPkt);
+ }
+
+ if (completeReq)
+ {
+ // If this is a send request, set info to data sent, else it will be
+ // zero.
+ if (REQUEST_MINOR_FUNCTION(pRequest) == TDI_SEND)
+ {
+ PTDI_REQUEST_KERNEL_SEND pParam;
+
+ pParam = (PTDI_REQUEST_KERNEL_SEND)
+ REQUEST_PARAMETERS(pRequest);
+
+ REQUEST_INFORMATION(pRequest) = pParam->SendLength;
+ DBGPRINT(SEND, DBG,
+ ("IpxSendComplete: complete req %lx.%lx...\n",
+ REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ CTEAssert(pRequest != NULL);
+ CTEAssert(REQUEST_STATUS(pRequest) != STATUS_PENDING);
+ SpxCompleteRequest(pRequest);
+ }
+ else
+ {
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx DISC Request %lx with %lx.%lx\n",
+ pSpxConnFile, pRequest, REQUEST_STATUS(pRequest),
+ REQUEST_INFORMATION(pRequest)));
+
+ DBGPRINT(SEND, DBG,
+ ("SpxSendComplete: %lx.%lx.%lx\n",
+ pSpxConnFile->scf_RefCount,
+ pSpxConnFile->scf_Flags,
+ pSpxConnFile->scf_Flags2));
+
+ // Set the request in the connection, and deref for it.
+ InsertTailList(
+ &pSpxConnFile->scf_DiscLinkage,
+ REQUEST_LINKAGE(pRequest));
+ }
+
+ SpxConnFileDereference(pSpxConnFile, CFREF_VERIFY);
+ }
+
+ return;
+
+} // SpxSendComplete
+
+
+
diff --git a/private/ntos/tdi/isn/spx/spxtimer.c b/private/ntos/tdi/isn/spx/spxtimer.c
new file mode 100644
index 000000000..bdb4e1d7f
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxtimer.c
@@ -0,0 +1,637 @@
+/*
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ spxtimer.c
+
+Abstract:
+
+ This file implements the timer routines used by the stack.
+
+Author:
+
+ Jameel Hyder (jameelh@microsoft.com)
+ Nikhil Kamkolkar (nikhilk@microsoft.com)
+
+
+Revision History:
+ 23 Feb 1993 Initial Version
+
+Notes: Tab stop: 4
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXTIMER
+
+// Discardable code after Init time
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, SpxTimerInit)
+#endif
+
+// Globals for this module
+PTIMERLIST spxTimerList = NULL;
+PTIMERLIST spxTimerTable[TIMER_HASH_TABLE] = {0};
+PTIMERLIST spxTimerActive = NULL;
+CTELock spxTimerLock = {0};
+LARGE_INTEGER spxTimerTick = {0};
+KTIMER spxTimer = {0};
+KDPC spxTimerDpc = {0};
+ULONG spxTimerId = 1;
+LONG spxTimerCount = 0;
+USHORT spxTimerDispatchCount = 0;
+BOOLEAN spxTimerStopped = FALSE;
+
+
+NTSTATUS
+SpxTimerInit(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize the timer component for the appletalk stack.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+#if !defined(_PNP_POWER)
+ BOOLEAN TimerStarted;
+#endif !_PNP_POWER
+
+ // Initialize the timer and its associated Dpc. timer will be kicked
+ // off when we get the first card arrival notification from ipx
+ KeInitializeTimer(&spxTimer);
+ CTEInitLock(&spxTimerLock);
+ KeInitializeDpc(&spxTimerDpc, spxTimerDpcRoutine, NULL);
+ spxTimerTick = RtlConvertLongToLargeInteger(SPX_TIMER_TICK);
+#if !defined(_PNP_POWER)
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+#endif !_PNP_POWER
+ return STATUS_SUCCESS;
+}
+
+
+
+
+ULONG
+SpxTimerScheduleEvent(
+ IN TIMER_ROUTINE Worker, // Routine to invoke when time expires
+ IN ULONG MsTime, // Schedule after this much time
+ IN PVOID pContext // Context(s) to pass to the routine
+ )
+/*++
+
+Routine Description:
+
+ Insert an event in the timer event list. If the list is empty, then
+ fire off a timer. The time is specified in ms. We convert to ticks.
+ Each tick is currently 100ms. It may not be zero or negative. The internal
+ timer fires at 100ms granularity.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+ ULONG DeltaTime;
+ ULONG Id = 0;
+
+ // Convert to ticks.
+ DeltaTime = MsTime/SPX_MS_TO_TICKS;
+ if (DeltaTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ DeltaTime = 1;
+ }
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Converting %ld to ticks %ld\n",
+ MsTime, DeltaTime));
+
+ // Negative or Zero DeltaTime is invalid.
+ CTEAssert (DeltaTime > 0);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerScheduleEvent: Routine %lx, Time %d, Context %lx\n",
+ Worker, DeltaTime, pContext));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, FATAL,
+ ("SpxTimerScheduleEvent: Called after Flush !!\n"));
+ }
+
+ else do
+ {
+ pList = SpxBPAllocBlock(BLKID_TIMERLIST);
+
+ if (pList == NULL)
+ {
+ break;
+ }
+
+#if DBG
+ pList->tmr_Signature = TMR_SIGNATURE;
+#endif
+ pList->tmr_Cancelled = FALSE;
+ pList->tmr_Worker = Worker;
+ pList->tmr_AbsTime = DeltaTime;
+ pList->tmr_Context = pContext;
+
+ Id = pList->tmr_Id = spxTimerId++;
+
+ // Take care of wrap around
+ if (spxTimerId == 0)
+ spxTimerId = 1;
+
+ // Enqueue this handler
+ spxTimerEnqueue(pList);
+ } while (FALSE);
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ return Id;
+}
+
+
+
+VOID
+spxTimerDpcRoutine(
+ IN PKDPC pKDpc,
+ IN PVOID pContext,
+ IN PVOID SystemArgument1,
+ IN PVOID SystemArgument2
+ )
+/*++
+
+Routine Description:
+
+ This is called in at DISPATCH_LEVEL when the timer expires. The entry at
+ the head of the list is decremented and if ZERO unlinked and dispatched.
+ If the list is non-empty, the timer is fired again.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ BOOLEAN TimerStarted;
+ ULONG ReEnqueueTime;
+ CTELockHandle lockHandle;
+
+ pKDpc; pContext; SystemArgument1; SystemArgument2;
+
+#if defined(_PNP_POWER)
+ CTEGetLock(&spxTimerLock, &lockHandle);
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+ return;
+ }
+#else
+ if (spxTimerStopped)
+ {
+ DBGPRINT(SYSTEM, ERR,
+ ("spxTimerDpc: Enetered after Flush !!!\n"));
+ return;
+ }
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+#endif _PNP_POWER
+
+ SpxTimerCurrentTime ++; // Update our relative time
+
+#ifdef PROFILING
+ // This is the only place where this is changed. And it always increases.
+ SpxStatistics.stat_ElapsedTime = SpxTimerCurrentTime;
+#endif
+
+ // We should never be here if we have no work to do
+ if ((spxTimerList != NULL))
+ {
+ // Careful here. If two guys wanna go off together - let them !!
+ if (spxTimerList->tmr_RelDelta != 0)
+ (spxTimerList->tmr_RelDelta)--;
+
+ // Dispatch the entry if it is ready to go
+ if (spxTimerList->tmr_RelDelta == 0)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+
+ // Unlink from the list
+ spxTimerList = pList->tmr_Next;
+ if (spxTimerList != NULL)
+ spxTimerList->tmr_Prev = &spxTimerList;
+
+ // Unlink from the hash table now
+ for (ppList = &spxTimerTable[pList->tmr_Id % TIMER_HASH_TABLE];
+ *ppList != NULL;
+ ppList = &((*ppList)->tmr_Overflow))
+ {
+ CTEAssert(VALID_TMR(*ppList));
+ if (*ppList == pList)
+ {
+ *ppList = pList->tmr_Overflow;
+ break;
+ }
+ }
+
+ CTEAssert (*ppList == pList->tmr_Overflow);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ spxTimerDispatchCount ++;
+ spxTimerCount --;
+ spxTimerActive = pList;
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // If reenqueue time is 0, do not requeue. If 1, then requeue with
+ // current value, else use value specified.
+ ReEnqueueTime = (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerDpcRoutine: Reenequeu time %lx.%lx\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerActive = NULL;
+ spxTimerDispatchCount --;
+
+ if (ReEnqueueTime != TIMER_DONT_REQUEUE)
+ {
+ // If this chappie was cancelled while it was running
+ // and it wants to be re-queued, do it right away.
+ if (pList->tmr_Cancelled)
+ {
+ (*pList->tmr_Worker)(pList->tmr_Context, FALSE);
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ else
+ {
+ if (ReEnqueueTime != TIMER_REQUEUE_CUR_VALUE)
+ {
+ pList->tmr_AbsTime = ReEnqueueTime/SPX_MS_TO_TICKS;
+ if (pList->tmr_AbsTime == 0)
+ {
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld\n",
+ pList->tmr_AbsTime));
+ }
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerDispatch: Requeue at %ld.%ld\n",
+ ReEnqueueTime, pList->tmr_AbsTime));
+ }
+
+ spxTimerEnqueue(pList);
+ }
+ }
+ else
+ {
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ }
+ }
+
+#if defined(_PNP_POWER)
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+
+ // it is possible that while we were here in Dpc, PNP_ADD_DEVICE
+ // restarted the timer, so this assert is commented out for PnP
+// CTEAssert(!TimerStarted);
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+#else
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ if (!spxTimerStopped)
+ {
+ TimerStarted = KeSetTimer(&spxTimer,
+ spxTimerTick,
+ &spxTimerDpc);
+ CTEAssert(!TimerStarted);
+ }
+#endif _PNP_POWER
+}
+
+
+VOID
+spxTimerEnqueue(
+ IN PTIMERLIST pListNew
+ )
+/*++
+
+Routine Description:
+
+ Here is a thesis on the code that follows.
+
+ The timer events are maintained as a list which the timer dpc routine
+ looks at every timer tick. The list is maintained in such a way that only
+ the head of the list needs to be updated every tick i.e. the entire list
+ is never scanned. The way this is achieved is by keeping delta times
+ relative to the previous entry.
+
+ Every timer tick, the relative time at the head of the list is decremented.
+ When that goes to ZERO, the head of the list is unlinked and dispatched.
+
+ To give an example, we have the following events queued at time slots
+ X Schedule A after 10 ticks.
+ X+3 Schedule B after 5 ticks.
+ X+5 Schedule C after 4 ticks.
+ X+8 Schedule D after 6 ticks.
+
+ So A will schedule at X+10, B at X+8 (X+3+5), C at X+9 (X+5+4) and
+ D at X+14 (X+8+6).
+
+ The above example covers all the situations.
+
+ - NULL List.
+ - Inserting at head of list.
+ - Inserting in the middle of the list.
+ - Appending to the list tail.
+
+ The list will look as follows.
+
+ BEFORE AFTER
+ ------ -----
+
+ X Head -->| Head -> A(10) ->|
+ A(10)
+
+ X+3 Head -> A(7) ->| Head -> B(5) -> A(2) ->|
+ B(5)
+
+ X+5 Head -> B(3) -> A(2) ->| Head -> B(3) -> C(1) -> A(1) ->|
+ C(4)
+
+ X+8 Head -> C(1) -> A(1) ->| Head -> C(1) -> A(1) -> D(4) ->|
+ D(6)
+
+ The granularity is one tick. THIS MUST BE CALLED WITH THE TIMER LOCK HELD.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ ULONG DeltaTime = pListNew->tmr_AbsTime;
+
+ // The DeltaTime is adjusted in every pass of the loop to reflect the
+ // time after the previous entry that the new entry will schedule.
+ for (ppList = &spxTimerList;
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Next)
+ {
+ CTEAssert(VALID_TMR(pList));
+ if (DeltaTime <= pList->tmr_RelDelta)
+ {
+ pList->tmr_RelDelta -= DeltaTime;
+ break;
+ }
+ DeltaTime -= pList->tmr_RelDelta;
+ }
+
+
+ // Link this in the chain
+ pListNew->tmr_RelDelta = DeltaTime;
+ pListNew->tmr_Next = pList;
+ pListNew->tmr_Prev = ppList;
+ *ppList = pListNew;
+ if (pList != NULL)
+ {
+ pList->tmr_Prev = &pListNew->tmr_Next;
+ }
+
+ // Now link it in the hash table
+ pListNew->tmr_Overflow = spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE];
+ spxTimerTable[pListNew->tmr_Id % TIMER_HASH_TABLE] = pListNew;
+ spxTimerCount ++;
+}
+
+
+
+
+VOID
+SpxTimerFlushAndStop(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Force all entries in the timer queue to be dispatched immediately. No
+ more queue'ing of timer routines is permitted after this. The timer
+ essentially shuts down.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList;
+ CTELockHandle lockHandle;
+
+ CTEAssert (KeGetCurrentIrql() == LOW_LEVEL);
+
+ DBGPRINT(SYSTEM, ERR,
+ ("SpxTimerFlushAndStop: Entered\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ spxTimerStopped = TRUE;
+
+ KeCancelTimer(&spxTimer);
+
+ if (spxTimerList != NULL)
+ {
+ // Dispatch all entries right away
+ while (spxTimerList != NULL)
+ {
+ pList = spxTimerList;
+ CTEAssert(VALID_TMR(pList));
+ spxTimerList = pList->tmr_Next;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("spxTimerFlushAndStop: Dispatching %lx\n",
+ pList->tmr_Worker));
+
+ // The timer routines assume they are being called at DISPATCH
+ // level. This is OK since we are calling with SpinLock held.
+
+ (*pList->tmr_Worker)(pList->tmr_Context, TRUE);
+
+ spxTimerCount --;
+ SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ }
+ RtlZeroMemory(spxTimerTable, sizeof(spxTimerTable));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ // Wait for all timer routines to complete
+ while (spxTimerDispatchCount != 0)
+ {
+ SpxSleep(SPX_TIMER_WAIT);
+ }
+}
+
+
+
+
+BOOLEAN
+SpxTimerCancelEvent(
+ IN ULONG TimerId,
+ IN BOOLEAN ReEnqueue
+ )
+/*++
+
+Routine Description:
+
+ Cancel a previously scheduled timer event, if it hasn't fired already.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PTIMERLIST pList, *ppList;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: Entered for TimerId %ld\n", TimerId));
+
+ CTEAssert(TimerId != 0);
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (ppList = &spxTimerTable[TimerId % TIMER_HASH_TABLE];
+ (pList = *ppList) != NULL;
+ ppList = &pList->tmr_Overflow)
+ {
+ CTEAssert(VALID_TMR(pList));
+ // If we find it, cancel it
+ if (pList->tmr_Id == TimerId)
+ {
+ // Unlink this from the hash table
+ *ppList = pList->tmr_Overflow;
+
+ // ... and from the list
+ if (pList->tmr_Next != NULL)
+ {
+ pList->tmr_Next->tmr_RelDelta += pList->tmr_RelDelta;
+ pList->tmr_Next->tmr_Prev = pList->tmr_Prev;
+ }
+ *(pList->tmr_Prev) = pList->tmr_Next;
+
+ spxTimerCount --;
+ if (ReEnqueue)
+ spxTimerEnqueue(pList);
+ else SpxBPFreeBlock(pList, BLKID_TIMERLIST);
+ break;
+ }
+ }
+
+ // If we could not find it in the list, see if it currently running.
+ // If so mark him to not reschedule itself, only if reenqueue was false.
+ if (pList == NULL)
+ {
+ if ((spxTimerActive != NULL) &&
+ (spxTimerActive->tmr_Id == TimerId) &&
+ !ReEnqueue)
+ {
+ spxTimerActive->tmr_Cancelled = TRUE;
+ }
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+
+ DBGPRINT(SYSTEM, INFO,
+ ("SpxTimerCancelEvent: %s for Id %ld\n",
+ (pList != NULL) ? "Success" : "Failure", TimerId));
+
+ return (pList != NULL);
+}
+
+
+
+
+#if DBG
+
+VOID
+SpxTimerDumpList(
+ VOID
+ )
+{
+ PTIMERLIST pList;
+ ULONG CumTime = 0;
+ CTELockHandle lockHandle;
+
+ DBGPRINT(DUMP, FATAL,
+ ("TIMER LIST: (Times are in %dms units\n", 1000));
+ DBGPRINT(DUMP, FATAL,
+ ("\tTimerId Time(Abs) Time(Rel) Routine Address\n"));
+
+ CTEGetLock(&spxTimerLock, &lockHandle);
+
+ for (pList = spxTimerList;
+ pList != NULL;
+ pList = pList->tmr_Next)
+ {
+ CumTime += pList->tmr_RelDelta;
+ DBGPRINT(DUMP, FATAL,
+ ("\t% 6lx %5d %5ld %lx\n",
+ pList->tmr_Id, pList->tmr_AbsTime, CumTime, pList->tmr_Worker));
+ }
+
+ CTEFreeLock(&spxTimerLock, lockHandle);
+}
+
+#endif
diff --git a/private/ntos/tdi/isn/spx/spxutils.c b/private/ntos/tdi/isn/spx/spxutils.c
new file mode 100644
index 000000000..024a36988
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/spxutils.c
@@ -0,0 +1,484 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxutils.c
+
+Abstract:
+
+ This contains all utility routines for the ISN SPX module.
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+// Define module number for event logging entries
+#define FILENUM SPXUTILS
+
+UINT
+SpxUtilWstrLength(
+ IN PWSTR Wstr
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ UINT length = 0;
+
+ while (*Wstr++)
+ {
+ length += sizeof(WCHAR);
+ }
+
+ return length;
+}
+
+
+
+
+LONG
+SpxRandomNumber(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ LARGE_INTEGER Li;
+ static LONG seed = 0;
+
+ // Return a positive pseudo-random number; simple linear congruential
+ // algorithm. ANSI C "rand()" function.
+
+ if (seed == 0)
+ {
+ KeQuerySystemTime(&Li);
+ seed = Li.LowPart;
+ }
+
+ seed *= (0x41C64E6D + 0x3039);
+
+ return (seed & 0x7FFFFFFF);
+}
+
+
+
+
+NTSTATUS
+SpxUtilGetSocketType(
+ PUNICODE_STRING RemainingFileName,
+ PBYTE SocketType
+ )
+/*++
+
+Routine Description:
+
+ For PROTO_SPX, i'd return a device name from the dll of the form
+ \Device\IsnSpx\SpxStream (for SOCK_STREAM) or
+ \Device\IsnSpx\Spx (for SOCK_SEQPKT)
+
+ and for PROTO_SPXII (the more common case we hope, even if
+ internally we degrade to SPX1 cause of the remote client's
+ limitations)
+ \Device\IsnSpx\Stream (for SOCK_STREAM) or
+ \Device\IsnSpx (for SOCK_SEQPKT)
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING typeString;
+
+ *SocketType = SOCKET2_TYPE_SEQPKT;
+
+ // Check for the socket type
+ do
+ {
+ if (RemainingFileName->Length == 0)
+ {
+ break;
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_STREAM;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET1_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET1_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET1_TYPE_SEQPKT;
+ break;
+ }
+ }
+
+ if ((UINT)RemainingFileName->Length ==
+ SpxUtilWstrLength(SOCKET2STREAM_SUFFIX))
+ {
+ RtlInitUnicodeString(&typeString, SOCKET2STREAM_SUFFIX);
+
+ // Case insensitive compare
+ if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
+ {
+ *SocketType = SOCKET2_TYPE_STREAM;
+ break;
+ }
+ }
+
+ status = STATUS_NO_SUCH_DEVICE;
+
+ } while (FALSE);
+
+ return(status);
+}
+
+
+
+
+#define ONE_MS_IN_100ns -10000L // 1ms in 100ns units
+
+VOID
+SpxSleep(
+ IN ULONG TimeInMs
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ KTIMER SleepTimer;
+
+ ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
+
+ KeInitializeTimer(&SleepTimer);
+
+ KeSetTimer(&SleepTimer,
+ RtlConvertLongToLargeInteger(TimeInMs * ONE_MS_IN_100ns),
+ NULL);
+
+ KeWaitForSingleObject(&SleepTimer, UserRequest, KernelMode, FALSE, NULL);
+ return;
+}
+
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+SpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_IPX.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+Return Value:
+
+ A pointer to the IPX address, or NULL if none 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 IPX one.
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX)
+ {
+ if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
+ {
+ return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} // SpxParseTdiAddress
+
+
+
+BOOLEAN
+SpxValidateTdiAddress(
+ 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))
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: runt address\n"));
+
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++)
+ {
+ if (addressName->Address > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd)
+ {
+ DBGPRINT(TDI, ERR,
+ ("SpxValidateTdiAddress: address too short\n"));
+
+ return FALSE;
+ }
+ return TRUE;
+
+} // SpxValidateTdiAddress
+
+
+
+
+ULONG
+SpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG AddressBufferLength,
+ IN UCHAR Network[4],
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a TRANSPORT_ADDRESS in the specified
+ buffer, given the socket, network and node. It will write
+ less than the full address if the buffer is too short.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ AddressBufferLength - The length of the buffer.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ The number of bytes written into AddressBuffer.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+ TA_IPX_ADDRESS TempAddress;
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ }
+ else
+ {
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)&TempAddress;
+ }
+
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)Network;
+ SpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(SpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+ if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
+ {
+ return sizeof(TA_IPX_ADDRESS);
+ }
+ else
+ {
+ RtlCopyMemory(AddressBuffer, &TempAddress, AddressBufferLength);
+ return AddressBufferLength;
+ }
+
+} // SpxBuildTdiAddress
+
+
+
+VOID
+SpxBuildTdiAddressFromIpxAddr(
+ IN PVOID AddressBuffer,
+ IN PBYTE pIpxAddr
+ )
+{
+ TA_IPX_ADDRESS UNALIGNED * SpxAddress;
+
+ SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+ SpxAddress->TAAddressCount = 1;
+ SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)pIpxAddr;
+ RtlCopyMemory(
+ SpxAddress->Address[0].Address[0].NodeAddress,
+ pIpxAddr+4,
+ 6);
+
+ GETSHORT2SHORT(
+ &SpxAddress->Address[0].Address[0].Socket,
+ pIpxAddr + 10);
+
+ return;
+}
+
+
+
+VOID
+SpxCalculateNewT1(
+ IN struct _SPX_CONN_FILE * pSpxConnFile,
+ IN int NewT1
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ NewT1 - New value for the RTT in ms.
+
+Return Value:
+
+
+--*/
+{
+ int baseT1, error;
+
+ //
+ // VAN JACOBSEN Algorithm. From Internetworking with Tcp/ip
+ // (Comer) book.
+ //
+
+ error = NewT1 - (pSpxConnFile->scf_AveT1 >> 3);
+ pSpxConnFile->scf_AveT1 += error;
+ if (pSpxConnFile->scf_AveT1 <= 0) // Make sure not too small
+ {
+ pSpxConnFile->scf_AveT1 = SPX_T1_MIN;
+ }
+
+ if (error < 0)
+ error = -error;
+
+ error -= (pSpxConnFile->scf_DevT1 >> 2);
+ pSpxConnFile->scf_DevT1 += error;
+ if (pSpxConnFile->scf_DevT1 <= 0)
+ pSpxConnFile->scf_DevT1 = 1;
+
+ baseT1 = (((pSpxConnFile->scf_AveT1 >> 2) + pSpxConnFile->scf_DevT1) >> 1);
+
+ // If less then min - set it
+ if (baseT1 < SPX_T1_MIN)
+ baseT1 = SPX_T1_MIN;
+
+ // Set the new value
+ DBGPRINT(TDI, DBG,
+ ("SpxCalculateNewT1: Old value %lx New %lx\n",
+ pSpxConnFile->scf_BaseT1, baseT1));
+
+ pSpxConnFile->scf_BaseT1 = baseT1;
+
+ // At the time of restarting the timer,we convert this to a tick value.
+ return;
+}
+
diff --git a/private/ntos/tdi/isn/spx/up/makefile b/private/ntos/tdi/isn/spx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/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/spx/up/sources b/private/ntos/tdi/isn/spx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isn/spx/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