summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isnp
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/isnp
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/isnp/dirs28
-rw-r--r--private/ntos/tdi/isnp/inc/bind.h563
-rw-r--r--private/ntos/tdi/isnp/inc/ioctls.h155
-rw-r--r--private/ntos/tdi/isnp/inc/isn.h41
-rw-r--r--private/ntos/tdi/isnp/ipx/action.c1802
-rw-r--r--private/ntos/tdi/isnp/ipx/adapter.c636
-rw-r--r--private/ntos/tdi/isnp/ipx/address.c1843
-rw-r--r--private/ntos/tdi/isnp/ipx/config.c1715
-rw-r--r--private/ntos/tdi/isnp/ipx/config.h132
-rw-r--r--private/ntos/tdi/isnp/ipx/device.c599
-rw-r--r--private/ntos/tdi/isnp/ipx/dirs22
-rw-r--r--private/ntos/tdi/isnp/ipx/driver.c4219
-rw-r--r--private/ntos/tdi/isnp/ipx/event.c143
-rw-r--r--private/ntos/tdi/isnp/ipx/ind.c4047
-rw-r--r--private/ntos/tdi/isnp/ipx/internal.c1233
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxprocs.h1525
-rw-r--r--private/ntos/tdi/isnp/ipx/ipxtypes.h1999
-rw-r--r--private/ntos/tdi/isnp/ipx/isnipx.h531
-rw-r--r--private/ntos/tdi/isnp/ipx/loopback.c280
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.c3793
-rw-r--r--private/ntos/tdi/isnp/ipx/mac.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/ipx/ndis.c2204
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.ini191
-rw-r--r--private/ntos/tdi/isnp/ipx/nwlnkipx.rc12
-rw-r--r--private/ntos/tdi/isnp/ipx/packet.c1560
-rw-r--r--private/ntos/tdi/isnp/ipx/precomp.h44
-rw-r--r--private/ntos/tdi/isnp/ipx/query.c297
-rw-r--r--private/ntos/tdi/isnp/ipx/receive.c466
-rw-r--r--private/ntos/tdi/isnp/ipx/rip.c2655
-rw-r--r--private/ntos/tdi/isnp/ipx/send.c1651
-rw-r--r--private/ntos/tdi/isnp/ipx/sources.inc74
-rw-r--r--private/ntos/tdi/isnp/ipx/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf89
-rw-r--r--private/ntos/tdi/isnp/ipx/up/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/action.c221
-rw-r--r--private/ntos/tdi/isnp/nb/address.c2406
-rw-r--r--private/ntos/tdi/isnp/nb/autodial.c526
-rw-r--r--private/ntos/tdi/isnp/nb/bind.c593
-rw-r--r--private/ntos/tdi/isnp/nb/cache.c2746
-rw-r--r--private/ntos/tdi/isnp/nb/config.c661
-rw-r--r--private/ntos/tdi/isnp/nb/config.h70
-rw-r--r--private/ntos/tdi/isnp/nb/connect.c3628
-rw-r--r--private/ntos/tdi/isnp/nb/datagram.c1089
-rw-r--r--private/ntos/tdi/isnp/nb/device.c461
-rw-r--r--private/ntos/tdi/isnp/nb/dirs22
-rw-r--r--private/ntos/tdi/isnp/nb/driver.c1794
-rw-r--r--private/ntos/tdi/isnp/nb/event.c117
-rw-r--r--private/ntos/tdi/isnp/nb/frame.c1095
-rw-r--r--private/ntos/tdi/isnp/nb/isnnb.h787
-rw-r--r--private/ntos/tdi/isnp/nb/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/nbcount.c177
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/nbcount.rc11
-rw-r--r--private/ntos/tdi/isnp/nb/nbcount/sources29
-rw-r--r--private/ntos/tdi/isnp/nb/nbiprocs.h1530
-rw-r--r--private/ntos/tdi/isnp/nb/nbitypes.h1511
-rw-r--r--private/ntos/tdi/isnp/nb/nwlnknb.ini43
-rw-r--r--private/ntos/tdi/isnp/nb/nwlnknb.rc12
-rw-r--r--private/ntos/tdi/isnp/nb/packet.c1482
-rw-r--r--private/ntos/tdi/isnp/nb/precomp.h42
-rw-r--r--private/ntos/tdi/isnp/nb/query.c1817
-rw-r--r--private/ntos/tdi/isnp/nb/receive.c1303
-rw-r--r--private/ntos/tdi/isnp/nb/send.c2886
-rw-r--r--private/ntos/tdi/isnp/nb/session.c2450
-rw-r--r--private/ntos/tdi/isnp/nb/sources.inc69
-rw-r--r--private/ntos/tdi/isnp/nb/timer.c1233
-rw-r--r--private/ntos/tdi/isnp/nb/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/nb/up/sources29
-rw-r--r--private/ntos/tdi/isnp/spx/dirs22
-rw-r--r--private/ntos/tdi/isnp/spx/globals.c87
-rw-r--r--private/ntos/tdi/isnp/spx/h/fwddecls.h28
-rw-r--r--private/ntos/tdi/isnp/spx/h/globals.h67
-rw-r--r--private/ntos/tdi/isnp/spx/h/isnspx.h363
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxaddr.h426
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxbind.h32
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxconn.h1666
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxdev.h204
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxerror.h246
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxmem.h142
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxntdef.h72
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxpkt.h466
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxquery.h54
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxrecv.h89
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxreg.h65
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxsend.h34
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxtimer.h101
-rw-r--r--private/ntos/tdi/isnp/spx/h/spxutils.h178
-rw-r--r--private/ntos/tdi/isnp/spx/mp/makefile6
-rw-r--r--private/ntos/tdi/isnp/spx/mp/sources29
-rw-r--r--private/ntos/tdi/isnp/spx/nwlnkspx.rc12
-rw-r--r--private/ntos/tdi/isnp/spx/precomp.h1
-rw-r--r--private/ntos/tdi/isnp/spx/sources.inc65
-rw-r--r--private/ntos/tdi/isnp/spx/spxaddr.c1729
-rw-r--r--private/ntos/tdi/isnp/spx/spxbind.c600
-rw-r--r--private/ntos/tdi/isnp/spx/spxconn.c3862
-rw-r--r--private/ntos/tdi/isnp/spx/spxcpkt.c4131
-rw-r--r--private/ntos/tdi/isnp/spx/spxcutil.c1738
-rw-r--r--private/ntos/tdi/isnp/spx/spxdev.c242
-rw-r--r--private/ntos/tdi/isnp/spx/spxdrvr.c1008
-rw-r--r--private/ntos/tdi/isnp/spx/spxerror.c316
-rw-r--r--private/ntos/tdi/isnp/spx/spxmem.c897
-rw-r--r--private/ntos/tdi/isnp/spx/spxpkt.c1594
-rw-r--r--private/ntos/tdi/isnp/spx/spxquery.c259
-rw-r--r--private/ntos/tdi/isnp/spx/spxrecv.c2837
-rw-r--r--private/ntos/tdi/isnp/spx/spxreg.c400
-rw-r--r--private/ntos/tdi/isnp/spx/spxsend.c262
-rw-r--r--private/ntos/tdi/isnp/spx/spxtimer.c637
-rw-r--r--private/ntos/tdi/isnp/spx/spxutils.c484
-rw-r--r--private/ntos/tdi/isnp/spx/up/makefile6
-rw-r--r--private/ntos/tdi/isnp/spx/up/sources29
114 files changed, 91125 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/dirs b/private/ntos/tdi/isnp/dirs
new file mode 100644
index 000000000..a93e8e700
--- /dev/null
+++ b/private/ntos/tdi/isnp/dirs
@@ -0,0 +1,28 @@
+!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:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= \
+ ipx \
+ nb \
+ spx
+
+OPTIONAL_DIRS=
diff --git a/private/ntos/tdi/isnp/inc/bind.h b/private/ntos/tdi/isnp/inc/bind.h
new file mode 100644
index 000000000..60294349d
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/bind.h
@@ -0,0 +1,563 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ bind.h
+
+Abstract:
+
+ Private include file for the ISN transport. It defines the
+ structures used for binding between IPX and the upper drivers.
+
+Author:
+
+ Adam Barr (adamba) 04-Oct-1993
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 5-July-1995
+ Bug fixes - tagged [SA]
+
+--*/
+
+#ifndef _ISN_BIND_
+#define _ISN_BIND_
+
+//
+// Retrieve the common definitions.
+//
+
+#include <isnkrnl.h>
+
+
+//
+// Define the IOCTL used for binding between the upper
+// drivers and IPX.
+//
+
+#define _IPX_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_TRANSPORT, request, method, FILE_ANY_ACCESS)
+
+#define IOCTL_IPX_INTERNAL_BIND _IPX_CONTROL_CODE( 0x1234, METHOD_BUFFERED )
+
+
+//
+// Identifier for the drivers in ISN.
+//
+
+#define IDENTIFIER_NB 0
+#define IDENTIFIER_SPX 1
+#define IDENTIFIER_RIP 2
+#define IDENTIFIER_IPX 3
+
+#ifdef _PNP_POWER
+//
+// This the number of PVOIDs in the beginning of the SEND_RESERVED
+// section of a packet header, to be set aside by the ISN clients (NB/SPX)
+// for IPX's private use.
+//
+#define SEND_RESERVED_COMMON_SIZE 8
+#endif
+
+//
+// Definition of a RIP router table entry.
+//
+
+typedef struct _IPX_ROUTE_ENTRY {
+ UCHAR Network[4];
+ USHORT NicId;
+ UCHAR NextRouter[6];
+ NDIS_HANDLE NdisBindingContext;
+ USHORT Flags;
+ USHORT Timer;
+ UINT Segment;
+ USHORT TickCount;
+ USHORT HopCount;
+ LIST_ENTRY AlternateRoute;
+ LIST_ENTRY NicLinkage;
+ struct {
+ LIST_ENTRY Linkage;
+ ULONG Reserved[1];
+ } PRIVATE;
+} IPX_ROUTE_ENTRY, * PIPX_ROUTE_ENTRY;
+
+//
+// Definition of the Flags values.
+//
+
+#define IPX_ROUTER_PERMANENT_ENTRY 0x0001 // entry should never be deleted
+#define IPX_ROUTER_LOCAL_NET 0x0002 // locally attached network
+#define IPX_ROUTER_SCHEDULE_ROUTE 0x0004 // call ScheduleRouteHandler after using
+#define IPX_ROUTER_GLOBAL_WAN_NET 0x0008 // this is for rip's global network number
+
+
+//
+// Definition of the structure provided on a find
+// route/find route completion call.
+//
+
+//
+// [SA] Bug #15094 added node number to the structure.
+//
+
+typedef struct _IPX_FIND_ROUTE_REQUEST {
+ UCHAR Network[4];
+ UCHAR Node[6] ;
+ IPX_LOCAL_TARGET LocalTarget;
+ UCHAR Identifier;
+ UCHAR Type;
+ UCHAR Reserved1[2];
+ PVOID Reserved2;
+ LIST_ENTRY Linkage;
+} IPX_FIND_ROUTE_REQUEST, *PIPX_FIND_ROUTE_REQUEST;
+
+//
+// Definitions for the Type value.
+//
+
+#define IPX_FIND_ROUTE_NO_RIP 1 // fail if net is not in database
+#define IPX_FIND_ROUTE_RIP_IF_NEEDED 2 // return net if in database, otherwise RIP out
+#define IPX_FIND_ROUTE_FORCE_RIP 3 // re-RIP even if net is in database
+
+
+//
+// Structure used when querying the line information
+// for a specific NID ID.
+//
+
+typedef struct _IPX_LINE_INFO {
+ UINT LinkSpeed;
+ UINT MaximumPacketSize;
+ UINT MaximumSendSize;
+ UINT MacOptions;
+} IPX_LINE_INFO, *PIPX_LINE_INFO;
+
+
+
+//
+// Functions provided by the upper driver.
+//
+
+typedef VOID
+(*IPX_INTERNAL_RECEIVE) (
+ 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
+);
+
+typedef VOID
+(*IPX_INTERNAL_RECEIVE_COMPLETE) (
+ IN USHORT NicId
+);
+
+typedef VOID
+(*IPX_INTERNAL_STATUS) (
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_SEND_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA_COMPLETE) (
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE_COMPLETE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_UP) (
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+);
+
+typedef VOID
+(*IPX_INTERNAL_LINE_DOWN) (
+ IN USHORT NicId
+);
+
+typedef VOID
+(*IPX_INTERNAL_SCHEDULE_ROUTE) (
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+#if defined(_PNP_POWER)
+
+//
+// following opcodes are used when calling the
+// above handler.
+//
+typedef enum _IPX_PNP_OPCODE {
+ IPX_PNP_ADD_DEVICE, // 0 - addition of the first adapter
+ IPX_PNP_DELETE_DEVICE, // 1 - deletion of the last adapter
+ IPX_PNP_TRANSLATE_DEVICE, // 2 - translate device resource
+ IPX_PNP_TRANSLATE_ADDRESS, // 3 - translate address resource
+ IPX_PNP_ADDRESS_CHANGE, // 4 - Adapter address or Reserved address changed
+ IPX_PNP_MAX_OPCODES, // 5
+} IPX_PNP_OPCODE, *PIPX_PNP_OPCODE;
+
+//
+// PnP event notification handler.
+//
+typedef VOID
+(*IPX_INTERNAL_PNP_NOTIFICATION) (
+ IN IPX_PNP_OPCODE PnPOpcode,
+ IN OUT PVOID PnpData
+);
+
+//
+// Pointer to this structure is passed in PnPData portion of
+// the above handler when the opcode is ADD_DEVICE or DELETE_DEVICE.
+//
+typedef struct _IPX_PNP_INFO {
+ ULONG NetworkAddress;
+ UCHAR NodeAddress[6];
+ BOOLEAN NewReservedAddress; // where the above is a new reserved
+ // address for the Ipx clients.
+ BOOLEAN FirstORLastDevice; // is this a first card arrival or last card deletion.
+ IPX_LINE_INFO LineInfo; // New LineInfo.
+ NIC_HANDLE NicHandle;
+} IPX_PNP_INFO, *PIPX_PNP_INFO;
+
+#endif _PNP_POWER
+
+//
+// Input to the bind IOCTL
+//
+
+typedef struct _IPX_INTERNAL_BIND_INPUT {
+ USHORT Version;
+ UCHAR Identifier;
+ BOOLEAN BroadcastEnable;
+ UINT LookaheadRequired;
+ UINT ProtocolOptions;
+ IPX_INTERNAL_RECEIVE ReceiveHandler;
+ IPX_INTERNAL_RECEIVE_COMPLETE ReceiveCompleteHandler;
+ IPX_INTERNAL_STATUS StatusHandler;
+ IPX_INTERNAL_SEND_COMPLETE SendCompleteHandler;
+ IPX_INTERNAL_TRANSFER_DATA_COMPLETE TransferDataCompleteHandler;
+ IPX_INTERNAL_FIND_ROUTE_COMPLETE FindRouteCompleteHandler;
+ IPX_INTERNAL_LINE_UP LineUpHandler;
+ IPX_INTERNAL_LINE_DOWN LineDownHandler;
+ IPX_INTERNAL_SCHEDULE_ROUTE ScheduleRouteHandler;
+#if defined(_PNP_POWER)
+ IPX_INTERNAL_PNP_NOTIFICATION PnPHandler;
+#endif _PNP_POWER
+ ULONG RipParameters;
+} IPX_INTERNAL_BIND_INPUT, * PIPX_INTERNAL_BIND_INPUT;
+
+#if defined(_PNP_POWER)
+#define ISN_VERSION 2
+#endif _PNP_POWER
+//
+// Bit mask values for RipParameters.
+//
+
+#define IPX_RIP_PARAM_GLOBAL_NETWORK 0x00000001 // single network for all WANS
+
+
+
+//
+// Functions provided by the lower driver.
+//
+
+typedef NDIS_STATUS
+(*IPX_INTERNAL_SEND) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+);
+
+typedef VOID
+(*IPX_INTERNAL_FIND_ROUTE) (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+);
+
+typedef NTSTATUS
+(*IPX_INTERNAL_QUERY) (
+ IN ULONG InternalQueryType,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif _PNP_POWER
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+typedef VOID
+(*IPX_INTERNAL_TRANSFER_DATA)(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+//
+// Definitions of the internal query types. In all cases
+// STATUS_SUCCESS is returned if the request succeeds, and
+// STATUS_BUFFER_TOO_SMALL is returned, and BufferLengthNeeded
+// set if specified, if the buffer is too short. Other
+// return codes are defined below. The routine never pends.
+//
+
+//
+// This is used to query the line info. NicId specifies which one
+// to query. Buffer contains an IPX_LINE_INFO structure which is
+// used to return the information. Other return values:
+//
+// STATUS_INVALID_PARAMETER - NicId is invalid.
+//
+
+#define IPX_QUERY_LINE_INFO 1
+
+//
+// This is used to query the maximum NicId. NicId is unused. The
+// Buffer contains a USHORT which is used to return the information.
+//
+
+#define IPX_QUERY_MAXIMUM_NIC_ID 2
+
+//
+// This is used to determine if the IPX address specified was sent
+// by our local machine. If the address is the source address of a
+// received frame, NicId should be the ID that was indicated; otherwise
+// it should be set to 0. Buffer holds a TDI_ADDRESS_IPX. This
+// call returns STATUS_SUCCESS if the address is local, and
+// STATUS_NO_SUCH_DEVICE if not.
+//
+
+#define IPX_QUERY_IS_ADDRESS_LOCAL 3
+
+//
+// This is used to query the receive buffer space of a given NicId.
+// Buffer contains a ULONG which is used to return the information.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_RECEIVE_BUFFER_SPACE 4
+
+//
+// This is used to query the local IPX address of a given NicId.
+// Buffer contains a TDI_ADDRESS_IPX structure (the Socket is
+// returned as 0). If it is queried on net 0 it returns the
+// virtual network if there is one, otherwise STATUS_INVALID_PARAMETER.
+// It returns STATUS_INVALID_PARAMETER if NicId is invalid.
+//
+
+#define IPX_QUERY_IPX_ADDRESS 5
+
+//
+// This is used to return the source routing information for
+// a give remote address. NicId will be the NIC the packet was
+// received from. The IPX_SOURCE_ROUTING_QUERY is contained
+// in Buffer. Always returns STATUS_SUCCESS, although the
+// SourceRoutingLength may be 0 for unknown remotes.
+//
+// The source routing is return in the direction it was received
+// from the remote, not the direction used in replying. The
+// MaximumSendSize includes the IPX header (as it does in
+// IPX_LINE_INFO).
+//
+
+#define IPX_QUERY_SOURCE_ROUTING 6
+
+typedef struct _IPX_SOURCE_ROUTING_INFO {
+ USHORT Identifier; // input: the caller's IDENTIFIER_SPX, _NB, etc.
+ UCHAR RemoteAddress[6]; // input: the remote address
+ UCHAR SourceRouting[18]; // output: room for the maximum source route
+ USHORT SourceRoutingLength; // output: the valid length of source route
+ ULONG MaximumSendSize; // output: based on nic and source routing
+} IPX_SOURCE_ROUTING_INFO, * PIPX_SOURCE_ROUTING_INFO;
+
+//
+// This is used to query the maximum NicId over which outgoing type
+// 20 packets should be sent. It will be less than or equal to
+// the IPX_QUERY_MAXIMUM_NIC_ID value. What's excluded are down wan
+// lines and dialin wan lines if DisableDialinNetbios bit 1 is set.
+//
+
+#define IPX_QUERY_MAX_TYPE_20_NIC_ID 7
+
+#if defined(_PNP_POWER)
+
+//
+// This are used by NB to pass down these TDI queries which cannot
+// be completed in NB.
+//
+
+#define IPX_QUERY_DATA_LINK_ADDRESS 8
+#define IPX_QUERY_NETWORK_ADDRESS 9
+
+#endif _PNP_POWER
+
+//
+// Output of a non-RIP bind.
+//
+
+typedef struct _IPX_INTERNAL_BIND_OUTPUT {
+ USHORT Version;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_LINE_INFO LineInfo;
+ IPX_INTERNAL_SEND SendHandler;
+ IPX_INTERNAL_FIND_ROUTE FindRouteHandler;
+ IPX_INTERNAL_QUERY QueryHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+} IPX_INTERNAL_BIND_OUTPUT, * PIPX_INTERNAL_BIND_OUTPUT;
+
+
+
+//
+// Lower driver functions provided only for RIP.
+//
+
+typedef UINT
+(*IPX_INTERNAL_GET_SEGMENT) (
+ IN UCHAR Network[4]
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_ROUTE) (
+ IN UINT Segment,
+ IN UCHAR Network[4]
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_ADD_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef BOOLEAN
+(*IPX_INTERNAL_DELETE_ROUTE) (
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_FIRST_ROUTE) (
+ IN UINT Segment
+);
+
+typedef PIPX_ROUTE_ENTRY
+(*IPX_INTERNAL_GET_NEXT_ROUTE) (
+ IN UINT Segment
+);
+
+typedef VOID
+(*IPX_INTERNAL_INCREMENT_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+typedef ULONG
+(*IPX_INTERNAL_QUERY_WAN_INACTIVITY) (
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+
+);
+
+//
+// Describes a single network.
+//
+
+typedef struct _IPX_NIC_DATA {
+ USHORT NicId;
+ UCHAR Node[6];
+ UCHAR Network[4];
+ IPX_LINE_INFO LineInfo;
+ NDIS_MEDIUM DeviceType;
+ ULONG EnableWanRouter;
+} IPX_NIC_DATA, * PIPX_NIC_DATA;
+
+
+//
+// Describes all networks.
+//
+
+typedef struct _IPX_NIC_INFO_BUFFER {
+ USHORT NicCount;
+ USHORT VirtualNicId;
+ UCHAR VirtualNetwork[4];
+ IPX_NIC_DATA NicData[1];
+} IPX_NIC_INFO_BUFFER, * PIPX_NIC_INFO_BUFFER;
+
+
+//
+// Output from a RIP bind (the actual structure size is
+// based on the number of IPX_NIC_DATA elements in the
+// final IPX_NIC_INFO_BUFFER structure).
+//
+
+typedef struct _IPX_INTERNAL_BIND_RIP_OUTPUT {
+ USHORT Version;
+ USHORT MaximumNicCount;
+ USHORT MacHeaderNeeded;
+ USHORT IncludedHeaderOffset;
+ IPX_INTERNAL_SEND SendHandler;
+ UINT SegmentCount;
+ KSPIN_LOCK * SegmentLocks;
+ IPX_INTERNAL_GET_SEGMENT GetSegmentHandler;
+ IPX_INTERNAL_GET_ROUTE GetRouteHandler;
+ IPX_INTERNAL_ADD_ROUTE AddRouteHandler;
+ IPX_INTERNAL_DELETE_ROUTE DeleteRouteHandler;
+ IPX_INTERNAL_GET_FIRST_ROUTE GetFirstRouteHandler;
+ IPX_INTERNAL_GET_NEXT_ROUTE GetNextRouteHandler;
+ IPX_INTERNAL_INCREMENT_WAN_INACTIVITY IncrementWanInactivityHandler;
+ IPX_INTERNAL_QUERY_WAN_INACTIVITY QueryWanInactivityHandler;
+ IPX_INTERNAL_TRANSFER_DATA TransferDataHandler;
+ IPX_NIC_INFO_BUFFER NicInfoBuffer;
+} IPX_INTERNAL_BIND_RIP_OUTPUT, * PIPX_INTERNAL_BIND_RIP_OUTPUT;
+
+#endif // _ISN_BIND_
+
+
+#ifndef _IPXCP_CONFIG_
+#define _IPXCP_CONFIG_
+
+typedef struct _IPXCP_CONFIGURATION {
+ USHORT Version;
+ USHORT Length;
+ UCHAR Network[4];
+ UCHAR LocalNode[6];
+ UCHAR RemoteNode[6];
+ ULONG ConnectionClient; // 0 - Server, 1 - Client
+} IPXCP_CONFIGURATION, *PIPXCP_CONFIGURATION;
+
+#endif // _IPXCP_CONFIG_
+
diff --git a/private/ntos/tdi/isnp/inc/ioctls.h b/private/ntos/tdi/isnp/inc/ioctls.h
new file mode 100644
index 000000000..e7dd7b81a
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/ioctls.h
@@ -0,0 +1,155 @@
+#define VER_IOCH "@(#)MCS ipx/h/ioctls.h 1.00.00 - 08 APR 1993";
+
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Driver for Windows NT
+*
+* Module: ipx/h/ioctls.h
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+* IOCTL defines
+*
+****************************************************************************/
+
+/** Ioctls for IPX - (X) = User callable **/
+
+/**
+ ioctls will values 100 - 150 were added for the NT port.
+**/
+
+#define I_MIPX (('I' << 24) | ('D' << 16) | ('P' << 8))
+#define MIPX_SETNODEADDR I_MIPX | 0 /* Set the node address */
+#define MIPX_SETNETNUM I_MIPX | 1 /* Set the network number */
+#define MIPX_SETPTYPE I_MIPX | 2 /* (X) Set the packet type */
+#define MIPX_SENTTYPE I_MIPX | 3 /* (X) Set the xport type */
+#define MIPX_SETPKTSIZE I_MIPX | 4 /* Set the packet size */
+#define MIPX_SETSAP I_MIPX | 5 /* Set the sap/type field */
+#define MIPX_SENDOPTS I_MIPX | 6 /* (X) Send options on recv */
+#define MIPX_NOSENDOPTS I_MIPX | 7 /* (X) Don't send options on recv */
+#define MIPX_SENDSRC I_MIPX | 8 /* (X) Send source address up */
+#define MIPX_NOSENDSRC I_MIPX | 9 /* (X) Don't Send source address up */
+#define MIPX_CONVBCAST I_MIPX | 10 /* Convert TKR bcast to func addr */
+#define MIPX_NOCONVBCAST I_MIPX | 11 /* Don't cnvrt TKR bcast to funcaddr */
+#define MIPX_SETCARDTYPE I_MIPX | 12 /* Set 802.3 or ETH type */
+#define MIPX_STARGROUP I_MIPX | 13 /* This is stargroup */
+#define MIPX_SWAPLENGTH I_MIPX | 14 /* Set flag for swapping 802.3 length */
+#define MIPX_SENDDEST I_MIPX | 15 /* (X) Send dest. address up */
+#define MIPX_NOSENDDEST I_MIPX | 16 /* (X) Don't send dest. address up */
+#define MIPX_SENDFDEST I_MIPX | 17 /* (X) Send final dest. address up */
+#define MIPX_NOSENDFDEST I_MIPX | 18 /* (X) Don't send final dest. up */
+
+/** Added for NT port **/
+
+#define MIPX_SETVERSION I_MIPX | 100 /* Set card version */
+#define MIPX_GETSTATUS I_MIPX | 101
+#define MIPX_SENDADDROPT I_MIPX | 102 /* (X) Send ptype w/addr on recv */
+#define MIPX_NOSENDADDROPT I_MIPX | 103 /* (X) Stop sending ptype on recv */
+#define MIPX_CHECKSUM I_MIPX | 104 /* Enable/Disable checksum */
+#define MIPX_GETPKTSIZE I_MIPX | 105 /* Get max packet size */
+#define MIPX_SENDHEADER I_MIPX | 106 /* Send header with data */
+#define MIPX_NOSENDHEADER I_MIPX | 107 /* Don't send header with data */
+#define MIPX_SETCURCARD I_MIPX | 108 /* Set current card for IOCTLs */
+#define MIPX_SETMACTYPE I_MIPX | 109 /* Set the Cards MAC type */
+#define MIPX_DOSROUTE I_MIPX | 110 /* Do source routing on this card*/
+#define MIPX_NOSROUTE I_MIPX | 111 /* Don't source routine the card*/
+#define MIPX_SETRIPRETRY I_MIPX | 112 /* Set RIP retry count */
+#define MIPX_SETRIPTO I_MIPX | 113 /* Set RIP timeout */
+#define MIPX_SETTKRSAP I_MIPX | 114 /* Set the token ring SAP */
+#define MIPX_SETUSELLC I_MIPX | 115 /* Put LLC hdr on packets */
+#define MIPX_SETUSESNAP I_MIPX | 116 /* Put SNAP hdr on packets */
+#define MIPX_8023LEN I_MIPX | 117 /* 1=make even, 0=dont make even*/
+#define MIPX_SENDPTYPE I_MIPX | 118 /* Send ptype in options on recv*/
+#define MIPX_NOSENDPTYPE I_MIPX | 119 /* Don't send ptype in options */
+#define MIPX_FILTERPTYPE I_MIPX | 120 /* Filter on recv ptype */
+#define MIPX_NOFILTERPTYPE I_MIPX | 121 /* Don't Filter on recv ptype */
+#define MIPX_SETSENDPTYPE I_MIPX | 122 /* Set pkt type to send with */
+#define MIPX_GETCARDINFO I_MIPX | 123 /* Get info on a card */
+#define MIPX_SENDCARDNUM I_MIPX | 124 /* Send card num up in options */
+#define MIPX_NOSENDCARDNUM I_MIPX | 125 /* Dont send card num in options*/
+#define MIPX_SETROUTER I_MIPX | 126 /* Set router enabled flag */
+#define MIPX_SETRIPAGE I_MIPX | 127 /* Set RIP age timeout */
+#define MIPX_SETRIPUSAGE I_MIPX | 128 /* Set RIP usage timeout */
+#define MIPX_SETSROUTEUSAGE I_MIPX| 129 /* Set the SROUTE usage timeout */
+#define MIPX_SETINTNET I_MIPX | 130 /* Set internal network number */
+#define MIPX_NOVIRTADDR I_MIPX | 131 /* Turn off virtual net num */
+#define MIPX_VIRTADDR I_MIPX | 132 /* Turn on virtual net num */
+#define MIPX_SETBCASTFLAG I_MIPX | 133 /* Turn on bcast flag in addr */
+#define MIPX_NOBCASTFLAG I_MIPX | 134 /* Turn off bcast flag in addr */
+#define MIPX_GETNETINFO I_MIPX | 135 /* Get info on a network num */
+#define MIPX_SETDELAYTIME I_MIPX | 136 /* Set cards delay time */
+#define MIPX_SETROUTEADV I_MIPX | 137 /* Route advertise timeout */
+#define MIPX_SETSOCKETS I_MIPX | 138 /* Set default sockets */
+#define MIPX_SETLINKSPEED I_MIPX | 139 /* Set the link speed for a card*/
+#define MIPX_SETWANFLAG I_MIPX | 140
+#define MIPX_GETCARDCHANGES I_MIPX | 141 /* Wait for card changes */
+#define MIPX_GETMAXADAPTERS I_MIPX | 142
+#define MIPX_REUSEADDRESS I_MIPX | 143
+#define MIPX_RERIPNETNUM I_MIPX | 144 /* ReRip a network */
+
+/** For Source Routing Support **/
+
+#define MIPX_SRCLEAR I_MIPX | 200 /* Clear the source routing table*/
+#define MIPX_SRDEF I_MIPX | 201 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRBCAST I_MIPX | 202 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRMULTI I_MIPX | 203 /* 0=Single Rte, 1=All Routes */
+#define MIPX_SRREMOVE I_MIPX | 204 /* Remove a node from the table */
+#define MIPX_SRLIST I_MIPX | 205 /* Get the source routing table */
+#define MIPX_SRGETPARMS I_MIPX | 206 /* Get source routing parms */
+
+#define MIPX_SETSHOULDPUT I_MIPX | 210 /* Turn on should put call */
+#define MIPX_DELSHOULDPUT I_MIPX | 211 /* Turn off should put call */
+#define MIPX_GETSHOULDPUT I_MIPX | 212 /* Get ptr to mipx_shouldput */
+
+/** Added for ISN **/
+
+#define MIPX_RCVBCAST I_MIPX | 300 /* (X) Enable broadcast reception */
+#define MIPX_NORCVBCAST I_MIPX | 301 /* (X) Disable broadcast reception */
+#define MIPX_ADAPTERNUM I_MIPX | 302 /* Get maximum adapter number */
+#define MIPX_NOTIFYCARDINFO I_MIPX | 303 /* Pend until card info changes */
+#define MIPX_LOCALTARGET I_MIPX | 304 /* Get local target for address */
+#define MIPX_NETWORKINFO I_MIPX | 305 /* Return info about remote net */
+#define MIPX_ZEROSOCKET I_MIPX | 306 /* Use 0 as source socket on sends */
+
+/** Ioctls for SPX **/
+
+#define I_MSPX (('S' << 24) | ('P' << 16) | ('P' << 8))
+#define MSPX_SETADDR I_MSPX | 0 /* Set the network address */
+#define MSPX_SETPKTSIZE I_MSPX | 1 /* Set the packet size per card */
+#define MSPX_SETDATASTREAM I_MSPX | 2 /* Set datastream type */
+
+/** Added for NT port **/
+
+#define MSPX_SETASLISTEN I_MSPX | 100 /* Set as a listen socket */
+#define MSPX_GETSTATUS I_MSPX | 101 /* Get running status */
+#define MSPX_GETQUEUEPTR I_MSPX | 102 /* Get ptr to the streams queue */
+#define MSPX_SETDATAACK I_MSPX | 103 /* Set DATA ACK option */
+#define MSPX_NODATAACK I_MSPX | 104 /* Turn off DATA ACK option */
+#define MSPX_SETMAXPKTSOCK I_MSPX | 105 /* Set the packet size per socket */
+#define MSPX_SETWINDOWCARD I_MSPX | 106 /* Set window size for card */
+#define MSPX_SETWINDOWSOCK I_MSPX | 107 /* Set window size for 1 socket */
+#define MSPX_SENDHEADER I_MSPX | 108 /* Send header with data */
+#define MSPX_NOSENDHEADER I_MSPX | 109 /* Don't send header with data */
+#define MSPX_GETPKTSIZE I_MSPX | 110 /* Get the packet size per card */
+#define MSPX_SETCONNCNT I_MSPX | 111 /* Set the conn req count */
+#define MSPX_SETCONNTO I_MSPX | 112 /* Set the conn req timeout */
+#define MSPX_SETALIVECNT I_MSPX | 113 /* Set the keepalive count */
+#define MSPX_SETALIVETO I_MSPX | 114 /* Set the keepalive timeout */
+#define MSPX_SETALWAYSEOM I_MSPX | 115 /* Turn on always EOM flag */
+#define MSPX_NOALWAYSEOM I_MSPX | 116 /* Turn off always EOM flag */
diff --git a/private/ntos/tdi/isnp/inc/isn.h b/private/ntos/tdi/isnp/inc/isn.h
new file mode 100644
index 000000000..7b7e23601
--- /dev/null
+++ b/private/ntos/tdi/isnp/inc/isn.h
@@ -0,0 +1,41 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ isn.h
+
+Abstract:
+
+ Private include file for the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+
diff --git a/private/ntos/tdi/isnp/ipx/action.c b/private/ntos/tdi/isnp/ipx/action.c
new file mode 100644
index 000000000..807391cae
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/action.c
@@ -0,0 +1,1802 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiAction
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#include <packon.h>
+
+typedef struct _GET_PKT_SIZE {
+ ULONG Unknown;
+ ULONG MaxDatagramSize;
+} GET_PKT_SIZE, *PGET_PKT_SIZE;
+
+
+//
+// These structures are used to set and query information
+// about our source routing table.
+//
+
+typedef struct _SR_GET_PARAMETERS {
+ ULONG BoardNumber; // 0-based
+ ULONG SrDefault; // 0 = single route, 1 = all routes
+ ULONG SrBroadcast;
+ ULONG SrMulticast;
+} SR_GET_PARAMETERS, *PSR_GET_PARAMETERS;
+
+typedef struct _SR_SET_PARAMETER {
+ ULONG BoardNumber; // 0-based
+ ULONG Parameter; // 0 = single route, 1 = all routes
+} SR_SET_PARAMETER, *PSR_SET_PARAMETER;
+
+typedef struct _SR_SET_REMOVE {
+ ULONG BoardNumber; // 0-based
+ UCHAR MacAddress[6]; // remote to drop routing for
+} SR_SET_REMOVE, *PSR_SET_REMOVE;
+
+typedef struct _SR_SET_CLEAR {
+ ULONG BoardNumber; // 0-based
+} SR_SET_CLEAR, *PSR_SET_CLEAR;
+
+#include <packoff.h>
+
+typedef struct _ISN_ACTION_GET_DETAILS {
+ USHORT NicId; // passed by caller, returns count if it is 0
+ BOOLEAN BindingSet; // returns TRUE if in a set
+ UCHAR Type; // 1 = lan, 2 = up wan, 3 = down wan
+ ULONG FrameType; // returns 0 through 3
+ ULONG NetworkNumber; // returns virtual net if NicId is 0
+ UCHAR Node[6]; // adapter MAC address
+ WCHAR AdapterName[64]; // terminated with Unicode NULL
+} ISN_ACTION_GET_DETAILS, *PISN_ACTION_GET_DETAILS;
+
+
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ Device - The device for the operation.
+
+ Request - Describes the action request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ union {
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PISN_ACTION_GET_NETWORK_INFO GetNetworkInfo;
+ PISN_ACTION_GET_DETAILS GetDetails;
+ PSR_GET_PARAMETERS GetSrParameters;
+ PSR_SET_PARAMETER SetSrParameter;
+ PSR_SET_REMOVE SetSrRemove;
+ PSR_SET_CLEAR SetSrClear;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PGET_PKT_SIZE GetPktSize;
+ PIPX_NETNUM_DATA IpxNetnumData;
+ } u; // BUGBUG: Make these unaligned??
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNWLINK_ACTION NwlinkAction;
+ ULONG Segment;
+ ULONG AdapterNum;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ IPX_DEBUG (ACTION, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ IPX_DEBUG (ACTION, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ //DbgPrint("NwlinkAction->Option is (%x)\n", 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 MIPX_SETSENDPTYPE:
+
+ //
+ // IPX_PTYPE: Data is a single byte packet type.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETSENDPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->DefaultPacketType = NwlinkAction->Data[0];
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_FILTERPTYPE:
+
+ //
+ // IPX_FILTERPTYPE: Data is a single byte to filter on.
+ //
+
+ if (DataLength >= 1) {
+ IPX_DEBUG (ACTION, ("%lx: MIPX_FILTERPTYPE %x\n", AddressFile, NwlinkAction->Data[0]));
+ AddressFile->FilteredType = NwlinkAction->Data[0];
+ AddressFile->FilterOnPacketType = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_NOFILTERPTYPE:
+
+ //
+ // IPX_STOPFILTERPTYPE.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOFILTERPTYPE\n", AddressFile));
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ReceiveIpxHeader || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (TRUE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDADDROPT:
+
+ //
+ // IPX_EXTENDED_ADDRESS (FALSE).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDADDROPT\n", AddressFile));
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ReceiveFlagsAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SETRCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SETRCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NORCVFLAGS:
+
+ //
+ // No sockopt yet.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVFLAGS\n", AddressFile));
+ AddressFile->ReceiveFlagsAddressing = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveIpxHeader ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_SENDHEADER:
+
+ //
+ // IPX_RECVHDR (TRUE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_SENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ break;
+
+ case MIPX_NOSENDHEADER:
+
+ //
+ // IPX_RECVHDR (FALSE);
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOSENDHEADER\n", AddressFile));
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->SpecialReceiveProcessing = (BOOLEAN)
+ (AddressFile->ExtendedAddressing || AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->FilterOnPacketType || AddressFile->IsSapSocket);
+ break;
+
+ case MIPX_RCVBCAST:
+
+ //
+ // Broadcast reception enabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_RCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = TRUE;
+ IpxAddBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_NORCVBCAST:
+
+ //
+ // Broadcast reception disabled.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NORCVBCAST\n", AddressFile));
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (AddressFile->EnableBroadcast) {
+
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETPKTSIZE:
+
+ //
+ // IPX_MAXSIZE.
+ //
+ // BUGBUG: Figure out what the first length is for.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETPKTSIZE\n", AddressFile));
+ if (DataLength >= sizeof(GET_PKT_SIZE)) {
+ u.GetPktSize = (PGET_PKT_SIZE)(NwlinkAction->Data);
+ u.GetPktSize->Unknown = 0;
+ u.GetPktSize->MaxDatagramSize = Device->Information.MaxDatagramSize;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = Device->SapNicCount;
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_ADAPTERNUM2:
+
+ //
+ // IPX_MAX_ADAPTER_NUM.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ADAPTERNUM2\n", AddressFile));
+ if (DataLength >= sizeof(ULONG)) {
+ *(UNALIGNED ULONG *)(NwlinkAction->Data) = MIN (Device->MaxBindings, Device->ValidBindings);
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case MIPX_GETCARDINFO:
+ case MIPX_GETCARDINFO2:
+
+ //
+ // GETCARDINFO is IPX_ADDRESS.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_GETCARDINFO (%d)\n",
+ AddressFile, *(UNALIGNED UINT *)NwlinkAction->Data));
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if (((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) ||
+ ((NwlinkAction->Option == MIPX_GETCARDINFO2) && (AdapterNum <= (ULONG) MIN (Device->MaxBindings, Device->ValidBindings)))) {
+
+#ifdef _PNP_POWER
+// Get lock
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(Device, AdapterNum);
+#else
+ Binding = Device->Bindings[AdapterNum];
+#endif
+ if (Binding == NULL) {
+
+ //
+ // This should be a binding in the WAN range
+ // of an adapter which is currently not
+ // allocated. We scan back to the previous
+ // non-NULL binding, which should be on the
+ // same adapter, and return a down line with
+ // the same characteristics as that binding.
+ //
+
+ UINT i = AdapterNum;
+
+ do {
+ --i;
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ } while (Binding == NULL);
+
+ CTEAssert (Binding->Adapter->MacInfo.MediumAsync);
+ CTEAssert (i >= Binding->Adapter->FirstWanNicId);
+ CTEAssert (AdapterNum <= Binding->Adapter->LastWanNicId);
+
+ u.IpxAddressData->status = FALSE;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+
+ } else {
+
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Device->WanGlobalNetworkNumber)) {
+
+ //
+ // In this case we make it look like one big wan
+ // net, so the line is "up" or "down" depending
+ // on whether we have given him the first indication
+ // or not.
+ //
+
+ u.IpxAddressData->status = Device->GlobalNetworkIndicated;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Device->GlobalWanNetwork;
+
+ } else {
+
+ u.IpxAddressData->status = Binding->LineUp;
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ }
+
+ }
+
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+
+ Adapter = Binding->Adapter;
+ u.IpxAddressData->wan = Adapter->MacInfo.MediumAsync;
+ u.IpxAddressData->maxpkt =
+ (NwlinkAction->Option == MIPX_GETCARDINFO) ?
+ Binding->AnnouncedMaxDatagramSize :
+ Binding->RealMaxDatagramSize;
+ u.IpxAddressData->linkspeed = Binding->MediumSpeed;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ } else {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ } else {
+#if 1
+ //
+ // Support the old format query for now.
+ //
+
+ typedef struct _IPX_OLD_ADDRESS_DATA {
+ UINT adapternum;
+ UCHAR netnum[4];
+ UCHAR nodenum[6];
+ } IPX_OLD_ADDRESS_DATA, *PIPX_OLD_ADDRESS_DATA;
+
+ if (DataLength >= sizeof(IPX_OLD_ADDRESS_DATA)) {
+ u.IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+ AdapterNum = u.IpxAddressData->adapternum+1;
+
+ if ((AdapterNum >= 1) && (AdapterNum <= Device->SapNicCount)) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, AdapterNum)) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[AdapterNum]) {
+ *(UNALIGNED ULONG *)u.IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(u.IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+#else
+ Status = STATUS_BUFFER_TOO_SMALL;
+#endif
+ }
+ break;
+
+ case MIPX_NOTIFYCARDINFO:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_NOTIFYCARDINFO (%lx)\n", AddressFile, Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+ if (DataLength >= sizeof(IPX_ADDRESS_DATA)) {
+ InsertTailList(
+ &Device->AddressNotifyQueue,
+ REQUEST_LINKAGE(Request)
+ );
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->AddressNotifyQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_LINECHANGE:
+
+ //
+ // IPX_ADDRESS_NOTIFY.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_LINECHANGE (%lx)\n", Request));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // If the device is open and there is room in the
+ // buffer for the data, insert it in our queue.
+ // It will be completed when a change happens or
+ // the driver is unloaded.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ InsertTailList(
+ &Device->LineChangeQueue,
+ REQUEST_LINKAGE(Request)
+ );
+
+ IoSetCancelRoutine (Request, IpxCancelAction);
+ if (Request->Cancel) {
+ (VOID)RemoveTailList (&Device->LineChangeQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ Status = STATUS_CANCELLED;
+ } else {
+ IpxReferenceDevice (Device, DREF_LINE_CHANGE);
+ Status = STATUS_PENDING;
+ }
+ } else {
+ Status = STATUS_DEVICE_NOT_READY;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ break;
+
+ case MIPX_GETNETINFO_NR:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // A query on network 0 means that the caller wants
+ // information about our directly attached net.
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ //
+ // The tick count is the number of 1/18.21 second ticks
+ // it takes to deliver a 576-byte packet. Our link speed
+ // is in 100 bit-per-second units. We calculate it as
+ // follows (LS is the LinkSpeed):
+ //
+ // 576 bytes 8 bits 1 second 1821 ticks
+ // * ------ * ------------- * ----------
+ // 1 byte LS * 100 bits 100 seconds
+ //
+ // which becomes 839 / LinkSpeed -- we add LinkSpeed
+ // to the top to round up.
+ //
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+
+#ifdef _PNP_POWER
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ //
+ // To maintain the lock order: BindAccessLock > RIP table
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+#else
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO_NR failed net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+ }
+
+ break;
+
+ case MIPX_RERIPNETNUM:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId]) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_RERIPNETNUM queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_GETNETINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network (this is called by sockets apps).
+ //
+
+ if (DataLength < sizeof(IPX_NETNUM_DATA)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.IpxNetnumData = (PIPX_NETNUM_DATA)(NwlinkAction->Data);
+
+ //
+ // BUGBUG: Allow net 0 queries??
+ //
+
+ if (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum == 0) {
+
+ if (Device->LinkSpeed == 0) {
+ u.IpxNetnumData->netdelay = 16;
+ } else {
+ u.IpxNetnumData->netdelay = (USHORT)((839 + Device->LinkSpeed) /
+ (Device->LinkSpeed));
+ }
+ u.IpxNetnumData->hopcount = 0;
+ u.IpxNetnumData->cardnum = 0;
+ RtlMoveMemory (u.IpxNetnumData->router, Device->SourceAddress.NodeAddress, 6);
+
+ } else {
+
+ Segment = RipGetSegment(u.IpxNetnumData->netnum);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(MIN (Device->MaxBindings, Binding->MasterBinding->NicId) - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, u.IpxNetnumData->netnum);
+
+ if ((RouteEntry != NULL) &&
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+
+ u.IpxNetnumData->hopcount = RouteEntry->HopCount;
+ u.IpxNetnumData->netdelay = RouteEntry->TickCount;
+
+ if (Binding->BindingSetMember) {
+ u.IpxNetnumData->cardnum = (INT)(Binding->MasterBinding->NicId - 1);
+ } else {
+ u.IpxNetnumData->cardnum = (INT)(RouteEntry->NicId - 1);
+ }
+ RtlMoveMemory (u.IpxNetnumData->router, RouteEntry->NextRouter, 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (*(UNALIGNED ULONG *)u.IpxNetnumData->netnum, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.IpxNetnumData;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingReripNetnum,
+ REQUEST_LINKAGE(Request));
+
+ IPX_DEBUG (ACTION, ("MIPX_GETNETINFO queued net %lx\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)(u.IpxNetnumData->netnum))));
+
+ }
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+
+ break;
+
+ case MIPX_SENDPTYPE:
+ case MIPX_NOSENDPTYPE:
+
+ //
+ // For the moment just use OptionsLength >= 1 to indicate
+ // that the send options include the packet type.
+ //
+ // BUGBUG: Do we need to worry about card num being there?
+ //
+
+#if 0
+ IPX_DEBUG (ACTION, ("%lx: MIPS_%sSENDPTYPE\n", AddressFile,
+ NwlinkAction->Option == MIPX_SENDPTYPE ? "" : "NO"));
+#endif
+ break;
+
+ case MIPX_ZEROSOCKET:
+
+ //
+ // Sends from this address should be from socket 0;
+ // This is done the simple way by just putting the
+ // information in the address itself, instead of
+ // making it per address file (this is OK since
+ // this call is not exposed through winsock).
+ //
+
+ IPX_DEBUG (ACTION, ("%lx: MIPX_ZEROSOCKET\n", AddressFile));
+ AddressFile->Address->SendSourceSocket = 0;
+ AddressFile->Address->LocalAddress.Socket = 0;
+ break;
+
+
+ //
+ // This next batch are the source routing options. They
+ // are submitted by the IPXROUTE program.
+ //
+ // BUGBUG: Do we expose all binding set members to this?
+
+ case MIPX_SRGETPARMS:
+
+ if (DataLength >= sizeof(SR_GET_PARAMETERS)) {
+ u.GetSrParameters = (PSR_GET_PARAMETERS)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.GetSrParameters->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.GetSrParameters->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRGETPARMS (%d)\n", u.GetSrParameters->BoardNumber+1));
+ u.GetSrParameters->SrDefault = (Binding->AllRouteDirected) ? 1 : 0;
+ u.GetSrParameters->SrBroadcast = (Binding->AllRouteBroadcast) ? 1 : 0;
+ u.GetSrParameters->SrMulticast = (Binding->AllRouteMulticast) ? 1 : 0;
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRDEF:
+ case MIPX_SRBCAST:
+ case MIPX_SRMULTI:
+
+ if (DataLength >= sizeof(SR_SET_PARAMETER)) {
+ u.SetSrParameter = (PSR_SET_PARAMETER)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrParameter->BoardNumber+1)) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrParameter->BoardNumber+1]) {
+ if (NwlinkAction->Option == MIPX_SRDEF) {
+
+ //
+ // BUGBUG: The compiler generates strange
+ // code which always makes this path be
+ // taken????
+ //
+
+ IPX_DEBUG (ACTION, ("MIPX_SRDEF %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteDirected = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else if (NwlinkAction->Option == MIPX_SRBCAST) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRBCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteBroadcast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ } else {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRMCAST %d (%d)\n",
+ u.SetSrParameter->Parameter, u.SetSrParameter->BoardNumber+1));
+ Binding->AllRouteMulticast = (BOOLEAN)u.SetSrParameter->Parameter;
+
+ }
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRREMOVE:
+
+ if (DataLength >= sizeof(SR_SET_REMOVE)) {
+ u.SetSrRemove = (PSR_SET_REMOVE)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrRemove->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrRemove->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRREMOVE %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x (%d)\n",
+ u.SetSrRemove->MacAddress[0],
+ u.SetSrRemove->MacAddress[1],
+ u.SetSrRemove->MacAddress[2],
+ u.SetSrRemove->MacAddress[3],
+ u.SetSrRemove->MacAddress[4],
+ u.SetSrRemove->MacAddress[5],
+ u.SetSrRemove->BoardNumber+1));
+ MacSourceRoutingRemove (Binding, u.SetSrRemove->MacAddress);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case MIPX_SRCLEAR:
+
+ if (DataLength >= sizeof(SR_SET_CLEAR)) {
+ u.SetSrClear = (PSR_SET_CLEAR)(NwlinkAction->Data);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (Binding = NIC_ID_TO_BINDING(Device, u.SetSrClear->BoardNumber+1)) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (Binding = Device->Bindings[u.SetSrClear->BoardNumber+1]) {
+
+ IPX_DEBUG (ACTION, ("MIPX_SRCLEAR (%d)\n", u.SetSrClear->BoardNumber+1));
+ MacSourceRoutingClear (Binding);
+
+ } else {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+#endif
+ } else {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+
+ //
+ // These are new for ISN (not supported in NWLINK).
+ //
+
+ case MIPX_LOCALTARGET:
+
+ //
+ // A request for the local target for an IPX address.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_LOCAL_TARGET)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)(NwlinkAction->Data);
+ Segment = RipGetSegment((PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See if this route is local.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetLocalTarget->IpxAddress.NetworkAddress);
+
+ if ((RouteEntry != NULL) &&
+ (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY)) {
+
+ //
+ // This is a local net, to send to it you just use
+ // the appropriate NIC ID and the real MAC address.
+ //
+
+ if ((RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) == 0) {
+
+ //
+ // It's the virtual net, send via the first card.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, 1);
+#else
+ u.GetLocalTarget->LocalTarget.NicId = 1;
+#endif
+
+ } else {
+
+#ifdef _PNP_POWER
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+
+ } else {
+
+ FILL_LOCAL_TARGET(&u.GetLocalTarget->LocalTarget, RouteEntry->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[RouteEntry->NicId];
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ u.GetLocalTarget->LocalTarget.NicId = Binding->NicId;
+ } else {
+
+ u.GetLocalTarget->LocalTarget.NicId = RouteEntry->NicId;
+
+ }
+#endif
+
+ }
+
+ RtlCopyMemory(
+ u.GetLocalTarget->LocalTarget.MacAddress,
+ u.GetLocalTarget->IpxAddress.NodeAddress,
+ 6);
+
+ } else {
+
+ //
+ // This call will return STATUS_PENDING if we successfully
+ // queue a RIP request for the packet.
+ //
+
+ Status = RipQueueRequest (u.GetLocalTarget->IpxAddress.NetworkAddress, RIP_REQUEST);
+ CTEAssert (Status != STATUS_SUCCESS);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this request for completion when the RIP response
+ // arrives. We save the network in the information
+ // field for easier retrieval later.
+ //
+
+ REQUEST_INFORMATION(Request) = (ULONG)u.GetLocalTarget;
+ InsertTailList(
+ &Device->Segments[Segment].WaitingLocalTarget,
+ REQUEST_LINKAGE(Request));
+
+ }
+
+#ifdef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+ }
+#ifndef _PNP_POWER
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#endif
+
+
+ break;
+
+ case MIPX_NETWORKINFO:
+
+ //
+ // A request for network information about the immediate
+ // route to a network.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_NETWORK_INFO)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetNetworkInfo = (PISN_ACTION_GET_NETWORK_INFO)(NwlinkAction->Data);
+
+ if (u.GetNetworkInfo->Network == 0) {
+
+ //
+ // This is information about the local card.
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Device->LinkSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Device->Information.MaxDatagramSize;
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&u.GetNetworkInfo->Network);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // See which net card this is routed on.
+ //
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&u.GetNetworkInfo->Network);
+
+ if ((RouteEntry != NULL) &&
+#ifdef _PNP_POWER
+ (Binding = NIC_ID_TO_BINDING(Device, RouteEntry->NicId))) {
+#else
+ (Binding = Device->Bindings[RouteEntry->NicId])) {
+#endif
+
+ //
+ // Our medium speed is stored in 100 bps, we
+ // convert to bytes/sec by multiplying by 12
+ // (should really be 100/8 = 12.5).
+ //
+
+ u.GetNetworkInfo->LinkSpeed = Binding->MediumSpeed * 12;
+ u.GetNetworkInfo->MaximumPacketSize = Binding->AnnouncedMaxDatagramSize;
+
+ } else {
+
+ //
+ // Fail the call, we don't have a route yet.
+ // BUGBUG: This requires that a packet has been
+ // sent to this net already; nwrdr says this is
+ // OK, they will send their connect request
+ // before they query. On the server it should
+ // have RIP running so all nets should be in
+ // the database.
+ //
+
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ break;
+
+ case MIPX_CONFIG:
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(ISN_ACTION_GET_DETAILS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetDetails = (PISN_ACTION_GET_DETAILS)(NwlinkAction->Data);
+
+ if (u.GetDetails->NicId == 0) {
+
+ //
+ // This is information about the local card. We also
+ // tell him the total number of bindings in NicId.
+ //
+
+ u.GetDetails->NetworkNumber = Device->VirtualNetworkNumber;
+ u.GetDetails->NicId = (USHORT)MIN (Device->MaxBindings, Device->ValidBindings);
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, u.GetDetails->NicId);
+#else
+ Binding = Device->Bindings[u.GetDetails->NicId];
+#endif
+
+ if ((Binding != NULL) &&
+ (u.GetDetails->NicId <= MIN (Device->MaxBindings, Device->ValidBindings))) {
+
+ ULONG StringLoc;
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ u.GetDetails->NetworkNumber = Binding->LocalAddress.NetworkAddress;
+ if (Binding->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) {
+ u.GetDetails->FrameType = ISN_FRAME_TYPE_ARCNET;
+ } else {
+ u.GetDetails->FrameType = Binding->FrameType;
+ }
+ u.GetDetails->BindingSet = Binding->BindingSetMember;
+ if (Binding->Adapter->MacInfo.MediumAsync) {
+ if (Binding->LineUp) {
+ u.GetDetails->Type = 2;
+ } else {
+ u.GetDetails->Type = 3;
+ }
+ } else {
+ u.GetDetails->Type = 1;
+ }
+
+ RtlCopyMemory (u.GetDetails->Node, Binding->LocalMacAddress.Address, 6);
+
+ //
+ // Copy the adapter name, including the final NULL.
+ //
+
+ StringLoc = (Binding->Adapter->AdapterNameLength / sizeof(WCHAR)) - 2;
+ while (Binding->Adapter->AdapterName[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(
+ u.GetDetails->AdapterName,
+ &Binding->Adapter->AdapterName[StringLoc+1],
+ Binding->Adapter->AdapterNameLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ } else {
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+ }
+
+ break;
+
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ IPX_DEBUG (ACTION, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* IpxTdiAction */
+
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request = (PREQUEST)Irp;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ UINT IOCTLType;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Find the request on the address notify queue.
+ //
+
+ Found = FALSE;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (p = Device->AddressNotifyQueue.Flink;
+ p != &Device->AddressNotifyQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_NOTIFYCARDINFO;
+ break;
+ }
+ }
+
+ if (!Found) {
+ for (p = Device->LineChangeQueue.Flink;
+ p != &Device->LineChangeQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ IOCTLType = MIPX_LINECHANGE;
+ break;
+ }
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+ if (IOCTLType == MIPX_NOTIFYCARDINFO) {
+ IPX_DEBUG(ACTION, ("Cancelled action NOTIFYCARDINFO %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ } else {
+ IPX_DEBUG(ACTION, ("Cancelled action LINECHANGE %lx\n", Request));
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+ }
+
+ }
+#if DBG
+ else {
+ IPX_DEBUG(ACTION, ("Cancelled action orphan %lx\n", Request));
+ }
+#endif
+
+} /* IpxCancelAction */
+
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine aborts any line change IRPs posted by the
+ control channel with the specified open context. It is
+ called when a control channel is being shut down.
+
+Arguments:
+
+ ControlChannelContext - The context assigned to the control
+ channel when it was opened.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ CTELockHandle LockHandle;
+ LIST_ENTRY AbortList;
+ PLIST_ENTRY p;
+ PREQUEST Request;
+ KIRQL irql;
+
+
+ InitializeListHead (&AbortList);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ p = Device->LineChangeQueue.Flink;
+
+ while (p != &Device->LineChangeQueue) {
+ LARGE_INTEGER ControlChId;
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ CCID_FROM_REQUEST(ControlChId, Request);
+
+ p = p->Flink;
+
+ if (ControlChId.QuadPart == ((PLARGE_INTEGER)ControlChannelContext)->QuadPart) {
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ InsertTailList (&AbortList, REQUEST_LINKAGE(Request));
+ }
+ }
+
+ while (!IsListEmpty (&AbortList)) {
+
+ p = RemoveHeadList (&AbortList);
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IPX_DEBUG(ACTION, ("Aborting line change %lx\n", Request));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Device->Lock, &LockHandle);
+ }
+
+ CTEFreeLock(&Device->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+} /* IpxAbortLineChanges */
+
diff --git a/private/ntos/tdi/isnp/ipx/adapter.c b/private/ntos/tdi/isnp/ipx/adapter.c
new file mode 100644
index 000000000..479570e48
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/adapter.c
@@ -0,0 +1,636 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ adapter.c
+
+Abstract:
+
+ This module contains code which implements the ADAPTER object.
+ Routines are provided to reference, and dereference transport
+ adapter objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// These are init only until binding is really dynamic.
+//
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateAdapter)
+#endif
+#endif _PNP_POWER
+
+
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Binding->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Binding->ReferenceCount);
+
+} /* IpxRefBinding */
+
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+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:
+
+ Binding - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Binding->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyBinding (Binding);
+ }
+
+} /* IpxDerefBinding */
+
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+ AdapterName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PADAPTER Adapter;
+#if 0
+ UINT i, j;
+#endif
+
+ Adapter = (PADAPTER)IpxAllocateMemory (sizeof(ADAPTER) + AdapterName->Length + sizeof(WCHAR), MEMORY_ADAPTER, "Adapter");
+
+#ifdef _PNP_POWER
+ if (Adapter == NULL) {
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx failed\n", AdapterName));
+ }
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %lx %lx succeeded\n", Adapter, AdapterName));
+#else
+ if (Adapter == NULL) {
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws failed\n", AdapterName->Buffer));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Create adapter %ws succeeded\n", AdapterName->Buffer));
+#endif
+
+ RtlZeroMemory(Adapter, sizeof(ADAPTER));
+
+ //
+ // Copy over the adapter name.
+ //
+
+ Adapter->AdapterNameLength = AdapterName->Length + sizeof(WCHAR);
+ Adapter->AdapterName = (PWCHAR)(Adapter+1);
+ RtlCopyMemory(
+ Adapter->AdapterName,
+ AdapterName->Buffer,
+ AdapterName->Length);
+ Adapter->AdapterName[AdapterName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+
+#if DBG
+ RtlCopyMemory(Adapter->Signature1, "IAD1", 4);
+#endif
+
+ Adapter->Type = IPX_ADAPTER_SIGNATURE;
+ Adapter->Size = sizeof(ADAPTER);
+
+ CTEInitLock (&Adapter->Lock);
+
+ InitializeListHead (&Adapter->RequestCompletionQueue);
+
+ InitializeListHead (&Adapter->ReceiveBufferPoolList);
+
+ ExInitializeSListHead (&Adapter->ReceiveBufferList);
+
+ Adapter->Device = Device;
+ Adapter->DeviceLock = &Device->Lock;
+ IpxReferenceDevice (Device, DREF_ADAPTER);
+
+#if 0
+ Adapter->ReceiveBufferPool.Next = NULL;
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Adapter->Bindings[i] = NULL;
+ }
+ Adapter->BindingCount = 0;
+
+ for (i = 0; i < IDENTIFIER_TOTAL; i++) {
+ for (j = 0; j < SOURCE_ROUTE_HASH_SIZE; j++) {
+ Adapter->SourceRoutingHeads[i][j] = (PSOURCE_ROUTE)NULL;
+ }
+ }
+#endif
+
+ //
+ // BUGBUG: For the moment, we have to do the source
+ // routing operation on any type where broadcast
+ // may not be used for discovery -- improve this
+ // hopefully.
+ //
+
+ Adapter->SourceRoutingEmpty[IDENTIFIER_RIP] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_IPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_SPX] = FALSE;
+ Adapter->SourceRoutingEmpty[IDENTIFIER_NB] = TRUE;
+
+#ifdef _PNP_POWER
+ //
+ // Lock here? [BUGBUGZZ]
+ //
+ Adapter->ReferenceCount = 1;
+#endif
+
+ *AdapterPtr = Adapter;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateAdapter */
+
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Adapter - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Database, Hash;
+ PSOURCE_ROUTE Current;
+ ULONG ReceiveBufferPoolSize;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ PLIST_ENTRY p;
+ UINT i;
+
+ IPX_DEBUG (ADAPTER, ("Destroy adapter %lx\n", Adapter));
+
+ //
+ // Free any receive buffer pools this adapter has.
+ //
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (Adapter->MaxReceivePacketSize * Device->InitReceiveBuffers);
+
+ while (!IsListEmpty (&Adapter->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Adapter->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, IPX_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ IpxDeinitializeReceiveBuffer (Adapter, ReceiveBuffer, Adapter->MaxReceivePacketSize);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ IpxFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+
+ //
+ // Free all the source routing information for this adapter.
+ //
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+ }
+ }
+ }
+
+ IpxDereferenceDevice (Adapter->Device, DREF_ADAPTER);
+ IpxFreeMemory (Adapter, sizeof(ADAPTER) + Adapter->AdapterNameLength, MEMORY_ADAPTER, "Adapter");
+
+} /* IpxDestroyAdapter */
+
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a binding structure.
+
+Arguments:
+
+ Device - The device.
+
+ ConfigBinding - Information about this binding. If this is
+ NULL then this is a WAN binding and all the relevant
+ information will be filled in by the caller.
+
+ NetworkNumberIndex - The index in the frame type array for
+ ConfigBinding indicating which frame type this binding is for.
+ Not used if ConfigBinding is not provided.
+
+ AdapterName - Used for error logging.
+
+ BindingPtr - Returns the allocated binding structure.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ PBINDING Binding;
+#ifdef _PNP_POWER
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBinding;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBinding(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+GotBinding:
+
+ Binding = CONTAINING_RECORD (s, BINDING, PoolLinkage);
+
+#else
+ Binding = (PBINDING)IpxAllocateMemory (sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+
+ //
+ // We can't vsprintf a %ws at DPC level, so we check for
+ // that. Only WAN bindings will be created then.
+ //
+
+ if (Binding == NULL) {
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws failed\n", AdapterName));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN failed\n"));
+ }
+#endif
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+#endif
+
+#if DBG
+ if (KeGetCurrentIrql() == 0) {
+ IPX_DEBUG (ADAPTER, ("Create binding %ws succeeded, %lx\n", AdapterName, Binding));
+ } else {
+ IPX_DEBUG (ADAPTER, ("Create binding WAN succeeded\n"));
+ }
+#endif
+
+ RtlZeroMemory(Binding, sizeof(BINDING));
+
+ //
+ // Initialize the reference count.
+ //
+
+ Binding->ReferenceCount = 1;
+#if DBG
+ Binding->RefTypes[BREF_BOUND] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Binding->Signature1, "IBI1", 4);
+#endif
+
+ Binding->Type = IPX_BINDING_SIGNATURE;
+ Binding->Size = sizeof(BINDING);
+
+ Binding->Device = Device;
+ Binding->DeviceLock = &Device->Lock;
+
+ if (ConfigBinding != NULL) {
+
+ ULONG Temp = ConfigBinding->NetworkNumber[NetworkNumberIndex];
+ Binding->ConfiguredNetworkNumber = REORDER_ULONG (Temp);
+
+ Binding->AutoDetect = ConfigBinding->AutoDetect[NetworkNumberIndex];
+ Binding->DefaultAutoDetect = ConfigBinding->DefaultAutoDetect[NetworkNumberIndex];
+
+ Binding->AllRouteDirected = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_DEF];
+ Binding->AllRouteBroadcast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_BC];
+ Binding->AllRouteMulticast = (BOOLEAN)ConfigBinding->Parameters[BINDING_ALL_ROUTE_MC];
+
+ }
+
+ Binding->ReceiveBroadcast = TRUE;
+#if 0
+ Binding->BindingSetMember = FALSE;
+ Binding->NextBinding = (PBINDING)NULL;
+ Binding->DialOutAsync = FALSE;
+#endif
+
+ //
+ // We set Binding->FrameType later, after we can map it based on the
+ // media type of the adapter we bind to.
+ //
+
+ *BindingPtr = Binding;
+
+ return STATUS_SUCCESS;
+
+} /* IpxCreateBinding */
+
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a binding structure.
+
+Arguments:
+
+ Binding - Pointer to a transport binding structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IPX_DEBUG (ADAPTER, ("Destroy binding %lx\n", Binding));
+
+#ifdef _PNP_POWER
+
+ IPX_PUSH_ENTRY_LIST(
+ &IpxDevice->BindingList,
+ &Binding->PoolLinkage,
+ &IpxDevice->SListsLock);
+#else
+ IpxFreeMemory (Binding, sizeof(BINDING), MEMORY_ADAPTER, "Binding");
+#endif
+
+} /* IpxDestroyBinding */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 bindings to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ UINT BindingNum;
+ PBINDING Binding;
+ CTELockHandle LockHandle;
+
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ BindingPool = (PIPX_BINDING_POOL)IpxAllocateMemory (BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ if (BindingPool == NULL) {
+ IPX_DEBUG (PNP, ("Could not allocate binding pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PNP, ("Initializing Binding pool %lx, %d bindings\n",
+ BindingPool, Device->InitBindings));
+
+ BindingPool->BindingCount = Device->InitBindings;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BindingNum = 0; BindingNum < BindingPool->BindingCount; BindingNum++) {
+
+ Binding = &BindingPool->Bindings[BindingNum];
+ IPX_PUSH_ENTRY_LIST (&Device->BindingList, &Binding->PoolLinkage, &Device->SListsLock);
+
+#ifdef IPX_TRACK_POOL
+ Binding->Pool = BindingPool;
+#endif
+ }
+
+ InsertTailList (&Device->BindingPoolList, &BindingPool->Linkage);
+
+ Device->AllocatedBindings += BindingPool->BindingCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBindingPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a binding from the device context's pool.
+ If there are no bindings in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated binding.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedBindings < Device->MaxPoolBindings) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBindingPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BindingList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBinding */
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/address.c b/private/ntos/tdi/isnp/ipx/address.c
new file mode 100644
index 000000000..1049bc8de
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/address.c
@@ -0,0 +1,1843 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ 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;
+
+} /* IpxParseTdiAddress */
+
+
+BOOLEAN
+IpxValidateTdiAddress(
+ 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)) {
+ IpxPrint0 ("IpxValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ IpxPrint0 ("IpxValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* IpxValidateTdiAddress */
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ 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.
+
+Arguments:
+
+ AddressBuffer - The buffer that will hold the address.
+
+ Network - The network number.
+
+ Node - The node address.
+
+ Socket - The socket.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TA_IPX_ADDRESS UNALIGNED * IpxAddress;
+
+ IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
+
+ IpxAddress->TAAddressCount = 1;
+ IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
+ IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
+ IpxAddress->Address[0].Address[0].NetworkAddress = Network;
+ IpxAddress->Address[0].Address[0].Socket = Socket;
+ RtlCopyMemory(IpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
+
+} /* IpxBuildTdiAddress */
+#endif
+
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the IPX transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TA_ADDRESS UNALIGNED *AddressName;
+ USHORT Socket;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ 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
+
+
+ //
+ // If we are a dedicated router, we cannot let addresses
+ // be opened.
+ //
+
+ if (Device->DedicatedRouter) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ IpxPrint1("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;
+ found = TRUE;
+ }
+ break;
+
+ } else {
+
+ AddressName = (PTA_ADDRESS)(AddressName->Address +
+ AddressName->AddressLength);
+
+ }
+
+ }
+
+ if (!found) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, request %lx has no IPX Address\n", Request));
+ return STATUS_NONEXISTENT_EA_ENTRY;
+ }
+
+ if (Socket == 0) {
+
+ Socket = IpxAssignSocket (Device);
+
+ if (Socket == 0) {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, no unique socket found\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ IPX_DEBUG (ADDRESS, ("OpenAddress, assigned socket %lx\n", REORDER_USHORT(Socket)));
+ }
+
+ } else {
+
+ IPX_DEBUG (ADDRESS, ("OpenAddress, socket %lx\n", REORDER_USHORT(Socket)));
+
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = IpxCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return status;
+ }
+
+ //
+ // We mark this socket specially.
+ //
+
+ if (Socket == SAP_SOCKET) {
+ AddressFile->IsSapSocket = TRUE;
+ AddressFile->SpecialReceiveProcessing = TRUE;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Address = IpxLookupAddress (Device, Socket);
+
+ if (Address == NULL) {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // This address doesn't exist. Create it.
+ // registering it.
+ //
+
+ Address = IpxCreateAddress (
+ Device,
+ Socket);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+
+ if (Device->State == DEVICE_STATE_STOPPING) {
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Request = Request;
+ AddressFile->Address = Address;
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+ InsertTailList (&Address->AddressFileDatabase, &AddressFile->Linkage);
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ AddressFile->Request = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ IpxDestroyAddressFile (AddressFile);
+
+ }
+
+ } else {
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IPX_DEBUG (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ AddressFile->Request = NULL;
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ IpxReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ status = STATUS_SUCCESS;
+
+ }
+ }
+
+ //
+ // Remove the reference from IpxLookupAddress.
+ //
+
+ IpxDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* IpxOpenAddress */
+
+
+USHORT
+IpxAssignSocket(
+ 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.
+
+--*/
+
+{
+ USHORT InitialSocket, CurrentSocket, AddressSocket;
+ ULONG CurrentHash;
+ BOOLEAN Conflict;
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ //
+ // Loop through all possible sockets, starting at
+ // Device->CurrentSocket, looking for a suitable one.
+ // Device->CurrentSocket rotates through the possible
+ // sockets to improve the chances of finding one
+ // quickly.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InitialSocket = Device->CurrentSocket;
+ Device->CurrentSocket = (USHORT)(Device->CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(Device->CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ Device->CurrentSocket = Device->SocketStart;
+ }
+
+ CurrentSocket = InitialSocket;
+
+ do {
+
+ //
+ // Scan all addresses; if we find one with a socket
+ // that conflicts with this one, we can't use it.
+ //
+ // NOTE: Device->Lock is acquired here.
+ //
+
+ Conflict = FALSE;
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+ AddressSocket = REORDER_USHORT(Address->Socket);
+
+ if ((AddressSocket + Device->SocketUniqueness > CurrentSocket) &&
+ (AddressSocket < CurrentSocket + Device->SocketUniqueness)) {
+ Conflict = TRUE;
+ break;
+ }
+ }
+
+ //
+ // If we've found a conflict, no need to check the other
+ // queues.
+ //
+
+ if (Conflict) {
+ break;
+ }
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // We intentionally free the lock here so that we
+ // never spend too much time with it held.
+ //
+
+ if (!Conflict) {
+
+ //
+ // We went through the address list without
+ // finding a conflict; use this socket.
+ //
+
+ return REORDER_USHORT(CurrentSocket);
+ }
+
+ CurrentSocket = (USHORT)(CurrentSocket + Device->SocketUniqueness);
+ if ((USHORT)(CurrentSocket+Device->SocketUniqueness) > Device->SocketEnd) {
+ CurrentSocket = Device->SocketStart;
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ } while (CurrentSocket != InitialSocket);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Could not find one to assign.
+ //
+
+ return (USHORT)0;
+
+} /* IpxAssignSocket */
+
+
+PADDRESS
+IpxCreateAddress(
+ 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.
+
+--*/
+
+{
+ PADDRESS Address;
+ PIPX_SEND_RESERVED SendReserved;
+ PIPX_RECEIVE_RESERVED ReceiveReserved;
+ NDIS_STATUS Status;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ Address = (PADDRESS)IpxAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address %lx failed\n", REORDER_USHORT(Socket)));
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address %lx (%lx)\n", Address, REORDER_USHORT(Socket)));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->SendPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail1;
+ }
+#endif
+
+ if (IpxInitializeSendPacket (Device, &Address->SendPacket, Address->SendPacketHeader) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail1:
+#endif
+ Address->SendPacketInUse = TRUE;
+ } else {
+ SendReserved = SEND_RESERVED(&Address->SendPacket);
+ SendReserved->Address = Address;
+ SendReserved->OwnedByAddress = TRUE;
+ Address->SendPacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+
+#if BACK_FILL
+ {
+ PIPX_SEND_RESERVED BackFillReserved;
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleSendPacket(Device, &Address->BackFillPacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail2;
+ }
+#endif
+ if (IpxInitializeBackFillPacket (Device, &Address->BackFillPacket, NULL) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail2:
+#endif
+ Address->BackFillPacketInUse = TRUE;
+ } else {
+ BackFillReserved = SEND_RESERVED(&Address->BackFillPacket);
+ BackFillReserved->Address = Address;
+ Address->BackFillPacketInUse = FALSE;
+ BackFillReserved->OwnedByAddress = TRUE;
+#ifdef IPX_TRACK_POOL
+ BackFillReserved->Pool = NULL;
+#endif
+ }
+ }
+#endif
+
+#ifndef IPX_OWN_PACKETS
+ IpxAllocateSingleReceivePacket(Device, &Address->ReceivePacket, &Status);
+ if (Status != NDIS_STATUS_SUCCESS) {
+ goto Fail3;
+ }
+#endif
+ if (IpxInitializeReceivePacket (Device, &Address->ReceivePacket) != STATUS_SUCCESS) {
+#ifndef IPX_OWN_PACKETS
+Fail3:
+#endif
+ Address->ReceivePacketInUse = TRUE;
+ } else {
+ ReceiveReserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+ ReceiveReserved->Address = Address;
+ ReceiveReserved->OwnedByAddress = TRUE;
+ Address->ReceivePacketInUse = FALSE;
+#ifdef IPX_TRACK_POOL
+ ReceiveReserved->Pool = NULL;
+#endif
+ }
+
+ Address->Type = IPX_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+ Address->Socket = Socket;
+ Address->SendSourceSocket = Socket;
+
+ //
+ // Save our local address for building datagrams quickly.
+ //
+
+ RtlCopyMemory (&Address->LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ Address->LocalAddress.Socket = Socket;
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+ InsertTailList (&Device->AddressDatabases[IPX_HASH_SOCKET(Socket)], &Address->Linkage);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* IpxCreateAddress */
+
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == IPX_ADDRESS_SIGNATURE) ) {
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (!Address->Stopping) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ IpxPrint1("IpxVerifyAddressFile: AF %lx exception\n", Address);
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* IpxVerifyAddressFile */
+
+
+VOID
+IpxDestroyAddress(
+ 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 IpxDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by IpxDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address %lx (%lx)\n", Address, REORDER_USHORT(Address->Socket)));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Address->Linkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ if (!Address->SendPacketInUse) {
+ IpxDeinitializeSendPacket (Device, &Address->SendPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->SendPacket);
+#endif
+ }
+
+ if (!Address->ReceivePacketInUse) {
+ IpxDeinitializeReceivePacket (Device, &Address->ReceivePacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleReceivePacket (Device, Address->ReceivePacket);
+#endif
+ }
+
+#if BACK_FILL
+ if (!Address->BackFillPacketInUse) {
+ IpxDeinitializeBackFillPacket (Device, &Address->BackFillPacket);
+#ifndef IPX_OWN_PACKETS
+ IpxFreeSingleSendPacket (Device, Address->BackFillPacket);
+#endif
+ }
+#endif
+ IpxFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* IpxDestroyAddress */
+
+
+#if DBG
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddress */
+
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ // ++Address->ReferenceCount;
+ (VOID)InterlockedIncrement(&Address->ReferenceCount);
+
+} /* IpxRefAddressLock */
+#endif
+
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->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.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddress */
+
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddress to remove it from the system. This routine can
+ only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &Address->ReferenceCount,
+ (ULONG)-1,
+ Address->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.DestroyAddressQueueItem,
+ IpxDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ IpxDestroyAddress(Address);
+#endif
+
+ }
+
+} /* IpxDerefAddressSync */
+
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)IpxAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ IPX_DEBUG (ADDRESS, ("Create address file failed\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ IPX_DEBUG (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = IPX_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+#if 0
+ AddressFile->SpecialReceiveProcessing = FALSE;
+ AddressFile->ExtendedAddressing = FALSE;
+ AddressFile->ReceiveIpxHeader = FALSE;
+ AddressFile->FilterOnPacketType = FALSE;
+ AddressFile->DefaultPacketType = 0;
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+#endif
+
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ AddressFile->ReceiveDatagramHandler = TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+
+ //
+ // [CH] Added these handlers for chained buffer receives
+ //
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ AddressFile->ChainedReceiveDatagramHandler = TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+
+ AddressFile->RegisteredErrorHandler = FALSE;
+ AddressFile->ErrorHandler = TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+
+ return AddressFile;
+
+} /* IpxCreateAddressFile */
+
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by IpxDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+
+ IPX_DEBUG (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle1);
+ Address->Stopping = TRUE;
+ if (Device->LastAddress == Address) {
+ Device->LastAddress = NULL;
+ }
+ CTEFreeLock (&Device->Lock, LockHandle1);
+
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ CTEFreeLock (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ //
+ // Now dereference the owning address.
+ //
+
+ IpxDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ IpxFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ IpxCompleteRequest (CloseRequest);
+ IpxFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxDestroyAddressFile */
+
+
+#if DBG
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFile */
+
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ //++AddressFile->ReferenceCount;
+ (VOID)InterlockedIncrement(&AddressFile->ReferenceCount);
+
+} /* IpxRefAddressFileLock */
+
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ 1,
+ AddressFile->AddressLock);
+
+} /* IpxRefAddressFileSync */
+
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // 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) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFile */
+
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ IpxDestroyAddressFile to remove it from the system. This routine
+ can only be called when we are synchronized (inside an IPX_SYNC_START/
+ IPX_SYNC_END pair, with a lock held, or in an indication).
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+
+ oldvalue = IPX_ADD_ULONG (
+ &AddressFile->ReferenceCount,
+ (ULONG)-1,
+ AddressFile->AddressLock);
+
+ //
+ // 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) {
+ IpxDestroyAddressFile (AddressFile);
+ }
+
+} /* IpxDerefAddressFileSync */
+#endif
+
+
+PADDRESS
+IpxLookupAddress(
+ 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.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ ULONG Hash = IPX_HASH_SOCKET (Socket);
+
+ p = Device->AddressDatabases[Hash].Flink;
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->Stopping) {
+ continue;
+ }
+
+ if (Address->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.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ }
+
+ }
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* IpxLookupAddress */
+
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PREQUEST Request;
+ PADDRESS Address = AddressFile->Address;
+ PLIST_ENTRY p;
+ KIRQL irql;
+
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ CTEFreeLock (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+ return STATUS_SUCCESS;
+ }
+
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!(IsListEmpty(&AddressFile->ReceiveDatagramQueue))) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IoAcquireCancelSpinLock( &irql );
+ CTEGetLock(&Address->Lock, &LockHandle);
+
+ }
+
+ CTEFreeLock(&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock( irql );
+
+} /* IpxStopAddressFile */
+
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If this address file had broadcasts enabled, turn it off.
+ //
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ if (AddressFile->EnableBroadcast) {
+ AddressFile->EnableBroadcast = FALSE;
+ IpxRemoveBroadcast (Device);
+ }
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* IpxCloseAddressFile */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/config.c b/private/ntos/tdi/isnp/ipx/config.c
new file mode 100644
index 000000000..f5d8aefbf
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.c
@@ -0,0 +1,1715 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN IPX module.
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 19-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+IpxGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetBindingValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxGetFrameType(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxGetConfiguration)
+#pragma alloc_text(INIT,IpxFreeConfiguration)
+
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxGetConfigValue)
+#pragma alloc_text(INIT,IpxGetBindingValue)
+#pragma alloc_text(INIT,IpxGetFrameType)
+#pragma alloc_text(INIT,IpxWriteDefaultAutoDetectType)
+#endif
+
+#pragma alloc_text(INIT,IpxAddBind)
+#pragma alloc_text(INIT,IpxAddExport)
+#pragma alloc_text(INIT,IpxReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG Ten = 10;
+ ULONG Fifteen = 15;
+ ULONG Fifty = 50;
+ ULONG DefaultSocketStart = 0x4000;
+ ULONG DefaultSocketEnd = 0x8000;
+ ULONG RipSegments = RIP_SEGMENTS;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"DedicatedRouter", &Zero } ,
+ { L"InitDatagrams", &Ten } ,
+ { L"MaxDatagrams", &Fifty } ,
+ { L"RipAgeTime", &Five } , // minutes
+ { L"RipCount", &Five } ,
+ { L"RipTimeout", &One } , // half-second
+ { L"RipUsageTime", &Fifteen } , // minutes
+ { L"SourceRouteUsageTime", &Ten } , // minutes
+ { L"SocketUniqueness", &Eight } ,
+ { L"SocketStart", &DefaultSocketStart } ,
+ { L"SocketEnd", &DefaultSocketEnd } ,
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"MaxMemoryUsage", &Zero } ,
+ { L"RipTableSize", &RipSegments } ,
+ { L"VirtualNetworkOptional", &One } ,
+ { L"EthernetPadToEven", &One } ,
+ { L"EthernetExtraPadding", &Zero } ,
+ { L"SingleNetworkActive", &Zero } ,
+ { L"DisableDialoutSap", &Zero } ,
+ { L"DisableDialinNetbios", &One } ,
+ { L"VerifySourceAddress", &One } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = IpxAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ InitializeListHead (&Config->BindingList);
+ Config->DriverObject = DriverObject;
+
+ //
+ // Read in the NDIS binding information.
+ //
+ // IpxReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)IpxAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ IpxFreeConfiguration(Config);
+ IpxWriteResourceErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = IpxReadLinkageInformation (Config);
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // It logged an error if it failed.
+ //
+
+ IpxFreeConfiguration(Config);
+ return Status;
+ }
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-14) Call IpxGetConfigValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = IpxGetConfigValue;
+ 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->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxFreeConfiguration(Config);
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ //
+ // For PnP, we need to keep this path around
+ //
+#ifndef _PNP_POWER
+ IpxFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+#endif _PNP_POWER
+
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfiguration */
+
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to get free any storage that was allocated
+ by IpxGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PBINDING_CONFIG Binding;
+
+ while (!IsListEmpty (&Config->BindingList)) {
+ p = RemoveHeadList (&Config->BindingList);
+ Binding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ IpxFreeMemory (Binding->AdapterName.Buffer, Binding->AdapterName.MaximumLength, MEMORY_CONFIG, "NameBuffer");
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ IpxFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ IpxFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* IpxFreeConfiguration */
+
+
+NTSTATUS
+IpxGetConfigValue(
+ 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))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 904,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Config->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetConfigValue */
+
+
+NTSTATUS
+IpxGetBindingValue(
+ 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 NetConfig\DriverNN
+ node to set the per-binding 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 BINDING_CONFIG structure.
+
+ EntryContext - The index in Binding->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n",
+ (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData));
+ Binding->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData;
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetBindingValue */
+
+
+NTSTATUS
+IpxGetFrameType(
+ 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 of the entry in the "PktType" and
+ "NetworkNumber" multi-strings for a given binding.
+
+Arguments:
+
+ ValueName - The name of the value ("PktType" or "NetworkNumber" -- ignored).
+
+ ValueType - The type of the value (REG_MULTI_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the BINDING_CONFIG structure.
+
+ EntryContext - A pointer to a count of multi-string entries.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context;
+ ULONG IntegerValue;
+ PWCHAR Cur;
+ PULONG Count = (PULONG)EntryContext;
+
+ if ((ValueType != REG_SZ) ||
+ (*Count >= 4)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IntegerValue = 0;
+ for (Cur = (PWCHAR)(ValueData); ; Cur++) {
+ if (*Cur >= L'0' && *Cur <= L'9') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'0');
+ } else if (*Cur >= L'A' && *Cur <= L'F') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'A' + 10);
+ } else if (*Cur >= L'a' && *Cur <= L'f') {
+ IntegerValue = (IntegerValue * 16) + (*Cur - L'a' + 10);
+ } else {
+ break;
+ }
+ }
+
+ if (((PWCHAR)ValueName)[0] == L'P') {
+
+ //
+ // PktType. We map arcnet to 802_3 so the code around
+ // here can assume there are only four packets type --
+ // the frame type is ignored later for arcnet.
+ //
+
+ if ((IntegerValue > ISN_FRAME_TYPE_ARCNET) &&
+ (IntegerValue != ISN_FRAME_TYPE_AUTO)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Binding->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 903,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (CONFIG, ("PktType(%d) is %lx\n", *Count, IntegerValue));
+ if (IntegerValue == ISN_FRAME_TYPE_ARCNET) {
+ Binding->FrameType[*Count] = ISN_FRAME_TYPE_802_3;
+ } else {
+ Binding->FrameType[*Count] = IntegerValue;
+ }
+
+ } else {
+
+ //
+ // NetworkNumber
+ //
+
+ IPX_DEBUG (CONFIG, ("NetworkNumber(%d) is %d\n", *Count, IntegerValue));
+ Binding->NetworkNumber[*Count] = IntegerValue;
+
+ }
+
+ ++(*Count);
+
+ return STATUS_SUCCESS;
+
+} /* IpxGetFrameType */
+
+
+NTSTATUS
+IpxAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure. It
+ also queries the per-binding information and stores it.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PBINDING_CONFIG Binding;
+ PULONG CurBindNum = ((PULONG)EntryContext);
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ PWSTR ValueDataWstr = (PWSTR)ValueData;
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+
+ Binding = (PBINDING_CONFIG)IpxAllocateMemory (sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ if (Binding == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ sizeof(BINDING_CONFIG),
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "NameBuffer");
+ if (NameBuffer == NULL) {
+ IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding");
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Binding->AdapterName.Buffer = NameBuffer;
+ Binding->AdapterName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Binding->AdapterName.MaximumLength = (USHORT)ValueLength;
+
+ Binding->DriverObject = Config->DriverObject;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+ InsertTailList (&Config->BindingList, &Binding->Linkage);
+ ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+
+ StringLoc = (ValueLength / sizeof(WCHAR)) - 2;
+ while (ValueDataWstr[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &ValueDataWstr[StringLoc+1], ValueLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", ValueData, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if (Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddBind */
+
+
+NTSTATUS
+IpxAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ IPX_DEBUG (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ IpxWriteResourceErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ ValueLength,
+ MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxAddExport */
+
+
+NTSTATUS
+IpxReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk;
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call IpxAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 901,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+#ifndef _PNP_POWER
+//
+// This will be done as and when adapters appear.
+//
+ //
+ // 1) Change to call IpxAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = IpxAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&Config->BindCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ Config->BindCount = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ //
+ // For the moment fail if we find no bindings -- eventually when
+ // we support dynamic binding we should stick around in this case.
+ //
+
+ if ((Status != STATUS_SUCCESS) || (Config->BindCount == 0)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 902,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+#endif
+ return STATUS_SUCCESS;
+
+} /* IpxReadLinkageInformation */
+
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we were unable to detect the default
+ auto-detect type and instead found a different one. We update
+ the "DefaultAutoDetectType" in the registry.
+
+Arguments:
+
+ RegistryPath - The name of IPX's node in the registry.
+
+ Adapter - The adapter which we auto-detected on.
+
+ FrameType - The new auto-detected value.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR FullRegistryPath;
+ PUCHAR CurRegistryPath;
+ ULONG FullRegistryPathLength;
+ ULONG AdapterNameLength;
+ WCHAR NetConfigName[] = L"\\NetConfig";
+ static PWCHAR FrameTypeNames[4] = { L"Ethernet II", L"802.3", L"802.2", L"SNAP" };
+ PWCHAR CurAdapterName;
+ NTSTATUS Status;
+
+
+ //
+ // We need to allocate a buffer which contains the registry path,
+ // followed by "NetConfig", followed by the adapter name, and
+ // then NULL-terminated.
+ //
+
+ CurAdapterName = &Adapter->AdapterName[(Adapter->AdapterNameLength/sizeof(WCHAR))-2];
+ while (*CurAdapterName != L'\\') {
+ --CurAdapterName;
+ }
+ CurAdapterName;
+ AdapterNameLength = Adapter->AdapterNameLength - ((CurAdapterName - Adapter->AdapterName) * sizeof(WCHAR)) - sizeof(WCHAR);
+
+ FullRegistryPathLength = RegistryPath->Length + sizeof(NetConfigName) + AdapterNameLength;
+
+ FullRegistryPath = (PWSTR)IpxAllocateMemory (FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+ if (FullRegistryPath == NULL) {
+ IpxWriteResourceErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ FullRegistryPathLength,
+ MEMORY_CONFIG);
+ return;
+ }
+
+ CurRegistryPath = (PUCHAR)FullRegistryPath;
+ RtlCopyMemory (CurRegistryPath, RegistryPath->Buffer, RegistryPath->Length);
+ CurRegistryPath += RegistryPath->Length;
+ RtlCopyMemory (CurRegistryPath, NetConfigName, sizeof(NetConfigName) - sizeof(WCHAR));
+ CurRegistryPath += (sizeof(NetConfigName) - sizeof(WCHAR));
+ RtlCopyMemory (CurRegistryPath, CurAdapterName, AdapterNameLength);
+ CurRegistryPath += AdapterNameLength;
+ *(PWCHAR)CurRegistryPath = L'\0';
+
+ Status = RtlWriteRegistryValue(
+ RTL_REGISTRY_ABSOLUTE,
+ FullRegistryPath,
+ L"DefaultAutoDetectType",
+ REG_DWORD,
+ &FrameType,
+ sizeof(ULONG));
+
+ IpxFreeMemory (FullRegistryPath, FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath");
+
+ IpxWriteGeneralErrorLog(
+ IpxDevice->DeviceObject,
+ EVENT_IPX_NEW_DEFAULT_TYPE,
+ 888,
+ STATUS_SUCCESS,
+ FrameTypeNames[FrameType],
+ 0,
+ NULL);
+
+} /* IpxWriteDefaultAutoDetectType */
+
+
+#ifdef _PNP_POWER
+//
+// Vnet# and VnetOptional
+//
+#define VIRTUAL_NETWORK_PARAMETERS 2
+
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the virtual network number
+ from the registry. This is called on appearance/disappearance of an
+ adapter from the system. We read the registry, starting at RegistryPath,
+ to get the value of the VirtualNetworkNumber parameter. If it doesn't
+ exist, we use the default set in ipxcnfg.h file.
+ Adapted from IpxGetConfiguration().
+
+Arguments:
+
+ Config - Contians the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[VIRTUAL_NETWORK_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG Zero = 0;
+ ULONG One = 1;
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[VIRTUAL_NETWORK_PARAMETERS] = {
+ { L"VirtualNetworkNumber", &Zero } ,
+ { L"VirtualNetworkOptional", &One } };
+ UINT i;
+
+ //
+ // Read the virtual net number from the parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below IPX
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net number key
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetConfigValue;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = ParameterValues[0].KeyName;
+ QueryTable[1].EntryContext = (PVOID)CONFIG_VIRTUAL_NETWORK;
+ QueryTable[1].DefaultType = REG_DWORD;
+ QueryTable[1].DefaultData = (PVOID)(ParameterValues[0].DefaultValue);
+ QueryTable[1].DefaultLength = sizeof(ULONG);
+
+ //
+ // 2) Call IpxGetConfigValue for the virtual net optional key
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetConfigValue;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = ParameterValues[1].KeyName;
+ QueryTable[2].EntryContext = (PVOID)CONFIG_VIRTUAL_OPTIONAL;
+ QueryTable[2].DefaultType = REG_DWORD;
+ QueryTable[2].DefaultData = (PVOID)(ParameterValues[1].DefaultValue);
+ QueryTable[2].DefaultLength = sizeof(ULONG);
+
+ //
+ // 15) Stop
+ //
+
+ QueryTable[3].QueryRoutine = NULL;
+ QueryTable[3].Flags = 0;
+ QueryTable[3].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 905,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxPnPGetNetworkNumber */
+
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by IPX to read the adapter-specific parameters
+ from the registry on PnP appearance of an adapter in the system.
+ We read the registry, starting at RegistryPath\NetConfig\DeviceName.
+
+ Adapted from IpxAddBind().
+
+Arguments:
+
+ Config - Config structure - supplies the DeviceObject and RegistryPathBuffer.
+
+ DeviceName - name of the adapter that was added.
+
+ Binding - Returns the configuration information per adapter.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR
+ otherwise.
+
+--*/
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4];
+ ULONG FrameTypeCount, NetworkNumberCount;
+ ULONG StringLoc;
+ BOOLEAN AutoDetect;
+ ULONG AutoDetectLoc;
+ ULONG SlideCount;
+ PWCHAR NameBuffer;
+ NTSTATUS Status;
+ BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX];
+ ULONG Zero = 0;
+ ULONG One = 1;
+ ULONG DefaultBindSap = 0x8137;
+ ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2;
+ PWSTR Subkey = L"NetConfig\\12345678901234567890"; // BUGBUG: hack
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[BINDING_PARAMETERS] = {
+ { L"MaxPktSize", &Zero } ,
+ { L"BindSap", &DefaultBindSap } ,
+ { L"DefaultAutoDetectType", &DefaultAutoDetectType } ,
+ { L"SourceRouting", &One } ,
+ { L"SourceRouteDef", &Zero } ,
+ { L"SourceRouteBcast", &Zero } ,
+ { L"SourceRouteMcast", &Zero } ,
+ { L"EnableFuncaddr", &One } ,
+ { L"EnableWanRouter", &One } };
+ ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = {
+ ISN_FRAME_TYPE_802_2,
+ ISN_FRAME_TYPE_802_3,
+ ISN_FRAME_TYPE_ETHERNET_II,
+ ISN_FRAME_TYPE_SNAP };
+
+ UINT i, j, k;
+
+ FrameTypeCount = 0;
+ NetworkNumberCount = 0;
+
+ //
+ // The structure is allocated OK, insert it into the list.
+ //
+
+// InsertTailList (&Config->BindingList, &Binding->Linkage);
+// ++(*CurBindNum);
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the NetConfig\XXXX key below IPX
+ // (we construct the right name in Subkey,
+ // first scan back to find the \, then copy
+ // the rest over, including the final '\0').
+ //
+ StringLoc = (DeviceName->MaximumLength / sizeof(WCHAR)) - 2;
+ while (DeviceName->Buffer[StringLoc] != L'\\') {
+ --StringLoc;
+ }
+ RtlCopyMemory(&Subkey[10], &DeviceName->Buffer[StringLoc+1], DeviceName->MaximumLength - ((StringLoc+1) * sizeof(WCHAR)));
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 2) Call IpxGetFrameType for each part of the
+ // "PktType" multi-string.
+ //
+
+ QueryTable[1].QueryRoutine = IpxGetFrameType;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"PktType";
+ QueryTable[1].EntryContext = &FrameTypeCount;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Call IpxGetFrameType for each part of the
+ // "NetworkNumber" multi-string.
+ //
+
+ QueryTable[2].QueryRoutine = IpxGetFrameType;
+ QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[2].Name = L"NetworkNumber";
+ QueryTable[2].EntryContext = &NetworkNumberCount;
+ QueryTable[2].DefaultType = REG_NONE;
+
+ //
+ // 4-11) Call IpxGetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < BINDING_PARAMETERS; i++) {
+
+ QueryTable[i+3].QueryRoutine = IpxGetBindingValue;
+ QueryTable[i+3].Flags = 0;
+ QueryTable[i+3].Name = ParameterValues[i].KeyName;
+ QueryTable[i+3].EntryContext = (PVOID)i;
+ QueryTable[i+3].DefaultType = REG_DWORD;
+ QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+3].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 12) Stop
+ //
+
+ QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL;
+ QueryTable[BINDING_PARAMETERS+3].Flags = 0;
+ QueryTable[BINDING_PARAMETERS+3].Name = NULL;
+
+
+ IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", DeviceName->Buffer, Subkey));
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Binding,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // The binding will get freed during cleanup.
+ //
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 906,
+ Status,
+ Subkey,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ if (FrameTypeCount == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_NO_FRAME_TYPES,
+ 907,
+ Status,
+ Subkey + 10,
+ 0,
+ NULL);
+ }
+
+ if (FrameTypeCount > NetworkNumberCount) {
+ for (i = NetworkNumberCount; i <FrameTypeCount; i++) {
+ Binding->NetworkNumber[i] = 0;
+ }
+ }
+ Binding->FrameTypeCount = FrameTypeCount;
+
+ //
+ // Go through and eliminate duplicates from the frame
+ // type array.
+ //
+
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+
+ for (j = i+1; j < Binding->FrameTypeCount; j++) {
+
+ if (Binding->FrameType[j] == Binding->FrameType[i]) {
+
+ IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j));
+
+ //
+ // A duplicate, slide everything else down.
+ //
+
+ for (k = j+1; k < Binding->FrameTypeCount; k++) {
+ Binding->FrameType[k-1] = Binding->FrameType[k];
+ Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k];
+ }
+ --Binding->FrameTypeCount;
+
+ --j; // so we check whoever just moved into this spot.
+ }
+ }
+ }
+
+
+ //
+ // Mark all the explicitly configured frame types, and
+ // see if we have to auto-detect.
+ //
+
+ for (i = 0; i < 4; i++) {
+ FrameTypeUsed[i] = FALSE;
+ }
+
+ AutoDetect = FALSE;
+ for (i = 0; i < Binding->FrameTypeCount; i++) {
+ if ((Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO)) {
+ AutoDetectLoc = i;
+ AutoDetect = TRUE;
+ } else {
+ Binding->AutoDetect[i] = FALSE;
+ Binding->DefaultAutoDetect[i] = FALSE;
+ FrameTypeUsed[Binding->FrameType[i]] = TRUE;
+ }
+ }
+
+ if (!AutoDetect) {
+ IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n"));
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Slide everything that is past the auto-detect point up
+ // to the end.
+ //
+
+ //
+ // Fixed this loop which can spill over if the FrameTypeCount is 4 and the SlideCount > 0.
+ // Here, the FrameTypeCount is 1-based, whereas the indices are 0-based, we need to make
+ // the index 1-based for this to work. So, instead of (3-Binding->FrameTypeCount), we use
+ // (4-Binding->FrameTypeCount). This loop copies all the non-auto-detect frametypes down to
+ // the bottom of the array to make space after the last auto-detect frame-type for filling
+ // in the frametypes in the preference order.
+ //
+#if 0
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)];
+ }
+#else
+ SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1;
+ for (j = 3; j > 3 - SlideCount; j--) {
+ Binding->FrameType[j] = Binding->FrameType[j-(4-Binding->FrameTypeCount)];
+ Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(4-Binding->FrameTypeCount)];
+ Binding->AutoDetect[j] = Binding->AutoDetect[j-(4-Binding->FrameTypeCount)];
+ Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(4-Binding->FrameTypeCount)];
+ }
+#endif
+
+ //
+ // Now fill in any frame types that are not hard-coded,
+ // this will start at AutoDetectLoc and exactly fill up
+ // the gap created when we slid things up above. We
+ // first put the default auto-detect at the first spot.
+ //
+
+ if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) {
+ Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE;
+ ++AutoDetectLoc;
+ FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE;
+ }
+
+ //
+ // Now fill in the array, using the preference order in
+ // the BindingPreference array (this comes into effect
+ // because the first frame type in our list that we
+ // find is used).
+ //
+
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ if (!FrameTypeUsed[BindingPreference[i]]) {
+ Binding->FrameType[AutoDetectLoc] = BindingPreference[i];
+ Binding->NetworkNumber[AutoDetectLoc] = 0;
+ Binding->AutoDetect[AutoDetectLoc] = TRUE;
+ Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE;
+ ++AutoDetectLoc;
+ }
+ }
+
+ Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX;
+
+#if DBG
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i]));
+ }
+#endif
+
+ return STATUS_SUCCESS;
+} /* IpxPnPGetAdapterParameters */
+
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/config.h b/private/ntos/tdi/isnp/ipx/config.h
new file mode 100644
index 000000000..ba6e76d83
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/config.h
@@ -0,0 +1,132 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN IPX module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_DEDICATED_ROUTER 0
+#define CONFIG_INIT_DATAGRAMS 1
+#define CONFIG_MAX_DATAGRAMS 2
+#define CONFIG_RIP_AGE_TIME 3
+#define CONFIG_RIP_COUNT 4
+#define CONFIG_RIP_TIMEOUT 5
+#define CONFIG_RIP_USAGE_TIME 6
+#define CONFIG_ROUTE_USAGE_TIME 7
+#define CONFIG_SOCKET_UNIQUENESS 8
+#define CONFIG_SOCKET_START 9
+#define CONFIG_SOCKET_END 10
+#define CONFIG_VIRTUAL_NETWORK 11
+#define CONFIG_MAX_MEMORY_USAGE 12
+#define CONFIG_RIP_TABLE_SIZE 13
+#define CONFIG_VIRTUAL_OPTIONAL 14
+#define CONFIG_ETHERNET_PAD 15
+#define CONFIG_ETHERNET_LENGTH 16
+#define CONFIG_SINGLE_NETWORK 17
+#define CONFIG_DISABLE_DIALOUT_SAP 18
+#define CONFIG_DISABLE_DIALIN_NB 19
+#define CONFIG_VERIFY_SOURCE_ADDRESS 20
+
+#define CONFIG_PARAMETERS 21
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ PWSTR RegistryPathBuffer; // path to config info
+ ULONG BindCount; // entries in BindingList
+ LIST_ENTRY BindingList; // one per binding
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+//
+// These are used to index into the Parameters array in BINDING_CONFIG.
+//
+
+#define BINDING_MAX_PKT_SIZE 0
+#define BINDING_BIND_SAP 1
+#define BINDING_DEFAULT_AUTO_DETECT 2
+#define BINDING_SOURCE_ROUTE 3
+#define BINDING_ALL_ROUTE_DEF 4
+#define BINDING_ALL_ROUTE_BC 5
+#define BINDING_ALL_ROUTE_MC 6
+#define BINDING_ENABLE_FUNC_ADDR 7
+#define BINDING_ENABLE_WAN 8
+
+#define BINDING_PARAMETERS 9
+
+
+//
+// One of these is allocated per adapter we are to bind to.
+//
+
+typedef struct _BINDING_CONFIG {
+
+ LIST_ENTRY Linkage; // for chaining on BindingList
+ NDIS_STRING AdapterName; // NDIS adapter to bind to
+ ULONG FrameTypeCount; // number of frame types defined (max. 4)
+ // == number of valid entries in arrays:
+ ULONG FrameType[ISN_FRAME_TYPE_MAX]; // ISN_FRAME_TYPE_XXX
+ ULONG NetworkNumber[ISN_FRAME_TYPE_MAX]; // may be 0
+ BOOLEAN AutoDetect[ISN_FRAME_TYPE_MAX]; // remove if net number can't be found
+ BOOLEAN DefaultAutoDetect[ISN_FRAME_TYPE_MAX]; // use this if multiple or none found
+ ULONG Parameters[BINDING_PARAMETERS]; // index defined above
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} BINDING_CONFIG, * PBINDING_CONFIG;
+
+
+NTSTATUS
+IpxGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+IpxFreeConfiguration (
+ IN PCONFIG Config
+ );
+
+VOID
+IpxWriteDefaultAutoDetectType(
+ IN PUNICODE_STRING RegistryPath,
+ IN struct _ADAPTER * Adapter,
+ IN ULONG FrameType
+ );
+
+#ifdef _PNP_POWER
+NTSTATUS
+IpxPnPGetVirtualNetworkNumber (
+ IN PCONFIG Config
+ );
+
+NTSTATUS
+IpxPnPGetAdapterParameters(
+ IN PCONFIG Config,
+ IN PNDIS_STRING DeviceName,
+ IN OUT PBINDING_CONFIG Binding
+ );
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/ipx/device.c b/private/ntos/tdi/isnp/ipx/device.c
new file mode 100644
index 000000000..f2d9d19f4
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/device.c
@@ -0,0 +1,599 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE_CONTEXT object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxCreateDevice)
+#endif
+
+
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement(&Device->ReferenceCount);
+
+} /* IpxRefDevice */
+
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ IpxDestroyDevice (Device);
+ }
+
+} /* IpxDerefDevice */
+
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ 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.
+
+ SegmentCount - The number of segments in the RIP router table.
+
+ 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 LocksOffset;
+ ULONG SegmentsOffset;
+ ULONG DeviceNameOffset;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) +
+ (sizeof(CTELock) * SegmentCount) +
+ (sizeof(ROUTER_SEGMENT) * SegmentCount) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ IPX_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject->DeviceExtension;
+
+ IPX_DEBUG(DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ Device->DeviceObject = deviceObject;
+
+ LocksOffset = sizeof(DEVICE);
+ SegmentsOffset = LocksOffset + (sizeof(CTELock) * SegmentCount);
+ DeviceNameOffset = SegmentsOffset + (sizeof(ROUTER_SEGMENT) * SegmentCount);
+
+ //
+ // Set some internal pointers.
+ //
+
+ Device->SegmentLocks = (CTELock *)(((PUCHAR)Device) + LocksOffset);
+ Device->Segments = (PROUTER_SEGMENT)(((PUCHAR)Device) + SegmentsOffset);
+ Device->SegmentCount = SegmentCount;
+
+ for (i = 0; i < SegmentCount; i++) {
+
+ CTEInitLock (&Device->SegmentLocks[i]);
+ InitializeListHead (&Device->Segments[i].WaitingForRoute);
+ InitializeListHead (&Device->Segments[i].FindWaitingForRoute);
+ InitializeListHead (&Device->Segments[i].WaitingLocalTarget);
+ InitializeListHead (&Device->Segments[i].WaitingReripNetnum);
+ InitializeListHead (&Device->Segments[i].Entries);
+ Device->Segments[i].EnumerateLocation = &Device->Segments[i].Entries;
+
+ }
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(((PUCHAR)Device) + DeviceNameOffset);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "IDC1", 4);
+ RtlCopyMemory(Device->Signature2, "IDC2", 4);
+#endif
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 0; // no sends allowed
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTIONLESS_MODE | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_ROUTE_DIRECTED;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.NumberOfResources = IPX_TDI_RESOURCES;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+
+#if 0
+ //
+ // These will be filled in after all the binding is done.
+ //
+
+ Device->Information.MaxDatagramSize = 0;
+ Device->Information.MaximumLookaheadData = 0;
+
+
+ Device->SourceRoutingUsed = FALSE;
+ Device->SourceRoutingTime = 0;
+ Device->RipPacketCount = 0;
+
+ Device->RipShortTimerActive = FALSE;
+ Device->RipSendTime = 0;
+#endif
+
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+#ifdef _PNP_POWER
+ //
+ // Init the resource that guards the binding array/indices
+ //
+ CTEInitLock (&Device->BindAccessLock);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingRipPackets);
+ CTEInitTimer (&Device->RipShortTimer);
+ CTEInitTimer (&Device->RipLongTimer);
+
+ CTEInitTimer (&Device->SourceRoutingTimer);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock);
+ CTEInitLock (&Device->Lock);
+ CTEInitLock (&Device->SListsLock);
+
+ Device->ControlChannelIdentifier.QuadPart = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+#if BACK_FILL
+ InitializeListHead (&Device->GlobalBackFillPacketList);
+#endif
+
+ InitializeListHead (&Device->AddressNotifyQueue);
+ InitializeListHead (&Device->LineChangeQueue);
+
+ for (i = 0; i < IPX_ADDRESS_HASH_COUNT; i++) {
+ InitializeListHead (&Device->AddressDatabases[i]);
+ }
+
+#if BACK_FILL
+ InitializeListHead (&Device->BackFillPoolList);
+#endif
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+
+#ifdef _PNP_POWER
+ InitializeListHead (&Device->BindingPoolList);
+#endif
+
+ ExInitializeSListHead (&Device->SendPacketList);
+ ExInitializeSListHead (&Device->ReceivePacketList);
+#if BACK_FILL
+ ExInitializeSListHead (&Device->BackFillPacketList);
+#endif
+
+#ifdef _PNP_POWER
+ ExInitializeSListHead (&Device->BindingList);
+#endif
+
+#if 0
+ Device->MemoryUsage = 0;
+ Device->SendPacketList.Next = NULL;
+ Device->ReceivePacketList.Next = NULL;
+ Device->Bindings = NULL;
+ Device->BindingCount = 0;
+#endif
+
+ KeQuerySystemTime (&Device->IpxStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ Device->Type = IPX_DEVICE_SIGNATURE;
+ Device->Size = sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* IpxCreateDevice */
+
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_POOL SendPool;
+ PIPX_SEND_PACKET SendPacket;
+ PIPX_RECEIVE_POOL ReceivePool;
+ PIPX_RECEIVE_PACKET ReceivePacket;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT SendPoolSize;
+ UINT ReceivePoolSize;
+ UINT i;
+#if BACK_FILL
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+ PIPX_SEND_PACKET BackFillPacket;
+#endif
+
+#ifdef _PNP_POWER
+ PIPX_BINDING_POOL BindingPool;
+ UINT BindingPoolSize;
+ PBINDING Binding;
+#endif
+
+ IPX_DEBUG (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the packets out of its pools.
+ //
+
+#if _PNP_POWER
+ BindingPoolSize = FIELD_OFFSET (IPX_BINDING_POOL, Bindings[0]) +
+ (sizeof(BINDING) * Device->InitBindings);
+
+ while (!IsListEmpty (&Device->BindingPoolList)) {
+
+ p = RemoveHeadList (&Device->BindingPoolList);
+ BindingPool = CONTAINING_RECORD (p, IPX_BINDING_POOL, Linkage);
+ IPX_DEBUG (PACKET, ("Free binding pool %lx\n", BindingPool));
+ IpxFreeMemory (BindingPool, BindingPoolSize, MEMORY_PACKET, "BindingPool");
+
+ }
+#endif
+
+#ifdef IPX_OWN_PACKETS
+
+#if BACK_FILL
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < BackFillPool->PacketCount; i++) {
+ BackFillPacket = &BackFillPool->Packets[i];
+ IpxDeinitializeBackFillPacket (Device, BackFillPacket);
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ IpxFreeMemory (BackFillPool, BackFillPoolSize, MEMORY_PACKET, "BackPool");
+ }
+#endif
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (((IPX_MAXIMUM_MAC + sizeof(IPX_HEADER) + 3) & ~3) * Device->InitDatagrams);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ IpxDeinitializeSendPacket (Device, SendPacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ IpxFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ IpxDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ IPX_DEBUG (PACKET, ("Free receive packet pool %lx\n", ReceivePool));
+ IpxFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+#else
+
+#if BACK_FILL
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->BackFillPacketList, &Device->Lock)) {
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET BackFillPacket;
+
+ BackFillPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeBackFillPacket (Device, &BackFillPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->BackFillPoolList)) {
+
+ p = RemoveHeadList (&Device->BackFillPoolList);
+ BackFillPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", BackFillPool));
+ NdisFreePacketPool (BackFillPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (BackFillPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+ }
+#endif
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->SendPacketList, &Device->Lock)){
+ PIPX_SEND_RESERVED Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ IPX_SEND_PACKET SendPacket;
+ PUCHAR Header = Reserved->Header;
+
+ SendPacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeSendPacket (Device, &SendPacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, IPX_SEND_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", SendPool));
+ NdisFreePacketPool (SendPool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (SendPool->Header, PACKET_HEADER_SIZE * Device->InitDatagrams, MEMORY_PACKET, "SendPool");
+
+ IpxFreeMemory (SendPool, sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+ }
+
+ while (s = IPX_POP_ENTRY_LIST(&Device->ReceivePacketList, &Device->Lock)){
+ PIPX_RECEIVE_RESERVED Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+ ReceivePacket.Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ IpxDeinitializeReceivePacket (Device, &ReceivePacket);
+ Device->MemoryUsage -= (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED));
+ }
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, IPX_RECEIVE_POOL, Linkage);
+
+ IPX_DEBUG (PACKET, ("Free packet pool %lx\n", ReceivePool));
+ NdisFreePacketPool (ReceivePool->PoolHandle);
+ Device->MemoryUsage -= FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]);
+
+ IpxFreeMemory (ReceivePool, sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+ }
+
+#endif IPX_OWN_PACKETS
+ //
+ // Destroy all rip table entries.
+ //
+
+ for (i = 0; i < Device->SegmentCount; i++) {
+
+ RouteEntry = RipGetFirstRoute(i);
+ while (RouteEntry != NULL) {
+
+ (VOID)RipDeleteRoute(i, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ RouteEntry = RipGetNextRoute(i);
+
+ }
+
+ }
+
+ IPX_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (IpxMemoryTag[i].BytesAllocated != 0) {
+ IPX_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, IpxMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice (Device->DeviceObject);
+ }
+
+} /* IpxDestroyDevice */
+
diff --git a/private/ntos/tdi/isnp/ipx/dirs b/private/ntos/tdi/isnp/ipx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/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/isnp/ipx/driver.c b/private/ntos/tdi/isnp/ipx/driver.c
new file mode 100644
index 000000000..7c32cd0e3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/driver.c
@@ -0,0 +1,4219 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+ Sanjay Anand (SanjayAn) 18-Sept-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE IpxDevice = NULL;
+PIPX_PADDING_BUFFER IpxPaddingBuffer = NULL;
+
+#if DBG
+
+UCHAR IpxTempDebugBuffer[150];
+ULONG IpxDebug = 0x0;
+ULONG IpxMemoryDebug = 0xffffffd3;
+UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+PUCHAR IpxDebugMemoryLoc = IpxDebugMemory[0];
+PUCHAR IpxDebugMemoryEnd = IpxDebugMemory[IPX_MEMORY_LOG_SIZE];
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (IpxTempDebugBuffer, 150);
+ ArgLen = vsprintf(IpxTempDebugBuffer, FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (IpxDebugMemoryLoc, 64);
+ RtlCopyMemory( IpxDebugMemoryLoc, IpxTempDebugBuffer, ArgLen );
+
+ IpxDebugMemoryLoc += 64;
+ if (IpxDebugMemoryLoc >= IpxDebugMemoryEnd) {
+ IpxDebugMemoryLoc = IpxDebugMemory[0];
+ }
+ }
+}
+
+
+DEFINE_LOCK_STRUCTURE(IpxMemoryInterlock);
+MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+DEFINE_LOCK_STRUCTURE(IpxGlobalInterlock);
+
+#endif
+
+#if DBG
+
+//
+// Use for debug printouts
+//
+
+PUCHAR FrameTypeNames[5] = { "Ethernet II", "802.3", "802.2", "SNAP", "Arcnet" };
+#define OutputFrameType(_Binding) \
+ (((_Binding)->Adapter->MacInfo.MediumType == NdisMediumArcnet878_2) ? \
+ FrameTypeNames[4] : \
+ FrameTypeNames[(_Binding)->FrameType])
+#endif
+
+
+#ifdef IPX_PACKET_LOG
+
+ULONG IpxPacketLogDebug = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_SEND_OTHER;
+USHORT IpxPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(IpxPacketLogLock);
+IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc = IpxPacketLog;
+PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd = &IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PIPX_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&IpxPacketLogLock, &LockHandle);
+
+ PacketLog = IpxPacketLogLoc;
+
+ ++IpxPacketLogLoc;
+ if (IpxPacketLogLoc >= IpxPacketLogEnd) {
+ IpxPacketLogLoc = IpxPacketLog;
+ }
+ *(UNALIGNED ULONG *)IpxPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&IpxPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(IPX_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->IpxHeader, IpxHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* IpxLogPacket */
+
+#endif // IPX_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+//
+// This is now shared with other modules
+//
+#ifndef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+#endif _PNP_POWER
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+
+//
+// These routines can be called at any time in case of PnP.
+//
+#ifndef _PNP_POWER
+#pragma alloc_text(INIT,IpxResolveAutoDetect)
+#pragma alloc_text(INIT,IpxResolveBindingSets)
+#pragma alloc_text(INIT,IpxBindToAdapter)
+#endif
+
+#endif
+
+UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+ULONG IpxFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the IPX 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 IPX's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ UINT SuccessfulOpens, ValidBindings;
+#ifdef _PNP_POWER
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("NWLNKIPX");
+#else
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("IPX Transport");
+#endif
+ PDEVICE Device;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG BindingCount, BindingIndex;
+ PBINDING * BindingArray;
+ PLIST_ENTRY p;
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG Temp;
+ UINT i;
+ BOOLEAN CountedWan;
+
+ PCONFIG Config = NULL;
+ PBINDING_CONFIG ConfigBinding;
+
+#if 0
+ DbgPrint ("IPX: FailLoad at %lx\n", &IpxFailLoad);
+ DbgBreakPoint();
+
+ if (IpxFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+
+ //
+ // This ordering matters because we use it to quickly
+ // determine if packets are internally generated or not.
+ //
+
+ CTEAssert (IDENTIFIER_NB < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_SPX < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP < IDENTIFIER_IPX);
+ CTEAssert (IDENTIFIER_RIP_INTERNAL > IDENTIFIER_IPX);
+
+ //
+ // We assume that this structure is not packet in between
+ // the fields.
+ //
+
+ CTEAssert (FIELD_OFFSET (TDI_ADDRESS_IPX, Socket) + sizeof(USHORT) == 12);
+
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+
+ IPX_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&IpxGlobalInterlock);
+ CTEInitLock (&IpxMemoryInterlock);
+ for (i = 0; i < MEMORY_MAX; i++) {
+ IpxMemoryTag[i].Tag = i;
+ IpxMemoryTag[i].BytesAllocated = 0;
+ }
+#endif
+#ifdef IPX_PACKET_LOG
+ CTEInitLock (&IpxPacketLogLock);
+#endif
+
+#ifdef IPX_OWN_PACKETS
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ IPX_DEBUG (DEVICE, ("IPX loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = IpxGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed, it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, IPX initialization failed.\n");
+ return status;
+
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Initialize the TDI layer.
+ //
+ TdiInitialize();
+#endif
+
+ //
+ // make ourselves known to the NDIS wrapper.
+ //
+
+ status = IpxRegisterProtocol ((PNDIS_STRING)&ProtocolName);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxFreeConfiguration(Config);
+ PANIC ("IpxInitialize: RegisterProtocol failed!\n");
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 607,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ return status;
+
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = IpxDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = IpxDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = IpxDispatchDeviceControl;
+
+ DriverObject->DriverUnload = IpxUnload;
+
+ SuccessfulOpens = 0;
+
+ status = IpxCreateDevice(
+ DriverObject,
+ &Config->DeviceName,
+ Config->Parameters[CONFIG_RIP_TABLE_SIZE],
+ &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return status;
+ }
+
+ IpxDevice = Device;
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->DedicatedRouter = (BOOLEAN)(Config->Parameters[CONFIG_DEDICATED_ROUTER] != 0);
+ Device->InitDatagrams = Config->Parameters[CONFIG_INIT_DATAGRAMS];
+ Device->MaxDatagrams = Config->Parameters[CONFIG_MAX_DATAGRAMS];
+ Device->RipAgeTime = Config->Parameters[CONFIG_RIP_AGE_TIME];
+ Device->RipCount = Config->Parameters[CONFIG_RIP_COUNT];
+ Device->RipTimeout =
+ ((Config->Parameters[CONFIG_RIP_TIMEOUT] * 500) + (RIP_GRANULARITY/2)) /
+ RIP_GRANULARITY;
+ Device->RipUsageTime = Config->Parameters[CONFIG_RIP_USAGE_TIME];
+ Device->SourceRouteUsageTime = Config->Parameters[CONFIG_ROUTE_USAGE_TIME];
+ Device->SocketUniqueness = Config->Parameters[CONFIG_SOCKET_UNIQUENESS];
+ Device->SocketStart = (USHORT)Config->Parameters[CONFIG_SOCKET_START];
+ Device->SocketEnd = (USHORT)Config->Parameters[CONFIG_SOCKET_END];
+ Device->MemoryLimit = Config->Parameters[CONFIG_MAX_MEMORY_USAGE];
+ Device->VerifySourceAddress = (BOOLEAN)(Config->Parameters[CONFIG_VERIFY_SOURCE_ADDRESS] != 0);
+
+ Device->InitReceivePackets = (Device->InitDatagrams + 1) / 2;
+ Device->InitReceiveBuffers = (Device->InitDatagrams + 1) / 2;
+
+ Device->MaxReceivePackets = 10; // BUGBUG: config this?
+ Device->MaxReceiveBuffers = 10;
+
+#ifdef _PNP_POWER
+ Device->InitBindings = 5; // BUGBUG: config this?
+
+ //
+ // RAS max is 240 (?) + 10 max LAN
+ //
+ Device->MaxPoolBindings = 250; // BUGBUG: config this?
+#endif
+
+ //
+ // Have to reverse this.
+ //
+#ifndef _PNP_POWER
+//
+// Look at this only when the first adapter appears.
+//
+ Temp = Config->Parameters[CONFIG_VIRTUAL_NETWORK];
+ Device->VirtualNetworkNumber = REORDER_ULONG (Temp);
+#endif
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config->Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ Device->CurrentSocket = Device->SocketStart;
+
+ Device->EthernetPadToEven = (BOOLEAN)(Config->Parameters[CONFIG_ETHERNET_PAD] != 0);
+ Device->EthernetExtraPadding = (Config->Parameters[CONFIG_ETHERNET_LENGTH] & 0xfffffffe) + 1;
+
+ Device->SingleNetworkActive = (BOOLEAN)(Config->Parameters[CONFIG_SINGLE_NETWORK] != 0);
+ Device->DisableDialoutSap = (BOOLEAN)(Config->Parameters[CONFIG_DISABLE_DIALOUT_SAP] != 0);
+ Device->DisableDialinNetbios = (UCHAR)(Config->Parameters[CONFIG_DISABLE_DIALIN_NB]);
+
+#ifdef _PNP_POWER
+//
+// Used later to access the registry.
+//
+ Device->RegistryPathBuffer = Config->RegistryPathBuffer;
+ Device->RegistryPath.Length = RegistryPath->Length;
+ Device->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
+ Device->RegistryPath.Buffer = Device->RegistryPathBuffer;
+#endif _PNP_POWER
+
+ //
+ // ActiveNetworkWan will start as FALSE, which is correct.
+ //
+
+ //
+ // Allocate our initial packet pool. We do not allocate
+ // receive and receive buffer pools until we need them,
+ // because in many cases we never do.
+ //
+
+#if BACK_FILL
+ IpxAllocateBackFillPool (Device);
+#endif
+
+ IpxAllocateSendPool (Device);
+
+#ifdef _PNP_POWER
+ IpxAllocateBindingPool (Device);
+#endif
+
+ //
+ // Allocate one 1-byte buffer for odd length packets.
+ //
+
+ IpxPaddingBuffer = IpxAllocatePaddingBuffer(Device);
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ 801,
+ STATUS_INSUFFICIENT_RESOURCES,
+ NULL,
+ 0,
+ NULL);
+
+ IpxFreeConfiguration(Config);
+ IpxDeregisterProtocol();
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Initialize the loopback structures
+ //
+ IpxInitLoopback();
+
+//
+// All this will be done on appearance of adapters.
+//
+
+#ifndef _PNP_POWER
+
+ //
+ // Bind to all the configured adapters.
+ //
+
+ InitializeListHead (&Device->InitialBindingList);
+
+ p = Config->BindingList.Flink;
+
+ while (p != &Config->BindingList) {
+
+ ConfigBinding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage);
+ p = p->Flink;
+
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList.
+ //
+
+ status = IpxBindToAdapter (Device, ConfigBinding, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ if (status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding->AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ ++SuccessfulOpens;
+
+ }
+
+ }
+
+
+ IpxFreeConfiguration(Config);
+
+ if (SuccessfulOpens == 0) {
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ } else {
+
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext);
+
+ //
+ // Allocate the device binding array and transfer those
+ // on the list to it. First count up the bindings.
+ //
+
+ BindingCount = 0;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ Adapter->FirstWanNicId = (USHORT)(BindingCount+1);
+ Adapter->LastWanNicId = (USHORT)(BindingCount + Adapter->WanNicIdCount);
+ BindingCount += Adapter->WanNicIdCount;
+ } else {
+ ++BindingCount;
+ }
+ }
+
+ BindingArray = (PBINDING *)IpxAllocateMemory ((BindingCount+1) * sizeof(BINDING), MEMORY_BINDING, "Binding array");
+
+ if (BindingArray == NULL) {
+
+ while (!IsListEmpty (&Device->InitialBindingList)) {
+ p = RemoveHeadList (&Device->InitialBindingList);
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+ IpxDestroyBinding (Binding);
+ }
+
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ SuccessfulOpens = 0;
+ goto InitFailed;
+ }
+
+ RtlZeroMemory (BindingArray, (BindingCount+1) * sizeof(BINDING));
+
+ //
+ // Now walk the list transferring bindings to the array.
+ //
+
+ BindingIndex = 1;
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ ) {
+
+ Binding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ p = p->Flink; // we overwrite the linkage in here, so save it.
+
+ BindingArray[BindingIndex] = Binding;
+ Binding->NicId = (USHORT)BindingIndex;
+
+ if (Binding->ConfiguredNetworkNumber != 0) {
+
+ //
+ // If the configured network number is non-zero, then
+ // use it, unless we are unable to insert a rip table
+ // entry for it (duplicates are OK because they will
+ // become binding set members -- BUGBUG: What if the
+ // duplicate is a different media or frame type, then
+ // it won't get noted as a binding set).
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // These are a union with the InitialLinkage fields.
+ //
+
+ Binding->NextBinding = NULL;
+ Binding->CurrentSendBinding = NULL;
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->MacInfo.MediumAsync) {
+ CTEAssert (Adapter->FirstWanNicId == BindingIndex);
+ BindingIndex += Adapter->WanNicIdCount;
+ } else {
+ ++BindingIndex;
+ }
+ }
+
+ CTEAssert (BindingIndex == BindingCount+1);
+
+ Device->Bindings = BindingArray;
+ Device->BindingCount = BindingCount;
+
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ status = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (status == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ for (i = 1; i <= Device->BindingCount; i++) {
+
+ Binding = Device->Bindings[i];
+
+ //
+ // Skip empty WAN slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ status = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((status != STATUS_SUCCESS) &&
+ (status != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ }
+
+ ValidBindings = Device->BindingCount;
+
+ if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, RegistryPath);
+
+ }
+
+ Device->ValidBindings = ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This sets Device->HighestExternalNicId
+ // and Device->HighestType20NicId.
+ //
+
+ IpxResolveBindingSets (Device, ValidBindings);
+
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // Success; see if there is a virtual network configured.
+ //
+
+ if (Device->VirtualNetworkNumber != 0) {
+
+ status = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ Device->Bindings[1]->Adapter->NdisBindingHandle,
+ 1);
+
+ if (status != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (status == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+
+ //
+ // This will get set to FALSE if RIP binds.
+ //
+
+ Device->RipResponder = TRUE;
+
+ } else {
+
+NoVirtualNetwork:
+
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ RtlCopyMemory(&Device->SourceAddress, &Device->Bindings[1]->LocalAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ }
+
+
+ //
+ // Now get SapNicCount -- regular adapters are counted
+ // as one, but all the WAN lines together only count for one.
+ // We also calculate FirstLanNicId and FirstWanNicId here.
+ //
+
+ CountedWan = FALSE;
+ Device->SapNicCount = 0;
+
+ Device->FirstLanNicId = (USHORT)-1;
+ Device->FirstWanNicId = (USHORT)-1;
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Device->Bindings[i]) {
+
+ if (Device->Bindings[i]->Adapter->MacInfo.MediumAsync) {
+
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = i;
+ }
+
+ if (CountedWan) {
+ continue;
+ } else {
+ CountedWan = TRUE;
+ }
+
+ } else {
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = i;
+ }
+
+ }
+
+ } else {
+
+ //
+ // NULL bindings are WANs and are not the first one,
+ // so don't count them.
+ //
+
+ CTEAssert (Device->FirstWanNicId != -1);
+ CTEAssert (CountedWan);
+ continue;
+ }
+
+ ++Device->SapNicCount;
+
+ }
+ }
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = 1;
+ }
+ if (Device->FirstWanNicId == (USHORT)-1) {
+ Device->FirstWanNicId = 1;
+ }
+
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = Device->Bindings[1]->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = Device->Bindings[1]->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = Device->Bindings[1]->RealMaxDatagramSize; // smallest binding value
+
+ if (Device->Bindings[1]->LineUp) {
+ LinkSpeed = Device->Bindings[1]->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = Device->Bindings[1]->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = Device->Bindings[1]->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ Device->State = DEVICE_STATE_OPEN;
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ }
+
+InitFailed:
+
+ if (SuccessfulOpens == 0) {
+
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ } else {
+
+ return STATUS_SUCCESS;
+ }
+
+#else // _PNP_POWER
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ PTA_ADDRESS TdiRegistrationAddress;
+
+ //
+ // Pre-allocate the binding array
+ // Later, we will allocate the LAN/WAN and SLAVE bindings separately
+ // [BUGBUGZZ] Read the array size from registry?
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ Device->MaxBindings = MAX_BINDINGS;
+
+ //
+ // Allocate the TA_ADDRESS structure - this will be used in all TdiRegisterNetAddress
+ // notifications.
+ //
+ TdiRegistrationAddress = (PTA_ADDRESS)IpxAllocateMemory (
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ if (TdiRegistrationAddress == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxFreeMemory(BindingArray, sizeof(BindingArray), MEMORY_BINDING, "Binding Array");
+ IpxDereferenceDevice (Device, DREF_CREATE);
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ RtlZeroMemory (BindingArray, MAX_BINDINGS * sizeof(BIND_ARRAY_ELEM));
+ RtlZeroMemory (TdiRegistrationAddress, 2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX));
+
+ Device->Bindings = BindingArray;
+
+ TdiRegistrationAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ TdiRegistrationAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+
+ //
+ // Store the pointer in the Device.
+ //
+ Device->TdiRegistrationAddress = TdiRegistrationAddress;
+
+ //
+ // Device state is loaded, but not opened. It is opened when at least
+ // one adapter has appeared.
+ //
+ Device->State = DEVICE_STATE_LOADED;
+
+ Device->FirstLanNicId = Device->FirstWanNicId = (USHORT)1; // will be changed later
+
+ IpxFreeConfiguration(Config);
+
+ //
+ // We use this event when unloading to signal that we
+ // can proceed...initialize it here so we know it is
+ // ready to go when unload is called.
+ //
+
+ KeInitializeEvent(
+ &IpxDevice->UnloadEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ return STATUS_SUCCESS;
+}
+#endif // _PNP_POWER
+} /* DriverEntry */
+
+
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+#ifdef _PNP_POWER
+ IN CTELockHandle *LockHandle1,
+#endif
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called for auto-detect bindings to
+ remove any bindings that were not successfully found.
+ It also updates "DefaultAutoDetectType" in the registry
+ if needed.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+ RegistryPath - The path to the ipx registry, used if we have
+ to write a value back.
+
+Return Value:
+
+ The updated number of bindings.
+
+--*/
+
+{
+ PBINDING Binding, TmpBinding;
+ UINT i, j;
+
+ //
+ // Get rid of any auto-detect devices which we
+ // could not find nets for. We also remove any
+ // devices which are not the first ones
+ // auto-detected on a particular adapter.
+ //
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // If this was auto-detected and was not the default,
+ // or it was the default, but nothing was detected for
+ // it *and* something else *was* detected (which means
+ // we will use that frame type when we get to it),
+ // we may need to remove this binding.
+ //
+
+ if (Binding->AutoDetect &&
+ (!Binding->DefaultAutoDetect ||
+ (Binding->DefaultAutoDetect &&
+ (Binding->LocalAddress.NetworkAddress == 0) &&
+ Binding->Adapter->AutoDetectResponse))) {
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) ||
+ (Binding->Adapter->AutoDetectFound)) {
+
+ //
+ // Remove this binding.
+ //
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) no net found\n",
+ i, Binding->FrameType));
+ } else {
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) adapter already auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ CTEAssert (Binding->NicId == i);
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ //
+ // Remove any routes through this NIC, and
+ // adjust any NIC ID's above this one in the
+ // database down by one.
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ Binding->Adapter->Bindings[Binding->FrameType] = NULL;
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifndef _PNP_POWER
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#else
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#endif _PNP_POWER
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, NULL);
+#else
+ Device->Bindings[ValidBindings] = NULL;
+#endif
+ --Binding->Adapter->BindingCount;
+ --ValidBindings;
+
+ --i; // so we check the binding that was just moved.
+
+ //
+ // Wait 100 ms before freeing the binding,
+ // in case an indication is using it.
+ //
+
+ KeStallExecutionProcessor(100000);
+
+ IpxDestroyBinding (Binding);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detected OK\n",
+ i, Binding->FrameType));
+
+#if DBG
+ DbgPrint ("IPX: Auto-detected non-default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+
+ //
+ // Save it in the registry for the next boot.
+ //
+#ifdef _PNP_POWER
+//
+// This cannot be done at DPC, so, drop the IRQL
+//
+ IPX_FREE_LOCK1(&Device->BindAccessLock, *LockHandle1);
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+ IPX_GET_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ IpxWriteDefaultAutoDetectType(
+ RegistryPath,
+ Binding->Adapter,
+ Binding->FrameType);
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+ }
+
+ } else {
+
+ if (Binding->AutoDetect) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) auto-detect default\n",
+ i, Binding->FrameType));
+
+#if DBG
+ if (Binding->LocalAddress.NetworkAddress != 0) {
+ DbgPrint ("IPX: Auto-detected default frame type %s, net %lx\n",
+ OutputFrameType(Binding),
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+ } else {
+ DbgPrint ("IPX: Using default auto-detect frame type %s\n",
+ OutputFrameType(Binding));
+ }
+#endif
+
+ Binding->Adapter->AutoDetectFound = TRUE;
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Binding %d (%d) not auto-detected\n",
+ i, Binding->FrameType));
+ }
+
+ }
+
+ }
+
+
+ for (i = 1; i <= ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (Binding = Device->Bindings[i]) {
+#endif
+ CTEAssert (Binding->NicId == i);
+ IPX_DEBUG (AUTO_DETECT, ("Binding %lx, type %d, auto %d\n",
+ Binding, Binding->FrameType, Binding->AutoDetect));
+ }
+
+ }
+
+ return ValidBindings;
+
+} /* IpxResolveAutoDetect */
+
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to determine if we have any
+ binding sets and rearrange the bindings the way we
+ like. The order is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ValidBindings - The total number of bindings present.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding, MasterBinding, TmpBinding;
+ UINT i, j;
+ ULONG WanCount, DuplicateCount;
+
+ //
+ // First loop through and push all the wan bindings
+ // to the end.
+ //
+#ifdef _PNP_POWER
+
+ WanCount = Device->HighestExternalNicId - Device->HighestLanNicId;
+
+#else
+
+ WanCount = 0;
+
+ //
+ // For PnP, we dont do this as the bindings are in order
+ // at the time of insertion
+ //
+ for (i = 1; i <= (ValidBindings-WanCount); ) {
+
+ Binding = Device->Bindings[i];
+
+ if ((Binding == NULL) || Binding->Adapter->MacInfo.MediumAsync) {
+
+ //
+ // Put this binding at the end, and slide all the
+ // others down. If it is a NULL WAN binding then we
+ // don't have to do some of this.
+ //
+
+#if DBG
+ //
+ // Any non-NULL bindings should be correct in this
+ // respect at any point.
+ //
+
+ if (Binding != NULL) {
+ CTEAssert (Binding->NicId == i);
+ }
+#endif
+
+ //
+ // If the Binding is NULL we won't have anything in the
+ // database at this binding, but we still need to adjust
+ // any NIC ID's in the database which are above this.
+ //
+
+ RipAdjustForBindingChange ((USHORT)i, (USHORT)ValidBindings, IpxBindingMoved);
+
+ //
+ // Slide the bindings above this down.
+ //
+
+ for (j = i+1; j <= ValidBindings; j++) {
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+
+ //
+ // Put this binding at the end.
+ //
+
+ Device->Bindings[ValidBindings] = Binding;
+ if (Binding != NULL) {
+ if ((Binding->Adapter->MacInfo.MediumAsync) &&
+ (Binding->Adapter->FirstWanNicId == Binding->NicId)) {
+ Binding->Adapter->FirstWanNicId = (USHORT)ValidBindings;
+ Binding->Adapter->LastWanNicId += (USHORT)(ValidBindings - Binding->NicId);
+ }
+ Binding->NicId = (USHORT)ValidBindings;
+ }
+ ++WanCount;
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ } else {
+
+ i++;
+
+ }
+
+ }
+#endif _PNP_POWER
+ //
+ // Now go through and find the LAN duplicates and
+ // create binding sets from them.
+ //
+
+ DuplicateCount = 0;
+
+ for (i = 1; i <= (ValidBindings-(WanCount+DuplicateCount)); ) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ CTEAssert (Binding != NULL); // because we are only looking at LAN bindings
+
+ CTEAssert (!Binding->Adapter->MacInfo.MediumAsync);
+
+ if (Binding->LocalAddress.NetworkAddress == 0) {
+ i++;
+ continue;
+ }
+
+ //
+ // See if any previous bindings match the
+ // frame type, medium type, and number of
+ // this network (for the moment we match on
+ // frame type and medium type too so that we
+ // don't have to worry about different frame
+ // formats and header offsets within a set).
+ //
+
+ for (j = 1; j < i; j++) {
+#ifdef _PNP_POWER
+ MasterBinding = NIC_ID_TO_BINDING(Device, j);
+#else
+ MasterBinding = Device->Bindings[j];
+#endif
+ if ((MasterBinding->LocalAddress.NetworkAddress == Binding->LocalAddress.NetworkAddress) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+ break;
+ }
+
+ }
+
+ if (j == i) {
+ i++;
+ continue;
+ }
+
+ //
+ // We have a duplicate. First slide it down to the
+ // end. Note that we change any router entries that
+ // use our real NicId to use the real NicId of the
+ // master (there should be no entries in the rip
+ // database that have the NicId of a binding slave).
+ //
+
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+
+ for (j = i+1; j <= ValidBindings; j++) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, j);
+ INSERT_BINDING(Device, j-1, TmpBinding);
+#else
+ TmpBinding = Device->Bindings[j];
+ Device->Bindings[j-1] = TmpBinding;
+#endif
+ if (TmpBinding) {
+ if ((TmpBinding->Adapter->MacInfo.MediumAsync) &&
+ (TmpBinding->Adapter->FirstWanNicId == TmpBinding->NicId)) {
+ --TmpBinding->Adapter->FirstWanNicId;
+ --TmpBinding->Adapter->LastWanNicId;
+ }
+ --TmpBinding->NicId;
+ }
+ }
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, ValidBindings, Binding);
+#else
+ Device->Bindings[ValidBindings] = Binding;
+#endif
+
+ Binding->NicId = (USHORT)ValidBindings;
+ ++DuplicateCount;
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Keep i the same, to check the new binding at
+ // this position.
+ //
+
+ }
+#ifndef _PNP_POWER
+ Device->HighestExternalNicId = (USHORT)(ValidBindings - DuplicateCount);
+ Device->HighestType20NicId = (USHORT)(ValidBindings-(WanCount+DuplicateCount));
+#else
+ Device->HighestLanNicId -= (USHORT)DuplicateCount;
+
+ if (Device->HighestLanNicId == 0) {
+ CTEAssert(FALSE);
+ }
+
+ Device->HighestExternalNicId -= (USHORT)DuplicateCount;
+ Device->HighestType20NicId -= (USHORT)DuplicateCount;
+ Device->SapNicCount -= (USHORT)DuplicateCount;
+#endif _PNP_POWER
+} /* IpxResolveBindingSets */
+
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding,
+#ifdef _PNP_POWER
+ IN PADAPTER *AdapterPtr,
+#endif
+ IN ULONG FrameTypeIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles binding the transport to a new
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Device - The IPX device object.
+
+ ConfigBinding - The configuration info for this binding.
+
+ AdapterPtr - pointer to the adapter to bind to in case of PnP.
+
+ FrameTypeIndex - The index into ConfigBinding's array of frame
+ types for this adapter. The routine is called once for
+ every valid frame type.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+
+#ifndef _PNP_POWER
+ //
+ // Adapter came in as a parameter
+ //
+ PADAPTER Adapter = NULL;
+#else
+ PADAPTER Adapter = *AdapterPtr;
+#endif
+
+ PBINDING Binding, OldBinding;
+ ULONG FrameType, MappedFrameType;
+ PLIST_ENTRY p;
+
+ //
+ // We can't bind more than one adapter unless we have a
+ // virtual network configured or we are allowed to run
+ // with a virtual network of 0.
+ //
+
+ if (Device->BindingCount == 1) {
+ if ((Device->VirtualNetworkNumber == 0) &&
+ (!Device->VirtualNetworkOptional)) {
+
+ IPX_DEBUG (ADAPTER, ("Cannot bind to more than one adapter\n"));
+ DbgPrint ("IPX: Disallowing multiple bind ==> VirtualNetwork is 0\n");
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 666,
+ STATUS_NOT_SUPPORTED,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+
+ //
+ // First allocate the memory for the binding.
+ //
+
+ status = IpxCreateBinding(
+ Device,
+ ConfigBinding,
+ FrameTypeIndex,
+ ConfigBinding->AdapterName.Buffer,
+ &Binding);
+
+ if (status != STATUS_SUCCESS) {
+ return status;
+ }
+
+ FrameType = ConfigBinding->FrameType[FrameTypeIndex];
+
+//
+// In PnP case, we dont need to check for existing adapters since
+// we supply a NULL adapter in the parameters if it needs to be created
+//
+#ifndef _PNP_POWER
+
+ //
+ // Check if there is already an NDIS binding to this adapter,
+ // and if so, that there is not already a binding with this
+ // frame type.
+ //
+
+
+ for (p = Device->InitialBindingList.Flink;
+ p != &Device->InitialBindingList;
+ p = p->Flink) {
+
+ OldBinding = CONTAINING_RECORD (p, BINDING, InitialLinkage);
+
+ if (RtlEqualMemory(
+ OldBinding->Adapter->AdapterName,
+ ConfigBinding->AdapterName.Buffer,
+ OldBinding->Adapter->AdapterNameLength)) {
+
+ Adapter = OldBinding->Adapter;
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ break;
+
+ }
+ }
+#endif _PNP_POWER
+
+ if (Adapter == NULL) {
+
+ //
+ // No binding to this adapter exists, so create a
+ // new one.
+ //
+
+ status = IpxCreateAdapter(
+ Device,
+ &ConfigBinding->AdapterName,
+ &Adapter);
+
+ if (status != STATUS_SUCCESS) {
+ IpxDestroyBinding(Binding);
+ return status;
+ }
+
+ //
+ // Save these now (they will be the same for all bindings
+ // on this adapter).
+ //
+
+ Adapter->ConfigMaxPacketSize = ConfigBinding->Parameters[BINDING_MAX_PKT_SIZE];
+ Adapter->SourceRouting = (BOOLEAN)ConfigBinding->Parameters[BINDING_SOURCE_ROUTE];
+ Adapter->EnableFunctionalAddress = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_FUNC_ADDR];
+ Adapter->EnableWanRouter = (BOOLEAN)ConfigBinding->Parameters[BINDING_ENABLE_WAN];
+
+ Adapter->BindSap = (USHORT)ConfigBinding->Parameters[BINDING_BIND_SAP];
+ Adapter->BindSapNetworkOrder = REORDER_USHORT(Adapter->BindSap);
+ CTEAssert (Adapter->BindSap == 0x8137);
+ CTEAssert (Adapter->BindSapNetworkOrder == 0x3781);
+
+ //
+ // Now fire up NDIS so this adapter talks
+ //
+
+ status = IpxInitializeNdis(
+ Adapter,
+ ConfigBinding);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // Log an error.
+ //
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 601,
+ status,
+ ConfigBinding->AdapterName.Buffer,
+ 0,
+ NULL);
+
+ IpxDestroyAdapter (Adapter);
+ IpxDestroyBinding (Binding);
+
+ //
+ // Returning this status informs the caller to not
+ // try any more frame types on this adapter.
+ //
+
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+
+ }
+
+ //
+ // For 802.5 bindings we need to start the source routing
+ // timer to time out old entries.
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->SourceRouting)) {
+
+ if (!Device->SourceRoutingUsed) {
+
+ Device->SourceRoutingUsed = TRUE;
+ IpxReferenceDevice (Device, DREF_SR_TIMER);
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+ }
+ }
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ IPX_DEBUG (ADAPTER, ("Create new bind to adapter %ws, type %d\n",
+ ConfigBinding->AdapterName.Buffer,
+ MappedFrameType));
+
+ IpxAllocateReceiveBufferPool (Adapter);
+
+#ifdef _PNP_POWER
+ *AdapterPtr = Adapter;
+#endif
+ }
+#ifdef _PNP_POWER
+ else {
+ //
+ // get the mapped frame type
+ //
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ FrameType,
+ &MappedFrameType);
+
+ if (Adapter->Bindings[MappedFrameType] != NULL) {
+
+ IPX_DEBUG (ADAPTER, ("Bind to adapter %ws, type %d exists\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+
+ //
+ // If this was the auto-detect default for this
+ // adapter and it failed, we need to make the
+ // previous one the default, so that at least
+ // one binding will stick around.
+ //
+
+ if (ConfigBinding->DefaultAutoDetect[FrameTypeIndex]) {
+ IPX_DEBUG (ADAPTER, ("Default auto-detect changed from %d to %d\n",
+ FrameType, MappedFrameType));
+ Adapter->Bindings[MappedFrameType]->DefaultAutoDetect = TRUE;
+ }
+
+ IpxDestroyBinding (Binding);
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ IPX_DEBUG (ADAPTER, ("Using existing bind to adapter %ws, type %d\n",
+ Adapter->AdapterName,
+ MappedFrameType));
+ }
+#endif _PNP_POWER
+
+ //
+ // The local node address starts out the same as the
+ // MAC address of the adapter (on WAN this will change).
+ // The local MAC address can also change for WAN.
+ //
+
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Adapter->LocalMacAddress.Address, 6);
+ RtlCopyMemory (Binding->LocalMacAddress.Address, Adapter->LocalMacAddress.Address, 6);
+
+
+ //
+ // Save the send handler.
+ //
+
+ Binding->SendFrameHandler = NULL;
+ Binding->FrameType = MappedFrameType;
+
+ //
+ // BUGBUG: Put this in InitializeBindingInfo.
+ //
+
+ switch (Adapter->MacInfo.RealMediumType) {
+ case NdisMedium802_3:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrame802_3802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_3802_2; break;
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrame802_3EthernetII; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_3Snap; break;
+ }
+ break;
+ case NdisMedium802_5:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrame802_5802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrame802_5Snap; break;
+ }
+ break;
+ case NdisMediumFddi:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameFddi802_3; break;
+ case ISN_FRAME_TYPE_802_2: Binding->SendFrameHandler = IpxSendFrameFddi802_2; break;
+ case ISN_FRAME_TYPE_SNAP: Binding->SendFrameHandler = IpxSendFrameFddiSnap; break;
+ }
+ break;
+ case NdisMediumArcnet878_2:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_802_3: Binding->SendFrameHandler = IpxSendFrameArcnet878_2; break;
+ }
+ break;
+ case NdisMediumWan:
+ switch (MappedFrameType) {
+ case ISN_FRAME_TYPE_ETHERNET_II: Binding->SendFrameHandler = IpxSendFrameWanEthernetII; break;
+ }
+ break;
+ }
+
+ if (Binding->SendFrameHandler == NULL) {
+ DbgPrint ("BUGBUG!: SendFrameHandler is NULL\n");
+ }
+
+ Adapter->Bindings[MappedFrameType] = Binding;
+ ++Adapter->BindingCount;
+
+ Binding->Adapter = Adapter;
+
+#ifndef _PNP_POWER
+ InsertTailList (&Device->InitialBindingList, &Binding->InitialLinkage);
+#endif _PNP_POWER
+
+ //
+ // NicId and ExternalNicId will be filled in later when the binding
+ // is assigned a spot in the Device->Bindings array.
+ //
+
+ //
+ // Initialize the per-binding MAC information
+ //
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (Adapter->MaxSendPacketSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = Adapter->MaxSendPacketSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ Binding->MediumSpeed = Adapter->MediumSpeed;
+ if (Adapter->MacInfo.MediumAsync) {
+ Binding->LineUp = FALSE;
+ } else {
+ Binding->LineUp = TRUE;
+ }
+
+ MacInitializeBindingInfo(
+ Binding,
+ Adapter);
+
+ return STATUS_SUCCESS;
+
+} /* IpxBindToAdapter */
+
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the specified SourceAddress indicates
+ the packet was sent by us, and FALSE otherwise.
+
+Arguments:
+
+ SourceAddress - The source IPX address.
+
+Return Value:
+
+ TRUE if the address is local.
+
+--*/
+
+{
+ PBINDING Binding;
+ UINT i;
+
+ //
+ // First see if it is a virtual network address or not.
+ //
+
+ if (RtlEqualMemory (VirtualNode, SourceAddress->NodeAddress, 6)) {
+
+ //
+ // This is us if we have a virtual network configured.
+ // If we don't have a virtual node, we fall through to the
+ // other check -- an arcnet card configured as node 1 will
+ // have what we think of as the "virtual node" as its
+ // real node address.
+ //
+
+ if ((IpxDevice->VirtualNetwork) &&
+ (IpxDevice->VirtualNetworkNumber == SourceAddress->NetworkAddress)) {
+ return TRUE;
+ }
+
+ }
+
+ //
+ // Check through our list of adapters to see if one of
+ // them is the source node.
+ //
+ {
+ ULONG Index = MIN (IpxDevice->MaxBindings, IpxDevice->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ if (((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) &&
+#else
+ if (((Binding = IpxDevice->Bindings[i]) != NULL) &&
+#endif _PNP_POWER
+ (RtlEqualMemory (Binding->LocalAddress.NodeAddress, SourceAddress->NodeAddress, 6))) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+
+} /* IpxIsAddressLocal */
+
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles unbinding the transport from an
+ adapter. It can be called at any point during the life
+ of the transport.
+
+Arguments:
+
+ Binding - The adapter to unbind.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PADAPTER Adapter = Binding->Adapter;
+
+ Adapter->Bindings[Binding->FrameType] = NULL;
+ --Adapter->BindingCount;
+
+ IpxDereferenceBinding (Binding, BREF_BOUND);
+
+ if (Adapter->BindingCount == 0) {
+
+ //
+ // DereferenceAdapter is a NULL macro for load-only.
+ //
+ // BUGBUG: Revisit Post 4.0
+ //
+#ifdef _PNP_LATER
+ //
+ // Take away the creation reference. When the in-use ref is taken off,
+ // we destroy this adapter.
+ //
+ IpxDereferenceAdapter(Adapter);
+#else
+ //
+ // Free the packet pools, etc. and close the
+ // adapter.
+ //
+
+ IpxCloseNdis (Adapter);
+
+ IpxDestroyAdapter (Adapter);
+#endif
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxUnBindFromAdapter */
+
+
+VOID
+IpxUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has IPX open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+ IpxDevice->State = DEVICE_STATE_STOPPING;
+
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+
+ //
+ // Walk the list of device contexts.
+ //
+
+ for (i = 1; i <= IpxDevice->BindingCount; i++) {
+#ifdef _PNP_POWER
+ if ((Binding = NIC_ID_TO_BINDING(IpxDevice, i)) != NULL) {
+ INSERT_BINDING(IpxDevice, i, NULL);
+#else
+ if (IpxDevice->Bindings[i] != NULL) {
+ Binding = IpxDevice->Bindings[i];
+ IpxDevice->Bindings[i] = NULL;
+#endif _PNP_POWER
+
+ IpxUnBindFromAdapter (Binding);
+
+ }
+
+ }
+
+#ifdef _PNP_POWER
+
+ IpxFreeMemory ( IpxDevice->Bindings,
+ IpxDevice->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ //
+ // Deallocate the TdiRegistrationAddress and RegistryPathBuffer.
+ //
+ IpxFreeMemory ( IpxDevice->TdiRegistrationAddress,
+ (2 * sizeof(USHORT) + sizeof(TDI_ADDRESS_IPX)),
+ MEMORY_ADDRESS,
+ "Tdi Address");
+
+ IpxFreeMemory ( IpxDevice->RegistryPathBuffer,
+ IpxDevice->RegistryPath.Length + sizeof(WCHAR),
+ MEMORY_CONFIG,
+ "RegistryPathBuffer");
+
+#endif
+
+ KeResetEvent(
+ &IpxDevice->UnloadEvent
+ );
+ IpxDevice->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ IpxDereferenceDevice (IpxDevice, DREF_CREATE);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Now free the padding buffer.
+ //
+
+ IpxFreePaddingBuffer (IpxDevice);
+
+ //
+ // Now do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&IpxDevice->AddressResource);
+ IoDeleteDevice (IpxDevice->DeviceObject);
+
+ //
+ // Finally, remove ourselves as an NDIS protocol.
+ //
+
+ IpxDeregisterProtocol();
+
+} /* IpxUnload */
+
+
+NTSTATUS
+IpxDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPX device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = IpxDevice;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PREQUEST Request;
+ UINT i;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+#ifdef _PNP_POWER
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+ 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 = IpxOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ } else {
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ //
+ // LowPart is in the OPEN_CONTEXT directly.
+ // HighPart goes into the upper 2 bytes of the OPEN_TYPE.
+ //
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier.LowPart);
+
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) = (Device->ControlChannelIdentifier.HighPart << 16);
+ (ULONG)(REQUEST_OPEN_TYPE(Request)) |= IPX_FILE_TYPE_CONTROL;
+
+ ++(Device->ControlChannelIdentifier.QuadPart);
+
+ if (Device->ControlChannelIdentifier.QuadPart > MAX_CCID) {
+ Device->ControlChannelIdentifier.QuadPart = 1;
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile->Address
+ // which is removed by IpxCloseAddressFile.
+ //
+
+ Status = IpxVerifyAddressFile(AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = IpxCloseAddressFile (Device, Request);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ IPX_DEBUG (DEVICE, ("CCID: (%d, %d)\n", ControlChannelId.HighPart, ControlChannelId.LowPart));
+
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+ if (Device->UpperDriverControlChannel[i].QuadPart ==
+ ControlChannelId.QuadPart) {
+ Status = IpxInternalUnbind (Device, i);
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ Status = STATUS_INVALID_HANDLE;
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)(REQUEST_OPEN_TYPE(Request)) & IPX_CC_MASK) {
+ case TDI_TRANSPORT_ADDRESS_FILE:
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile(AddressFile);
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ IpxStopAddressFile (AddressFile);
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IPX_FILE_TYPE_CONTROL:
+ {
+ LARGE_INTEGER ControlChannelId;
+
+ CCID_FROM_REQUEST(ControlChannelId, Request);
+
+ //
+ // Check for any line change IRPs submitted by this
+ // address.
+ //
+
+ IpxAbortLineChanges ((PVOID)&ControlChannelId);
+
+ 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;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* IpxDispatchOpenClose */
+
+#define IOCTL_IPX_LOAD_SPX _IPX_CONTROL_CODE( 0x5678, METHOD_BUFFERED )
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwLoadDriver(
+ IN PUNICODE_STRING DriverServiceName
+ );
+
+
+NTSTATUS
+IpxDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ static NDIS_STRING SpxServiceName = NDIS_STRING_CONST ("\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkSpx");
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ case IOCTL_TDI_QUERY_DIRECT_SENDDG_HANDLER: {
+
+ PULONG EntryPoint;
+
+ //
+ // This is the LanmanServer trying to get the send
+ // entry point.
+ //
+
+ IPX_DEBUG (BIND, ("Direct send entry point being returned\n"));
+
+ EntryPoint = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+ *EntryPoint = (ULONG)IpxTdiSendDatagram;
+
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ break;
+ }
+
+ case IOCTL_IPX_INTERNAL_BIND:
+
+ //
+ // This is a client trying to bind.
+ //
+
+ CTEAssert ((IOCTL_IPX_INTERNAL_BIND & 0x3) == METHOD_BUFFERED);
+ CTEAssert (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
+
+#ifdef _PNP_POWER
+
+ if ((Device->State == DEVICE_STATE_CLOSED) ||
+ (Device->State == DEVICE_STATE_STOPPING)) {
+#else
+ if (Device->State != DEVICE_STATE_OPEN) {
+#endif
+ Status = STATUS_INVALID_DEVICE_STATE;
+
+ } else {
+
+ Status = IpxInternalBind (Device, Irp);
+
+ }
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ case IOCTL_IPX_LOAD_SPX:
+
+ //
+ // The SPX helper dll is asking us to load SPX.
+ //
+
+ Status = ZwLoadDriver (&SpxServiceName);
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ break;
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = IpxDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+ return Status;
+
+} /* IpxDispatchDeviceControl */
+
+
+NTSTATUS
+IpxDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = IpxDevice;
+ PREQUEST Request;
+
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+#if DBG
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+#endif
+
+ //
+ // 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_SEND_DATAGRAM:
+ Status = IpxTdiSendDatagram (DeviceObject, Request);
+ break;
+
+ case TDI_ACTION:
+ Status = IpxTdiAction (Device, Request);
+ break;
+
+ case TDI_QUERY_INFORMATION:
+ Status = IpxTdiQueryInformation (Device, Request);
+ break;
+
+ case TDI_RECEIVE_DATAGRAM:
+ Status = IpxTdiReceiveDatagram (Request);
+ break;
+
+ case TDI_SET_EVENT_HANDLER:
+ Status = IpxTdiSetEventHandler (Request);
+ break;
+
+ case TDI_SET_INFORMATION:
+ Status = IpxTdiSetInformation (Device, Request);
+ break;
+
+
+ //
+ // Something we don't know about was submitted.
+ //
+
+ default:
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ if (Status == STATUS_PENDING) {
+
+ return STATUS_PENDING;
+
+ } else {
+
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+ return Status;
+ }
+
+ } else {
+
+ //
+ // The device was not open.
+ //
+
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+} /* IpxDispatchInternal */
+
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = IpxDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ IpxPrint1 ("IPX: Could not allocate %d: limit\n", BytesNeeded);
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' XPI');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ IpxPrint1("IPX: Could not allocate %d: no pool\n", BytesNeeded);
+ if (ChargeDevice) {
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_TRANSPORT_RESOURCE_POOL,
+ BytesNeeded,
+ Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+} /* IpxpAllocateMemory */
+
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* IpxpFreeMemory */
+
+#if DBG
+
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = IpxpAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &IpxMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* IpxpAllocateTaggedMemory */
+
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with IpxpAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ (VOID)IPX_ADD_ULONG(
+ &IpxMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &IpxMemoryInterlock);
+
+ IpxpFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* IpxpFreeTaggedMemory */
+
+#endif
+
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry which has
+ a %3 value that needs to be converted to a string. It is currently
+ used for EVENT_TRANSPORT_RESOURCE_POOL and EVENT_IPX_INTERNAL_NET_
+ INVALID.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - The transport event code.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated -- will be put in the dump data.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet and converted for use as the %3 string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ PDEVICE Device = IpxDevice;
+ static WCHAR UniqueErrorBuffer[9] = L"00000000";
+ UINT CurrentDigit;
+ INT i;
+
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ i = 8;
+ do {
+ CurrentDigit = TempUniqueError & 0xf;
+ TempUniqueError >>= 4;
+ i--;
+ if (CurrentDigit >= 0xa) {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ UniqueErrorBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ } while (TempUniqueError);
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR));
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ 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 = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer + i, sizeof(UniqueErrorBuffer) - (i * sizeof(WCHAR)));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteResourceErrorLog */
+
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR DriverName[9] = L"NwlnkIpx";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (DeviceObject->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteGeneralErrorLog */
+
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ DeviceObject - Pointer to the system device object.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ PDEVICE Device = IpxDevice;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ DeviceObject,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* IpxWriteOidErrorLog */
+
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ Updates datagram sizes, lookahead sizes, etc. in the Device as a result
+ of a new binding coming in.
+
+Arguments:
+
+ Device - The IPX device object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG AnnouncedMaxDatagram, RealMaxDatagram, MaxLookahead;
+ ULONG LinkSpeed, MacOptions;
+ ULONG i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ IPX_GET_LOCK(&Device->BindAccessLock, &LockHandle);
+
+ //
+ // Calculate some values based on all the bindings.
+ //
+
+ MaxLookahead = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MaxLookaheadData; // largest binding value
+ AnnouncedMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->AnnouncedMaxDatagramSize; // smallest binding value
+ RealMaxDatagram = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->RealMaxDatagramSize; // smallest binding value
+
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->LineUp) {
+ LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed; // smallest binding value
+ } else {
+ LinkSpeed = 0xffffffff;
+ }
+ MacOptions = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->Adapter->MacInfo.MacOptions; // AND of binding values
+
+ for (i = 2; i <= Device->ValidBindings; i++) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ if (Binding->MaxLookaheadData > MaxLookahead) {
+ MaxLookahead = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < AnnouncedMaxDatagram) {
+ AnnouncedMaxDatagram = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < RealMaxDatagram) {
+ RealMaxDatagram = Binding->RealMaxDatagramSize;
+ }
+
+ if (Binding->LineUp && (Binding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = Binding->MediumSpeed;
+ }
+ MacOptions &= Binding->Adapter->MacInfo.MacOptions;
+
+ }
+
+ Device->Information.MaxDatagramSize = AnnouncedMaxDatagram;
+ Device->RealMaxDatagramSize = RealMaxDatagram;
+ Device->Information.MaximumLookaheadData = MaxLookahead;
+
+ //
+ // If we couldn't find anything better, use the speed from
+ // the first binding.
+ //
+
+ if (LinkSpeed == 0xffffffff) {
+ Device->LinkSpeed = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->MediumSpeed;
+ } else {
+ Device->LinkSpeed = LinkSpeed;
+ }
+ Device->MacOptions = MacOptions;
+
+ IPX_FREE_LOCK(&Device->BindAccessLock, LockHandle);
+}
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update the binding array to
+ add the new bindings that appeared in this PnP event.
+ The order of bindings in the array is as follows:
+
+ - First comes the first binding to each LAN network
+ - Following that are all WAN bindings
+ - Following that are any duplicate bindings to LAN networks
+ (the others in the "binding set").
+
+ This routine inserts the bindings while maintaining this
+ order by resolving binding sets.
+
+ The bindings are also inserted into the RIP database.
+
+ If "global wan net" is true we will advertise up to
+ and including the first wan binding as the highest nic
+ id; otherwise we advertise up to and including the last
+ wan binding. In all cases the duplicate bindings are
+ hidden.
+
+ Updates the SapNicCount, Device->FirstLanNicId and Device->FirstWanNicId
+
+Arguments:
+
+ Device - The IPX device object.
+
+ Adapter - The adapter added in this PnP event
+
+ ValidBindings - the number of bindings valid for this adapter (if LAN)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i, j;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS status;
+
+ //
+ // Insert in proper place; if WAN, after all the WAN bindings
+ // If LAN, check for binding sets and insert in proper place
+ // Also, insert into the Rip Tables.
+ //
+
+ //
+ // Go thru' the bindings for this adapter, inserting into the
+ // binding array in place
+ //
+ for (i = 0; i < ConfigBinding->FrameTypeCount; i++) {
+ ULONG MappedFrameType;
+
+ //
+ // Store in the preference order.
+ // Map the frame types since we could have a case where the user selects a FrameType (say, EthernetII on FDDI)
+ // which maps to a different FrameType (802.2). Then we would fail to find the binding in the adapter array;
+ // we could potentialy add a binding twice (if two frame types map to the same Frame, then we would go to the
+ // mapped one twice). This is taken care of by purging dups from the ConfigBinding->FrameType array when we
+ // create the bindings off of the Adapter (see call to IpxBindToAdapter).
+ //
+
+ MacMapFrameType(
+ Adapter->MacInfo.RealMediumType,
+ ConfigBinding->FrameType[i],
+ &MappedFrameType);
+
+ Binding = Adapter->Bindings[MappedFrameType];
+
+ if (!Binding){
+ continue;
+ }
+
+ CTEAssert(Binding->FrameType == MappedFrameType);
+
+ if (Adapter->MacInfo.MediumAsync) {
+ //
+ // WAN: Place after the HighestExternalNicId, with space for WanLine # of bindings.
+ // Update the First/LastWanNicId.
+ //
+ Adapter->FirstWanNicId = (USHORT)Device->HighestExternalNicId+1;
+ Adapter->LastWanNicId = (USHORT)(Device->HighestExternalNicId + Adapter->WanNicIdCount);
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+Adapter->WanNicIdCount >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, Adapter->WanNicIdCount);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // Move Slaves down by WanNicIdCount# of entries
+ //
+ for (j = Device->ValidBindings; j > Device->HighestExternalNicId; j--) {
+ INSERT_BINDING(Device, j+Adapter->WanNicIdCount, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+Adapter->WanNicIdCount)->NicId += (USHORT)Adapter->WanNicIdCount;
+ }
+ }
+
+ //
+ // Insert the WAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestExternalNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestExternalNicId+1);
+
+ Binding->NicId = (USHORT)Device->HighestExternalNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId += (USHORT)Adapter->WanNicIdCount;
+ Device->ValidBindings += (USHORT)Adapter->WanNicIdCount;
+ Device->BindingCount += (USHORT)Adapter->WanNicIdCount;
+ Device->SapNicCount++;
+
+ //
+ // Since we initialize FirstWanNicId to 1, we need to compare against that.
+ // In case of no LAN bindings, we are fine since we have only one WAN binding initally
+ // (all the other WAN lines have place holders).
+ //
+ if (Device->FirstWanNicId == (USHORT)1) {
+ Device->FirstWanNicId = Binding->NicId;
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+
+ //
+ // Since WAN can have only one frame type, break
+ //
+ break;
+
+ } else {
+
+ Device->BindingCount++;
+
+ //
+ // Make sure we dont overflow the array
+ // Re-alloc the array to fit the new bindings
+ //
+ if (Device->ValidBindings+1 >= Device->MaxBindings) {
+ status = IpxPnPReallocateBindingArray(Device, 1);
+ CTEAssert(status == STATUS_SUCCESS);
+ }
+
+ //
+ // LAN: Figure out if it is a slave binding only for non-auto-detect bindings.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (j = 1; j < Index; j++) {
+ MasterBinding = NIC_ID_TO_BINDING_NO_ILOCK(Device, j);
+ if ((MasterBinding->ConfiguredNetworkNumber) &&
+ (MasterBinding->ConfiguredNetworkNumber == Binding->ConfiguredNetworkNumber) &&
+ (MasterBinding->FrameType == Binding->FrameType) &&
+ (MasterBinding->Adapter->MacInfo.MediumType == Binding->Adapter->MacInfo.MediumType)) {
+
+ CTEAssert(Binding->ConfiguredNetworkNumber);
+ break;
+ }
+ }
+ }
+
+ if (j < Device->HighestExternalNicId) {
+ //
+ // Slave binding
+ //
+
+ //
+ // Now make MasterBinding the head of a binding set.
+ //
+
+ if (MasterBinding->BindingSetMember) {
+
+ //
+ // Just insert ourselves in the chain.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %ws is also on network %lx\n",
+ Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Add %lx to binding set of %lx\n", Binding, MasterBinding));
+
+ CTEAssert (MasterBinding->CurrentSendBinding);
+ Binding->NextBinding = MasterBinding->NextBinding;
+
+ } else {
+
+ //
+ // Start the chain with the two bindings in it.
+ //
+
+#if DBG
+ DbgPrint ("IPX: %lx and %lx are on the same network %lx, will load balance\n",
+ MasterBinding->Adapter->AdapterName, Binding->Adapter->AdapterName,
+ REORDER_ULONG (Binding->LocalAddress.NetworkAddress));
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Create new %lx in binding set of %lx\n", Binding, MasterBinding));
+
+ MasterBinding->BindingSetMember = TRUE;
+ MasterBinding->CurrentSendBinding = MasterBinding;
+ MasterBinding->MasterBinding = MasterBinding;
+ Binding->NextBinding = MasterBinding;
+
+ }
+
+ MasterBinding->NextBinding = Binding;
+ Binding->BindingSetMember = TRUE;
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->CurrentSendBinding = NULL;
+ Binding->MasterBinding = MasterBinding;
+
+ //
+ // Since the master binding looks like all members of
+ // the binding set to people querying from above, we have
+ // to make it the worst-case of all the elements. Generally
+ // these will be equal since the frame type and media is
+ // the same.
+ //
+
+ if (Binding->MaxLookaheadData > MasterBinding->MaxLookaheadData) {
+ MasterBinding->MaxLookaheadData = Binding->MaxLookaheadData;
+ }
+ if (Binding->AnnouncedMaxDatagramSize < MasterBinding->AnnouncedMaxDatagramSize) {
+ MasterBinding->AnnouncedMaxDatagramSize = Binding->AnnouncedMaxDatagramSize;
+ }
+ if (Binding->RealMaxDatagramSize < MasterBinding->RealMaxDatagramSize) {
+ MasterBinding->RealMaxDatagramSize = Binding->RealMaxDatagramSize;
+ }
+ if (Binding->MediumSpeed < MasterBinding->MediumSpeed) {
+ MasterBinding->MediumSpeed = Binding->MediumSpeed;
+ }
+
+ //
+ // Place the binding after the last slave binding
+ //
+ INSERT_BINDING(Device, Device->ValidBindings+1, Binding);
+ SET_VERSION(Device, Device->ValidBindings+1);
+
+ Binding->NicId = (USHORT)Device->ValidBindings+1;
+
+ //
+ // Update the indices
+ //
+ Device->ValidBindings++;
+
+ } else {
+
+ //
+ // Not a binding set slave binding - just add it after the last LAN binding
+ //
+
+ //
+ // Move WAN and Slaves down by 1 entry
+ //
+ for (j = Device->ValidBindings; j > Device->HighestLanNicId; j--) {
+ INSERT_BINDING(Device, j+1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ if (NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, j+1)->NicId++;
+ }
+ }
+
+ //
+ // Insert the LAN binding in the place just allocated
+ //
+ INSERT_BINDING(Device, Device->HighestLanNicId+1, Binding);
+ SET_VERSION(Device, Device->HighestLanNicId+1);
+ Binding->NicId = (USHORT)Device->HighestLanNicId+1;
+
+ //
+ // Update the indices
+ //
+ Device->HighestLanNicId++;
+ Device->HighestExternalNicId++;
+ Device->ValidBindings++;
+ Device->HighestType20NicId++;
+ Device->SapNicCount++;
+
+ if (Device->FirstLanNicId == (USHORT)-1) {
+ Device->FirstLanNicId = Binding->NicId;
+ }
+
+ }
+
+ }
+
+ //
+ // Insert this binding in the RIP Tables
+ //
+ if (Binding->ConfiguredNetworkNumber != 0) {
+ status = RipInsertLocalNetwork(
+ Binding->ConfiguredNetworkNumber,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->Adapter->MediumSpeed) / Binding->Adapter->MediumSpeed));
+
+ if ((status == STATUS_SUCCESS) ||
+ (status == STATUS_DUPLICATE_NAME)) {
+
+ Binding->LocalAddress.NetworkAddress = Binding->ConfiguredNetworkNumber;
+ }
+ }
+
+ //
+ // BUGBUGZZ Make this inline later
+ //
+ // This should be done after all the auto-detect bindings have been thrown away.
+ //
+ // IpxPnPUpdateDevice(Device, Binding);
+ }
+} /* IpxPnPUpdateBindingArray */
+
+
+VOID
+IpxPnPToLoad()
+/*++
+
+Routine Description:
+
+ This routine takes the driver to LOADED state (from OPEN) when all
+ PnP adapters have been removed from the machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. When the function returns, the driver is in LOADED state.
+
+--*/
+
+{
+ PBINDING Binding;
+ PREQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ NTSTATUS ntStatus;
+
+ IPX_DEBUG(PNP, ("Going back to loaded state\n"));
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ if ((ntStatus = TdiDeregisterDeviceObject(IpxDevice->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ //
+ // Complete any pending address notify requests.
+ //
+
+ while ((p = ExInterlockedRemoveHeadList(
+ &IpxDevice->AddressNotifyQueue,
+ &IpxDevice->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ REQUEST_STATUS(Request) = STATUS_DEVICE_NOT_READY;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (IpxDevice, Request);
+
+ IpxDereferenceDevice (IpxDevice, DREF_ADDRESS_NOTIFY);
+ }
+
+ //
+ // Cancel the source routing timer if used.
+ //
+
+ if (IpxDevice->SourceRoutingUsed) {
+
+ IpxDevice->SourceRoutingUsed = FALSE;
+ if (CTEStopTimer (&IpxDevice->SourceRoutingTimer)) {
+ IpxDereferenceDevice (IpxDevice, DREF_SR_TIMER);
+ }
+ }
+
+
+ //
+ // Cancel the RIP long timer, and if we do that then
+ // send a RIP DOWN message if needed.
+ //
+
+ if (CTEStopTimer (&IpxDevice->RipLongTimer)) {
+
+ if (IpxDevice->RipResponder) {
+
+ if (RipQueueRequest (IpxDevice->VirtualNetworkNumber, RIP_DOWN) == STATUS_PENDING) {
+
+ //
+ // If we queue a request, it will stop the timer.
+ //
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+
+ IpxDereferenceDevice (IpxDevice, DREF_LONG_TIMER);
+
+ } else {
+
+ //
+ // We couldn't stop the timer, which means it is running,
+ // so we need to wait for the event that is kicked when
+ // the RIP DOWN messages are done.
+ //
+
+ if (IpxDevice->RipResponder) {
+
+ KeWaitForSingleObject(
+ &IpxDevice->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+ }
+ }
+} /* IpxPnPToLoad */
+
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine reallocates the binding array when the number of bindings go above
+ Device->MaxBindings.
+
+Arguments:
+
+ Device - pointer to the device.
+ Size - the number of new entries required.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBIND_ARRAY_ELEM BindingArray;
+ ULONG Pad=2; // extra bindings we keep around
+ ULONG NewSize = Size + Pad + Device->MaxBindings;
+
+ //
+ // The absolute max WAN bindings.
+ //
+ CTEAssert(Size < 2048);
+
+ //
+ // Re-allocate the new array
+ //
+ BindingArray = (PBIND_ARRAY_ELEM)IpxAllocateMemory (
+ NewSize * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ if (BindingArray == NULL) {
+ IpxWriteGeneralErrorLog(
+ (PVOID)Device->DeviceObject,
+ EVENT_IPX_NO_ADAPTERS,
+ 802,
+ STATUS_DEVICE_DOES_NOT_EXIST,
+ NULL,
+ 0,
+ NULL);
+ IpxDereferenceDevice (Device, DREF_CREATE);
+
+ DbgPrint ("Failed to allocate memory in binding array expansion\n");
+
+ //
+ // Unload the driver here? In case of WAN, we can tolerate this failure. What about LAN? [BUGBUGZZ]
+ //
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory (BindingArray, NewSize * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Copy the old array into the new one.
+ //
+ RtlCopyMemory (BindingArray, Device->Bindings, (Device->ValidBindings+1) * sizeof(BIND_ARRAY_ELEM));
+
+ //
+ // Free the old one.
+ //
+ IpxFreeMemory ( Device->Bindings,
+ Device->MaxBindings * sizeof(BIND_ARRAY_ELEM),
+ MEMORY_BINDING,
+ "Binding array");
+
+ IPX_DEBUG(PNP, ("Expand bindarr old: %lx, new: %lx, oldsize: %lx\n",
+ Device->Bindings, BindingArray, Device->MaxBindings));
+
+ //
+ // Use interlocked exchange to assign this since we dont take the BindAccessLock anymore.
+ //
+ // Device->Bindings = BindingArray;
+ SET_VALUE(Device->Bindings, BindingArray);
+
+ Device->MaxBindings = (USHORT)NewSize;
+
+ return STATUS_SUCCESS;
+}
+#endif _PNP_POWER
+
diff --git a/private/ntos/tdi/isnp/ipx/event.c b/private/ntos/tdi/isnp/ipx/event.c
new file mode 100644
index 000000000..a64f85d34
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/event.c
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added a new event type - TDI_EVENT_CHAINED_RECEIVE_DATAGRAM
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Request - Pointer to the request
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+ Status = IpxVerifyAddressFile (AddressFile);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ CTEGetLock (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+
+ switch (Parameters->EventType) {
+
+ case TDI_EVENT_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+ AddressFile->ReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ReceiveDatagramHandler =
+ (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+ //
+ // [SA] New event handler to receive chained buffers
+ //
+ case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)TdiDefaultChainedRcvDatagramHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = NULL;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = FALSE;
+ } else {
+ AddressFile->ChainedReceiveDatagramHandler =
+ (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
+ AddressFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredChainedReceiveDatagramHandler = TRUE;
+ }
+
+ break;
+
+ case TDI_EVENT_ERROR:
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+ AddressFile->ErrorHandlerContext = NULL;
+ AddressFile->RegisteredErrorHandler = FALSE;
+ } else {
+ AddressFile->ErrorHandler =
+ (PTDI_IND_ERROR)Parameters->EventHandler;
+ AddressFile->ErrorHandlerContext = Parameters->EventContext;
+ AddressFile->RegisteredErrorHandler = TRUE;
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } /* switch */
+
+ CTEFreeLock (&AddressFile->Address->Lock, LockHandle);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ REQUEST_INFORMATION(Request) = 0;
+
+ return Status;
+
+} /* IpxTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isnp/ipx/ind.c b/private/ntos/tdi/isnp/ipx/ind.c
new file mode 100644
index 000000000..f43a524bc
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ind.c
@@ -0,0 +1,4047 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ind.c
+
+Abstract:
+
+ This module contains code which implements the indication handler
+ for the IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+
+ 1. Added IpxReceivePacket which receives buffers that can be owned
+ 2. Changed IpxReceiveIndication to call a new function IpxReceiveIndicationNew
+ which takes an extra parameter to indicate whether this is a chained receive or
+ not.
+ 3. Changed IpxProcessDatagram to take the MDL ptr to indicate chained receive,
+ a client count and the headerbuffersize as params.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is declared here so it will be in the same function
+// as IpxReceiveIndication and we can inline it.
+//
+
+
+#if defined(_M_IX86)
+_inline
+#endif
+VOID
+IpxProcessDatagram(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING Binding,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_DATAGRAM_OPTIONS DatagramOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast,
+ IN PINT pTdiClientCount,
+ IN UINT HeaderBufferSize,
+ IN PMDL pMdl,
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routing handles incoming IPX datagrams.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Adapter - The adapter the frame was received on.
+
+ Binding - The binding of the adapter it was received on.
+
+ MacReceiveContext - The context to use when calling
+ NdisTransferData.
+
+ DatagramOptions - Contains the datagram options, which
+ consists of room for the packet type, padding, and
+ the local target of the remote the frame was received from.
+
+ LookaheadBuffer - The lookahead data.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The length of the packet, starting at the IPX
+ header.
+
+ Broadcast - TRUE if the packet was broadcast.
+
+ pTdiClientCount - to return count of the number of TDI clients above us
+ so NDIS can obtain that many ref counts on the buffer.
+
+ HeaderBufferSize - the size of the MAC header buffer - used to determine
+ the offsets into the TSDU.
+
+ pMdl - Mdl chain pointer - non-NULL if chained receive
+
+ BindingContext - In case of loopback, this contains IPX_LOOPBACK_COOKIE
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)LookaheadBuffer;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PADDRESS_FILE ReferencedAddressFile;
+ PREQUEST Request;
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_IPX UNALIGNED * DatagramAddress;
+ ULONG IndicateBytesCopied;
+ IPX_ADDRESS_EXTENDED_FLAGS SourceAddress;
+ ULONG SourceAddressLength;
+ ULONG RequestCount;
+ PNDIS_BUFFER NdisBuffer;
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PIRP Irp;
+ UINT ByteOffset, BytesToTransfer;
+ ULONG BytesTransferred;
+ BOOLEAN LastAddressFile;
+ ULONG IndicateOffset;
+ PNDIS_PACKET ReceivePacket;
+ PIPX_RECEIVE_RESERVED Reserved;
+ PLIST_ENTRY p, q;
+ PSINGLE_LIST_ENTRY s;
+ USHORT DestinationSocket;
+ USHORT SourceSocket;
+ ULONG Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // First scan the device's address database, looking for
+ // the destination socket of this frame.
+ //
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Address = Device->LastAddress) &&
+ (Address->Socket == DestinationSocket)) {
+
+ //
+ // Device->LastAddress cannot be stopping, so
+ // we use it.
+ //
+
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+
+ Hash = IPX_DEST_SOCKET_HASH (IpxHeader);
+
+ for (p = Device->AddressDatabases[Hash].Flink;
+ p != &Device->AddressDatabases[Hash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if ((Address->Socket == DestinationSocket) &&
+ (!Address->Stopping)) {
+ IpxReferenceAddressLock (Address, AREF_RECEIVE);
+ Device->LastAddress = Address;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ goto FoundAddress;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If we had found an address we would have jumped
+ // past here.
+ //
+
+ return;
+
+FoundAddress:
+
+ SourceSocket = *(USHORT UNALIGNED *)&IpxHeader->SourceSocket;
+ IpxBuildTdiAddress(
+ &SourceAddress.IpxAddress,
+ (*(ULONG UNALIGNED *)(IpxHeader->SourceNetwork) == 0) ?
+ Binding->LocalAddress.NetworkAddress :
+ *(UNALIGNED ULONG *)(IpxHeader->SourceNetwork),
+ IpxHeader->SourceNode,
+ SourceSocket);
+
+ DatagramOptions->PacketType = IpxHeader->PacketType;
+
+
+ //
+ // Now that we have found the address, scan its list of
+ // address files for clients that want this datagram.
+ //
+ // If we have to release the address lock to indicate to
+ // a client, we reference the current address file. If
+ // we get an IRP we transfer the reference to that;
+ // otherwise we store the address file in ReferencedAddressFile
+ // and deref it the next time we release the lock.
+ //
+
+ ReferencedAddressFile = NULL;
+ RequestCount = 0;
+
+ ++Device->TempDatagramsReceived;
+ Device->TempDatagramBytesReceived += (PacketSize - sizeof(IPX_HEADER));
+
+ //
+ // If LastAddressFile is TRUE, it means we did an indication
+ // to the client on the last address file in the address'
+ // list, and we did not reacquire the lock when we were
+ // done.
+ //
+
+ LastAddressFile = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue; // next address file
+ }
+
+ //
+ // Set these to the common values, then change them.
+ //
+
+ SourceAddressLength = sizeof(TA_IPX_ADDRESS);
+ IndicateOffset = sizeof(IPX_HEADER);
+
+ if (AddressFile->SpecialReceiveProcessing) {
+
+ //
+ // On dial out lines, we don't indicate packets to
+ // the SAP socket if DisableDialoutSap is set.
+ //
+
+ if ((AddressFile->IsSapSocket) &&
+ (Binding->DialOutAsync) &&
+ (Device->DisableDialoutSap || Device->SingleNetworkActive)) {
+
+ //
+ // Go to the next address file (although it will
+ // likely fail this test too).
+ //
+
+ continue;
+
+ }
+
+ //
+ // Set this, since generally we want it.
+ //
+
+ SourceAddress.PacketType = IpxHeader->PacketType;
+
+ //
+ // See if we fail a packet type filter.
+ //
+
+ if (AddressFile->FilterOnPacketType) {
+ if (AddressFile->FilteredType != IpxHeader->PacketType) {
+ continue;
+ }
+ }
+
+ //
+ // Calculate how long the addresses expected are.
+ //
+
+ if (AddressFile->ReceiveFlagsAddressing ||
+ AddressFile->ExtendedAddressing) {
+
+ SourceAddress.Flags = 0;
+ if (Broadcast) {
+ SourceAddress.Flags = IPX_EXTENDED_FLAG_BROADCAST;
+ }
+ if (IpxIsAddressLocal((TDI_ADDRESS_IPX UNALIGNED *)
+ &SourceAddress.IpxAddress.Address[0].Address[0])) {
+ SourceAddress.Flags |= IPX_EXTENDED_FLAG_LOCAL;
+ }
+ SourceAddressLength = sizeof(IPX_ADDRESS_EXTENDED_FLAGS);
+ SourceAddress.IpxAddress.Address[0].AddressLength +=
+ (sizeof(IPX_ADDRESS_EXTENDED_FLAGS) - sizeof(TA_IPX_ADDRESS));
+
+ }
+
+ //
+ // Determine how much of the packet the client wants.
+ //
+
+ if (AddressFile->ReceiveIpxHeader) {
+ IndicateOffset = 0;
+ }
+ }
+
+ //
+ // First scan the address' receive datagram queue
+ // for datagrams that match. We do a quick check
+ // to see if the list is empty.
+ //
+
+ q = AddressFile->ReceiveDatagramQueue.Flink;
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ do {
+
+ Request = LIST_ENTRY_TO_REQUEST(q);
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReceiveDatagramInformation;
+
+ if ((DatagramInformation != NULL) &&
+ (DatagramInformation->RemoteAddress != NULL) &&
+ (DatagramAddress = IpxParseTdiAddress(DatagramInformation->RemoteAddress)) &&
+ (DatagramAddress->Socket != SourceSocket)) {
+
+ //
+ // The address that this datagram is looking for is
+ // not satisfied by this frame.
+ //
+ // BUGBUG: Speed this up; worry about node and network?
+ //
+
+ q = q->Flink;
+ continue; // next receive datagram on this address file
+
+ } else {
+
+ //
+ // We found a datagram on the queue.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Found RDG on %lx\n", AddressFile));
+ RemoveEntryList (q);
+ REQUEST_INFORMATION(Request) = 0;
+
+ goto HandleDatagram;
+
+ }
+
+ } while (q != &AddressFile->ReceiveDatagramQueue);
+
+ }
+
+ //
+ // If we found a datagram we would have jumped past here,
+ // so looking for a datagram failed; see if the
+ // client has a receive datagram handler registered.
+ //
+
+ //
+ // Look for the chained receive handler if the MDL is not NULL
+ //
+ if (pMdl && AddressFile->RegisteredChainedReceiveDatagramHandler) {
+
+ //
+ // Chained receive both above and below => we indicate the entire MDL up.
+ // Offset the LookaheadBuffer by the size of the MAC header.
+ //
+ LookaheadBufferOffset += HeaderBufferSize;
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IndicateBytesCopied = 0;
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IPX_DEBUG(RECEIVE, ("ChainedIndicate RecvLen: %d, StartOffset: %d, Tsdu: %lx\n",
+ PacketSize - IndicateOffset, IndicateOffset, pMdl));
+
+ //
+ // Will return SUCCESS if the client did not take ownership of the Tsdu
+ // PENDING if the client took ownership and will free it later (using TdiFreeReceiveChain).
+ // DATA_NOT_ACCEPTED if the client did not take ownership and did not copy the data.
+ //
+
+ //
+ // Since NDIS needs an array of PNDIS_PACKETs when the TDI client returns this packet,
+ // we pass the Packet as the ReceiveContext here. The TDI client will pass in the address
+ // of this context on a ReturnPacket.
+ // Also, NDIS needs the PacketArray (not to be confused with the array of packetptrs. mentioned
+ // above) on an NdisTransferData call. These clients dont do this, but other clients like
+ // NB, SPX, RIP or TDI clients that do not have this new interface, can call NdisTransferData
+ // so we pass in the PacketArray as a parameter to them.
+ //
+ Status = (*AddressFile->ChainedReceiveDatagramHandler)(
+ AddressFile->ChainedReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead, // TdiRcvFlags|Adapter->MacInfo.CopyLookahead, Receive datagram flags
+ PacketSize - IndicateOffset, // ReceiveLength
+ IndicateOffset+LookaheadBufferOffset, // StartingOffset
+ pMdl, // Tsdu - MDL chain
+ (PNDIS_PACKET)MacReceiveContext); // TransportContext - pointer to the packet
+
+ if (Status != STATUS_DATA_NOT_ACCEPTED) {
+
+ if (Status == STATUS_PENDING) {
+ //
+ // We assume here that the client referenced the packet which will
+ // be removed when the packet is freed.
+ // Increment the Tdi client count
+ //
+ (*pTdiClientCount)++;
+ }
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+ // RequestCount should always be 0 here.
+ //
+
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+
+ } else {
+ //
+ // Since no IRP can be returned here, we continue to the next addressfile
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ //if (RequestCount == 0) {
+ // return;
+ //}
+ goto BreakWithoutLock;
+ }
+ }
+
+ } else if (AddressFile->RegisteredReceiveDatagramHandler) {
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // Set this so we can exit without reacquiring
+ // the lock.
+ //
+
+ if (p == &Address->AddressFileDatabase) {
+ LastAddressFile = TRUE;
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+ IndicateBytesCopied = 0;
+
+ if (PacketSize > LookaheadBufferSize) {
+ IPX_DEBUG(RECEIVE, ("Indicate %d/%d to %lx on %lx\n",
+ LookaheadBufferSize, PacketSize,
+ AddressFile->ReceiveDatagramHandler, AddressFile));
+ }
+
+ Status = (*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->ReceiveDatagramHandlerContext,
+ SourceAddressLength,
+ &SourceAddress,
+ sizeof(IPX_DATAGRAM_OPTIONS),
+ DatagramOptions,
+ Adapter->MacInfo.CopyLookahead,
+ LookaheadBufferSize - IndicateOffset, // indicated
+ PacketSize - IndicateOffset, // available
+ &IndicateBytesCopied, // taken
+ LookaheadBuffer + IndicateOffset, // data
+ &Irp);
+
+
+ if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The handler accepted the data or did not
+ // return an IRP; in either case there is
+ // nothing else to do, so go to the next
+ // address file.
+ //
+
+ ReferencedAddressFile = AddressFile;
+ if (!LastAddressFile) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ } else {
+
+ //
+ // In this case we have no cleanup, so just leave
+ // if there are no datagrams pending.
+ //
+
+ if (RequestCount == 0) {
+ return;
+ }
+ goto BreakWithoutLock;
+ }
+
+ } else {
+
+ //
+ // The client returned an IRP.
+ //
+
+ IPX_DEBUG (RECEIVE, ("Indicate IRP %lx, taken %d\n", Irp, IndicateBytesCopied));
+
+ Request = IpxAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ ReferencedAddressFile = AddressFile;
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ if (!LastAddressFile) {
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+ }
+
+#if DBG
+ //
+ // Make sure the IRP file object is right.
+ //
+
+ if (IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext != AddressFile) {
+ DbgPrint ("IRP %lx does not match AF %lx, H %lx C %lx\n",
+ Irp, AddressFile,
+ AddressFile->ReceiveDatagramHandler,
+ AddressFile->ReceiveDatagramHandlerContext);
+ DbgBreakPoint();
+ }
+#endif
+ //
+ // Set up the information field so we know
+ // how much to skip in it.
+ //
+
+ IpxTransferReferenceAddressFile (AddressFile, AFREF_INDICATION, AFREF_RCV_DGRAM);
+ REQUEST_INFORMATION(Request) = IndicateBytesCopied;
+
+ //
+ // Fall out of the if and continue via
+ // HandleDatagram...
+ //
+
+ }
+
+ } else {
+
+ //
+ // No posted datagram, no handler; go to the next
+ // address file.
+ //
+
+ continue; // next address file
+
+ }
+
+HandleDatagram:
+
+ //
+ // At this point, Request is set to the request
+ // that will hold for this address file, and
+ // REQUEST_INFORMATION() is the offset to start
+ // the transfer at.
+ //
+
+ //
+ // First copy over the source address while it is handy.
+ //
+
+ DatagramInformation =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->
+ ReturnDatagramInformation;
+
+ if (DatagramInformation != NULL) {
+
+ RtlCopyMemory(
+ DatagramInformation->RemoteAddress,
+ &SourceAddress,
+ (ULONG)DatagramInformation->RemoteAddressLength < SourceAddressLength ?
+ DatagramInformation->RemoteAddressLength : SourceAddressLength);
+ RtlCopyMemory(
+ DatagramInformation->Options,
+ &DatagramOptions,
+ (ULONG)DatagramInformation->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS) ?
+ DatagramInformation->OptionsLength : sizeof(IPX_DATAGRAM_OPTIONS));
+
+ }
+
+ //
+ // Now check if this is the first request that will
+ // take the data, otherwise queue it up.
+ //
+
+ if (RequestCount == 0) {
+
+ //
+ // First one; we need to allocate a packet for the transfer.
+ //
+
+ //if (Address->ReceivePacketInUse) {
+ if (InterlockedExchangeAdd(&Address->ReceivePacketInUse, 0) != 0) {
+ //
+ // Need a packet, check the pool.
+ //
+
+ s = IpxPopReceivePacket (Device);
+
+ if (s == NULL) {
+
+ //
+ // None in pool, fail the request.
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_RECEIVE_RESERVED, PoolLinkage);
+ ReceivePacket = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } else {
+
+ // Address->ReceivePacketInUse = TRUE;
+ InterlockedIncrement(&Address->ReceivePacketInUse);
+
+ ReceivePacket = PACKET(&Address->ReceivePacket);
+ Reserved = RECEIVE_RESERVED(&Address->ReceivePacket);
+
+ }
+
+ CTEAssert (IsListEmpty(&Reserved->Requests));
+
+ Reserved->SingleRequest = Request;
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ ByteOffset = REQUEST_INFORMATION(Request) + LookaheadBufferOffset + IndicateOffset;
+ BytesToTransfer =
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
+
+ if (BytesToTransfer > (PacketSize - IndicateOffset)) {
+ BytesToTransfer = PacketSize - IndicateOffset;
+ }
+
+ } else {
+
+ if (RequestCount == 1) {
+
+ //
+ // There is already one request. We need to
+ // allocate a buffer.
+ //
+
+ s = IpxPopReceiveBuffer (Adapter);
+
+ if (s == NULL) {
+
+ //
+ // No buffers, fail the request.
+ //
+ // BUGBUG: Should we fail the transfer for the
+ // first request too?
+ //
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_INSUFFICIENT_RESOURCES;
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ if (!LastAddressFile) {
+ continue;
+ } else {
+ goto BreakWithoutLock;
+ }
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD(s, IPX_RECEIVE_BUFFER, PoolLinkage);
+ NdisBuffer = ReceiveBuffer->NdisBuffer;
+
+ //
+ // Convert this to a queued multiple piece request.
+ //
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Reserved->SingleRequest));
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = ReceiveBuffer;
+
+ ByteOffset = LookaheadBufferOffset;
+ BytesToTransfer = PacketSize;
+
+ }
+
+ InsertTailList(&Reserved->Requests, REQUEST_LINKAGE(Request));
+
+ }
+
+ //
+ // We are done setting up this address file's transfer,
+ // proceed to the next one.
+ //
+
+ ++RequestCount;
+
+ if (LastAddressFile) {
+ goto BreakWithoutLock;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+BreakWithoutLock:
+
+ if (ReferencedAddressFile) {
+ IpxDereferenceAddressFileSync (ReferencedAddressFile, AFREF_INDICATION);
+ ReferencedAddressFile = NULL;
+ }
+
+
+ //
+ // We can be transferring directly into a request's buffer,
+ // transferring into an intermediate buffer, or not
+ // receiving the packet at all.
+ //
+
+ if (RequestCount > 0) {
+
+ //
+ // If this is true, then ReceivePacket, Reserved,
+ // and NdisBuffer are all set up correctly.
+ //
+
+ CTEAssert (ReceivePacket);
+ CTEAssert (Reserved == (PIPX_RECEIVE_RESERVED)(ReceivePacket->ProtocolReserved));
+
+
+ NdisChainBufferAtFront(ReceivePacket, NdisBuffer);
+
+ IPX_DEBUG (RECEIVE, ("Transfer into %lx, offset %d bytes %d\n",
+ NdisBuffer, ByteOffset, BytesToTransfer));
+
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("Loopback Copy from packet: %lx to packet: %lx\n", ReceivePacket, MacReceiveContext));
+
+ NdisCopyFromPacketToPacket(
+ ReceivePacket, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset - loopback packet
+ &BytesTransferred); // BytesCopied
+
+ NdisStatus = NDIS_STATUS_SUCCESS;
+
+ } else {
+ NdisTransferData(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ ReceivePacket,
+ &BytesTransferred);
+ }
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ IpxTransferDataComplete(
+ (NDIS_HANDLE)Adapter,
+ ReceivePacket,
+ NdisStatus,
+ BytesTransferred);
+ }
+ }
+
+
+ IpxDereferenceAddressSync (Address, AREF_RECEIVE);
+
+} /* IpxProcessDatagram */
+
+
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+ //
+ // Call the actual receive indication handler and indicate that this is not a
+ // chained receive
+ //
+
+ return IpxReceiveIndicationNew (
+ BindingContext,
+ ReceiveContext, // ReceiveContext
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ PacketSize, // PacketSize
+ NULL, // pMdl - non-NULL => chained receive.
+ NULL // pTdiClientCount - used in chained recv case to keep count of TDI clients
+ );
+
+}
+
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ This routine is time critical, so we only allocate a
+ buffer and copy the packet into it. We also perform minimal
+ validation on this packet. It gets queued to the device context
+ to allow for processing later.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ ReceiveContext - A magic cookie for the MAC.
+
+ HeaderBuffer - pointer to a buffer containing the packet header.
+
+ HeaderBufferSize - the size of the header.
+
+ LookaheadBuffer - pointer to a buffer containing the negotiated minimum
+ amount of buffer I get to look at (not including header).
+
+ LookaheadBufferSize - the size of the above. May be less than asked
+ for, if that's all there is.
+
+ PacketSize - Overall size of the packet (not including header).
+
+ pMdl - pointer to MDL chain if chained, NULL if this came from indication.
+
+Return Value:
+
+ NDIS_STATUS - status of operation, one of:
+
+ NDIS_STATUS_SUCCESS if packet accepted,
+ NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
+ NDIS_any_other_thing if I understand, but can't handle.
+
+--*/
+{
+
+ IPX_DATAGRAM_OPTIONS DatagramOptions;
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PBINDING Binding;
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header = (PUCHAR)HeaderBuffer;
+ PUCHAR Lookahead = (PUCHAR)LookaheadBuffer;
+ ULONG PacketLength;
+ UINT IpxPacketSize;
+ ULONG Length802_3;
+ USHORT Saps;
+ ULONG DestinationNetwork;
+ ULONG SourceNetwork;
+ PUCHAR DestinationNode;
+ USHORT DestinationSocket;
+ ULONG IpxHeaderOffset;
+ PIPX_HEADER IpxHeader;
+ UINT i;
+ BOOLEAN IsBroadcast;
+ BOOLEAN IsLoopback = FALSE;
+#if DBG
+ PUCHAR DestMacAddress;
+ ULONG ReceiveFlag;
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif _PNP_POWER
+
+ //
+ // Reject packets that are too short to hold even the
+ // basic IPX header (this ignores any extra 802.2 etc.
+ // headers but is good enough because a runt will fail
+ // the IPX header packet length check).
+ //
+
+ if (PacketSize < sizeof(IPX_HEADER)) {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // If this is a loopback packet, no need to do figure out the
+ // MAC header.
+ //
+ if (BindingContext == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+#ifdef _PNP_POWER
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, 1);
+
+ if (!Binding) {
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, 0);
+#else
+ if ((Binding = IpxDevice->Bindings[1]) == NULL) {
+ goto NotValidLoopback;
+ }
+
+ Adapter = Binding->Adapter;
+
+ DatagramOptions.LocalTarget.NicId = 0;
+#endif
+
+ //
+ // Do this copy later, from the IpxHeader.
+ //
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+ }
+
+ //
+ // Ipx header starts at the top of the LookAheadBuffer
+ //
+ IpxHeaderOffset = 0;
+
+ IPX_DEBUG (LOOPB, ("Loopback packet received: %lx\n", ReceiveContext));
+
+#if DBG
+ DestMacAddress = DatagramOptions.LocalTarget.MacAddress;
+#endif
+
+ IsLoopback = TRUE;
+ goto Loopback;
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Bump up the ref count so the adapter doesn't disappear from under
+ // us.
+ //
+ IpxReferenceAdapter(Adapter);
+#endif
+
+ //
+ // The first step is to construct the 8-byte local
+ // target from the packet. We store it in the 9-byte
+ // datagram options, leaving one byte at the front
+ // for use by IpxProcessDatagram when indicating to
+ // its TDI clients.
+ //
+
+#if DBG
+ Binding = NULL;
+#endif
+
+ if (Adapter->MacInfo.MediumType == NdisMedium802_3) {
+
+ //
+ // Try to figure out what the packet type is.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Header[12] < 0x06) {
+
+ //
+ // An 802.3 header; check the next bytes. They may
+ // be E0/E0 (802.2), FFFF (raw 802.3) or A0/A0 (SNAP).
+ //
+
+ Saps = *(UNALIGNED USHORT *)(Lookahead);
+
+ if (Saps == 0xffff) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 0;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+
+ } else if (Saps == 0xe0e0) {
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 3;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_3;
+ }
+ IpxHeaderOffset = 8;
+ Length802_3 = ((Header[12] << 8) | Header[13]);
+ goto Valid802_3;
+ }
+ }
+
+ goto NotValid802_3;
+
+ } else {
+
+ //
+ // It has an ethertype, see if it is ours.
+ //
+
+ if (*(UNALIGNED USHORT *)(Header+12) == Adapter->BindSapNetworkOrder) {
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ *((ULONG UNALIGNED *)(&Binding)) = *((ULONG UNALIGNED *)(&Header[2]));
+
+ CTEAssert(Binding != NULL);
+
+ if ((Binding != NULL) &&
+ (Binding->LineUp)) {
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+
+ //
+ // Check if this is a type 20 packet and
+ // we are disabling them on dialin lines -- we do
+ // this check here to avoid impacting the main
+ // indication path for LANs.
+ //
+ // The 0x02 bit of DisableDialinNetbios controls
+ // WAN->LAN packets, which we handle here.
+ //
+
+ if ((!Binding->DialOutAsync) &&
+ ((Device->DisableDialinNetbios & 0x02) != 0)) {
+
+ IpxHeader = (PIPX_HEADER)Lookahead; // IpxHeaderOffset is 0
+ if (IpxHeader->PacketType == 0x14) {
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ return STATUS_SUCCESS;
+ }
+ }
+
+ goto Valid802_3;
+ }
+ goto NotValid802_3;
+
+ } else if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_ETHERNET_II]) == NULL) {
+ goto NotValid802_3;
+ }
+
+ IpxHeaderOffset = 0;
+ Length802_3 = PacketSize; // set this so the check succeeds
+ goto Valid802_3;
+
+ }
+ }
+
+ goto NotValid802_3;
+
+Valid802_3:
+
+ if (Length802_3 > PacketSize) {
+ goto NotValid802_3;
+ } else if (Length802_3 < PacketSize) {
+ PacketSize = Length802_3;
+ if (LookaheadBufferSize > Length802_3) {
+ LookaheadBufferSize = Length802_3;
+ }
+ }
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+6, 6);
+#if DBG
+ DestMacAddress = Header;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMedium802_5) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValid802_5;
+ }
+
+ IpxHeaderOffset = 3;
+ goto Valid802_5;
+ }
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValid802_5;
+ }
+ IpxHeaderOffset = 8;
+ goto Valid802_5;
+ }
+ }
+
+ goto NotValid802_5;
+
+Valid802_5:
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+8, 6);
+ DatagramOptions.LocalTarget.MacAddress[0] &= 0x7f;
+
+#if DBG
+ DestMacAddress = Header+2;
+#endif
+
+ } else if (Adapter->MacInfo.MediumType == NdisMediumFddi) {
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ Saps = *(USHORT UNALIGNED *)(Lookahead);
+
+ if (Saps == 0xe0e0) {
+
+ if (Lookahead[2] == 0x03) {
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 3;
+ goto ValidFddi;
+ }
+
+ } else if (Saps == 0xffff) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 0;
+ goto ValidFddi;
+
+ } else if (Saps == 0xaaaa) {
+
+ if ((Lookahead[2] == 0x03) &&
+ (*(UNALIGNED USHORT *)(Lookahead+6) == Adapter->BindSapNetworkOrder)) {
+
+ if ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP]) == NULL) {
+ goto NotValidFddi;
+ }
+ IpxHeaderOffset = 8;
+ goto ValidFddi;
+ }
+ }
+
+ goto NotValidFddi;
+
+ValidFddi:
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, Header+7, 6);
+
+#if DBG
+ DestMacAddress = Header+1;
+#endif
+
+
+ } else {
+
+ //
+ // NdisMediumArcnet878_2
+ //
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ if ((Header[2] == ARCNET_PROTOCOL_ID) &&
+ ((Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_3]) != NULL)) {
+
+ IpxHeaderOffset = 0;
+ RtlZeroMemory (DatagramOptions.LocalTarget.MacAddress, 5);
+ DatagramOptions.LocalTarget.MacAddress[5] = Header[0];
+
+ } else {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+1, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+ }
+
+#if DBG
+ DestMacAddress = Header+2; // BUGBUG Need to log less than six bytes
+#endif
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+
+ //
+ // Make sure this didn't slip through.
+ //
+
+ CTEAssert (Binding != NULL);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->NicId;
+#endif
+
+Loopback:
+
+ //
+ // Now that we have validated the header and constructed
+ // the local target, indicate the packet to the correct
+ // client.
+ //
+
+ IpxHeader = (PIPX_HEADER)(Lookahead + IpxHeaderOffset);
+
+ PacketLength = (IpxHeader->PacketLength[0] << 8) | IpxHeader->PacketLength[1];
+
+ IpxPacketSize = PacketSize - IpxHeaderOffset;
+
+ if (PacketLength > IpxPacketSize) {
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, DestMacAddress, DatagramOptions.LocalTarget.MacAddress, (USHORT)PacketSize, IpxHeader, IpxHeader+1);
+ }
+#endif
+ IPX_DEBUG (BAD_PACKET, ("Packet len %d, IPX len %d\n",
+ PacketLength, IpxPacketSize));
+
+ return NDIS_STATUS_SUCCESS;
+
+ } else if (PacketLength < IpxPacketSize) {
+
+ IpxPacketSize = PacketLength;
+ if (LookaheadBufferSize > (PacketLength + IpxHeaderOffset)) {
+ LookaheadBufferSize = PacketLength + IpxHeaderOffset;
+ }
+
+ }
+
+ //
+ // Bug #33595 - (hotfixed in 3.51, checked into 4.0 beta2)
+ // Customer problem where NT allowed RIP/SAP to reply to an 802.5 functional address in the IPX source node. The source
+ // MAC address was proper in this case. We need to check for the case where if the packet's source network is the same
+ // as that of the binding it came on (=> did not come thru a router), then the SourceNodeAddress in the IPX header
+ // should be equal to the SourceAddress in the MAC header.
+ //
+ // This check is controlled through a registry value - VerifySourceAddress.
+ // In case of Arcnet, this check will not succeed.
+ // Also, for WAN, the node addresses will not match, so avoid check for those.
+
+ //
+ // If the source network is 0, we drop it. Auto-detect frames should have matching node (MAC) addresses.
+ // Loopback packets dont have a valid header, so skip this test for them.
+ //
+ // BUGBUG: For loopback pkts, do all the processing above, so we can avoid all these checks for IsLoopback here.
+ // Also, to prevent the RtlCopyMemory into the localtarget above, try to use the MAC header to indicate the
+ // correct binding to us so we dont use the first one always.
+ //
+ // CAVEAT:: when using the MAC header as a binding pointer, ensure that we use the adapter corresp, to that binding
+ // to enque all the receive requests. currently we enqueue them onto the first bindings adapter.
+ //
+ if (((*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (*(UNALIGNED ULONG *)IpxHeader->SourceNetwork == 0)) &&
+ (!IPX_NODE_EQUAL (IpxHeader->SourceNode, DatagramOptions.LocalTarget.MacAddress)) &&
+ Device->VerifySourceAddress &&
+ !IsLoopback &&
+ !Adapter->MacInfo.MediumAsync &&
+ (Adapter->MacInfo.MediumType != NdisMediumArcnet878_2)) {
+
+ IPX_DEBUG(BAD_PACKET, ("Local packet: Src MAC %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x ",
+ DatagramOptions.LocalTarget.MacAddress[0],
+ DatagramOptions.LocalTarget.MacAddress[1],
+ DatagramOptions.LocalTarget.MacAddress[2],
+ DatagramOptions.LocalTarget.MacAddress[3],
+ DatagramOptions.LocalTarget.MacAddress[4],
+ DatagramOptions.LocalTarget.MacAddress[5]));
+
+ IPX_DEBUG(BAD_PACKET, ("IPX Src Node %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+
+#ifdef IPX_PACKET_LOG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ DestinationSocket = *(USHORT UNALIGNED *)&IpxHeader->DestinationSocket;
+
+ //
+ // In order to have consistent local targets, copy over the target from the IpxHeader.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet copied the localtarget: %lx\n", IpxHeader->DestinationNode));
+ // RtlCopyMemory (DatagramOptions.LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ *((UNALIGNED ULONG *)DatagramOptions.LocalTarget.MacAddress) =
+ *((UNALIGNED ULONG *)IpxHeader->DestinationNode);
+
+ *((UNALIGNED USHORT *)(DatagramOptions.LocalTarget.MacAddress+4)) =
+ *((UNALIGNED USHORT *)(IpxHeader->DestinationNode+4));
+ }
+
+ ++Device->Statistics.PacketsReceived;
+
+ if (DestinationSocket != RIP_SOCKET) {
+
+ DestinationNetwork = *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork;
+ DestinationNode = IpxHeader->DestinationNode;
+
+RecheckPacket:
+
+ if (Device->MultiCardZeroVirtual) {
+
+ if ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ } else {
+
+ if ((DestinationNetwork == Device->SourceAddress.NetworkAddress) ||
+ (DestinationNetwork == 0)) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Device->SourceAddress.NodeAddress)) {
+ IsBroadcast = FALSE;
+ goto DestinationOk;
+ } else {
+ if ((IsBroadcast = IPX_NODE_BROADCAST(DestinationNode)) &&
+ (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+ }
+ } else {
+ IsBroadcast = IPX_NODE_BROADCAST(DestinationNode);
+ }
+
+ //
+ // We need to check for frames that are sent to the
+ // binding node and net, because if we have a virtual
+ // net we won't catch them in the check above. This
+ // will include any Netbios frames, since they don't
+ // use the virtual net. Doing the check like this will slow
+ // down netbios indications just a bit on a machine with
+ // a virtual network, but it saves a jump for other traffic
+ // vs. adding the check up there (the assumption is if we
+ // have a virtual net most traffic is NCP).
+ //
+ // Note that IsBroadcast is already set, so we don't have
+ // to do that.
+ //
+
+ if ((Device->VirtualNetwork) &&
+ ((DestinationNetwork == Binding->LocalAddress.NetworkAddress) ||
+ (DestinationNetwork == 0))) {
+
+ if (IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress)) {
+ goto DestinationOk;
+ } else {
+ if (IsBroadcast && (Binding->ReceiveBroadcast)) {
+ goto DestinationOk;
+ }
+
+ }
+
+ //
+ // If this is a binding set slave, check for the master's
+ // address.
+ //
+
+ if ((Binding->BindingSetMember) &&
+ (IPX_NODE_EQUAL (DestinationNode, Binding->MasterBinding->LocalAddress.NodeAddress))) {
+ goto DestinationOk;
+ }
+ }
+ }
+
+ //
+ // If this was a loopback packet that was sent on the second binding (but showed back up on the first one),
+ // then the networknumbers will not match. Allow the receive on the first binding itself.
+ //
+ if (IsLoopback) {
+ IPX_DEBUG (LOOPB, ("Loopback packet forced on first binding: %lx\n", ReceiveContext));
+ goto DestinationOk;
+ }
+
+ //
+ // If we did not receive this packet, it might be because
+ // our network is still 0 and this packet was actually
+ // sent to the real network number. If so we try to
+ // update our local address, and if successful we
+ // re-check the packet. We don't insert if we are
+ // not done with auto detection, to avoid colliding
+ // with that.
+ //
+ // To avoid problems if we are a router, we only update
+ // on packets that are broadcast or sent to us.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ (Device->AutoDetectState == AUTO_DETECT_STATE_DONE) &&
+ (DestinationNetwork != 0) &&
+ (IsBroadcast ||
+ IPX_NODE_EQUAL (DestinationNode, Binding->LocalAddress.NodeAddress))) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ DestinationNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d reconfigured to network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ //
+ // Jump back and re-process the packet; we know
+ // we won't loop through here again because the
+ // binding's network is now non-zero.
+ //
+
+ goto RecheckPacket;
+
+ }
+ }
+
+
+ //
+ // The only frames that will not already have jumped to
+ // DestinationOk are those to or from the SAP socket,
+ // so we check for those.
+ //
+
+ if ((*(USHORT UNALIGNED *)&IpxHeader->SourceSocket == SAP_SOCKET) ||
+ (DestinationSocket == SAP_SOCKET)) {
+
+DestinationOk:
+
+ //
+ // An IPX packet sent to us, or a SAP packet (which
+ // are not sent to the virtual address but still need
+ // to be indicated and not forwarded to RIP).
+ //
+
+ if (DestinationSocket == NB_SOCKET) {
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_NB | IPX_PACKET_LOG_RCV_ALL;
+#endif
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_NB].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_NB])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_NB, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We add HeaderBufferSize to the IpxHeaderOffset field since we do an NdisCopyFromPacketToPacket
+ // in IpxTransferData, which needs offset from the beginning of the packet.
+ // NdisTransferData adds the offset passed in to the beginning of the IPX packet.
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_NB] = TRUE;
+ }
+
+ //
+ // The router needs to see Netbios type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+
+ } else if (IpxHeader->PacketType == SPX_PACKET_TYPE) {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SPX | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ if (((!IsBroadcast) || (Device->UpperDrivers[IDENTIFIER_SPX].BroadcastEnable)) &&
+ (Device->UpperDriverBound[IDENTIFIER_SPX])) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_SPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_SPX] = TRUE;
+ }
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Received packet type %d, length %d\n",
+ Binding->FrameType,
+ IpxPacketSize));
+ IPX_DEBUG (RECEIVE, ("Source %lx %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(USHORT UNALIGNED *)&IpxHeader->SourceSocket,
+ IpxHeader->SourceNetwork[0],
+ IpxHeader->SourceNetwork[1],
+ IpxHeader->SourceNetwork[2],
+ IpxHeader->SourceNetwork[3],
+ IpxHeader->SourceNode[0],
+ IpxHeader->SourceNode[1],
+ IpxHeader->SourceNode[2],
+ IpxHeader->SourceNode[3],
+ IpxHeader->SourceNode[4],
+ IpxHeader->SourceNode[5]));
+ IPX_DEBUG (RECEIVE, ("Destination %d %2.2x-%2.2x-%2.2x-%2.2x %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ DestinationSocket,
+ IpxHeader->DestinationNetwork[0],
+ IpxHeader->DestinationNetwork[1],
+ IpxHeader->DestinationNetwork[2],
+ IpxHeader->DestinationNetwork[3],
+ IpxHeader->DestinationNode[0],
+ IpxHeader->DestinationNode[1],
+ IpxHeader->DestinationNode[2],
+ IpxHeader->DestinationNode[3],
+ IpxHeader->DestinationNode[4],
+ IpxHeader->DestinationNode[5]));
+
+#if DBG
+ if (IpxHeader->DestinationSocket == IpxPacketLogSocket) {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_SOCKET | IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ } else {
+ ReceiveFlag = IPX_PACKET_LOG_RCV_OTHER | IPX_PACKET_LOG_RCV_ALL;
+ }
+#endif
+
+ //
+ // Fiddle with this if so in the general case
+ // the jump is not made (BUGBUG the compiler
+ // still rearranges it).
+ //
+
+ if (Adapter->MacInfo.MediumType != NdisMedium802_5) {
+
+CallProcessDatagram:
+ //
+ // [SA] Returns a status now which needs to be returned to NDIS
+ // Also, MDL is passed in.
+ // We need to pass in the HeaderBufferSize too....
+ //
+ IpxProcessDatagram(
+ Device,
+ Adapter,
+ Binding,
+ ReceiveContext,
+ &DatagramOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset, // lookaheadbufferoffset
+ IpxPacketSize,
+ IsBroadcast,
+ pTdiClientCount,
+ HeaderBufferSize,
+ pMdl,
+ BindingContext);
+
+ } else {
+ if (!IsLoopback) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+ goto CallProcessDatagram;
+ }
+
+ //
+ // The router needs to see type 20 broadcasts.
+ //
+
+ if (IsBroadcast &&
+ (IpxHeader->PacketType == 0x14) &&
+ (Binding->ReceiveBroadcast)) {
+ goto RipIndication;
+ }
+ }
+
+ } else {
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // We need to let non-type 20 broadcast frames go to RIP to allow for lan-specific
+ // broadcasts. For logon over IPX, this allows the logon request to get thru the WAN
+ // line.
+ //
+ // if ( !IsBroadcast ) {
+
+RipIndication:;
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_RIP, Adapter, Header, HeaderBufferSize);
+ }
+
+ //
+ // We hide binding sets from the router, to avoid
+ // misordering packets which it routes.
+ //
+
+ if (!IsLoopback && Binding->BindingSetMember) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&DatagramOptions.LocalTarget, MIN (Device->MaxBindings, Binding->MasterBinding->NicId));
+#else
+ DatagramOptions.LocalTarget.NicId = Binding->MasterBinding->NicId;
+#endif
+ }
+
+ (*Device->UpperDrivers[IDENTIFIER_RIP].ReceiveHandler)(
+ (IsLoopback) ? BindingContext : Adapter->NdisBindingHandle,
+ ReceiveContext,
+ &DatagramOptions.LocalTarget,
+ Adapter->MacInfo.MacOptions,
+ (PUCHAR)IpxHeader,
+ LookaheadBufferSize - IpxHeaderOffset,
+ (IsLoopback) ? IpxHeaderOffset+HeaderBufferSize : IpxHeaderOffset,
+ IpxPacketSize);
+
+ Device->ReceiveCompletePending[IDENTIFIER_RIP] = TRUE;
+ }
+ // }
+ }
+
+ } else {
+
+ if ((Binding->ReceiveBroadcast) ||
+ (!IPX_NODE_BROADCAST(IpxHeader->DestinationNode))) {
+
+ SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork;
+
+ //
+ // Sent to the RIP socket; check if this binding needs a
+ // network number.
+ //
+
+ if ((Binding->LocalAddress.NetworkAddress == 0) &&
+ ((SourceNetwork = *(UNALIGNED LONG *)IpxHeader->SourceNetwork) != 0)) {
+
+ switch (Device->AutoDetectState) {
+
+ case AUTO_DETECT_STATE_DONE:
+
+ //
+ // We are done with auto-detect and running.
+ // Make sure this packet is useful. If the source
+ // MAC address and source IPX node are the same then
+ // it was not routed, and we also check that it is not
+ // an IPX broadcast (otherwise a misconfigured client
+ // might confuse us).
+ //
+
+ if ((RtlEqualMemory(
+ IpxHeader->SourceNode,
+ DatagramOptions.LocalTarget.MacAddress,
+ 6)) &&
+ (*(UNALIGNED ULONG *)(IpxHeader->DestinationNode) != 0xffffffff) &&
+ (*(UNALIGNED USHORT *)(IpxHeader->DestinationNode+4) != 0xffff)) {
+
+ CTEAssert (Binding->NicId != 0);
+
+ if (IpxUpdateBindingNetwork(
+ Device,
+ Binding,
+ *(UNALIGNED LONG *)IpxHeader->SourceNetwork) == STATUS_SUCCESS) {
+
+ IPX_DEBUG (RIP, ("Binding %d is network %lx\n",
+ Binding->NicId,
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress)));
+
+ }
+ }
+
+ break;
+
+ case AUTO_DETECT_STATE_RUNNING:
+
+ //
+ // We are waiting for rip responses to figure out our
+ // network number. We count the responses that match
+ // and do not match our current value; when the non-
+ // matching number exceeds it we switch (to whatever
+ // this frame happens to have). Note that on the first
+ // non-zero response this will be the case and we will
+ // switch to that network.
+ //
+ // After auto-detect is done we call RipInsertLocalNetwork
+ // for whatever the current network is on each binding.
+ //
+
+ if (SourceNetwork == Binding->TentativeNetworkAddress) {
+
+ ++Binding->MatchingResponses;
+
+ } else {
+
+ ++Binding->NonMatchingResponses;
+
+ if (Binding->NonMatchingResponses > Binding->MatchingResponses) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Switching to net %lx on %lx (%d - %d)\n",
+ REORDER_ULONG(SourceNetwork),
+ Binding,
+ Binding->NonMatchingResponses,
+ Binding->MatchingResponses));
+
+ Binding->TentativeNetworkAddress = SourceNetwork;
+ Binding->MatchingResponses = 1;
+ Binding->NonMatchingResponses = 0;
+ }
+
+ }
+
+ //
+ // If we are auto-detecting and we have just found
+ // a default, set this so that RIP stops trying
+ // to auto-detect on other nets. BUGBUG: Unless we
+ // are on a server doing multiple detects.
+ //
+
+ if (Binding->DefaultAutoDetect) {
+ Adapter->DefaultAutoDetected = TRUE;
+ }
+ Adapter->AutoDetectResponse = TRUE;
+
+ break;
+
+ default:
+
+ //
+ // We are still initializing, or are processing auto-detect
+ // responses, not the right time to start updating stuff.
+ //
+
+ break;
+
+ }
+
+ }
+
+
+ //
+ // See if any packets are waiting for a RIP response.
+ //
+
+ if (Device->RipPacketCount > 0) {
+
+ RIP_PACKET UNALIGNED * RipPacket = (RIP_PACKET UNALIGNED *)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_RESPONSE) &&
+ (RipPacket->NetworkEntry.NetworkNumber != 0xffffffff)) {
+
+ RipProcessResponse(
+ Device,
+ &DatagramOptions.LocalTarget,
+ RipPacket);
+ }
+ }
+
+
+ //
+ // See if this is a RIP response for our virtual network
+ // and we are the only person who could respond to it.
+ // We also respond to general queries on WAN lines since
+ // we are the only machine on it.
+ //
+
+ if (Device->RipResponder) {
+
+ PRIP_PACKET RipPacket =
+ (PRIP_PACKET)(IpxHeader+1);
+
+ if ((IpxPacketSize >= sizeof(IPX_HEADER) + sizeof(RIP_PACKET)) &&
+ (RipPacket->Operation == RIP_REQUEST) &&
+ ((RipPacket->NetworkEntry.NetworkNumber == Device->VirtualNetworkNumber) ||
+ (Adapter->MacInfo.MediumAsync && (RipPacket->NetworkEntry.NetworkNumber == 0xffffffff)))) {
+
+ //
+ // Update this so our response goes out correctly.
+ //
+
+ if (!IsLoopback && Adapter->MacInfo.MediumType == NdisMedium802_5) {
+ MacUpdateSourceRouting (IDENTIFIER_IPX, Adapter, Header, HeaderBufferSize);
+ }
+
+ RipSendResponse(
+ Binding,
+ (TDI_ADDRESS_IPX UNALIGNED *)(IpxHeader->SourceNetwork),
+ &DatagramOptions.LocalTarget);
+ }
+ }
+
+#if DBG
+ ReceiveFlag = IPX_PACKET_LOG_RCV_RIP | IPX_PACKET_LOG_RCV_ALL;
+#endif
+
+ //
+ // See if the RIP upper driver wants it too.
+ //
+
+ goto RipIndication;
+ }
+
+ }
+
+
+#ifdef _PNP_POWER
+ IpxDereferenceAdapter(Adapter);
+ IpxDereferenceBinding1(Binding, BREF_ADAPTER_ACCESS);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(ReceiveFlag)) {
+ IpxLogPacket(
+ FALSE,
+ DestMacAddress,
+ DatagramOptions.LocalTarget.MacAddress,
+ (USHORT)IpxPacketSize,
+ IpxHeader,
+ IpxHeader+1);
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+ //
+ // These are the failure routines for the various media types.
+ // They only differ in the debug logging.
+ //
+
+NotValid802_3:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header, Header+6, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValid802_5:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+2, Header+8, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+ return NDIS_STATUS_SUCCESS;
+
+NotValidFddi:
+
+#ifdef _PNP_POWER
+
+ IpxDereferenceAdapter(Adapter);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+NotValidLoopback:
+
+#ifdef IPX_PACKET_LOG
+ if (PACKET_LOG(IPX_PACKET_LOG_RCV_ALL)) {
+ IpxLogPacket(FALSE, Header+1, Header+7, (USHORT)PacketSize, LookaheadBuffer, (PUCHAR)LookaheadBuffer + sizeof(IPX_HEADER));
+ }
+#endif
+
+ return NDIS_STATUS_SUCCESS;
+
+} /* IpxReceiveIndication */
+
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a connection(less) frame has been received on the
+ physical link. We dispatch to the correct packet handler here.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PLIST_ENTRY linkage;
+
+
+ //
+ // Complete all pending receives. Do a quick check
+ // without the lock.
+ //
+
+ while (!IsListEmpty (&Adapter->RequestCompletionQueue)) {
+
+ linkage = IPX_REMOVE_HEAD_LIST(
+ &Adapter->RequestCompletionQueue,
+ Adapter->DeviceLock);
+
+ if (!IPX_LIST_WAS_EMPTY (&Adapter->RequestCompletionQueue, linkage)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(linkage);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_DEBUG (RECEIVE, ("Completing RDG on %lx\n", AddressFile));
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IpxCompleteRequest(Request);
+ IpxFreeRequest(Adapter->Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_RCV_DGRAM);
+
+ } else {
+
+ //
+ // IPX_REMOVE_HEAD_LIST returned nothing, so don't
+ // bother looping back.
+ //
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Unwind this loop for speed.
+ //
+
+ if (IpxDevice->AnyUpperDriverBound) {
+
+ PDEVICE Device = IpxDevice;
+
+ if ((Device->UpperDriverBound[0]) &&
+ (Device->ReceiveCompletePending[0])) {
+
+ (*Device->UpperDrivers[0].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[0] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[1]) &&
+ (Device->ReceiveCompletePending[1])) {
+
+ (*Device->UpperDrivers[1].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[1] = FALSE;
+
+ }
+
+ if ((Device->UpperDriverBound[2]) &&
+ (Device->ReceiveCompletePending[2])) {
+
+ (*Device->UpperDrivers[2].ReceiveCompleteHandler)(
+ (USHORT)1); // BUGBUG: Fix NIC ID or remove.
+ Device->ReceiveCompletePending[2] = FALSE;
+
+ }
+
+ }
+
+} /* IpxReceiveComplete */
+
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have decided that we now know
+ the network number for a binding which we previously thought
+ was zero.
+
+Arguments:
+
+ Device - The IPX device.
+
+ Binding - The binding being updated.
+
+ Network - The new network number.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Only binding set members should have these different,
+ // and they will not have a network of 0.
+ //
+
+ Status = RipInsertLocalNetwork(
+ Network,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if (Status == STATUS_SUCCESS) {
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ //
+ // Update the device address if we have no virtual net
+ // and there is one binding (!Device->MultiCardZeroVirtual)
+ // or this is the first binding, which is the one we
+ // appear to be if a) we have no virtual net defined and
+ // b) we are bound to multiple cards.
+ //
+#ifdef _PNP_POWER
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ if (!Device->VirtualNetwork) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Network;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Network));
+ }
+
+ }
+ }
+#else
+ if ((!Device->VirtualNetwork) &&
+ ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1))) {
+
+ Device->SourceAddress.NetworkAddress = Network;
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = Network;
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Let SPX know because it fills in its own
+ // headers. When we indicate a line up on NIC ID
+ // 0 it knows to requery the local address.
+ //
+ // BUGBUG: Line up indication to RIP/NB??
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+
+ IPX_LINE_INFO LineInfo;
+ LineInfo.LinkSpeed = Device->LinkSpeed;
+ LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo.MacOptions = Device->MacOptions;
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].LineUpHandler)(
+ 0,
+ &LineInfo,
+ Binding->Adapter->MacInfo.RealMediumType,
+ NULL);
+
+ }
+ }
+#endif
+ } else if (Status == STATUS_DUPLICATE_NAME) {
+
+ //
+ // If it was a duplicate we still set the binding's local
+ // address to the value so we can detect binding sets.
+ //
+
+ Binding->LocalAddress.NetworkAddress = Network;
+
+ }
+
+ return Status;
+
+} /* IpxUpdateBindingNetwork */
+
+
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ Packet - contains the packet received as well as some mediaspecific info.
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+ UINT HeaderBufferSize = NDIS_GET_PACKET_HEADER_SIZE(Packet);
+ UINT firstbufferLength, bufferLength;
+ PNDIS_BUFFER pFirstBuffer;
+ PUCHAR headerBuffer;
+ NTSTATUS ntStatus;
+ INT tdiClientCount = 0;
+
+ //
+ // Query the number of buffers, the first MDL's descriptor and the packet length
+ //
+ NdisGetFirstBufferFromPacket(Packet, // packet
+ &pFirstBuffer, // first buffer descriptor
+ &headerBuffer, // ptr to the start of packet
+ &firstbufferLength,// length of the header+lookahead
+ &bufferLength); // length of the bytes in the buffers
+
+ //
+ // ReceiveContext is the packet itself
+ //
+
+ ntStatus = IpxReceiveIndicationNew (
+ ProtocolBindingContext,
+ Packet, // ReceiveContext
+ headerBuffer,
+ HeaderBufferSize,
+ headerBuffer + HeaderBufferSize, // LookaheadBuffer
+ bufferLength - HeaderBufferSize, // LookaheadBufferSize
+ bufferLength - HeaderBufferSize, // PacketSize - since the whole packet is indicated
+ pFirstBuffer, // pMdl
+ &tdiClientCount // tdi client count
+ );
+
+ IPX_DEBUG(RECEIVE, ("IpxReceivePacket: Tdi Client Count is: %lx\n", tdiClientCount));
+
+ return tdiClientCount;
+} /* IpxReceivePacket */
+
+
+#ifdef _PNP_POWER
+
+#if defined(_M_IX86)
+_inline
+#endif
+BOOLEAN
+IpxNewVirtualNetwork(
+ IN PDEVICE Device,
+ IN BOOLEAN NewVirtualNetwork
+ )
+/*++
+
+Routine Description:
+
+ If the virtualnetwork number changed, this function records this fact
+ in the device.
+
+ Called with the BINDACCESSLOCK held.
+Arguments:
+
+ Device - Pointer to the Device.
+
+ NewVirtualNetwork - boolean to indicate if the virtual net# changed.
+
+Return Value:
+
+ BOOLEAN - to indicate whether SPX's reserved address was changed.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ UCHAR VirtualNode[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
+ BOOLEAN ReservedAddrChanged = FALSE;
+
+ if (Device->VirtualNetworkNumber) {
+
+ if (NewVirtualNetwork) {
+ //
+ // If a new one appeared.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Device->VirtualNetworkNumber,
+ 0, // NIC ID
+ NIC_ID_TO_BINDING(Device, 1)->Adapter->NdisBindingHandle,
+ 1);
+
+ if (ntStatus != STATUS_SUCCESS) {
+
+ //
+ // Log the appropriate error, then ignore the
+ // virtual network. If the error was
+ // INSUFFICIENT_RESOURCES, the RIP module
+ // will have already logged an error.
+ //
+
+ if (ntStatus == STATUS_DUPLICATE_NAME) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Ignoring virtual network %lx, conflict\n", REORDER_ULONG (Device->VirtualNetworkNumber)));
+
+ IpxWriteResourceErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_INTERNAL_NET_INVALID,
+ 0,
+ REORDER_ULONG (Device->VirtualNetworkNumber));
+ }
+
+ Device->VirtualNetworkNumber = 0;
+ goto NoVirtualNetwork;
+
+ }
+
+ //
+ // If the number is non-zero now, a new one appeared
+ //
+ Device->VirtualNetwork = TRUE;
+ Device->MultiCardZeroVirtual = FALSE;
+ RtlCopyMemory(Device->SourceAddress.NodeAddress, VirtualNode, 6);
+ Device->SourceAddress.NetworkAddress = Device->VirtualNetworkNumber;
+ ReservedAddrChanged = TRUE;
+
+ //
+ // If RIP is not bound, then this node is a RipResponder
+ //
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ Device->RipResponder = TRUE;
+ }
+ }
+
+ } else {
+NoVirtualNetwork:
+ Device->VirtualNetwork = FALSE;
+
+ //
+ // See if we need to be set up for the fake
+ // virtual network.
+ //
+
+ if (Device->ValidBindings > 1) {
+
+ CTEAssert (Device->VirtualNetworkOptional);
+
+ //
+ // In this case we return as our local node the
+ // address of the first card. We will also only
+ // direct SAP sends to that card.
+ //
+
+ Device->MultiCardZeroVirtual = TRUE;
+
+ } else {
+
+ Device->MultiCardZeroVirtual = FALSE;
+ }
+
+ if (NewVirtualNetwork) {
+ //
+ // The virtual network number disappeared this time
+ //
+
+ //
+ // Remove the prev. net # from the RIP tables here
+ //
+ RipAdjustForBindingChange (0, 0, IpxBindingDeleted);
+
+ //
+ // If we were a RipResponder, we are not anymore
+ //
+ if (Device->RipResponder) {
+ Device->RipResponder = FALSE;
+ }
+ }
+
+ //
+ // Since there is not virtual network number, SPX's reserved address is
+ // the address of the first binding. This could have changed because of
+ // several reasons: if there was a WAN binding only earlier and this time
+ // a LAN binding appeared, or if the first LAN binding disappeared. Instead
+ // of checking for all these conditions, check if the Device's sourceaddress
+ // and that of the first mis-match.
+ // NB uses the address of the first device always and hence does not need
+ // this mechanism to determine if this is a reserved address change.
+ //
+ if (!RtlEqualMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket))) {
+
+ RtlCopyMemory( &Device->SourceAddress,
+ &NIC_ID_TO_BINDING(Device, 1)->LocalAddress,
+ FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+
+ ReservedAddrChanged = TRUE;
+ }
+ }
+
+ return ReservedAddrChanged;
+}
+
+
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about a new
+ adapter in the machine. We are called here only if this adapter
+ is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING
+
+ BindContext - context to represent this bind indication
+
+ DeviceName - Name of the adapter that appeared (e.g. \Device\Lance1)
+
+ SystemSpecific1/2 - Not used here
+
+Return Value:
+
+ Status - NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PDEVICE Device = IpxDevice;
+ PADAPTER Adapter = NULL;
+ CONFIG Config;
+ UINT i;
+ ULONG Temp, SuccessfulOpens=0;
+ PBINDING Binding;
+ BINDING_CONFIG ConfigBinding;
+ ULONG ValidBindings;
+ USHORT AutoDetectReject;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN FirstDevice = FALSE;
+ BOOLEAN ReservedAddrChanged = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+ ConfigBinding.AdapterName = *DeviceName;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the virtual network number changed, record this fact.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ Device->VirtualNetworkNumber = Temp;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // For each FrameType and Network Number configured, initialize the
+ // FrameType array in the CONFIG_BINDING
+ //
+ ntStatus = IpxPnPGetAdapterParameters(
+ &Config,
+ DeviceName,
+ &ConfigBinding);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the adapter params: DeviceName: %lx\n", DeviceName->Buffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ IPX_DEBUG(PNP, ("ConfigBinding.FrameTypeCount: %lx\n", ConfigBinding.FrameTypeCount));
+
+ //
+ // Reset the auto-detect state to init so that if a receive occurs on this binding
+ // before we can place this binding in the device's binding array, we know of it.
+ //
+ Device->AutoDetectState = AUTO_DETECT_STATE_INIT;
+
+ //
+ // Register adapter with NDIS; query the various parameters; get the WAN line count
+ // if this is a WAN adapter.
+ // Allocate the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ConfigBinding.FrameTypeCount; i++) {
+
+ //
+ // If successful, this queues them on Device->InitialBindingList. [BUGBUGZZ] not right now
+ // Adapter is NULL first time and is allocated then. In subsequent calls,
+ // it is not NULL and the bindings are hooked to this adapter.
+
+ ntStatus = IpxBindToAdapter (Device, &ConfigBinding, &Adapter, i);
+
+ //
+ // If this failed because the adapter could not be bound
+ // to, then don't try any more frame types on this adapter.
+ // For other failures we do try the other frame types.
+ //
+
+ if (ntStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+ break;
+ }
+
+ //
+ // If the status is STATUS_NOT_SUPPORTED, then this frametype mapped to a previously
+ // initialized one. In this case, remove this index fron the FrameType array so that
+ // when we try to update the binding array, we dont have duplicates.
+ //
+ if (ntStatus == STATUS_NOT_SUPPORTED) {
+ ULONG j;
+
+ //
+ // Remove this frametype from the FrameType array.
+ //
+ for (j = i+1; j < ConfigBinding.FrameTypeCount; j++) {
+ ConfigBinding.FrameType[j-1] = ConfigBinding.FrameType[j];
+ }
+
+ --ConfigBinding.FrameTypeCount;
+
+ //
+ // Decrement so we see the one just moved up.
+ //
+ --i;
+
+#if DBG
+ for (j = 0; j < ISN_FRAME_TYPE_MAX; j++) {
+ IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d\n",
+ j, ConfigBinding.FrameType[j], ConfigBinding.NetworkNumber[j], ConfigBinding.AutoDetect[j]));
+ }
+#endif
+ continue;
+ }
+
+ if (ntStatus != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (ConfigBinding.AutoDetect[i]) {
+ Device->AutoDetect = TRUE;
+ }
+
+ CTEAssert(Adapter);
+
+ ++SuccessfulOpens;
+
+ //
+ // Even for WAN adapters, the FrameTypeCount is set to 4. We only need to
+ // allocate one binding for WAN; the others come later.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ break;
+ }
+ }
+
+ if (SuccessfulOpens == 0) {
+ goto InitFailed;
+ }
+
+ //
+ // Place all the bindings corresponding to this adapter in the binding array
+ // Also resolve binding sets for non-autodetect bindings.
+ //
+
+ //
+ // Obtain lock to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IpxPnPUpdateBindingArray (Device, Adapter, &ConfigBinding);
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If at least one card appeared here, set our state
+ // to open
+ //
+ // [BUGBUGZZ]: what if all these bindings are eliminated - then
+ // the state is not open...
+ //
+ if (Device->ValidBindings > 0) {
+ if (Device->State == DEVICE_STATE_LOADED) {
+ FirstDevice = TRUE;
+ Device->State = DEVICE_STATE_OPEN;
+ }
+ }
+
+ //
+ // We don't do auto-detect/bindingsets for WAN lines: skip over.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ goto jump_wan;
+ }
+
+ //
+ // Auto-detect the network number. Update the results for only the
+ // bindings corresponding to this adapter
+ //
+
+ //
+ // Queue a request to discover our locally attached
+ // adapter addresses. This must succeed because we
+ // just allocated our send packet pool. We need
+ // to wait for this, either because we are
+ // auto-detecting or because we need to determine
+ // if there are multiple cards on the same network.
+ //
+
+ KeInitializeEvent(
+ &Device->AutoDetectEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_RUNNING;
+
+ //
+ // Make this 0; after we are done waiting, which means
+ // the packet has been completed, we set it to the
+ // correct value.
+ //
+
+ // Device->IncludedHeaderOffset = 0;
+
+ IPX_BEGIN_SYNC (&SyncContext);
+ ntStatus = RipQueueRequest (0xffffffff, RIP_REQUEST);
+ IPX_END_SYNC (&SyncContext);
+
+ CTEAssert (ntStatus == STATUS_PENDING);
+
+ //
+ // This is set when this rip send completes.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Waiting for AutoDetectEvent\n"));
+
+ KeWaitForSingleObject(
+ &Device->AutoDetectEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_PROCESSING;
+
+ //
+ // Now that we are done receiving responses, insert the
+ // current network number for every auto-detect binding
+ // to the rip database.
+ //
+
+ //
+ // Obtain exclusive access to the Binding related stuff.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Note, here we go thru' only the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+
+ Binding = Adapter->Bindings[i];
+
+ //
+ // Skip empty binding slots or bindings that were configured
+ // for a certain network number, we inserted those above.
+ // If no network number was detected, also skip it.
+ //
+
+ if ((!Binding) ||
+ (Binding->ConfiguredNetworkNumber != 0) ||
+ (Binding->TentativeNetworkAddress == 0)) {
+
+ continue;
+ }
+
+ IPX_DEBUG (AUTO_DETECT, ("Final score for %lx on %lx is %d - %d\n",
+ REORDER_ULONG(Binding->TentativeNetworkAddress),
+ Binding,
+ Binding->MatchingResponses,
+ Binding->NonMatchingResponses));
+
+ //
+ // We don't care about the status.
+ //
+
+ ntStatus = RipInsertLocalNetwork(
+ Binding->TentativeNetworkAddress,
+ Binding->NicId,
+ Binding->Adapter->NdisBindingHandle,
+ (USHORT)((839 + Binding->MediumSpeed) / Binding->MediumSpeed));
+
+ if ((ntStatus != STATUS_SUCCESS) &&
+ (ntStatus != STATUS_DUPLICATE_NAME)) {
+
+ //
+ // We failed to insert, keep it at zero, hopefully
+ // we will be able to update later.
+ //
+
+#if DBG
+ DbgPrint ("IPX: Could not insert net %lx for binding %lx\n",
+ REORDER_ULONG(Binding->LocalAddress.NetworkAddress),
+ Binding);
+#endif
+ CTEAssert (Binding->LocalAddress.NetworkAddress == 0);
+
+ } else {
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ Binding->LocalAddress.NetworkAddress = Binding->TentativeNetworkAddress;
+ }
+
+ // ValidBindings = Device->BindingCount;
+
+ ValidBindings = Device->ValidBindings;
+
+ // [BUGBUGZZ] if (Device->AutoDetect) {
+
+ ValidBindings = IpxResolveAutoDetect (Device, ValidBindings, &LockHandle1, &Device->RegistryPath);
+
+ //}
+
+ //
+ // Adjust all the indices by the number of AutoDetect bindings thrown away
+ //
+ // AutoDetectReject = (USHORT)(Device->BindingCount - ValidBindings);
+
+ AutoDetectReject = (USHORT)(Device->ValidBindings - ValidBindings);
+
+ Device->HighestLanNicId -= AutoDetectReject;
+ Device->HighestExternalNicId -= AutoDetectReject;
+ Device->HighestType20NicId -= AutoDetectReject;
+ Device->SapNicCount -= AutoDetectReject;
+
+ Device->ValidBindings = (USHORT)ValidBindings;
+
+ //
+ // Now see if any bindings are actually on the same
+ // network. This updates the Device->HighestExternalNicId
+ // and Device->HighestType20NicId, SapNicCount, HighestLanNicId
+ //
+
+ //
+ // Do this only for the auto-detect bindings
+ // [BUGBUGZZ] check this
+ //
+
+ //if (Device->AutoDetect) {
+ IpxResolveBindingSets (Device, Device->HighestExternalNicId);
+ //}
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+jump_wan:
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+
+ //
+ // Enable this regardless of whether any of our clients enabled b'cast.
+ // NB always enables it, so we are fine.
+ //
+ // Since we dont increment the Broadcast count in the device, we will disable b'casts
+ // correctly if the count drops to 0.
+ //
+ // If the ISN clients appear before the adapters, they increment the BCount, but
+ // since the ValidBindings is 0, all works. Then, when the adapters appear, we enable
+ // the broadcasts here.
+ //
+ // If the adapters appear before the ISN clients, then the broadcast is enabled on
+ // the adapters here and the adapter's flag is set to indicate this, which will prevent
+ // any further calls to NDIS when the ISN clients force an IpxAddBroadcast.
+ //
+ Device->EnableBroadcastPending = TRUE;
+ IpxBroadcastOperation((PVOID)TRUE);
+
+ //
+ // For multiple adapters, use the offset of the first...why not.
+ //
+
+#if 0
+ Device->IncludedHeaderOffset = Device->Bindings[1]->DefHeaderSize;
+#endif
+
+ Device->IncludedHeaderOffset = MAC_HEADER_SIZE;
+
+ //
+ // This function updates flags like RipResponder, MultiCardZeroVirtual, etc.
+ // If the VirtualNetwork number changed (NewVirtualNetwork is TRUE), it updates
+ // the Device structure and the RIP tables accordingly.
+ // It returns a boolean to indicate if SPX's reserved address changed.
+ //
+ ReservedAddrChanged = IpxNewVirtualNetwork(Device, NewVirtualNetwork);
+
+ //
+ // Update the values once the auto-detect bindings have been thrown away...
+ //
+ IpxPnPUpdateDevice(Device);
+
+ Device->AutoDetectState = AUTO_DETECT_STATE_DONE;
+
+ IPX_DEBUG (DEVICE, ("Node is %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x, ",
+ Device->SourceAddress.NodeAddress[0], Device->SourceAddress.NodeAddress[1],
+ Device->SourceAddress.NodeAddress[2], Device->SourceAddress.NodeAddress[3],
+ Device->SourceAddress.NodeAddress[4], Device->SourceAddress.NodeAddress[5]));
+ IPX_DEBUG (DEVICE, ("Network is %lx\n",
+ REORDER_ULONG (Device->SourceAddress.NetworkAddress)));
+
+ //
+ // Start the timer which updates the RIP database
+ // periodically. For the first one we do a ten
+ // second timeout (hopefully this is enough time
+ // for RIP to start if it is going to).
+ //
+ if (FirstDevice) {
+ UNICODE_STRING devicename;
+
+ //
+ // Inform TDI clients about the open of our device object.
+ //
+ devicename.MaximumLength = (USHORT)Device->DeviceNameLength;
+ devicename.Length = (USHORT)Device->DeviceNameLength - sizeof(WCHAR);
+ devicename.Buffer = Device->DeviceName;
+
+ if ((ntStatus = TdiRegisterDeviceObject(
+ &devicename,
+ &Device->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterDeviceObject failed: %lx", ntStatus));
+ }
+
+ IpxReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 10000,
+ RipLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform NB and TDI of all the bindings corresponding to this adapter
+ //
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ //
+ // If a NULL binding or a binding set slave, dont inform NB about it.
+ //
+ if (!Binding || (Binding->NicId > Device->HighestExternalNicId)) {
+#if DBG
+ if (Binding) {
+ IPX_DEBUG(PNP, ("Binding: %lx, Binding set slave\n", Binding));
+ }
+#endif
+ continue;
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Lock taken to check the UpperDriverBound flag.
+ // We already have the BindAccessLock at this point.
+ //
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ // Ensure that we dont do it twice.
+ //
+ if (!Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ //
+ // Also, to ensure that the indications are done in the right order,
+ // check if the first card has been indicated yet.
+ //
+ if ((Binding->NicId != 1) &&
+ !NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_NB]) {
+
+ break;
+ }
+
+ Binding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ if (Binding->NicId == 1) {
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB add: %lx\n", Binding));
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Always true for SPX
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ if (FirstDevice) {
+
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // We could have informed the upper driver from IpxPnPIsnIndicate
+ //
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ //
+ // Inform SPX - the network/node address is the Virtual one if it exists
+ // else the address of the first binding
+ //
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+
+ //
+ // Not the first device - inform if the reserved address changed.
+ //
+ if (ReservedAddrChanged) {
+ if (!NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX]) {
+ NIC_ID_TO_BINDING_NO_ILOCK(Device, 1)->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ IPX_DEBUG(PNP, ("Reserved addr changed; SPX not told of first one yet\n"));
+ }
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("PnP to SPX add (res. addr change): %lx\n", Binding));
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Release access to the Binding related stuff.
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+InitFailed:
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+
+} /* IpxBindAdapter */
+
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives a Plug and Play notification about the removal
+ of an existing adapter from the machine. We are called here only if
+ this adapter is to be bound to us, so we don't make any checks for this.
+
+Arguments:
+
+ Status - NDIS_STATUS_SUCCESS, NDIS_STATUS_PENDING.
+
+ ProtocolBindingContext - the adapter that got removed.
+
+ UnbindContext - context to represent this bind indication.
+
+Return Value:
+
+ Void - return thru' Status above.
+
+--*/
+{
+ NTSTATUS ntStatus;
+ PADAPTER Adapter=(PADAPTER)ProtocolBindingContext;
+ CONFIG Config;
+ PBINDING Binding;
+ PDEVICE Device=IpxDevice;
+ ULONG i, Temp;
+ BOOLEAN NewVirtualNetwork = FALSE;
+ BOOLEAN NBReservedAddrChanged = FALSE;
+ BOOLEAN SPXInformed = FALSE;
+ IPX_PNP_INFO IpxPnPInfo;
+ PBINDING newMasterBinding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // Used for error logging
+ //
+ Config.DriverObject = (PDRIVER_OBJECT)Device->DeviceObject;
+
+ Config.RegistryPathBuffer = Device->RegistryPathBuffer;
+
+ //
+ // Read the registry to see if a virtual network number appeared/disappeared
+ //
+ ntStatus = IpxPnPGetVirtualNetworkNumber(&Config);
+
+ if (ntStatus != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("Could not read the vnet#: registrypathbuffer: %lx\n", Device->RegistryPathBuffer));
+ *Status = NDIS_STATUS_SUCCESS;
+ return;
+ }
+
+ Temp = REORDER_ULONG (Config.Parameters[CONFIG_VIRTUAL_NETWORK]);
+
+ //
+ // If the VirtualNetwork number changed, record it.
+ //
+ if (Device->VirtualNetworkNumber != Temp) {
+ NewVirtualNetwork = TRUE;
+ }
+
+ Device->VirtualNetworkOptional = (BOOLEAN)(Config.Parameters[CONFIG_VIRTUAL_OPTIONAL] != 0);
+
+ IPX_DEBUG(PNP, ("Virtual net # is: %lx\n", Temp));
+
+ //
+ // If the WAN adapter disappeared, we can simply remove all the WAN bindings since
+ // all of them correspond to this single WAN adapter. Since we tell NB only about
+ // the first one of these, we need to indicate removal of only one binding to NB.
+ //
+ if (Adapter->MacInfo.MediumAsync) {
+ USHORT wanLineCount = (USHORT)Adapter->WanNicIdCount;
+
+ CTEAssert(wanLineCount == (Device->HighestExternalNicId - Device->HighestLanNicId));
+
+ //
+ // If no more bindings remain, tell upper driver of the same.
+ // We go back to the loaded state.
+ //
+
+ if ((Device->ValidBindings - wanLineCount) == 0) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ Device->State = DEVICE_STATE_LOADED;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Give the PnP indication to indicate the deletion only if it was
+ // added before.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("PnP to NB delete: %lx\n", Binding));
+ }
+#if DBG
+ else {
+ DbgPrint("WAN adapter id: %lx not indicated to NB\n", Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Inform SPX only if this is the last device.
+ //
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (IpxPnPInfo.FirstORLastDevice && Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == 0);
+
+ //
+ // Get to the first WAN binding - this is always the one after the last LAN binding.
+ //
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, Device->HighestLanNicId+1);
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: delete WAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+ }
+
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Now remove these WAN bindings from the array. Move all the Slave bindings
+ // up to where the WAN bindings were.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ for (i = Device->HighestLanNicId+1; i <= Device->HighestExternalNicId; i++) {
+ //
+ // Unbind from the adapter - if it is not referenced by any other thread, it will
+ // be deleted at this point.
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(NIC_ID_TO_BINDING_NO_ILOCK(Device, i));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // Move the slave binding here.
+ //
+ INSERT_BINDING(Device, i, NIC_ID_TO_BINDING_NO_ILOCK(Device, i+wanLineCount));
+ }
+
+ /*
+ RtlCopyMemory( Device->Bindings[Device->HighestLanNicId+1],
+ Device->Bindings[Device->HighestExternalNicId+1],
+ (Device->ValidBindings - Device->HighestExternalNicId) * sizeof(PBIND_ARRAY_ELEM));
+ */
+
+ //
+ // Update the indices
+ //
+ Device->HighestExternalNicId -= wanLineCount;
+ Device->ValidBindings -= wanLineCount;
+ Device->BindingCount -= wanLineCount;
+ Device->SapNicCount = Device->HighestType20NicId = Device->HighestLanNicId;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ CTEAssert(Device->HighestLanNicId == Device->HighestExternalNicId);
+
+ } else {
+ //
+ // LAN adapter disappeared.
+ //
+
+ //
+ // Set up the LineInfo struct.
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ //
+ // For each binding corresponding to this adapter, inform NB only
+ // if the binding addition was indicated.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) {
+ Binding = Adapter->Bindings[i];
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We cannot receive on this binding anymore
+ //
+ Adapter->Bindings[i] = NULL;
+
+ //
+ // If this was a slave binding, dont inform of the deletion.
+ // Just remove the binding from the binding array and the bindingset list.
+ //
+
+ if (Binding->NicId > Device->HighestExternalNicId) {
+ PBINDING MasterBinding, tempBinding;
+
+ CTEAssert(Binding->BindingSetMember);
+ CTEAssert(Binding->CurrentSendBinding == NULL);
+
+ //
+ // Traverse the bindingset list and remove this binding from there.
+ //
+ tempBinding = MasterBinding = Binding->MasterBinding;
+
+ while (tempBinding->NextBinding != MasterBinding) {
+ if (tempBinding->NextBinding == Binding) {
+ tempBinding->NextBinding = tempBinding->NextBinding->NextBinding;
+ break;
+ }
+ tempBinding = tempBinding->NextBinding;
+ }
+
+ //
+ // If no more slaves, this is no longer a bindingset.
+ //
+ if (MasterBinding->NextBinding == MasterBinding) {
+ MasterBinding->BindingSetMember = FALSE;
+ MasterBinding->CurrentSendBinding = NULL;
+ MasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Slave binding: %lx removed, no master: %lx\n", Binding, MasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (Binding->NicId, MasterBinding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", Binding->NicId, MasterBinding->NicId));
+
+ //
+ // Null out the Slave binding.
+ //
+ INSERT_BINDING(Device, Binding->NicId, NULL);
+
+ --Device->ValidBindings;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+
+ continue;
+ }
+
+ //
+ // If this was the last binding, go back to loaded state and shut down the RIP timers.
+ //
+ if (Device->ValidBindings == 1) {
+ CTEAssert(Device->HighestExternalNicId == 1);
+ CTEAssert(Device->HighestLanNicId == 1);
+ CTEAssert(Device->SapNicCount == 1);
+ CTEAssert(Device->HighestType20NicId == 1);
+
+ Device->State = DEVICE_STATE_LOADED;
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+
+ //
+ // Shut down RIP timers, complete address notify requests, etc.
+ //
+ IpxPnPToLoad();
+
+ } else {
+ CTEAssert(Device->State == DEVICE_STATE_OPEN);
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ }
+
+ //
+ // If this was a master binding, promote a slave binding to master.
+ //
+ if (Binding->BindingSetMember) {
+
+ CTEAssert(Binding->CurrentSendBinding);
+ CTEAssert(Binding->MasterBinding == Binding);
+
+ //
+ // Promote the next slave to Master.
+ //
+ newMasterBinding = Binding->NextBinding;
+ INSERT_BINDING(Device, Binding->NicId, newMasterBinding);
+ newMasterBinding->CurrentSendBinding = newMasterBinding;
+ newMasterBinding->MasterBinding = newMasterBinding;
+
+ //
+ // If this is the only binding remaining out of its set,
+ // it is no longer part of a set.
+ //
+ if (newMasterBinding->NextBinding == Binding) {
+ newMasterBinding->NextBinding = newMasterBinding->CurrentSendBinding = NULL;
+ newMasterBinding->BindingSetMember = FALSE;
+ newMasterBinding->ReceiveBroadcast = TRUE;
+
+ IPX_DEBUG(PNP, ("Master binding: %lx removed, no master: %lx\n", Binding, newMasterBinding));
+ }
+
+ //
+ // Change the slave binding entries to have the master's NicId
+ //
+ RipAdjustForBindingChange (newMasterBinding->NicId, Binding->NicId, IpxBindingMoved);
+ IPX_DEBUG(PNP, ("RipAdjustForBindingChange (%d, %d, IpxBindingMoved)\n", newMasterBinding->NicId, Binding->NicId));
+
+ //
+ // Register slave's address with the TDI clients.
+ //
+ CTEAssert(!newMasterBinding->TdiRegistrationHandle);
+
+ RtlCopyMemory ( Device->TdiRegistrationAddress->Address,
+ &newMasterBinding->LocalAddress,
+ sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &newMasterBinding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ //
+ // Null out the slave binding
+ //
+ INSERT_BINDING(Device, newMasterBinding->NicId, NULL);
+
+ newMasterBinding->NicId = Binding->NicId;
+
+ IPX_DEBUG(PNP, ("Promoted a master binding: %lx, old master: %lx\n", newMasterBinding, Binding));
+ } else {
+
+ ULONG j;
+
+ //
+ // Remove the binding from the array
+ //
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDeleted);
+
+ for (j = Binding->NicId+1; j <= Device->HighestExternalNicId; j++) {
+ INSERT_BINDING(Device, j-1, NIC_ID_TO_BINDING_NO_ILOCK(Device, j));
+ --NIC_ID_TO_BINDING_NO_ILOCK(Device, j)->NicId;
+ }
+
+ INSERT_BINDING(Device, Device->HighestExternalNicId, NULL);
+
+ --Device->HighestExternalNicId;
+ --Device->HighestLanNicId;
+ --Device->HighestType20NicId;
+ --Device->SapNicCount;
+ }
+
+ --Device->ValidBindings;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+
+ //
+ // If this is the first binding, NB's reserved will change.
+ // When we inform SPX of an address change later, we dont have
+ // this binding to know if this binding was indicated to SPX earlier.
+ // So, set SPXInformed, which is used later to determine if an address
+ // change is to be indicated to SPX later.
+ //
+ // Since NB is informed of all adapters, we inform of the reserved address
+ // change to NB if the new Binding (now at NicId 1) was indicated earlier.
+ //
+ if (Binding->NicId == 1) {
+ NBReservedAddrChanged = TRUE;
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+ SPXInformed = TRUE;
+ }
+ }
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate its deletion to NB.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: delete LAN device: %lx\n", Binding));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // If this was a Master, indicate the addition of the (promoted) slave
+ //
+ if (Binding->BindingSetMember) {
+ IpxPnPInfo.NetworkAddress = newMasterBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, newMasterBinding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, newMasterBinding->NicId);
+
+ //
+ // In this case, we set the ReservedAddrChanged bit here itself so dont need
+ // to indicate a separate address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = (NBReservedAddrChanged) ? TRUE : FALSE;
+ NBReservedAddrChanged = FALSE;
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: add slave device: NicId: %lx\n", Binding->NicId));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ newMasterBinding->IsnInformed[IDENTIFIER_NB] = TRUE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ }
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+
+ //
+ // Last device - inform SPX if it is bound and this device was added earlier.
+ //
+ if (IpxPnPInfo.FirstORLastDevice) {
+ IPX_DEBUG(PNP, ("Last device - inform SPX\n"));
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ if (Binding->IsnInformed[IDENTIFIER_SPX]) {
+
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform SPX: last LAN device\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+
+ //
+ // Unbind from the adapter so it can be deleted
+ //
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IpxUnBindFromAdapter(Binding);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+
+ //
+ // Update the Device and RIP tables if this is not the last device.
+ // If the reserved address changed, inform NB and SPX of this change.
+ //
+ if (!IpxPnPInfo.FirstORLastDevice) {
+
+ Binding = NIC_ID_TO_BINDING_NO_ILOCK(Device, 1);
+
+ if (IpxNewVirtualNetwork(Device, NewVirtualNetwork)) {
+
+ IPX_DEBUG(PNP, ("SPX's reserved address changed\n"));
+
+ //
+ // SPX's reserved address changed
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+
+ //
+ // If this binding's addition was indicated earlier, indicate change of address.
+ //
+ if (SPXInformed) {
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+
+ IPX_DEBUG(PNP, ("Inform SPX: reserved address changed\n"));
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+
+ if (Device->VirtualNetwork) {
+ //
+ // new one appeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ //
+ // Old one disappeared
+ //
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ } else {
+
+ //
+ // Set the first binding's flag so that when this binding goes away, we remember
+ // to inform SPX of this device's removal.
+ //
+
+ IPX_DEBUG(PNP, ("Transfer SPX informed flag to NicId: %lx\n", Binding->NicId));
+ Binding->IsnInformed[IDENTIFIER_SPX] = TRUE;
+ }
+
+ if (NBReservedAddrChanged) {
+ //
+ // NB's reserved address changed.
+ //
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ //
+ // If this binding's addition was indicated earlier, indicate the change of reserved address.
+ //
+ if (Binding->IsnInformed[IDENTIFIER_NB]) {
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IPX_DEBUG(PNP, ("Inform NB: reserved address changed\n"));
+
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ } else {
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ }
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ //
+ // Re-calculate the values of datagram sizes in the Device.
+ //
+ IpxPnPUpdateDevice(Device);
+
+ IPX_DEBUG(PNP, ("BindingCount: %lu\n", Device->BindingCount));
+ IPX_DEBUG(PNP, ("ValidBindings: %lu\n", Device->ValidBindings));
+ IPX_DEBUG(PNP, ("HighestLanNicId: %lu\n", Device->HighestLanNicId));
+ IPX_DEBUG(PNP, ("HighestExternalNicId: %lu\n", Device->HighestExternalNicId));
+ IPX_DEBUG(PNP, ("HighestType20NicId: %lu\n", Device->HighestType20NicId));
+ IPX_DEBUG(PNP, ("SapNicCount: %lu\n", Device->SapNicCount));
+ IPX_DEBUG(PNP, ("BindingArray: %lx\n", Device->Bindings));
+} /* IpxUnbindAdapter */
+
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ )
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that a frame has been received on the physical link.
+ The packet passed up from NDIS can be held on to by the TDI clients
+ that request TDI_EVENT_RECEIVE_EX_DATAGRAM events with us.
+
+Arguments:
+
+ ProtocolBindingContext - The Adapter Binding specified at initialization time.
+
+ ReceivedPacket - The packet received
+
+ MediaSpecificInformation - Used for media such as Irda, wireless, etc. Not used here.
+
+ HeaderBufferSize - Size of the MAC header
+
+Return Value:
+
+ return of IpxReceiveIndicationNew(),
+
+--*/
+{
+} /* IpxTranslate */
+
+#endif _PNP_POWER
+
+
diff --git a/private/ntos/tdi/isnp/ipx/internal.c b/private/ntos/tdi/isnp/ipx/internal.c
new file mode 100644
index 000000000..f11790158
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/internal.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ internal.c
+
+Abstract:
+
+ This module contains the code to handle the internal
+ binding of the upper drivers to IPX.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 25-August-1995
+ Bug Fixes - tagged [SA]
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to bind to IPX.
+
+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.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+ PIPX_INTERNAL_BIND_INPUT BindInput;
+ PIPX_INTERNAL_BIND_OUTPUT BindOutput;
+ PIPX_INTERNAL_BIND_RIP_OUTPUT BindRipOutput;
+ CTELockHandle LockHandle;
+ PIPX_NIC_DATA NicData;
+ PBINDING Binding, LastRealBinding;
+ PADAPTER Adapter;
+ ULONG Identifier;
+ ULONG BindOutputSize;
+ BOOLEAN BroadcastEnable;
+ UINT i;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ (sizeof(IPX_INTERNAL_BIND_INPUT) - sizeof(ULONG))) {
+
+ IPX_DEBUG (BIND, ("Bind received, bad input length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.InputBufferLength,
+ sizeof (IPX_INTERNAL_BIND_INPUT)));
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ BindInput = (PIPX_INTERNAL_BIND_INPUT)(Irp->AssociatedIrp.SystemBuffer);
+
+ if (BindInput->Identifier >= UPPER_DRIVER_COUNT) {
+ IPX_DEBUG (BIND, ("Bind received, bad id %d\n", BindInput->Identifier));
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IPX_DEBUG (BIND, ("Bind received from id %d (%s)\n",
+ BindInput->Identifier,
+ IdStrings[BindInput->Identifier]));
+
+#ifdef _PNP_POWER
+// RIP gives us version == 1 whereas the others give us 2 (ISN_VERSION).
+// [BUGBUGZZ] - have RIP change?
+//
+ if (BindInput->Identifier == IDENTIFIER_RIP) {
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ } else {
+ if (BindInput->Version != ISN_VERSION) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+#else
+ if (BindInput->Version != 1) {
+ IPX_DEBUG (BIND, ("Bind: bad version %d/%d\n",
+ BindInput->Version, 1));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+
+ if (BindInput->Identifier != IDENTIFIER_RIP) {
+ BindOutputSize = sizeof(IPX_INTERNAL_BIND_OUTPUT);
+ } else {
+ BindOutputSize = FIELD_OFFSET (IPX_INTERNAL_BIND_RIP_OUTPUT, NicInfoBuffer.NicData[0]) +
+ (MIN (Device->MaxBindings, Device->HighestExternalNicId) * sizeof(IPX_NIC_DATA));
+ }
+
+ Irp->IoStatus.Information = BindOutputSize;
+
+ if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
+ BindOutputSize) {
+
+ IPX_DEBUG (BIND, ("Bind: bad output length %d/%d\n",
+ IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
+ BindOutputSize));
+
+ //
+ // Fail this request with BUFFER_TOO_SMALL. Since the
+ // I/O system may not copy the status block back to
+ // the user's status block, do that here so that
+ // he gets IoStatus.Information.
+ //
+
+ try {
+ *Irp->UserIosb = Irp->IoStatus;
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+ NOTHING;
+ }
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // We have verified the length, make sure we are not
+ // already bound.
+ //
+
+ Identifier = BindInput->Identifier;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Device->UpperDriverBound[Identifier]) {
+ IPX_DEBUG (BIND, ("Bind: already bound\n"));
+ CTEFreeLock (&Device->Lock, LockHandle);
+ return STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ {
+ LARGE_INTEGER ControlChId;
+
+ CCID_FROM_REQUEST(ControlChId, Irp);
+
+ IPX_DEBUG (BIND, ("Control ChId: (%d, %d) for Id: %d\n", ControlChId.HighPart, ControlChId.LowPart, Identifier));
+ Device->UpperDriverControlChannel[Identifier].QuadPart = ControlChId.QuadPart;
+ }
+
+ RtlCopyMemory(
+ &Device->UpperDrivers[Identifier],
+ BindInput,
+ sizeof (IPX_INTERNAL_BIND_INPUT)
+ );
+
+ BroadcastEnable = BindInput->BroadcastEnable;
+
+ //
+ // Now construct the output buffer.
+ //
+
+ if (Identifier != IDENTIFIER_RIP) {
+
+ BindOutput = (PIPX_INTERNAL_BIND_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindOutput->Version = 1;
+
+ //
+ // Tell netbios our first binding's net/node instead of the
+ // virtual one.
+ //
+#ifdef _PNP_POWER
+//
+// Fill the fields in only if the adapters have already appeared
+// Else, set NodeNumber to 0 so NB/SPX know of it.
+//
+ if ((*(UNALIGNED USHORT *)(Device->SourceAddress.NodeAddress+4) != 0) ||
+ (*(UNALIGNED ULONG *)Device->SourceAddress.NodeAddress != 0)) {
+
+ IPX_DEBUG(BIND, ("Device already opened\n"));
+ CTEAssert(Device->ValidBindings);
+
+ if (Identifier == IDENTIFIER_SPX) {
+
+ //
+ // For SPX, inform directly.
+ //
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ IpxPnPIsnIndicate((PVOID)Identifier);
+
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK(&Device->Lock, LockHandle);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+
+ IPX_GET_LOCK(&Device->Lock, &LockHandle);
+ } else {
+ //
+ // For NB, queue a work item which will go thru' the adapters list and
+ // inform the upper drivers about each of them.
+ //
+ ExInitializeWorkItem(
+ &Device->PnPIndicationsQueueItem,
+ IpxPnPIsnIndicate,
+ (PVOID)Identifier);
+ ExQueueWorkItem(&Device->PnPIndicationsQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+ IPX_DEBUG(BIND, ("Device not open\n"));
+ *((UNALIGNED ULONG *)BindOutput->Node) = 0;
+ *((UNALIGNED USHORT *)(BindOutput->Node+4)) = 0;
+ RtlZeroMemory(&BindOutput->LineInfo, sizeof(BindOutput->LineInfo));
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindOutput->IncludedHeaderOffset = MAC_HEADER_SIZE; // (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->SendHandler = IpxSendFramePreFwd;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+
+#else
+ if ((Identifier == IDENTIFIER_NB) &&
+ (Device->VirtualNetwork)) {
+ RtlCopyMemory(BindOutput->Node, Device->Bindings[1]->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->Bindings[1]->LocalAddress.NetworkAddress;
+ } else {
+
+ RtlCopyMemory(BindOutput->Node, Device->SourceAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)(BindOutput->Network) = Device->SourceAddress.NetworkAddress;
+ }
+
+ BindOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+
+ BindOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindOutput->LineInfo.LinkSpeed = Device->LinkSpeed;
+ BindOutput->LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ BindOutput->LineInfo.MacOptions = Device->MacOptions;
+
+ BindOutput->SendHandler = IpxSendFrame;
+ BindOutput->FindRouteHandler = IpxInternalFindRoute;
+ BindOutput->QueryHandler = IpxInternalQuery;
+#endif
+ BindOutput->TransferDataHandler = IpxTransferData;
+ } else {
+ //
+ // Set this so we stop RIPping for our virtual network (if
+ // we have one).
+ //
+
+ Device->RipResponder = FALSE;
+
+ //
+ // See if he wants a single wan network number.
+ //
+
+ if ((IrpSp->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(IPX_INTERNAL_BIND_INPUT)) ||
+ ((BindInput->RipParameters & IPX_RIP_PARAM_GLOBAL_NETWORK) == 0)) {
+
+ Device->WanGlobalNetworkNumber = FALSE;
+ Device->SapNicCount = Device->HighestExternalNicId;
+
+ } else {
+
+ Device->WanGlobalNetworkNumber = TRUE;
+
+ }
+
+ BindRipOutput = (PIPX_INTERNAL_BIND_RIP_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+
+ BindRipOutput->Version = 1;
+ BindRipOutput->MaximumNicCount = MIN (Device->MaxBindings, Device->HighestExternalNicId) + 1;
+
+ BindRipOutput->MacHeaderNeeded = MAC_HEADER_SIZE; //40;
+ BindRipOutput->IncludedHeaderOffset = (USHORT)Device->IncludedHeaderOffset;
+
+ BindRipOutput->SendHandler = IpxSendFrame;
+
+ BindRipOutput->SegmentCount = Device->SegmentCount;
+ BindRipOutput->SegmentLocks = Device->SegmentLocks;
+
+ BindRipOutput->GetSegmentHandler = RipGetSegment;
+ BindRipOutput->GetRouteHandler = RipGetRoute;
+ BindRipOutput->AddRouteHandler = RipAddRoute;
+ BindRipOutput->DeleteRouteHandler = RipDeleteRoute;
+ BindRipOutput->GetFirstRouteHandler = RipGetFirstRoute;
+ BindRipOutput->GetNextRouteHandler = RipGetNextRoute;
+
+ BindRipOutput->IncrementWanInactivityHandler = IpxInternalIncrementWanInactivity;
+ BindRipOutput->QueryWanInactivityHandler = IpxInternalQueryWanInactivity;
+
+ BindRipOutput->TransferDataHandler = IpxTransferData;
+
+ BindRipOutput->NicInfoBuffer.NicCount = (USHORT)MIN (Device->MaxBindings, Device->HighestExternalNicId);
+ BindRipOutput->NicInfoBuffer.VirtualNicId = 0;
+ if (Device->VirtualNetwork || Device->MultiCardZeroVirtual) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = Device->SourceAddress.NetworkAddress;
+ } else if (Device->DedicatedRouter) {
+ *(UNALIGNED ULONG *)(BindRipOutput->NicInfoBuffer.VirtualNetwork) = 0x0;
+ }
+
+ NicData = &BindRipOutput->NicInfoBuffer.NicData[0];
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+
+ //
+ // NULL bindings are WAN bindings, so we return the
+ // information from the last non-NULL binding found,
+ // which will be the first one on this adapter.
+ // Otherwise we save this as the last non-NULL one.
+ //
+
+ if (Binding == NULL) {
+ Binding = LastRealBinding;
+ } else {
+ LastRealBinding = Binding;
+ }
+
+ Adapter = Binding->Adapter;
+ NicData->NicId = i;
+ RtlCopyMemory (NicData->Node, Binding->LocalAddress.NodeAddress, 6);
+ *(UNALIGNED ULONG *)NicData->Network = Binding->LocalAddress.NetworkAddress;
+ NicData->LineInfo.LinkSpeed = Binding->MediumSpeed;
+ NicData->LineInfo.MaximumPacketSize =
+ Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ NicData->LineInfo.MaximumSendSize =
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ NicData->LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ NicData->DeviceType = Adapter->MacInfo.RealMediumType;
+ NicData->EnableWanRouter = Adapter->EnableWanRouter;
+
+ ++NicData;
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ }
+ if (BroadcastEnable) {
+ IpxAddBroadcast (Device);
+ }
+
+ Device->UpperDriverBound[Identifier] = TRUE;
+ Device->AnyUpperDriverBound = TRUE;
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalBind */
+
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used when one of the upper drivers submits
+ a request to unbind from IPX. It does this by closing the
+ control channel on which the bind ioctl was submitted.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+#if DBG
+ PUCHAR IdStrings[] = { "NB", "SPX", "RIP" };
+#endif
+
+ IPX_DEBUG (BIND, ("Unbind received from id %d (%s)\n",
+ Identifier,
+ IdStrings[Identifier]));
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (!Device->UpperDriverBound[Identifier]) {
+ CTEFreeLock (&Device->Lock, LockHandle);
+ IPX_DEBUG (BIND, ("No existing binding\n"));
+ return STATUS_SUCCESS;
+ }
+
+ Device->UpperDriverBound[Identifier] = FALSE;
+ Device->AnyUpperDriverBound = (BOOLEAN)
+ (Device->UpperDriverBound[IDENTIFIER_RIP] ||
+ Device->UpperDriverBound[IDENTIFIER_SPX] ||
+ Device->UpperDriverBound[IDENTIFIER_NB]);
+
+ if (Device->UpperDrivers[Identifier].BroadcastEnable) {
+ IpxRemoveBroadcast (Device);
+ }
+
+#ifdef _PNP_POWER
+ if (Device->ValidBindings > 0) {
+ //
+ // If SPX went away, reset the IsnIndicate flag in the first binding
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ CTEAssert(NIC_ID_TO_BINDING(Device, 1));
+
+ if (NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("SPX unbound: IsnInformed turned off\n"));
+ }
+ }
+
+ //
+ // If NB went away, reset all the Binding's flags
+ //
+ if (Identifier == IDENTIFIER_SPX) {
+ PBINDING Binding;
+ UINT i;
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i < Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if (Binding && Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = FALSE;
+ IPX_DEBUG(PNP, ("NB unbound: IsnInformed off for NicId: %lx\n", i));
+ }
+ }
+ }
+ }
+#endif
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // BUGBUG: Ensure that no calls are made to bogus
+ // handlers.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalUnbind */
+
+
+VOID
+IpxInternalFindRoute (
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to submit
+ requests to find a remote network, which is contained in
+ FindRouteRequest->Network. FindRouteRequest->Identifier must
+ contain the identifier of the upper driver.
+
+ This request is always asynchronous and is completed by
+ a call to the FindRouteComplete handler of the upper driver.
+
+ NOTE: As a currently unspecified extension to this call,
+ we returns the tick and hop counts as two USHORTs in the
+ PVOID Reserved2 structure of the request.
+
+Arguments:
+
+ FindRouteRequest - Describes the request and contains
+ storage for IPX to use while processing it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ TDI_ADDRESS_IPX TempAddress;
+ PBINDING Binding, MasterBinding;
+ NTSTATUS Status;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First see if we have a route to this network in our
+ // table.
+ //
+
+ TempAddress.NetworkAddress = *(UNALIGNED ULONG *)(FindRouteRequest->Network);
+ //
+ // [SA] Bug #15094 Copy over the Node address so it can be used in WAN cases
+ //
+
+ // RtlZeroMemory (TempAddress.NodeAddress, 6);
+
+ *((UNALIGNED ULONG *)TempAddress.NodeAddress) = *((UNALIGNED ULONG *)FindRouteRequest->Node);
+ *((UNALIGNED USHORT *)(TempAddress.NodeAddress+4)) = *((UNALIGNED USHORT *)(FindRouteRequest->Node+4));
+
+ Segment = RipGetSegment(FindRouteRequest->Network);
+#ifdef _PNP_POWER
+ //
+ // Since we maintain the order of locks as Bind > Device > RIP table
+ // Get the lock up-front.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ IPX_BEGIN_SYNC (&SyncContext);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ CTEAssert ((sizeof(USHORT)*2) <= sizeof(PVOID));
+
+ Status = RipGetLocalTarget(
+ Segment,
+ &TempAddress,
+ FindRouteRequest->Type,
+ &FindRouteRequest->LocalTarget,
+ (PUSHORT)&FindRouteRequest->Reserved2);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this find route request for completion when the
+ // RIP response arrives.
+ //
+
+ CTEAssert (FindRouteRequest->Type != IPX_FIND_ROUTE_NO_RIP); // should never pend
+
+ InsertTailList(
+ &Device->Segments[Segment].FindWaitingForRoute,
+ &FindRouteRequest->Linkage);
+
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ if (Status != STATUS_PENDING) {
+
+ if (Status == STATUS_SUCCESS && FindRouteRequest->LocalTarget.NicId) {
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &FindRouteRequest->LocalTarget.NicHandle);
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FILL_LOCAL_TARGET(&FindRouteRequest->LocalTarget, Binding->NicId);
+
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[FindRouteRequest->LocalTarget.NicId];
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+ FindRouteRequest->LocalTarget.NicId = Binding->NicId;
+
+ }
+#endif
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ (BOOLEAN)((Status == STATUS_SUCCESS) ? TRUE : FALSE));
+
+ }
+
+} /* IpxInternalFindRoute */
+
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for upper drivers to query
+ information from us.
+
+Arguments:
+
+ InternalQueryType - Identifies the type of the query.
+
+ NicId - The ID to query, if needed
+
+ Buffer - Input or output buffer for the query.
+
+ BufferLength - The length of the buffer.
+
+ BufferLengthNeeded - If the buffer is too short, this returns
+ the length needed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PBINDING Binding;
+ BOOLEAN BindingNeeded;
+ ULONG LengthNeeded;
+ PIPX_LINE_INFO LineInfo;
+ PUSHORT MaximumNicId;
+ PULONG ReceiveBufferSpace;
+ TDI_ADDRESS_IPX UNALIGNED * IpxAddress;
+ IPX_SOURCE_ROUTING_INFO UNALIGNED * SourceRoutingInfo;
+ ULONG SourceRoutingLength;
+ UINT MaxUserData;
+ PDEVICE Device = IpxDevice;
+#ifdef _PNP_POWER
+ USHORT NicId = NicHandle->NicId;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // First verify the parameters.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_LINE_INFO);
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = sizeof(USHORT);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ BindingNeeded = FALSE; // for now we don't need it
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(ULONG);
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ if ((NicId == 0) &&
+ (BufferLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RtlCopyMemory (Buffer, &Device->SourceAddress, sizeof(TDI_ADDRESS_IPX));
+ return STATUS_SUCCESS;
+
+ }
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(TDI_ADDRESS_IPX);
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ BindingNeeded = TRUE;
+ LengthNeeded = sizeof(IPX_SOURCE_ROUTING_INFO);
+ break;
+
+#ifdef _PNP_POWER
+ //
+ // These are moved down from NB/SPX to IPX. LengthNeeded is set to 0
+ // so we dont return BUFFER_TOO_SMALL here; we assume here that
+ // Bufferlength is also 0.
+ // Buffer is actually the IRP here.
+ //
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+
+ BindingNeeded = FALSE;
+ LengthNeeded = 0;
+ break;
+#endif
+ default:
+
+ return STATUS_NOT_SUPPORTED;
+
+ }
+
+
+ if (LengthNeeded > BufferLength) {
+ if (BufferLengthNeeded != NULL) {
+ *BufferLengthNeeded = LengthNeeded;
+ }
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (BindingNeeded) {
+
+ if (NicId == 0) {
+ NicId = 1;
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = IpxDevice->Bindings[NicId];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif
+ }
+
+
+ //
+ // Now return the data.
+ //
+
+ switch (InternalQueryType) {
+
+ case IPX_QUERY_LINE_INFO:
+
+ LineInfo = (PIPX_LINE_INFO)Buffer;
+ LineInfo->LinkSpeed = Binding->MediumSpeed;
+ LineInfo->MaximumPacketSize = Binding->MaxLookaheadData + sizeof(IPX_HEADER);
+ LineInfo->MaximumSendSize = Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER);
+ LineInfo->MacOptions = Binding->Adapter->MacInfo.MacOptions;
+ break;
+
+ case IPX_QUERY_MAXIMUM_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestExternalNicId);
+ break;
+
+ case IPX_QUERY_IS_ADDRESS_LOCAL:
+
+ IpxAddress = (TDI_ADDRESS_IPX UNALIGNED *)Buffer;
+ if (!IpxIsAddressLocal(IpxAddress)) {
+ return STATUS_NO_SUCH_DEVICE;
+ }
+ break;
+
+ case IPX_QUERY_RECEIVE_BUFFER_SPACE:
+
+ ReceiveBufferSpace = (PULONG)Buffer;
+ *ReceiveBufferSpace = Binding->Adapter->ReceiveBufferSpace;
+ break;
+
+ case IPX_QUERY_IPX_ADDRESS:
+
+ RtlCopyMemory (Buffer, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ break;
+
+ case IPX_QUERY_SOURCE_ROUTING:
+
+ SourceRoutingInfo = (IPX_SOURCE_ROUTING_INFO UNALIGNED *)Buffer;
+
+ MacLookupSourceRouting(
+ SourceRoutingInfo->Identifier,
+ Binding,
+ SourceRoutingInfo->RemoteAddress,
+ SourceRoutingInfo->SourceRouting,
+ &SourceRoutingLength);
+
+ //
+ // Reverse the direction of the source routing since it
+ // is returned in the outgoing order.
+ //
+
+ if (SourceRoutingLength > 0) {
+ SourceRoutingInfo->SourceRouting[0] &= 0x7f;
+ }
+ SourceRoutingInfo->SourceRoutingLength = (USHORT)SourceRoutingLength;
+
+ MacReturnMaxDataSize(
+ &Binding->Adapter->MacInfo,
+ SourceRoutingInfo->SourceRouting,
+ SourceRoutingLength,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ //
+ // MaxUserData does not include the MAC header but does include
+ // any extra 802.2 etc. headers, so we adjust for that to get the
+ // size starting at the IPX header.
+ //
+
+ SourceRoutingInfo->MaximumSendSize =
+ MaxUserData -
+ (Binding->DefHeaderSize - Binding->Adapter->MacInfo.MinHeaderLength);
+
+ break;
+
+ case IPX_QUERY_MAX_TYPE_20_NIC_ID:
+
+ MaximumNicId = (PUSHORT)Buffer;
+ *MaximumNicId = MIN (Device->MaxBindings, IpxDevice->HighestType20NicId);
+ break;
+
+#ifdef _PNP_POWER
+ case IPX_QUERY_DATA_LINK_ADDRESS:
+ case IPX_QUERY_NETWORK_ADDRESS:
+ //
+ // Call the TDI query equivalent here.
+ //
+ return IpxTdiQueryInformation(Device, (PREQUEST)Buffer);
+
+#endif
+ }
+
+#ifdef _PNP_POWER
+ //
+ // If Binding was needed earlier, it was referenced, deref it now.
+ //
+ if (BindingNeeded) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+
+ //
+ // If we haven't returned failure by now, succeed.
+ //
+
+ return STATUS_SUCCESS;
+
+} /* IpxInternalQuery */
+
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+// RIP not converted yet...
+//
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to increment
+ the inactivity counter on a wan binding. This is done every
+ minute.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ //
+ // [BUGBUGZZ] Change to NIC_HANDLE_TO_BINDING later. Not done yet since RIP not changed to
+ // use NICHANDLE instead of NicId
+ //
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ ++Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+
+ }
+#endif
+
+} /* IpxInternalIncrementWanInactivity */
+
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+)
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point where rip calls us to query
+ the inactivity counter on a wan binding.
+
+Arguments:
+
+ NicId - The NIC ID of the wan binding.
+
+Return Value:
+
+ The inactivity counter for this binding.
+
+--*/
+
+{
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ // Binding = NIC_HANDLE_TO_BINDING(IpxDevice, &NicHandle);
+
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NicId);
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ return Binding->WanInactivityCounter;
+
+ } else {
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[NicId];
+
+ if ((Binding != NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync)) {
+
+ return Binding->WanInactivityCounter;
+
+ } else {
+
+ CTEAssert (FALSE);
+ return 0;
+
+ }
+#endif
+
+} /* IpxInternalQueryWanInactivity */
+
+#ifdef _PNP_POWER
+
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+)
+
+/*++
+
+Routine Description:
+
+ This routine goes through the list of adapters and informs (thru' PnP indications)
+ the ISN drivers bound to IPX about any new adapters that have appeared before the
+ bind took place.
+
+ This is queued as a work item in the InternalBind routine.
+
+Arguments:
+
+ Param - the upper driver identifier.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Identifier = (ULONG)Param;
+ PDEVICE Device=IpxDevice;
+ ULONG i;
+ PBINDING Binding;
+ IPX_PNP_INFO IpxPnPInfo;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Set up the LineInfo struct.
+ //
+
+ //
+ // BUGBUG: Do we give Binding-specific information here?
+ //
+ IpxPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ IpxPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ IpxPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ switch(Identifier) {
+ case IDENTIFIER_NB:
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ //
+ // Inform about all the adapters
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+ Binding = NIC_ID_TO_BINDING(Device, i);
+
+ if (!Binding) {
+ continue;
+ }
+
+ //
+ // We could have informed the upper driver from IpxBindAdapter
+ //
+ if (!Binding->IsnInformed[Identifier]) {
+ Binding->IsnInformed[Identifier] = TRUE;
+
+ //
+ // Inform NB - the reserved network/node address is always that of the first
+ // binding
+ //
+ if (i==1) {
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ } else {
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+ IpxPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, (USHORT)i);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to NB add: %lx\n", Binding));
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ }
+ }
+ }
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ break;
+
+ case IDENTIFIER_SPX:
+ //
+ // For SPX this is called directly, with the IsnInformed flag appropriately set.
+ // This is done so that the IsnInformed flag cannot be changed under
+ // us by the BindAdapter routine.
+ //
+#if 0
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ if (!NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier]) {
+ NIC_ID_TO_BINDING(Device, 1)->IsnInformed[Identifier] = TRUE;
+#endif
+ IpxPnPInfo.FirstORLastDevice = TRUE;
+ //
+ // Inform of the reserved address only
+ //
+ if (Device->VirtualNetwork) {
+ IpxPnPInfo.NetworkAddress = Device->SourceAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Device->SourceAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 0);
+ } else {
+ IpxPnPInfo.NetworkAddress = NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, NIC_ID_TO_BINDING(Device, 1)->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, 1);
+ }
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+
+ // IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ (*Device->UpperDrivers[Identifier].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(PNP, ("IpxPnPIsnIndicate: PnP to SPX add: %lx\n", NIC_ID_TO_BINDING(Device, 1)));
+#if 0
+ } else {
+ CTEAssert(FALSE);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+#endif
+
+ }
+}
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/ipxprocs.h b/private/ntos/tdi/isnp/ipx/ipxprocs.h
new file mode 100644
index 000000000..abfcf6ec3
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxprocs.h
@@ -0,0 +1,1525 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+ 1. Added new functions - IpxReceivePacket, IpxReceiveIndicationNew
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define IpxPrint0(fmt) DbgPrint(fmt)
+#define IpxPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define IpxPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define IpxPrint0(fmt)
+#define IpxPrint1(fmt,v0)
+#define IpxPrint2(fmt,v0,v1)
+#define IpxPrint3(fmt,v0,v1,v2)
+#define IpxPrint4(fmt,v0,v1,v2,v3)
+#define IpxPrint5(fmt,v0,v1,v2,v3,v4)
+#define IpxPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define IPX_PACKET_LOG 1
+#endif
+
+#ifdef IPX_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _IPX_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER IpxHeader;
+ UCHAR Data[14];
+} IPX_PACKET_LOG_ENTRY, *PIPX_PACKET_LOG_ENTRY;
+
+#define IPX_PACKET_LOG_LENGTH 128
+extern ULONG IpxPacketLogDebug;
+extern USHORT IpxPacketLogSocket;
+EXTERNAL_LOCK(IpxPacketLogLock);
+extern IPX_PACKET_LOG_ENTRY IpxPacketLog[IPX_PACKET_LOG_LENGTH];
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogLoc;
+extern PIPX_PACKET_LOG_ENTRY IpxPacketLogEnd;
+
+//
+// Bit fields in IpxPacketLogDebug
+//
+
+#define IPX_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to IpxPacketLogSocket
+#define IPX_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-IPX)
+
+#define IPX_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define IPX_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define IPX_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define IPX_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define IPX_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from IpxPacketLogSocket
+
+VOID
+IpxLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID IpxHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (IpxPacketLogDebug & (_Bit))
+
+#else // IPX_PACKET_LOG
+
+#define IpxLogPacket(_MacHeader,_Length,_IpxHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // IPX_PACKET_LOG
+
+#ifdef _PNP_POWER
+//
+// In load-only PnP, references are not needed on adapters. This should be changed
+// to actually take the reference post 4.0.
+//
+// BUGBUG: Revisit Post 4.0 - Keep the actual instructions around for ease of activation later.
+//
+#define IpxReferenceAdapter(_adapter)
+ // InterlockedIncrement(&(_adapter)->ReferenceCount)
+
+#define IpxDereferenceAdapter(_adapter)
+/*
+ if (InterlockedDecrement(&(_adapter)->ReferenceCount) == 0) {\
+ IpxCloseNdis(_adapter); \
+ IpxDestroyAdapter(_adapter);\
+ }\
+*/
+#endif
+
+//
+// In load-only PnP case, we dont need the references on bindings. All such references
+// have been changed to this macro.
+//
+#define IpxReferenceBinding1(_Binding, _Type)
+
+#define IpxDereferenceBinding1(_Binding, _Type)
+
+#if DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefBinding (_Binding)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Binding)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefDevice (_Device)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefDevice (_Device)
+
+
+#define IpxReferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddress (_Address)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressLock (_Address)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressSync (_Address)
+
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFile (_AddressFile)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileLock (_AddressFile)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &IpxGlobalInterlock); \
+ IpxRefAddressFileSync (_AddressFile)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFile (_AddressFile)
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock); \
+ IpxDerefAddressFileSync (_AddressFile)
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &IpxGlobalInterlock); \
+ (VOID)IPX_ADD_ULONG ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &IpxGlobalInterlock);
+
+#else // DBG
+
+#define IpxReferenceBinding(_Binding, _Type) \
+ InterlockedIncrement(&(_Binding)->ReferenceCount)
+
+#define IpxDereferenceBinding(_Binding, _Type) \
+ IpxDerefBinding (_Binding)
+
+#define IpxReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define IpxDereferenceDevice(_Device, _Type) \
+ IpxDerefDevice (_Device)
+
+#define IpxReferenceAddress(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement(&(_Address)->ReferenceCount)
+
+#define IpxDereferenceAddress(_Address, _Type) \
+ IpxDerefAddress (_Address)
+
+#define IpxDereferenceAddressSync(_Address, _Type) \
+ IpxDerefAddressSync (_Address)
+
+#define IpxReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement(&(_AddressFile)->ReferenceCount)
+
+#define IpxReferenceAddressFileSync(_AddressFile, _Type) \
+ (VOID)IPX_ADD_ULONG( \
+ &(_AddressFile)->ReferenceCount, \
+ 1, \
+ (_AddressFile)->AddressLock)
+
+#define IpxDereferenceAddressFile(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxDereferenceAddressFileSync(_AddressFile, _Type) \
+ if (InterlockedDecrement(&(_AddressFile)->ReferenceCount) == 0) { \
+ IpxDestroyAddressFile (_AddressFile); \
+ }
+
+#define IpxTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define IpxAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ IpxpAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define IpxFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ IpxpFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define IPX_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define IPX_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+//
+// This routine does an ordered compare of two node addresses. It
+// can handle the first address having the source-routing bit on.
+//
+
+#define IPX_NODE_COMPARE(_A,_B,_R) \
+ if ((*(_R) = (*(UNALIGNED SHORT *)(((PUCHAR)(_A))+4) - *(UNALIGNED SHORT *)(((PUCHAR)(_B))+4))) == 0) { \
+ *(_R) = ((*(UNALIGNED LONG *)((PUCHAR)(_A)) & 0xffffff7f) - *(UNALIGNED LONG *)((PUCHAR)(_B))); \
+ }
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+IpxTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+IpxAbortLineChanges(
+ IN PVOID ControlChannelContext
+ );
+
+
+//
+// Routines in adapter.c
+//
+
+VOID
+IpxRefBinding(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxDerefBinding(
+ IN PBINDING Binding
+ );
+
+NTSTATUS
+IpxCreateAdapter(
+ IN PDEVICE Device,
+ IN PUNICODE_STRING AdapterName,
+ IN OUT PADAPTER *AdapterPtr
+ );
+
+VOID
+IpxDestroyAdapter(
+ IN PADAPTER Adapter
+ );
+
+NTSTATUS
+IpxCreateBinding(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigBinding OPTIONAL,
+ IN ULONG NetworkNumberIndex,
+ IN PWCHAR AdapterName,
+ IN OUT PBINDING *BindingPtr
+ );
+
+VOID
+IpxDestroyBinding(
+ IN PBINDING Binding
+ );
+
+#ifdef _PNP_POWER
+VOID
+IpxAllocateBindingPool(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopBinding(
+ PDEVICE Device
+ );
+#endif
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_IPX UNALIGNED *
+IpxParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
+ );
+
+BOOLEAN
+IpxValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+#if DBG
+
+VOID
+IpxBuildTdiAddress(
+ IN PVOID AddressBuffer,
+ IN ULONG Network,
+ IN UCHAR Node[6],
+ IN USHORT Socket
+ );
+
+#else
+
+#define IpxBuildTdiAddress(_AddressBuffer,_Network,_Node,_Socket) { \
+ TA_IPX_ADDRESS UNALIGNED * _IpxAddress = (TA_IPX_ADDRESS UNALIGNED *)(_AddressBuffer); \
+ _IpxAddress->TAAddressCount = 1; \
+ _IpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); \
+ _IpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; \
+ _IpxAddress->Address[0].Address[0].NetworkAddress = (_Network); \
+ _IpxAddress->Address[0].Address[0].Socket = (_Socket); \
+ RtlCopyMemory(_IpxAddress->Address[0].Address[0].NodeAddress, (_Node), 6); \
+}
+
+#endif
+
+NTSTATUS
+IpxOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+USHORT
+IpxAssignSocket(
+ IN PDEVICE Device
+ );
+
+PADDRESS
+IpxCreateAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxVerifyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+IpxRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+IpxDerefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+IpxDerefAddressSync(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+IpxCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+IpxRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxRefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+IpxDerefAddressFileSync(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+PADDRESS
+IpxLookupAddress(
+ IN PDEVICE Device,
+ IN USHORT Socket
+ );
+
+NTSTATUS
+IpxStopAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+NTSTATUS
+IpxCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+IpxRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+IpxCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN ULONG SegmentCount,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+IpxDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+#ifdef _PNP_POWER
+VOID
+IpxPnPUpdateDevice(
+ IN PDEVICE Device
+ );
+#endif
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+PVOID
+IpxpAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+IpxpFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+IpxpAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+IpxpFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+IpxWriteResourceErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+IpxWriteGeneralErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+IpxWriteOidErrorLog(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+#ifdef _PNP_POWER
+ULONG
+IpxResolveAutoDetect(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings,
+ IN CTELockHandle *LockHandle1,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+IpxResolveBindingSets(
+ IN PDEVICE Device,
+ IN ULONG ValidBindings
+ );
+
+NTSTATUS
+IpxBindToAdapter(
+ IN PDEVICE Device,
+ IN PBINDING_CONFIG ConfigAdapter,
+ IN PADAPTER *AdapterPtr,
+ IN ULONG FrameTypeIndex
+ );
+
+NTSTATUS
+IpxUnBindFromAdapter(
+ IN PBINDING Binding
+ );
+
+VOID
+IpxPnPUpdateBindingArray(
+ IN PDEVICE Device,
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxPnPToLoad();
+
+NTSTATUS
+IpxPnPReallocateBindingArray(
+ IN PDEVICE Device,
+ IN ULONG Size
+ );
+
+#endif _PNP_POWER
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+IpxTdiSetEventHandler(
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in ind.c
+//
+
+//
+// [CH] Added these two functions
+//
+INT
+IpxReceivePacket (
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ );
+
+NDIS_STATUS
+IpxReceiveIndicationNew(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize,
+ IN PMDL pMdl,
+ IN PINT pTdiClientCount
+ );
+
+NDIS_STATUS
+IpxReceiveIndication(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_HANDLE ReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT PacketSize
+ );
+
+VOID
+IpxReceiveComplete(
+ IN NDIS_HANDLE BindingContext
+ );
+
+NTSTATUS
+IpxUpdateBindingNetwork(
+ IN PDEVICE Device,
+ IN PBINDING Binding,
+ IN ULONG Network
+ );
+
+
+//
+// Routines in internal.c
+//
+
+NTSTATUS
+IpxInternalBind(
+ IN PDEVICE Device,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+IpxInternalUnbind(
+ IN PDEVICE Device,
+ IN UINT Identifier
+ );
+
+VOID
+IpxInternalFindRoute(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest
+ );
+
+NTSTATUS
+IpxInternalQuery(
+ IN ULONG InternalQueryType,
+#ifdef _PNP_POWER
+ IN PNIC_HANDLE NicHandle OPTIONAL,
+#else
+ IN USHORT NicId OPTIONAL,
+#endif
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG BufferLengthNeeded OPTIONAL
+);
+
+VOID
+IpxInternalIncrementWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+ULONG
+IpxInternalQueryWanInactivity(
+#ifdef _PNP_LATER
+ IN NIC_HANDLE NicHandle
+#else
+ IN USHORT NicId
+#endif
+);
+
+#ifdef _PNP_POWER
+VOID
+IpxPnPIsnIndicate(
+ IN PVOID Param
+);
+#endif
+
+//
+// Routines in ndis.c
+//
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ );
+
+VOID
+IpxDeregisterProtocol(
+ VOID
+ );
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ );
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ );
+
+BOOLEAN
+IpxIsAddressLocal(
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress
+ );
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ );
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ );
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ );
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ );
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ );
+
+
+#ifdef _PNP_POWER
+VOID
+IpxBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ );
+
+VOID
+IpxUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ );
+
+VOID
+IpxTranslate(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ OUT PNET_PNP_ID IdList,
+ IN ULONG IdListLength,
+ OUT PULONG BytesReturned
+ );
+#endif // _PNP_POWER
+
+//
+// Routines in mac.c
+//
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ );
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ );
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ );
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ );
+
+#ifdef _PNP_POWER
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+#endif
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ );
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR NextRouter[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ );
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ );
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ );
+#endif
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ );
+#endif
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ );
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ );
+#endif
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ IN PDEVICE Device
+ );
+
+#if BACK_FILL
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ IN PDEVICE Device
+ );
+#endif
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ );
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ );
+
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+IpxTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+IpxTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in receive.c
+//
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ );
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ );
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ );
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in rip.c
+//
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ );
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ );
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ );
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ );
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ );
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ );
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ );
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ );
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ );
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ );
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ );
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ );
+
+
+//
+// Routines in send.c
+//
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ );
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ );
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ );
+#else
+#define IpxConstructHeader(_Header,_PacketLength,_PacketType,_RemoteAddress,_LocalAddress) { \
+ PIPX_HEADER _IpxHeader = (PIPX_HEADER)(_Header); \
+ _IpxHeader->CheckSum = 0xffff; \
+ _IpxHeader->PacketLength[0] = (UCHAR)((_PacketLength) / 256); \
+ _IpxHeader->PacketLength[1] = (UCHAR)((_PacketLength) % 256); \
+ _IpxHeader->TransportControl = 0; \
+ _IpxHeader->PacketType = (_PacketType); \
+ RtlCopyMemory(_IpxHeader->DestinationNetwork, (PVOID)(_RemoteAddress), 12); \
+ RtlCopyMemory(_IpxHeader->SourceNetwork, (_LocalAddress), 12); \
+}
+#endif
+
+//
+// Routines in loopback.c
+//
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ );
+
+VOID
+IpxInitLoopback();
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ );
+
diff --git a/private/ntos/tdi/isnp/ipx/ipxtypes.h b/private/ntos/tdi/isnp/ipx/ipxtypes.h
new file mode 100644
index 000000000..0cc788a8f
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ipxtypes.h
@@ -0,0 +1,1999 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ipxtypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports - tagged [CH]
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+--*/
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _IPX_SEND_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+ UCHAR DestinationType; // one of DEF, BCAST, MCAST
+ struct _IPX_PADDING_BUFFER * PaddingBuffer; // if one was allocated
+ PNDIS_BUFFER PreviousTail; // if padding buffer was appended
+#ifdef _PNP_POWER
+ IPX_LOCAL_TARGET LocalTarget;
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ ULONG PacketLength; // length that comes into IpxSendFrame initially
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY WaitLinkage; // when on WaitingForRoute/WaitingRipPackets
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+
+ //
+ // The next fields are used differently depending on whether
+ // the packet is being used for a datagram send or a rip request.
+ //
+
+ union {
+ struct {
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+ USHORT CurrentNicId; // current binding being tried for net 0 sends
+ BOOLEAN Net0SendSucceeded; // at least one NdisSend succeeded for net 0 sends
+ BOOLEAN OutgoingSap; // packet is sent from the SAP socket
+ } SR_DG;
+ struct {
+ ULONG Network; // net we are looking for
+ USHORT CurrentNicId; // current binding being tried
+ UCHAR RetryCount; // number of times sent; 0xfe = response, 0xff = down
+ BOOLEAN RouteFound; // network has been found
+ USHORT SendTime; // timer expirations when sent.
+ BOOLEAN NoIdAdvance; // don't advance CurrentNicId this time.
+ } SR_RIP;
+ } u;
+
+ PUCHAR Header; // points to the MAC/IPX header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header;
+#if BACK_FILL
+ BOOLEAN BackFill; // 1 if we are using SMB's extended header
+ PNDIS_BUFFER IpxHeader; // Place holder for our IpxHeader
+ PNDIS_BUFFER MacHeader; // Place holder for our mac header
+ PVOID MappedSystemVa;
+ PVOID ByteOffset;
+ LONG UserLength;
+#endif
+} IPX_SEND_RESERVED, *PIPX_SEND_RESERVED;
+
+//
+// Values for the DestinationType field.
+//
+
+#define DESTINATION_DEF 1
+#define DESTINATION_BCAST 2
+#define DESTINATION_MCAST 3
+
+//
+// Used to indicate to IpxReceiveIndication that this is a loopback packet
+// Assumption: Ndis cannot return this as the NdisBindingHandle value since
+// that is a pointer (our pointers shd in kernel space, if not in Nonpaged pool).
+//
+#define IPX_LOOPBACK_COOKIE 0x00460007
+
+//
+// MIN/MAX macros
+//
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef _PNP_POWER
+
+//
+// In order to avoid a lock to read a value, this is used.
+// As long as the final value has made it to _b by the time
+// the check is made, this works fine.
+//
+
+#define ASSIGN_LOOP(_a, _b) \
+ do { \
+ _a = _b; \
+ } while ( _a != _b );
+
+//
+// Gets the value of a Ulong (possibly a pointer) by adding 0 in an interlocked manner.
+// This relies on the fact that the return of the ExchangeAdd will be the value prior to
+// addition. Since the value added is 0, the final value stays the same.
+//
+#define GET_VALUE(x) \
+ InterlockedExchangeAdd((PULONG)&(x), 0)
+
+#define SET_VALUE(x,y) \
+ InterlockedExchange((PLONG)&(x), (LONG)(y))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// We need to ensure that the binding array pointer is valid hence use the interlocked operation.
+// Also, the binding pointer read out of the array should be valid. Since the bindings are never
+// freed (IPX maintains a pool of bindings), the pointer thus retrieved will always point to
+// memory that belongs to us, which in the worst case could point to a re-claimed binding block.
+//
+// BUGBUGZZ: we can eliminate the second interlock if we always ensure that the bindings in an array
+// dont change i.e. when we move around bindings, do them in a copy and make that the master (thru'
+// a single ulong exchange).
+//
+// A problem that still remains here is that even if we get a valid (IPX owned non-paged) ptr out of
+// the array, we still cannot atomically get a ref on the binding
+// We might need those locks after all.... (revisit post SUR when the delete is enabled).
+//
+#define NIC_ID_TO_BINDING(_device, _nicid) \
+ ((PBINDING)GET_VALUE( ((PBIND_ARRAY_ELEM) GET_VALUE( (_device)->Bindings) )[_nicid].Binding ))
+
+/*
+PBINDING
+NIC_ID_TO_BINDING_NO_ILOCK (
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ );
+*/
+//
+// No interlocked operations are used here to get to the binding. This is used in the PnP add/delete
+// adapter paths on the assumption that NDIS will serialize the addition/deletion of cards. [JammelH: 5/15/96]
+//
+#define NIC_ID_TO_BINDING_NO_ILOCK(_device, _nicid) \
+ ((_device)->Bindings[_nicid].Binding)
+
+/*
+VOID
+INSERT_BINDING(
+ IN PDEVICE _device,
+ IN USHORT _nicid,
+ IN PBINDING _binding
+ )
+*/
+//
+// We dont do a get_value for the first arg of the macro since we are the writer and
+// this value cannot change from under us here (NDIS will not give us two PnP Add adapter
+// indications simultaneously).
+//
+#define INSERT_BINDING(_device, _nicid, _binding) \
+ SET_VALUE((_device)->Bindings[_nicid].Binding, (_binding));
+
+/*
+VOID
+SET_VERSION(
+ IN PDEVICE _device,
+ IN USHORT _nicid
+ )
+*/
+#define SET_VERSION(_device, _nicid) \
+ SET_VALUE((_device)->Bindings[_nicid].Version, ++(_device)->BindingVersionNumber);
+
+/*
+PBINDING
+NIC_HANDLE_TO_BINDING (
+ IN PDEVICE _device,
+ IN PNIC_HANDLE _nichandle,
+ );
+*/
+#ifdef _PNP_LATER
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ (((_nichandle)->Signature == IPX_BINDING_SIGNATURE) && \
+ ((_nichandle)->Version == (_device)->Bindings[(_nichandle)->NicId].Version)) ? \
+ (_device)->Bindings[(_nichandle)->NicId].Binding : NULL;
+#else
+
+#define NIC_HANDLE_TO_BINDING(_device, _nichandle) \
+ NIC_ID_TO_BINDING(_device, (_nichandle)->NicId);
+#endif
+
+/*
+VOID
+FILL_LOCAL_TARGET(
+ IN PLOCAL_TARGET _localtarget,
+ IN USHORT _nicid
+ )
+*/
+
+#define FILL_LOCAL_TARGET(_localtarget, _nicid) \
+ NIC_HANDLE_FROM_NIC((_localtarget)->NicHandle, _nicid)
+
+#ifdef _PNP_LATER
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic; \
+ _nichandle.Signature = IPX_BINDING_SIGNATURE; \
+ if (_nic == 0) { \
+ _nichandle.Version = 0; \
+ } else { \
+ _nichandle.Version = IpxDevice->Bindings[_nic].Version; \
+ }
+
+#else
+
+#define NIC_HANDLE_FROM_NIC(_nichandle, _nic) \
+ _nichandle.NicId = _nic;
+
+#endif
+
+#define NIC_FROM_LOCAL_TARGET(_localtarget) \
+ (_localtarget)->NicHandle.NicId
+
+#endif _PNP_POWER
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _IPX_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for IPX packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ BOOLEAN OwnedByAddress; // packet is owned by an address
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ struct _ADDRESS * Address; // that owns this packet, if ones does
+ PREQUEST SingleRequest; // if transfer is for one only
+ struct _IPX_RECEIVE_BUFFER * ReceiveBuffer; // if transfer is for multiple requests
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ LIST_ENTRY Requests; // waiting on this transfer
+} IPX_RECEIVE_RESERVED, *PIPX_RECEIVE_RESERVED;
+
+//
+// The amount of data we need in our standard header, rounded up
+// to the next longword bounday.
+//
+// [BUGBUGZZ] Make this declaration in one place
+//
+#define PACKET_HEADER_SIZE (MAC_HEADER_SIZE + IPX_HEADER_SIZE + RIP_PACKET_SIZE)
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+// #define IPX_OWN_PACKETS 1
+
+#define IpxAllocateSendPacket(_Device,_SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_SendPacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define IpxAllocateReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)(PACKET(_ReceivePacket))); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#ifdef IPX_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _IPX_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_SEND_RESERVED)];
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(IPX_RECEIVE_RESERVED)];
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define IpxFreeSendPacket(_Device,_Packet)
+
+#define IpxFreeReceivePacket(_Device,_Packet)
+
+#else // IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_SEND_PACKET, *PIPX_SEND_PACKET;
+
+typedef struct _IPX_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+ NDIS_HANDLE PoolHandle;
+} IPX_RECEIVE_PACKET, *PIPX_RECEIVE_PACKET;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define IpxAllocateSingleSendPacket(_Device,_SendPacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_SendPacket)->PoolHandle,1,sizeof(IPX_SEND_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, (_SendPacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxAllocateSingleReceivePacket(_Device,_ReceivePacket,_Status) { \
+ NdisAllocatePacketPool(_Status, &(_ReceivePacket)->PoolHandle,1,sizeof(IPX_RECEIVE_RESERVED)); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, (_ReceivePacket)->PoolHandle); \
+ if (*(_Status) == NDIS_STATUS_SUCCESS) { \
+ (_Device)->MemoryUsage += \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis packet memory\n"));\
+ }\
+ } else {\
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));\
+ }\
+}
+
+#define IpxFreeSingleSendPacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_SEND_RESERVED)); \
+}
+#define IpxFreeSingleReceivePacket(_Device,_Packet) { \
+ NdisFreePacket((_Packet).Packet); \
+ NdisFreePacketPool((_Packet).PoolHandle); \
+ (_Device)->MemoryUsage -= \
+ (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0])+ \
+ FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])+ \
+ sizeof(IPX_RECEIVE_RESERVED)); \
+}
+
+#define IpxFreeSendPacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#define IpxFreeReceivePacket(_Device,_Packet) NdisFreePacket(PACKET(_Packet))
+
+#endif // IPX_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PIPX_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PIPX_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+//
+// This is the structure that contains a receive buffer for
+// datagrams that are going to multiple recipients.
+//
+
+typedef struct _IPX_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ PUCHAR Data; // the actual data
+} IPX_RECEIVE_BUFFER, *PIPX_RECEIVE_BUFFER;
+
+
+//
+// This is the structure that contains a padding buffer for
+// padding ethernet frames out to an even number of bytes.
+//
+
+typedef struct _IPX_PADDING_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free list
+ PNDIS_BUFFER NdisBuffer; // length of the NDIS buffer
+ ULONG DataLength; // length of the data
+ UCHAR Data[1]; // the actual pad data
+} IPX_PADDING_BUFFER, *PIPX_PADDING_BUFFER;
+
+#ifdef IPX_OWN_PACKETS
+
+typedef struct _IPX_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_SEND_PACKET Packets[1];
+} IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+typedef struct _IPX_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ IPX_RECEIVE_PACKET Packets[1];
+} IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+#else
+
+typedef struct _IPX_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ PUCHAR Header;
+ NDIS_HANDLE PoolHandle;
+} IPX_PACKET_POOL, *PIPX_PACKET_POOL;
+
+typedef IPX_PACKET_POOL IPX_RECEIVE_POOL, *PIPX_RECEIVE_POOL;
+typedef IPX_PACKET_POOL IPX_SEND_POOL, *PIPX_SEND_POOL;
+
+#endif // IPX_OWN_PACKETS
+
+typedef struct _IPX_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+ IPX_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} IPX_RECEIVE_BUFFER_POOL, *PIPX_RECEIVE_BUFFER_POOL;
+
+//
+// Number of upper drivers we support.
+//
+
+#define UPPER_DRIVER_COUNT 3
+
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_RIP 4
+#define MEMORY_SOURCE_ROUTE 5
+#define MEMORY_BINDING 6
+#define MEMORY_QUERY 7
+
+#define MEMORY_MAX 8
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(IpxMemoryInterlock);
+extern MEMORY_TAG IpxMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+//
+// This defines the reasons we delete rip entries for a binding.
+//
+
+typedef enum _IPX_BINDING_CHANGE_TYPE {
+ IpxBindingDeleted,
+ IpxBindingMoved,
+ IpxBindingDown
+} IPX_BINDING_CHANGE_TYPE, *PIPX_BINDING_CHANGE_TYPE;
+
+
+//
+// This structure contains information about a single
+// source routing entry.
+//
+
+typedef struct _SOURCE_ROUTE {
+
+ struct _SOURCE_ROUTE * Next; // next in hash list
+
+ UCHAR MacAddress[6]; // remote MAC address
+ UCHAR TimeSinceUsed; // timer expirations since last used
+ UCHAR SourceRoutingLength; // length of the data
+
+ UCHAR SourceRouting[1]; // source routing data, stored as received in
+
+} SOURCE_ROUTE, *PSOURCE_ROUTE;
+
+#define SOURCE_ROUTE_SIZE(_SourceRoutingLength) \
+ (FIELD_OFFSET(SOURCE_ROUTE, SourceRouting[0]) + (_SourceRoutingLength))
+
+#define SOURCE_ROUTE_HASH_SIZE 16
+
+//
+// ULONG
+// MacSourceRoutingHash(
+// IN PUCHAR MacAddress
+// )
+//
+// /*++
+//
+// Routine Description:
+//
+// This routine returns a hash value based on the MAC address
+// that is pointed to. It will be between 0 and SOURCE_ROUTE_HASH_SIZE.
+//
+// Arguments:
+//
+// MacAddress - The MAC address. NOTE: The source-routing bit may
+// or may not be on in the first byte, this routine will handle
+// that.
+//
+// Return Value:
+//
+// The hash value.
+//
+// --*/
+//
+
+#define MacSourceRoutingHash(_MacAddress) \
+ ((ULONG)((_MacAddress)[5] % SOURCE_ROUTE_HASH_SIZE))
+
+
+
+//
+// this structure describes a single NDIS adapter that IPX is
+// bound to.
+//
+
+struct _DEVICE;
+
+typedef struct _ADAPTER {
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IAD1"
+#endif
+
+#ifdef _PNP_POWER
+ ULONG ReferenceCount;
+#endif
+
+ ULONG BindingCount; // number bound to this adapter
+
+ //
+ // Handle returned by the NDIS wrapper after we bind to it.
+ //
+
+ NDIS_HANDLE NdisBindingHandle;
+
+ //
+ // The queue of (currently receive only) requests waiting to complete.
+ //
+
+ LIST_ENTRY RequestCompletionQueue;
+
+ //
+ // IPX header normal offsets for directed and
+ // broadcast/multicast frames.
+ //
+
+ ULONG DefHeaderSizes[ISN_FRAME_TYPE_MAX];
+ ULONG BcMcHeaderSizes[ISN_FRAME_TYPE_MAX];
+
+ //
+ // List of buffers to be used for transfers.
+ //
+
+ ULONG AllocatedReceiveBuffers;
+ LIST_ENTRY ReceiveBufferPoolList;
+ SLIST_HEADER ReceiveBufferList;
+
+ //
+ // List of ethernet padding buffers.
+ //
+
+ ULONG AllocatedPaddingBuffers;
+ SINGLE_LIST_ENTRY PaddingBufferList;
+
+ struct _BINDING * Bindings[ISN_FRAME_TYPE_MAX]; // the binding for each frame type.
+
+ //
+ // TRUE if broadcast reception is enabled on this adapter.
+ //
+
+ BOOLEAN BroadcastEnabled;
+
+ //
+ // TRUE if we have enabled an auto-detected frame type
+ // on this adapter -- used to prevent multiple ones.
+ //
+
+ BOOLEAN AutoDetectFound;
+
+ //
+ // TRUE if we got a response to at least one of our
+ // auto-detect frames.
+ //
+
+ BOOLEAN AutoDetectResponse;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // For WAN adapters, we support multiple bindings per
+ // adapter, all with the same frame type. For them we
+ // demultiplex using the local mac address. This stores
+ // the range of device NIC IDs associated with this
+ // particular address.
+ //
+
+ USHORT FirstWanNicId;
+ USHORT LastWanNicId;
+ ULONG WanNicIdCount;
+
+ //
+ // This is based on the configuration.
+ //
+
+ USHORT BindSap; // usually 0x8137
+ USHORT BindSapNetworkOrder; // usually 0x3781
+ BOOLEAN SourceRouting;
+ BOOLEAN EnableFunctionalAddress;
+ BOOLEAN EnableWanRouter;
+ ULONG ConfigMaxPacketSize;
+
+ //
+ // TRUE if the tree is empty, so we can check quickly.
+ //
+
+ BOOLEAN SourceRoutingEmpty[IDENTIFIER_TOTAL];
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR AdapterName;
+ ULONG AdapterNameLength;
+
+ struct _DEVICE * Device;
+
+ CTELock Lock;
+ CTELock * DeviceLock;
+
+ //
+ // some MAC addresses we use in the transport
+ //
+
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // The value of Device->SourceRoutingTime the last time
+ // we checked the list for timeouts (this is so we can
+ // tell in the timeout code when two bindings point to the
+ // same adapter).
+ //
+
+ CHAR LastSourceRoutingTime;
+
+ //
+ // These are used while initializing the MAC driver.
+ //
+
+ KEVENT NdisRequestEvent; // used for pended requests.
+ NDIS_STATUS NdisRequestStatus; // records request status.
+ NDIS_STATUS OpenErrorStatus; // if Status is NDIS_STATUS_OPEN_FAILED.
+
+ //
+ // This is the Mac type we must build the packet header for and know the
+ // offsets for.
+ //
+
+ NDIS_INFORMATION MacInfo;
+
+ ULONG MaxReceivePacketSize; // does not include the MAC header
+ ULONG MaxSendPacketSize; // includes the MAC header
+ ULONG ReceiveBufferSpace; // as queried from the card
+
+ //
+ // This information is used to keep track of the speed of
+ // the underlying medium.
+ //
+
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+
+ //
+ // The source routing tree for each of the identifiers
+ //
+
+ PSOURCE_ROUTE SourceRoutingHeads[IDENTIFIER_TOTAL][SOURCE_ROUTE_HASH_SIZE];
+
+} ADAPTER, * PADAPTER;
+
+#define ASSERT_ADAPTER(_Adapter) \
+ CTEAssert (((_Adapter)->Type == IPX_ADAPTER_SIGNATURE) && ((_Adapter)->Size == sizeof(ADAPTER)))
+
+
+//
+// These are the media and frame type specific MAC header
+// constructors that we call in the main TDI send path.
+//
+
+typedef NDIS_STATUS
+(*IPX_SEND_FRAME_HANDLER) (
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ );
+
+
+#define BREF_BOUND 1
+#ifdef _PNP_POWER
+#define BREF_DEVICE_ACCESS 2
+#define BREF_ADAPTER_ACCESS 3
+#endif
+#define BREF_TOTAL 4
+
+typedef struct _BINDING {
+
+#if DBG
+ ULONG RefTypes[BREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IBI1"
+#endif
+
+ ULONG ReferenceCount;
+
+#ifdef _PNP_POWER
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+#endif
+
+ //
+ // Adapter this binding is on.
+ //
+
+ PADAPTER Adapter;
+
+ //
+ // ID identifying us to the system (will be the index
+ // in Device->Bindings[]).
+ //
+
+ USHORT NicId;
+
+ //
+ // For LANs these will be the same as the adapter's, for WANs
+ // they change on line up indications.
+ //
+
+ ULONG MaxSendPacketSize;
+ ULONG MediumSpeed; // in units of 100 bytes/sec
+ HARDWARE_ADDRESS LocalMacAddress; // our local hardware address.
+
+ //
+ // This is used for WAN lines, all sends go to this address
+ // which is given on line up.
+ //
+
+ HARDWARE_ADDRESS RemoteMacAddress;
+
+ //
+ // For WAN lines, holds the remote address indicated to us
+ // in the IPXCP_CONFIGURATION structure -- this is used to
+ // select a binding to send to when WanGlobalNetworkNumber
+ // is TRUE.
+ //
+
+ UCHAR WanRemoteNode[6];
+
+ //
+ // TRUE if this binding was set up to allow auto-detection,
+ // instead of being configured explicitly in the registry.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // TRUE if this binding was set up for auto-detection AND
+ // was the default in the registry.
+ //
+
+ BOOLEAN DefaultAutoDetect;
+
+ //
+ // During auto-detect when we are processing responses from
+ // various networks, these keep track of how many responses
+ // we have received that match the current guess at the
+ // network number, and how many don't (the current guess
+ // is stored in TentativeNetworkAddress).
+ //
+
+ USHORT MatchingResponses;
+ USHORT NonMatchingResponses;
+
+ //
+ // During auto-detect, stores the current guess at the
+ // network number.
+ //
+
+ ULONG TentativeNetworkAddress;
+
+ //
+ // TRUE if this binding is part of a binding set.
+ //
+
+ BOOLEAN BindingSetMember;
+
+ //
+ // TRUE if this binding should receive broadcasts (this
+ // rotates through the members of a binding set).
+ //
+
+ BOOLEAN ReceiveBroadcast;
+
+ //
+ // TRUE for WAN lines if we are up.
+ //
+
+ BOOLEAN LineUp;
+
+ //
+ // TRUE if this is a WAN line and is dialout.
+ //
+
+ BOOLEAN DialOutAsync;
+
+ union {
+
+ //
+ // Used when a binding is active, if it is a member
+ // of a binding set.
+ //
+
+ struct {
+
+ //
+ // Used to link members of a binding set in a circular list.
+ // NULL for non-set members.
+ //
+
+ struct _BINDING * NextBinding;
+
+ //
+ // If this binding is a master of a binding set, this points
+ // to the binding to use for the next send. For other members
+ // of a binding set it is NULL. We use this to determine
+ // if a binding is a master or not.
+ //
+
+ struct _BINDING * CurrentSendBinding;
+
+ //
+ // For binding set members, points to the master binding
+ // (if this is the master it points to itself).
+ //
+
+ struct _BINDING * MasterBinding;
+
+ };
+
+ //
+ // This is used when we are first binding to adapters,
+ // and the device's Bindings array is not yet allocated.
+ //
+
+ LIST_ENTRY InitialLinkage;
+
+ };
+
+ //
+ // Used by rip to keep track of unused wan lines.
+ //
+
+ ULONG WanInactivityCounter;
+
+ //
+ // Our local address, we don't use the socket but we keep
+ // it here so we can do quick copies. It contains the
+ // real network that we are bound to and our node
+ // address on that net (typically the adapter's MAC
+ // address but it will change for WANs).
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_FRAME_HANDLER SendFrameHandler;
+
+ struct _DEVICE * Device;
+
+ CTELock * DeviceLock;
+
+ ULONG DefHeaderSize; // IPX header offset for directed frames
+ ULONG BcMcHeaderSize; // IPX header offset for broadcast/multicast
+
+ ULONG AnnouncedMaxDatagramSize; // what we advertise -- assumes worst-case SR
+ ULONG RealMaxDatagramSize; // what will really break the card
+ ULONG MaxLookaheadData;
+
+ //
+ // Configuration parameters. We overlay all of them except
+ // FrameType over the worker thread item we use to delay
+ // deletion -- all the others are not needed once the
+ // binding is up. Some of the config parameters are stored
+ // in the adapter, these are the ones that are modified
+ // per-binding.
+ //
+
+ ULONG FrameType;
+ union {
+ struct {
+ ULONG ConfiguredNetworkNumber;
+ BOOLEAN AllRouteDirected;
+ BOOLEAN AllRouteBroadcast;
+ BOOLEAN AllRouteMulticast;
+ };
+ WORK_QUEUE_ITEM WanDelayedQueueItem;
+ };
+
+#ifdef _PNP_POWER
+ //
+ // Indicates whether this binding was indicated to the ISN driver
+ //
+ BOOLEAN IsnInformed[UPPER_DRIVER_COUNT];
+
+ //
+ // Keeps the NetAddressRegistrationHandle.
+ //
+ HANDLE TdiRegistrationHandle;
+#endif
+} BINDING, * PBINDING;
+
+
+#ifdef _PNP_POWER
+typedef struct _IPX_BINDING_POOL {
+ LIST_ENTRY Linkage;
+ UINT BindingCount;
+ BINDING Bindings[1];
+} IPX_BINDING_POOL, *PIPX_BINDING_POOL;
+#endif
+
+//
+// This structure defines the control structure for a single
+// router table segment.
+//
+
+typedef struct _ROUTER_SEGMENT {
+ LIST_ENTRY WaitingForRoute; // packets waiting for a route in this segment
+ LIST_ENTRY FindWaitingForRoute; // find route requests waiting for a route in this segment
+ LIST_ENTRY WaitingLocalTarget; // QUERY_IPX_LOCAL_TARGETs waiting for a route in this segment
+ LIST_ENTRY WaitingReripNetnum; // MIPX_RERIPNETNUMs waiting for a route in this segment
+ LIST_ENTRY Entries;
+ PLIST_ENTRY EnumerateLocation;
+} ROUTER_SEGMENT, *PROUTER_SEGMENT;
+
+
+//
+// Number of buckets in the address hash table. This is
+// a multiple of 2 so hashing is quick.
+//
+
+#define IPX_ADDRESS_HASH_COUNT 16
+
+//
+// Routine to convert a socket to a hash index. We use the
+// high bits because it is stored reversed.
+//
+
+#define IPX_HASH_SOCKET(_S) ((((_S) & 0xff00) >> 8) % IPX_ADDRESS_HASH_COUNT)
+
+//
+// This macro gets the socket hash right out of the IPX header.
+//
+
+#define IPX_DEST_SOCKET_HASH(_IpxHeader) (((PUCHAR)&(_IpxHeader)->DestinationSocket)[1] % IPX_ADDRESS_HASH_COUNT)
+
+
+//
+// This structure defines the per-device structure for IPX
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_SR_TIMER 4
+#define DREF_RIP_TIMER 5
+#define DREF_LONG_TIMER 6
+#define DREF_RIP_PACKET 7
+#define DREF_ADDRESS_NOTIFY 8
+#define DREF_LINE_CHANGE 9
+
+#define DREF_TOTAL 12
+
+#ifdef _PNP_POWER
+//
+// Pre-allocated binding array size
+//
+#define MAX_BINDINGS 50
+#endif _PNP_POWER
+
+#ifdef _PNP_POWER
+//
+// Our new binding array is composed of the following binding
+// array element
+//
+typedef struct _BIND_ARRAY_ELEM {
+ PBINDING Binding;
+ ULONG Version;
+} BIND_ARRAY_ELEM, *PBIND_ARRAY_ELEM;
+
+#endif _PNP_POWER
+
+typedef struct _DEVICE {
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ CTELock Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+
+ //
+ // These are temporary versions of these counters, during
+ // timer expiration we update the real ones.
+ //
+
+ ULONG TempDatagramBytesSent;
+ ULONG TempDatagramsSent;
+ ULONG TempDatagramBytesReceived;
+ ULONG TempDatagramsReceived;
+
+ //
+ // Configuration parameters.
+ //
+
+ BOOLEAN EthernetPadToEven;
+ BOOLEAN SingleNetworkActive;
+ BOOLEAN DisableDialoutSap;
+
+ //
+ // TRUE if we have multiple cards but a virtual network of 0.
+ //
+
+ BOOLEAN MultiCardZeroVirtual;
+
+ CTELock Lock;
+
+ //
+ // Lock to access the sequenced lists in the device.
+ //
+ CTELock SListsLock;
+
+ LONG ReferenceCount; // activity count/this provider.
+
+#ifdef _PNP_POWER
+
+ //
+ // Lock used to control the access to a binding (either from the
+ // binding array in the device or from the binding array in the
+ // adapter.
+ //
+ CTELock BindAccessLock;
+
+ //
+ // Registry Path for use when PnP adapters appear.
+ //
+ PWSTR RegistryPathBuffer;
+
+ UNICODE_STRING RegistryPath;
+
+ //
+ // Binding array has the Version number too
+ //
+ PBIND_ARRAY_ELEM Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+
+ //
+ // Monotonically increasing version number kept in bindings.
+ // Hopefully this will not wrap around...
+ //
+ ULONG BindingVersionNumber;
+#else
+ //
+ // During init we hold all bindings in a queue, but after we
+ // know the approximate number we allocate an array.
+ //
+
+ union {
+ LIST_ENTRY InitialBindingList; // only used during init.
+ struct {
+ PBINDING * Bindings; // allocated when number is determined.
+ ULONG BindingCount; // total allocated in Bindings.
+ };
+ };
+#endif _PNP_POWER
+
+
+ //
+ // ValidBindings is the number of bindings in the array which may
+ // be valid (they are lan bindings or down wan binding placeholders).
+ // It will be less than BindingCount by the number of auto-detect
+ // bindings that are thrown away. HighestExternalNicId is ValidBindings
+ // minus any binding set slaves which are moved to the end of the
+ // array. SapNicCount is like HighestExternalNicId except that
+ // if WanGlobalNetworkNumber is TRUE it will count all WAN bindings
+ // as one. HighestExternalType20NicId is like HighestExternalNicId
+ // except it stops when all the remaining bindings are down wan
+ // lines, or dialin wan lines if DisableDialinNetbios bit 1 is on.
+ //
+
+ USHORT ValidBindings;
+ USHORT HighestExternalNicId;
+ USHORT SapNicCount;
+ USHORT HighestType20NicId;
+#ifdef _PNP_POWER
+ //
+ // Keeps track of the last LAN binding's position in the binding array
+ //
+ USHORT HighestLanNicId;
+
+ //
+ // This keeps track of the current size of the binding array
+ //
+ USHORT MaxBindings;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+#if BACK_FILL
+ LIST_ENTRY GlobalBackFillPacketList;
+#endif
+
+ //
+ // Action requests from SAP waiting for an adapter status to change.
+ //
+
+ LIST_ENTRY AddressNotifyQueue;
+
+ //
+ // Action requests from nwrdr waiting for the WAN line
+ // to go up/down.
+ //
+
+ LIST_ENTRY LineChangeQueue;
+
+ //
+ // All packet pools are chained on these lists.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+
+
+#if BACK_FILL
+ LIST_ENTRY BackFillPoolList;
+ SLIST_HEADER BackFillPacketList;
+#endif
+
+#ifdef _PNP_POWER
+ LIST_ENTRY BindingPoolList;
+ SLIST_HEADER BindingList;
+#endif
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ PIPX_PADDING_BUFFER PaddingBuffer;
+
+ UCHAR State;
+
+ UCHAR FrameTypeDefault;
+
+ //
+ // This holds state if SingleNetworkActive is TRUE. If
+ // it is TRUE then WAN nets are active; if it is FALSE
+ // then LAN nets are active.
+ //
+
+ BOOLEAN ActiveNetworkWan;
+
+ //
+ // TRUE if we have a virtual network.
+ //
+
+ BOOLEAN VirtualNetwork;
+
+ //
+ // If we are set up for SingleNetworkActive, we may have
+ // to start our broadcast of net 0 frames somewhere other
+ // than NIC ID 1, so that we don't send to the wrong type.
+ //
+
+ USHORT FirstLanNicId;
+ USHORT FirstWanNicId;
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many of various resources have been allocated.
+ //
+
+ ULONG AllocatedDatagrams;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedPaddingBuffers;
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG InitDatagrams;
+ ULONG MaxDatagrams;
+ ULONG RipAgeTime;
+ ULONG RipCount;
+ ULONG RipTimeout;
+ ULONG RipUsageTime;
+ ULONG SourceRouteUsageTime;
+ USHORT SocketStart;
+ USHORT SocketEnd;
+ ULONG SocketUniqueness;
+ ULONG VirtualNetworkNumber;
+ ULONG EthernetExtraPadding;
+ BOOLEAN DedicatedRouter;
+ BOOLEAN VirtualNetworkOptional;
+ UCHAR DisableDialinNetbios;
+
+ //
+ // These are currently not read from the registry.
+ //
+
+ ULONG InitReceivePackets;
+ ULONG InitReceiveBuffers;
+ ULONG MaxReceivePackets;
+ ULONG MaxReceiveBuffers;
+
+#ifdef _PNP_POWER
+ ULONG MaxPoolBindings;
+ ULONG AllocatedBindings;
+ ULONG InitBindings;
+#endif
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ LARGE_INTEGER ControlChannelIdentifier;
+
+ //
+ // This registry parameter controls whether IPX checks (and discards)
+ // packets with mismatched Source addresses in the receive path.
+ //
+ BOOLEAN VerifySourceAddress;
+
+ //
+ // Where the current socket allocation is.
+ //
+ USHORT CurrentSocket;
+
+ //
+ // Number of segments in the RIP database.
+ //
+
+ ULONG SegmentCount;
+
+ //
+ // Points to an array of locks for the RIP database (these
+ // are stored outside of the ROUTER_SEGMENT so the array
+ // can be exposed to the RIP upper driver as one piece).
+ //
+
+ CTELock *SegmentLocks;
+
+ //
+ // Points to an array of ROUTER_SEGMENT fields for
+ // various RIP control fields.
+ //
+
+ ROUTER_SEGMENT *Segments;
+
+ //
+ // Queue of RIP packets waiting to be sent.
+ //
+
+ LIST_ENTRY WaitingRipPackets;
+ ULONG RipPacketCount;
+
+ //
+ // Timer that keeps RIP requests RIP_GRANULARITY ms apart.
+ //
+
+ BOOLEAN RipShortTimerActive;
+ USHORT RipSendTime;
+ CTETimer RipShortTimer;
+
+ //
+ // Timer that runs to age out unused rip entries (if the
+ // router is not bound) and re-rip every so often for
+ // active entries.
+ //
+
+ CTETimer RipLongTimer;
+
+ //
+ // This controls the source routing timeout code.
+ //
+
+ BOOLEAN SourceRoutingUsed; // TRUE if any 802.5 bindings exist.
+ CHAR SourceRoutingTime; // incremented each time timer fires.
+ CTETimer SourceRoutingTimer; // runs every minute.
+
+ //
+ // These are the merging of the binding values.
+ //
+
+ ULONG LinkSpeed;
+ ULONG MacOptions;
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // A pre-allocated header containing our node and network,
+ // plus an unused socket (so the structure is a known size
+ // for easy copying).
+ //
+
+ TDI_ADDRESS_IPX SourceAddress;
+
+ //
+ // The following field is an array of list heads of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabases[IPX_ADDRESS_HASH_COUNT]; // list of defined transport addresses.
+
+ //
+ // Holds the last address we looked up.
+ //
+
+ PVOID LastAddress;
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+ //
+ // Information.MaxDatagramSize is the minimum size we can
+ // send to all bindings assuming worst-case source routing;
+ // this is the value that won't break any network drivers.
+ //
+
+ ULONG RealMaxDatagramSize;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // Indicates whether each upper driver is bound
+ // (Netbios = 0, SPX = 1, RIP = 2).
+ //
+
+ BOOLEAN UpperDriverBound[UPPER_DRIVER_COUNT];
+
+ //
+ // TRUE if any driver is bound.
+ //
+
+ BOOLEAN AnyUpperDriverBound;
+
+ //
+ // Whether a receive complete should be indicated to
+ // this upper driver.
+ //
+
+ BOOLEAN ReceiveCompletePending[UPPER_DRIVER_COUNT];
+
+ //
+ // Control channel identifier for each of the upper
+ // drivers' bindings.
+ //
+
+ LARGE_INTEGER UpperDriverControlChannel[UPPER_DRIVER_COUNT];
+
+ //
+ // Entry points and other information for each of the
+ // upper drivers.
+ //
+
+ IPX_INTERNAL_BIND_INPUT UpperDrivers[UPPER_DRIVER_COUNT];
+
+ //
+ // How many upper drivers want broadcast enabled.
+ //
+
+ ULONG EnableBroadcastCount;
+
+ //
+ // Indicates if an enable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN EnableBroadcastPending;
+
+ //
+ // Indicates if a disable broadcast operation is in
+ // progress.
+ //
+
+ BOOLEAN DisableBroadcastPending;
+
+ //
+ // Indicates if the current operation should be
+ // reversed when it is finished.
+ //
+
+ BOOLEAN ReverseBroadcastOperation;
+
+ //
+ // TRUE if RIP wants a single network number for all WANs
+ //
+
+ BOOLEAN WanGlobalNetworkNumber;
+
+ //
+ // If WanGlobalNetworkNumber is TRUE, then this holds the
+ // actual value of the network number, once we know it.
+ //
+
+ ULONG GlobalWanNetwork;
+
+ //
+ // Set to TRUE if WanGlobalNetworkNumber is TRUE and we
+ // have already completed a queued notify from SAP. In
+ // this case GlobalWanNetwork will be set correctly.
+ //
+
+ BOOLEAN GlobalNetworkIndicated;
+
+ //
+ // TRUE if we need to act as a RIP announcer/responder
+ // for our virtual net.
+ //
+
+ BOOLEAN RipResponder;
+
+ //
+ // TRUE if we have already logged an error because someone
+ // sent a SAP response but we have multiple cards with no
+ // virtual network.
+ //
+
+ BOOLEAN SapWarningLogged;
+
+ //
+ // Used to queue up a worker thread to perform
+ // broadcast operations.
+ //
+
+ WORK_QUEUE_ITEM BroadcastOperationQueueItem;
+
+#ifdef _PNP_POWER
+ //
+ // Used to queue up a worker thread to perform
+ // PnP indications to upper drivers.
+ //
+
+ WORK_QUEUE_ITEM PnPIndicationsQueueItem;
+#endif
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+ //
+ // Counters for most of the statistics that IPX maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+
+ //
+ // This is TRUE if we have any adapters where we are
+ // auto-detecting the frame type.
+ //
+
+ BOOLEAN AutoDetect;
+
+ //
+ // This is TRUE if we are auto-detecting and we have
+ // found the default auto-detect type on the net.
+ //
+
+ BOOLEAN DefaultAutoDetected;
+
+ //
+ // Our state during auto-detect. After we are done this
+ // will stay at AutoDetectDone;
+ //
+
+ UCHAR AutoDetectState;
+
+ //
+ // If we are auto-detecting, this event is used to stall
+ // our initialization code while we do auto-detection --
+ // this is so we have a constant view of the world once
+ // we return from DriverEntry.
+ //
+
+ KEVENT AutoDetectEvent;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER IpxStartTime;
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // Points back to the system device object.
+ //
+
+ PDEVICE_OBJECT DeviceObject;
+
+#ifdef _PNP_POWER
+ //
+ // Used to store the Tdi registration handle for deviceobject notifications.
+ //
+ HANDLE TdiRegistrationHandle;
+
+ //
+ // Used to store the TA_ADDRESS which is indicated up to Tdi clients as adapters appear.
+ //
+ PTA_ADDRESS TdiRegistrationAddress;
+#endif
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+ ULONG DeviceNameLength;
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE IpxDevice;
+extern PIPX_PADDING_BUFFER IpxPaddingBuffer;
+#if DBG
+EXTERNAL_LOCK(IpxGlobalInterlock);
+#endif
+
+
+//
+// device state definitions
+//
+
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+
+#ifdef _PNP_POWER
+
+//
+// New state which comes between CLOSED and OPEN. At this state,
+// there are no adapters in the system and so no network activity
+// is possible.
+//
+#define DEVICE_STATE_LOADED 0x03
+#endif _PNP_POWER
+
+//
+// This is the state of our auto-detect if we do it.
+//
+
+#define AUTO_DETECT_STATE_INIT 0x00 // still initializing the device
+#define AUTO_DETECT_STATE_RUNNING 0x01 // sent ffffffff query, waiting for responses
+#define AUTO_DETECT_STATE_PROCESSING 0x02 // processing the responses
+#define AUTO_DETECT_STATE_DONE 0x03 // detection is done, IPX is active
+
+
+
+#define IPX_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ CTELock * AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST Request; // the request used for open or close
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ //
+ //
+ // TRUE if ExtendedAddressing, ReceiveIpxHeader,
+ // FilterOnPacketType, or ReceiveFlagAddressing is TRUE.
+ //
+
+ BOOLEAN SpecialReceiveProcessing;
+
+ //
+ // The remote address of a send datagram includes the
+ // packet type. and on a receive datagram includes
+ // the packet type AND a flags byte indicating information
+ // about the frame (was it broadcast, was it sent from
+ // this machine).
+ //
+
+ BOOLEAN ExtendedAddressing;
+
+ //
+ // TRUE if the address on a receive datagram includes
+ // the packet type and a flags byte (like ExtendedAddressing),
+ // but on send the address is normal (no packet type).
+ //
+
+ BOOLEAN ReceiveFlagsAddressing;
+
+ //
+ // Is the IPX header received with the data.
+ //
+
+ BOOLEAN ReceiveIpxHeader;
+
+ //
+ // The packet type to use if it is unspecified in the send.
+ //
+
+ UCHAR DefaultPacketType;
+
+ //
+ // TRUE if packet type filtering is enabled.
+ //
+
+ BOOLEAN FilterOnPacketType;
+
+ //
+ // The packet type to filter on.
+ //
+
+ UCHAR FilteredType;
+
+ //
+ // Does this address file want broadcast packets.
+ //
+
+ BOOLEAN EnableBroadcast;
+
+ //
+ // This is set to TRUE if this is the SAP socket -- we
+ // put this under SpecialReceiveProcessing to avoid
+ // hitting the main path.
+ //
+
+ BOOLEAN IsSapSocket;
+
+ //
+ // The following queue is used to queue receive datagram requests
+ // on this address file. Send datagram requests are queued on the
+ // address itself. These queues are managed by the EXECUTIVE interlocked
+ // list management routines. The actual objects which get queued to this
+ // structure are request control blocks (RCBs).
+ //
+
+ LIST_ENTRY ReceiveDatagramQueue; // FIFO of outstanding TdiReceiveDatagrams.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ //
+ // [CH] Added the chained receive handlers.
+ //
+
+ BOOLEAN RegisteredReceiveDatagramHandler;
+ BOOLEAN RegisteredChainedReceiveDatagramHandler;
+ BOOLEAN RegisteredErrorHandler;
+
+ //
+ // The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
+ // event handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which does
+ // not accept the incoming data.
+ //
+
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PVOID ReceiveDatagramHandlerContext;
+ PTDI_IND_CHAINED_RECEIVE_DATAGRAM ChainedReceiveDatagramHandler;
+ PVOID ChainedReceiveDatagramHandlerContext;
+
+ //
+ // The following function pointer always points to a TDI_IND_ERROR
+ // handler for the address. If the NULL handler is specified in a
+ // TdiSetEventHandler, this this points to an internal routine which
+ // simply returns successfully.
+ //
+
+ PTDI_IND_ERROR ErrorHandler;
+ PVOID ErrorHandlerContext;
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+
+#define AREF_TOTAL 4
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+/* ULONGs to allow for Interlocked operations.
+
+ BOOLEAN SendPacketInUse; // put these after so header is aligned.
+
+ BOOLEAN ReceivePacketInUse;
+#if BACK_FILL
+ BOOLEAN BackFillPacketInUse;
+#endif
+*/
+
+ ULONG SendPacketInUse; // put these after so header is aligned.
+
+ ULONG ReceivePacketInUse;
+#if BACK_FILL
+ ULONG BackFillPacketInUse;
+#endif
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ CTELock Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ USHORT Socket; // the socket this address corresponds to.
+ USHORT SendSourceSocket; // used for sends; may be == Socket or 0
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ BOOLEAN Stopping;
+ ULONG Flags; // attributes of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ CTELock * DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ //
+ // Holds our source address, used for construcing datagrams
+ // quickly.
+ //
+
+ TDI_ADDRESS_IPX LocalAddress;
+
+ IPX_SEND_PACKET SendPacket;
+ IPX_RECEIVE_PACKET ReceivePacket;
+
+#if BACK_FILL
+ IPX_SEND_PACKET BackFillPacket;
+#endif
+
+
+ UCHAR SendPacketHeader[IPX_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying IpxDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+#define ADDRESS_FLAGS_STOPPING 0x00000001
+
+//
+// In order to increase the range of ControlChannelIds, we have a large integer to represent
+// monotonically increasing ControlChannelIdentifiers. This large integer is packed into the
+// 6 Bytes as follows:
+//
+// REQUEST_OPEN_CONTEXT(_Request) - 4 bytes
+// Upper 2 bytes of REQUEST_OPEN_TYPE(_Request) - 2 bytes
+//
+// IPX_CC_MASK is used to mask out the upper 2 bytes of the OPEN_TYPE.
+// MAX_CCID is 2^48.
+//
+#define IPX_CC_MASK 0x0000ffff
+
+#define MAX_CCID 0xffffffffffff
+
+#define CCID_FROM_REQUEST(_ccid, _Request) \
+ (_ccid).LowPart = (ULONG)(REQUEST_OPEN_CONTEXT(_Request)); \
+ (_ccid).HighPart = ((ULONG)(REQUEST_OPEN_TYPE(_Request)) >> 16);
+
diff --git a/private/ntos/tdi/isnp/ipx/isnipx.h b/private/ntos/tdi/isnp/ipx/isnipx.h
new file mode 100644
index 000000000..df947d439
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/isnipx.h
@@ -0,0 +1,531 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnipx.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ IPX module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _ISNIPX_
+#define _ISNIPX_
+
+#define MAC_HEADER_SIZE ((IPX_MAXIMUM_MAC + 3) & ~3)
+#define RIP_PACKET_SIZE ((sizeof(RIP_PACKET) + 3) & ~3)
+#define IPX_HEADER_SIZE ((sizeof(IPX_HEADER) + 3) & ~3)
+
+//
+// Frame type definitions
+//
+
+#define ISN_FRAME_TYPE_ETHERNET_II 0
+#define ISN_FRAME_TYPE_802_3 1
+#define ISN_FRAME_TYPE_802_2 2
+#define ISN_FRAME_TYPE_SNAP 3
+#define ISN_FRAME_TYPE_ARCNET 4 // we ignore this
+#define ISN_FRAME_TYPE_MAX 4 // of the four standard ones
+
+#define ISN_FRAME_TYPE_AUTO 0xff
+
+
+//
+// This defines the size of the maximum MAC header required
+// (token-ring: MAC 14 bytes, RI 18 bytes, LLC 3 bytes, SNAP 5 bytes).
+//
+
+#define IPX_MAXIMUM_MAC 40
+
+//
+// This is an internal identifier used for RIP query packets.
+//
+
+#define IDENTIFIER_RIP_INTERNAL 4
+
+//
+// This is an internal identifier used for RIP response packets.
+//
+
+#define IDENTIFIER_RIP_RESPONSE 5
+
+
+//
+// This is the total number of "real" identifiers.
+//
+
+#define IDENTIFIER_TOTAL 4
+
+
+//
+// Some definitions (in the correct on-the-wire order).
+//
+
+#define RIP_PACKET_TYPE 0x01
+#define RIP_SOCKET 0x5304
+#define RIP_REQUEST 0x0100
+#define RIP_RESPONSE 0x0200
+#define RIP_DOWN 0x8200 // use high bit to indicate it
+
+#define SAP_PACKET_TYPE 0x04
+#define SAP_SOCKET 0x5204
+
+#define SPX_PACKET_TYPE 0x05
+
+#define NB_SOCKET 0x5504
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of a RIP network entry.
+//
+
+typedef struct _RIP_NETWORK_ENTRY {
+ ULONG NetworkNumber;
+ USHORT HopCount;
+ USHORT TickCount;
+} RIP_NETWORK_ENTRY, *PRIP_NETWORK_ENTRY;
+
+//
+// Definition of a single entry rip packet.
+//
+
+typedef struct _RIP_PACKET {
+ USHORT Operation;
+ RIP_NETWORK_ENTRY NetworkEntry;
+} RIP_PACKET, *PRIP_PACKET;
+
+#include <packoff.h>
+
+
+#define IPX_DEVICE_SIGNATURE 0x1401
+#define IPX_ADAPTER_SIGNATURE 0x1402
+#define IPX_BINDING_SIGNATURE 0x1403
+#define IPX_ADDRESS_SIGNATURE 0x1404
+#define IPX_ADDRESSFILE_SIGNATURE 0x1405
+
+#define IPX_FILE_TYPE_CONTROL (ULONG)0x4701 // file is type control
+
+
+//
+// Defined granularity of RIP timeouts in milliseconds
+//
+
+#define RIP_GRANULARITY 55
+
+
+//
+// The default number of segments in the RIP table.
+//
+
+#define RIP_SEGMENTS 7
+
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#if DBG
+
+extern ULONG IpxDebug;
+extern ULONG IpxMemoryDebug;
+
+#define IPX_MEMORY_LOG_SIZE 128
+extern UCHAR IpxDebugMemory[IPX_MEMORY_LOG_SIZE][64];
+extern PUCHAR IpxDebugMemoryLoc;
+extern PUCHAR IpxDebugMemoryEnd;
+
+VOID
+IpxDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define IPX_DEBUG(_Flag, _Print) { \
+ if (IpxDebug & (IPX_DEBUG_ ## _Flag)) { \
+ DbgPrint ("IPX: "); \
+ DbgPrint _Print; \
+ } \
+ if (IpxMemoryDebug & (IPX_DEBUG_ ## _Flag)) { \
+ IpxDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define IPX_DEBUG(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+
+
+//
+// PREQUEST
+// IpxAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define IpxAllocateRequest(_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
+// IpxFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define IpxFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// VOID
+// REQUEST_OPEN_CONTEXT_AND_PARAMS(
+// IN PREQUEST Request
+// OUT PVOID * OpenContext,
+// OUT PTDI_REQUEST_KERNEL * Parameters
+// );
+//
+// Simultaneously returns the open context and the parameters
+// for a request (this is an optimization since the send
+// datagram code needs them both).
+//
+
+#define REQUEST_OPEN_CONTEXT_AND_PARAMS(_Request,_OpenContext,_Parameters) { \
+ PIO_STACK_LOCATION _IrpSp = IoGetCurrentIrpStackLocation(_Request); \
+ *(_OpenContext) = _IrpSp->FileObject->FsContext; \
+ *(_Parameters) = (PTDI_REQUEST_KERNEL)(&_IrpSp->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)))
+
+
+//
+// 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
+// IpxCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define IpxCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+
+#define IPX_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define IPX_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define IPX_ADD_ULONG(_Pulong, _Ulong, _Lock) InterlockedExchangeAdd(_Pulong, _Ulong)
+
+#define IPX_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define IPX_BEGIN_SYNC(_SyncContext)
+#define IPX_END_SYNC(_SyncContext)
+
+#define IPX_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+#define IPX_DEFINE_LOCK_HANDLE_PARAM(_LockHandle) CTELockHandle _LockHandle;
+
+#define IPX_GET_LOCK(_Lock, _LockHandle) \
+ CTEGetLock(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK(_Lock, _LockHandle) \
+ CTEFreeLock(_Lock, _LockHandle)
+
+#define IPX_GET_LOCK1(_Lock, _LockHandle)
+
+#define IPX_FREE_LOCK1(_Lock, _LockHandle)
+
+#define IPX_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, _Lock)
+#define IPX_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define IPX_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, _Lock)
+#define IPX_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, _Lock)
+
+#define IPX_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntrySList(_Queue, _Lock)
+#define IPX_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntrySList(_Queue, _Entry, _Lock)
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER.
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define IPX_DEBUG_DEVICE 0x00000001
+#define IPX_DEBUG_ADAPTER 0x00000002
+#define IPX_DEBUG_ADDRESS 0x00000004
+#define IPX_DEBUG_SEND 0x00000008
+#define IPX_DEBUG_NDIS 0x00000010
+#define IPX_DEBUG_RECEIVE 0x00000020
+#define IPX_DEBUG_CONFIG 0x00000040
+#define IPX_DEBUG_PACKET 0x00000080
+#define IPX_DEBUG_RIP 0x00000100
+#define IPX_DEBUG_BIND 0x00000200
+#define IPX_DEBUG_ACTION 0x00000400
+#define IPX_DEBUG_BAD_PACKET 0x00000800
+#define IPX_DEBUG_SOURCE_ROUTE 0x00001000
+#define IPX_DEBUG_WAN 0x00002000
+#define IPX_DEBUG_AUTO_DETECT 0x00004000
+
+#ifdef _PNP_POWER
+#define IPX_DEBUG_PNP 0x00008000
+#endif
+
+#define IPX_DEBUG_LOOPB 0x00010000
+
+#endif
diff --git a/private/ntos/tdi/isnp/ipx/loopback.c b/private/ntos/tdi/isnp/ipx/loopback.c
new file mode 100644
index 000000000..be44bae5b
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/loopback.c
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ loopback.c
+
+Abstract:
+
+ This module contains the routines to implement loopback
+
+Author:
+
+ Sanjay Anand (SanjayAn) 2/6/96
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global lock to control access to the Loopback queue
+//
+DEFINE_LOCK_STRUCTURE(LoopLock)
+
+//
+// Head and tail of the Loopback queue
+//
+PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL;
+
+CTEEvent LoopXmitEvent;
+BOOLEAN LoopXmitRtnRunning = 0;
+
+//
+// MaximumPacket sized buffer to hold the lookahead data.
+//
+// ZZBUGBUG: In PnP this value can change
+//
+// PUCHAR LookaheadBuffer=NULL;
+#define LOOP_LOOKAHEAD_SIZE 128 + sizeof(IPX_HEADER) + 8 + 34
+
+
+VOID
+IpxDoLoopback(
+ IN CTEEvent *Event,
+ IN PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ Does the actual loopback.
+
+Arguments:
+
+ Event - Pointer to event structure.
+
+ Context - Pointer to ZZ
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet; // Pointer to packet being transmitted
+ PNDIS_BUFFER Buffer; // Current NDIS buffer being processed.
+ ULONG TotalLength; // Total length of send.
+ ULONG LookaheadLength; // Bytes in lookahead.
+ ULONG Copied; // Bytes copied so far.
+ PUCHAR CopyPtr; // Pointer to buffer being copied into.
+ PUCHAR SrcPtr; // Pointer to buffer being copied from.
+ ULONG SrcLength; // Length of src buffer.
+ BOOLEAN Rcvd = FALSE;
+ PIPX_SEND_RESERVED Reserved;
+ ULONG MacSize;
+ PNDIS_PACKET *PacketPtr;
+ UCHAR LookaheadBuffer[LOOP_LOOKAHEAD_SIZE];
+
+ IPX_DEFINE_LOCK_HANDLE(Handle)
+
+ KIRQL OldIrql;
+
+ CTEAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
+
+ //
+ // Raise IRQL so we can acquire locks at DPC level in the receive code.
+ // Also to be able to ReceiveIndicate at DPC
+ //
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ IPX_GET_LOCK(&LoopLock, &Handle);
+
+ if (LoopXmitRtnRunning) {
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+
+ LoopXmitRtnRunning = 1;
+
+ for (;;) {
+
+ //
+ // Get the next packet from the list.
+ //
+ Packet = LoopXmitHead;
+
+ if (Packet != (PNDIS_PACKET)NULL) {
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ LoopXmitHead = (PNDIS_PACKET)(Reserved->PaddingBuffer);
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ } else { // Nothing left to do.
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ break;
+ }
+
+ //
+ // We use the PaddingBuffer section as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx\n", Packet));
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength);
+
+ NdisQueryBuffer(Buffer, NULL, &MacSize);
+
+ IPX_DEBUG(LOOPB, ("Buffer: %lx Totalpktlen: %lx MacSize: %lx\n", Buffer, TotalLength, MacSize));
+
+ LookaheadLength = MIN(LOOP_LOOKAHEAD_SIZE, TotalLength);
+ Copied = 0;
+ CopyPtr = LookaheadBuffer;
+ while (Copied < LookaheadLength) {
+ ULONG ThisCopy; // Bytes to copy this time.
+
+#ifdef DBG
+ if (!Buffer) {
+ DbgBreakPoint();
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ LoopXmitRtnRunning = 0;
+ IPX_FREE_LOCK(&LoopLock, Handle);
+ KeLowerIrql(OldIrql);
+ return;
+ }
+#endif
+
+ NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength);
+ ThisCopy = MIN(SrcLength, LookaheadLength - Copied);
+ CTEMemCopy(CopyPtr, SrcPtr, ThisCopy);
+ Copied += ThisCopy;
+ CopyPtr += ThisCopy;
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ Rcvd = TRUE;
+
+#ifdef BACK_FILL
+ //
+ // For Backfill packets, the MAC header is not yet set up; for others, it is the size
+ // of the first MDL (17).
+ //
+ if ((Reserved->Identifier == IDENTIFIER_IPX) &&
+ (Reserved->BackFill)) {
+ MacSize = 0;
+ }
+#endif
+ IpxReceiveIndication( (NDIS_HANDLE)IPX_LOOPBACK_COOKIE, // BindingContext
+ Packet, // ReceiveContext
+ (MacSize) ? LookaheadBuffer : NULL, // HeaderBuffer
+ MacSize, // HeaderBufferSize
+ LookaheadBuffer+MacSize, // LookAheadBuffer
+ LookaheadLength-MacSize, // LookAheadBufferSize
+ TotalLength-MacSize); // PacketSize
+
+ IpxSendComplete(Context, Packet, NDIS_STATUS_SUCCESS);
+
+ //
+ // Give other threads a chance to run.
+ //
+ KeLowerIrql(OldIrql);
+ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+ IPX_GET_LOCK(&LoopLock, &Handle);
+ }
+
+ if (Rcvd) {
+ IpxReceiveComplete(Context);
+ }
+
+ KeLowerIrql(OldIrql);
+}
+
+
+VOID
+IpxInitLoopback()
+/*++
+
+Routine Description:
+
+ Initializes various loopback structures.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CTEInitLock(&LoopLock);
+ CTEInitEvent(&LoopXmitEvent, IpxDoLoopback);
+ return;
+}
+
+
+VOID
+IpxLoopbackEnque(
+ IN PNDIS_PACKET Packet,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Enqueues a packet to the loopbackQ
+
+Arguments:
+
+ Packet - The packet to be enqueued.
+
+ Context - Pointer to the adapter corresp to the first binding.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+ //
+ // We use the PaddingBuffer as the next ptr.
+ //
+ Reserved->PaddingBuffer = NULL;
+
+ IPX_GET_LOCK(&LoopLock, &LockHandle);
+
+ //
+ // LoopbackQ is empty
+ //
+ if (LoopXmitHead == (PNDIS_PACKET)NULL) {
+ LoopXmitHead = Packet;
+ } else {
+ Reserved = (PIPX_SEND_RESERVED)(LoopXmitTail->ProtocolReserved);
+ (PNDIS_PACKET)(Reserved->PaddingBuffer) = Packet;
+ }
+ LoopXmitTail = Packet;
+
+ IPX_DEBUG(LOOPB, ("Enqued packet: %lx, Reserved: %lx\n", Packet, Reserved));
+
+ //
+ // If this routine is not already running, schedule it as a work item.
+ //
+ if (!LoopXmitRtnRunning) {
+ CTEScheduleEvent(&LoopXmitEvent, Context);
+ }
+
+ IPX_FREE_LOCK(&LoopLock, LockHandle);
+}
diff --git a/private/ntos/tdi/isnp/ipx/mac.c b/private/ntos/tdi/isnp/ipx/mac.c
new file mode 100644
index 000000000..93f9e8a89
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.c
@@ -0,0 +1,3793 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.c
+
+Abstract:
+
+ This module contains code which implements Mac type dependent code for
+ the IPX transport.
+
+Environment:
+
+ Kernel mode (Actually, unimportant)
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define TR_LENGTH_MASK 0x1F // low 5 bits in byte
+#define TR_DIRECTION_MASK 0x80 // returns direction bit
+#define TR_DEFAULT_LENGTH 0x70 // default for outgoing
+#define TR_MAX_SIZE_MASK 0x70
+
+#define TR_PREAMBLE_AC 0x10
+#define TR_PREAMBLE_FC 0x40
+
+#define FDDI_HEADER_BYTE 0x57
+
+
+static UCHAR AllRouteSourceRouting[2] = { 0x82, TR_DEFAULT_LENGTH };
+static UCHAR SingleRouteSourceRouting[2] = { 0xc2, TR_DEFAULT_LENGTH };
+
+#define ROUTE_EQUAL(_A,_B) { \
+ (*(UNALIGNED USHORT *)(_A) == *(UNALIGNED USHORT *)(_B)) \
+}
+
+//
+// For back-fillable packets, chains the back-fill space as a MAC header
+// to the packet and sets the header pointer.
+//
+
+//
+// BUGBUG: We dont need to test for IDENTIFIER_IPX since it will always be
+// true for the mediumframe specific send handlers.
+//
+#define BACK_FILL_HEADER(_header, _reserved, _headerlength, _packet) \
+ if ((_reserved)->Identifier == IDENTIFIER_IPX) { \
+ if((_reserved)->BackFill) { \
+ CTEAssert ((_reserved)->HeaderBuffer); \
+ CTEAssert ((_reserved)->HeaderBuffer->MdlFlags & MDL_NETWORK_HEADER); \
+ _header = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->MappedSystemVa = (PCHAR)(_reserved)->HeaderBuffer->MappedSystemVa - _headerlength; \
+ (_reserved)->HeaderBuffer->ByteOffset -= _headerlength; \
+ NdisChainBufferAtFront(_packet,(PNDIS_BUFFER)(_reserved)->HeaderBuffer); \
+ } \
+ }
+
+//
+// In case of back-fillable packets, the adjusted length should include
+// the prev. bytecount of the headerbuffer.
+//
+#define BACK_FILL_ADJUST_BUFFER_LENGTH(_reserved, _headerlength) \
+ if((_reserved)->BackFill){ \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength+(_reserved)->HeaderBuffer->ByteCount); \
+ IPX_DEBUG(SEND,("mac user mdl %x\n", (_reserved)->HeaderBuffer)); \
+ } else { \
+ NdisAdjustBufferLength ((_reserved)->HeaderBuffer, _headerlength); \
+ }
+
+//
+// This is the interpretation of the length bits in
+// the 802.5 source-routing information.
+//
+
+ULONG SR802_5Lengths[8] = { 516, 1500, 2052, 4472,
+ 8144, 11407, 17800, 17800 };
+
+#ifndef _PNP_POWER
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MacInitializeMacInfo)
+#endif
+
+#endif
+
+
+VOID
+MacInitializeBindingInfo(
+ IN struct _BINDING * Binding,
+ IN struct _ADAPTER * Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the binding info based on the adapter's MacInfo
+ and the frame type of the binding.
+
+Arguments:
+
+ Binding - The newly created binding.
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG MaxUserData;
+
+ Binding->DefHeaderSize = Adapter->DefHeaderSizes[Binding->FrameType];
+ Binding->BcMcHeaderSize = Adapter->BcMcHeaderSizes[Binding->FrameType];
+
+ MacReturnMaxDataSize(
+ &Adapter->MacInfo,
+ NULL,
+ 0,
+ Binding->MaxSendPacketSize,
+ &MaxUserData);
+
+ Binding->MaxLookaheadData =
+ Adapter->MaxReceivePacketSize -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->AnnouncedMaxDatagramSize =
+ MaxUserData -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+ Binding->RealMaxDatagramSize =
+ Binding->MaxSendPacketSize -
+ Adapter->MacInfo.MaxHeaderLength -
+ sizeof(IPX_HEADER) -
+ (Binding->DefHeaderSize - Adapter->MacInfo.MinHeaderLength);
+
+} /* MacInitializeBindingInfo */
+
+
+VOID
+MacInitializeMacInfo(
+ IN NDIS_MEDIUM MacType,
+ OUT PNDIS_INFORMATION MacInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in the MacInfo table based on MacType.
+
+Arguments:
+
+ MacType - The MAC type we wish to decode.
+
+ MacInfo - The MacInfo structure to fill in.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacType) {
+ case NdisMedium802_3:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ case NdisMedium802_5:
+ MacInfo->SourceRouting = TRUE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x80;
+ MacInfo->MaxHeaderLength = 32;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_5;
+ break;
+ case NdisMediumFddi:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 13;
+ MacInfo->MinHeaderLength = 13;
+ MacInfo->MediumType = NdisMediumFddi;
+ break;
+ case NdisMediumArcnet878_2:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = FALSE;
+ MacInfo->BroadcastMask = 0x00;
+ MacInfo->MaxHeaderLength = 3;
+ MacInfo->MinHeaderLength = 3;
+ MacInfo->MediumType = NdisMediumArcnet878_2;
+ break;
+ case NdisMediumWan:
+ MacInfo->SourceRouting = FALSE;
+ MacInfo->MediumAsync = TRUE;
+ MacInfo->BroadcastMask = 0x01;
+ MacInfo->MaxHeaderLength = 14;
+ MacInfo->MinHeaderLength = 14;
+ MacInfo->MediumType = NdisMedium802_3;
+ break;
+ default:
+ CTEAssert(FALSE);
+ }
+ MacInfo->RealMediumType = MacType;
+
+} /* MacInitializeMacInfo */
+
+
+VOID
+MacMapFrameType(
+ IN NDIS_MEDIUM MacType,
+ IN ULONG FrameType,
+ OUT ULONG * MappedFrameType
+ )
+
+/*++
+
+Routine Description:
+
+ Maps the specified frame type to a value which is
+ valid for the medium.
+
+Arguments:
+
+ MacType - The MAC type we wish to map for.
+
+ FrameType - The frame type in question.
+
+ MappedFrameType - Returns the mapped frame type.
+
+Return Value:
+
+--*/
+
+{
+ switch (MacType) {
+
+ //
+ // Ethernet accepts all values, the default is 802.2.
+ //
+
+ case NdisMedium802_3:
+ if (FrameType >= ISN_FRAME_TYPE_MAX) {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ } else {
+ *MappedFrameType = FrameType;
+ }
+ break;
+
+ //
+ // Token-ring supports SNAP and 802.2 only.
+ //
+
+ case NdisMedium802_5:
+ if (FrameType == ISN_FRAME_TYPE_SNAP) {
+ *MappedFrameType = ISN_FRAME_TYPE_SNAP;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // FDDI supports SNAP, 802.2, and 802.3 only.
+ //
+
+ case NdisMediumFddi:
+ if ((FrameType == ISN_FRAME_TYPE_SNAP) || (FrameType == ISN_FRAME_TYPE_802_3)) {
+ *MappedFrameType = FrameType;
+ } else {
+ *MappedFrameType = ISN_FRAME_TYPE_802_2;
+ }
+ break;
+
+ //
+ // On arcnet there is only one frame type, use 802.3
+ // (it doesn't matter what we use).
+ //
+
+ case NdisMediumArcnet878_2:
+ *MappedFrameType = ISN_FRAME_TYPE_802_3;
+ break;
+
+ //
+ // WAN uses ethernet II because it includes the ethertype.
+ //
+
+ case NdisMediumWan:
+ *MappedFrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ break;
+
+ default:
+ CTEAssert(FALSE);
+ }
+
+} /* MacMapFrameType */
+
+//
+// BUGBUG -- use symbols instead of hardcoded values for mac header lengths
+// --pradeepb
+//
+
+VOID
+MacReturnMaxDataSize(
+ IN PNDIS_INFORMATION MacInfo,
+ IN PUCHAR SourceRouting,
+ IN UINT SourceRoutingLength,
+ IN UINT DeviceMaxFrameSize,
+ OUT PUINT MaxFrameSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the space available for user data in a MAC packet.
+ This will be the available space after the MAC header; all headers
+ headers will be included in this space.
+
+Arguments:
+
+ MacInfo - Describes the MAC we wish to decode.
+
+ SourceRouting - If we are concerned about a reply to a specific
+ frame, then this information is used.
+
+ SourceRouting - The length of SourceRouting.
+
+ MaxFrameSize - The maximum frame size as returned by the adapter.
+
+ MaxDataSize - The maximum data size computed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ switch (MacInfo->MediumType) {
+
+ case NdisMedium802_3:
+
+ //
+ // For 802.3, we always have a 14-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 14;
+ break;
+
+ case NdisMedium802_5:
+
+ //
+ // For 802.5, if we have source routing information then
+ // use that, otherwise assume the worst.
+ //
+
+ if (SourceRouting && SourceRoutingLength >= 2) {
+
+ UINT SRLength;
+
+ SRLength = SR802_5Lengths[(SourceRouting[1] & TR_MAX_SIZE_MASK) >> 4];
+ DeviceMaxFrameSize -= (SourceRoutingLength + 14);
+
+ if (DeviceMaxFrameSize < SRLength) {
+ *MaxFrameSize = DeviceMaxFrameSize;
+ } else {
+ *MaxFrameSize = SRLength;
+ }
+
+ } else {
+
+#if 0
+ if (DeviceMaxFrameSize < 608) {
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ } else {
+ *MaxFrameSize = 576;
+ }
+#endif
+ //
+ // bug # 6192. There is no point in assuming the worst. It only
+ // leads to lower throughput. Packets can get dropped by an
+ // an intermediate router for both cases (this one and the one
+ // above where 576 is chosen). In the above case, they will
+ // get dropped if two ethernet machines are communicating via
+ // a token ring. In this case, they will if two token ring
+ // machines with a frame size > max ethernet frame size are
+ // going over an ethernet. To fix the packet drop case, one
+ // should adjust the MaxPktSize Parameter of the card.
+ //
+ *MaxFrameSize = DeviceMaxFrameSize - 32;
+ }
+
+ break;
+
+ case NdisMediumFddi:
+
+ //
+ // For FDDI, we always have a 13-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 13;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // For Arcnet, we always have a 3-byte MAC header.
+ //
+
+ *MaxFrameSize = DeviceMaxFrameSize - 3;
+ break;
+
+ }
+
+} /* MacReturnMaxDataSize */
+
+#if 0
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: THIS FUNCTION IS REAL HACKY AND NEEDS TO BE WORKED AT. WE CAN
+ Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ PNDIS_BUFFER SecondBuffer = NULL;
+ PUCHAR SecondBufferData;
+ UINT SecondBufferLength;
+ USHORT SourceSocket;
+ PNDIS_BUFFER ThirdBuffer = NULL;
+ PUCHAR ThirdBufferData;
+ UINT ThirdBufferLength;
+
+ UNREFERENCED_PARAMETER (PacketLength);
+
+ //
+ // First get the source socket.
+ //
+
+#if 0
+ //
+ // Only time IncludedHeaderLength is less than the offset of
+ // SourceSocket in IPX header is when it 0 (from rip)
+ //
+ if (IncludedHeaderLength <= FIELD_OFFSET (IPX_HEADER, SourceSocket)) {
+#endif
+
+ //
+ // Get the second buffer in the packet (the ipx header is always in
+ // the second buffer - pradeepb.
+ //
+ // In this case
+ // there must be a second buffer or the packet is too
+ // short, so we don't check for NULL.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ SourceSocket = *(UNALIGNED USHORT *)
+ (&SecondBufferData[FIELD_OFFSET(IPX_HEADER, SourceSocket) - IncludedHeaderLength]);
+
+#if 0
+ }
+else {
+
+ SourceSocket = IpxHeader->SourceSocket;
+ }
+#endif
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+#if 0
+ //
+ // We assume the connection control flag and data stream type
+ // are in the same buffer.
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ SecondBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&SecondBufferData, &SecondBufferLength);
+
+ }
+#endif
+
+ ConnectionControlFlag = *(SecondBufferData + (sizeof(IPX_HEADER) - IncludedHeaderLength));
+ DataStreamType = *(SecondBufferData + (sizeof(IPX_HEADER) + 1 - IncludedHeaderLength));
+
+
+#if 0
+ } else {
+
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+ }
+
+#endif
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // This would be from the rip driver, if IncludedHeaderLength is
+ // 0. -- pradeepb
+ //
+ // At this point, we assume that total data length is in
+ // the same buffer as the others.
+ //
+ //
+ // real hacky way of doing things. One should be using
+ // FIELD_OFFSET(NB_SESSION, TotalDataLength) instead of 8.
+ // -- pradeepb
+ //
+
+ if (IncludedHeaderLength < sizeof(IPX_HEADER) + 2) {
+ TotalDataLength = *(USHORT UNALIGNED *)(SecondBufferData + (sizeof(IPX_HEADER) + 8 - IncludedHeaderLength));
+ } else {
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+ }
+
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive.
+ //
+
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // if from rip
+ //
+ if (IncludedHeaderLength <= sizeof(IPX_HEADER) + 1) {
+
+
+ //
+ // Get the second buffer
+ //
+#if 0
+ if (SecondBuffer == NULL) {
+
+ //
+ // Get the second buffer in the packet.
+ //
+
+ NdisQueryPacket(Packet, NULL, NULL, &SecondBuffer, NULL);
+ ThirdBuffer = NDIS_BUFFER_LINKAGE(SecondBuffer);
+ NdisQueryBuffer (ThirdBuffer, (PVOID *)&ThirdBufferData, &ThirdBufferLength);
+
+ }
+#endif
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+
+ } else {
+
+ //
+ // will we ever come here - pradeepb?
+ //
+ KeepAliveSignature = SecondBufferData[sizeof(IPX_HEADER) + 1 - IncludedHeaderLength];
+#if 0
+ KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
+#endif
+
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+
+ }
+
+ }
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+#endif
+
+
+VOID
+IpxUpdateWanInactivityCounter(
+ IN PBINDING Binding,
+ IN IPX_HEADER UNALIGNED * IpxHeader,
+ IN ULONG IncludedHeaderLength,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a frame is being sent on a WAN
+ line. It updates the inactivity counter for this binding
+ unless:
+
+ - The frame is from the RIP socket
+ - The frame is from the SAP socket
+ - The frame is a netbios keep alive
+ - The frame is an NCP keep alive
+
+ BUGBUG: Take the identifier as a parameter to optimize.
+
+Arguments:
+
+ Binding - The binding the frame is sent on.
+
+ IpxHeader - May contain the first bytes of the packet.
+
+ IncludedHeaderLength - The number of packet bytes at IpxHeader.
+
+ Packet - The full NDIS packet.
+
+ PacketLength - The length of the packet.
+
+Return Value:
+
+ None, but in some cases we return without resetting the
+ inactivity counter.
+
+Comments: Improve the instruction count here - pradeepb
+
+--*/
+
+{
+ USHORT SourceSocket;
+ PNDIS_BUFFER DataBuffer = NULL;
+ PUCHAR DataBufferData;
+ UINT DataBufferLength;
+
+
+ //
+ // First get the source socket.
+ //
+ SourceSocket = IpxHeader->SourceSocket;
+ if ((SourceSocket == RIP_SOCKET) ||
+ (SourceSocket == SAP_SOCKET)) {
+
+ return;
+
+ }
+
+ if (SourceSocket == NB_SOCKET) {
+
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT TotalDataLength;
+
+ //
+ // ConnectionControlFlag and DataStreamType will always follow
+ // IpxHeader
+ //
+ ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
+ DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
+
+ //
+ // If this is a SYS packet with or without a request for ACK and
+ // has session data in it.
+ //
+ if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
+ (DataStreamType == 0x06)) {
+
+ //
+ // TotalDataLength is in the same buffer.
+ //
+ TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
+
+ //
+ // No need to update the WAN activity counter
+ //
+ if (TotalDataLength == 0) {
+ return;
+ }
+ }
+
+ } else {
+
+ UCHAR KeepAliveSignature;
+
+
+ //
+ // Now see if it is an NCP keep alive. It can be from rip or from
+ // NCP on this machine
+ //
+ // NOTE: We cannot come here for an SMB packet - [IsaacHe - 12/15].
+ //
+ if (PacketLength == sizeof(IPX_HEADER) + 2) {
+
+ //
+ // Get the client data buffer
+ //
+ NdisQueryPacket(Packet, NULL, NULL, &DataBuffer, NULL);
+
+ //
+ // If the included header length is 0, it is from rip
+ //
+ if (IncludedHeaderLength == 0) {
+
+ //
+ // Get the second buffer in the packet. The second buffer
+ // contains the IPX header + other stuff
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(DataBuffer);
+ } else {
+ //
+ // Get the third buffer in the packet.
+ //
+ DataBuffer = NDIS_BUFFER_LINKAGE(NDIS_BUFFER_LINKAGE(DataBuffer));
+ }
+
+ NdisQueryBuffer (DataBuffer, (PVOID *)&DataBufferData, &DataBufferLength);
+ CTEAssert(DataBufferData);
+
+ if (IncludedHeaderLength == 0) {
+ KeepAliveSignature = DataBufferData[sizeof(IPX_HEADER) + 1];
+ } else {
+ KeepAliveSignature = DataBufferData[1];
+ }
+
+ if ((KeepAliveSignature == '?') ||
+ (KeepAliveSignature == 'Y')) {
+ return;
+ }
+ }
+ }
+
+
+ //
+ // This was a normal packet, so reset this.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+} /* IpxUpdateWanInactivityCounter */
+
+#if DBG
+ULONG IpxPadCount = 0;
+#endif
+
+#ifdef _PNP_POWER
+
+NDIS_STATUS
+IpxSendFramePreFwd(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NB/SPX to send a frame.
+
+Arguments:
+
+ LocalTarget - The local target of the send - NB will have the LocalTarget in the Send_Reserved part
+ of the packet; SPX will not now, but will later.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ Return of IpxSendFrame
+
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PDEVICE Device = IpxDevice;
+ PIPX_HEADER TempHeader;
+
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ //
+ // Set this now, will change later
+ //
+ Reserved->CurrentNicId = 0;
+
+ //
+ // Copy the LocalTarget into the send reserved area of the packet.
+ //
+ Reserved->LocalTarget = *LocalTarget;
+
+ //
+ // If the NicId in the handle is 0, then this could be a send
+ // over all NICs in the case of NB/SPX.
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ CTEAssert(Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX);
+
+ //
+ // Check the destination network in the IPX header. If this is 0,
+ // then we need to iterate the send over all NICs.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ if ((*(UNALIGNED ULONG *)(TempHeader->DestinationNetwork) == 0) &&
+ ((IPX_NODE_BROADCAST(TempHeader->DestinationNode)) ||
+ (Reserved->Identifier == IDENTIFIER_SPX))) {
+
+ //
+ // Start with the first NIC
+ // BUGBUG: Search for the first NIC
+ //
+
+ IPX_DEBUG(SEND, ("Iteration over NICs started, reserved: %lx\n", Reserved));
+ Reserved->CurrentNicId = 1;
+ Reserved->Net0SendSucceeded = FALSE;
+
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, 1);
+ Reserved->PacketLength = PacketLength;
+ } else {
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Recalculate packet counts here.
+ //
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, 17);
+ NdisRecalculatePacketCounts (Packet);
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ return IpxSendFrame (
+ &Reserved->LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+
+ } else {
+ return IpxSendFrame (
+ LocalTarget,
+ Packet,
+ PacketLength,
+ IncludedHeaderLength);
+ }
+}
+#endif
+
+
+NDIS_STATUS
+IpxSendFrame(
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ BUGBUG: Check that Binding is not NULL.
+
+Arguments:
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PDEVICE Device = IpxDevice;
+ PUCHAR Header;
+ PBINDING Binding, MasterBinding;
+ PADAPTER Adapter;
+ ULONG TwoBytes;
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ ULONG HeaderLength=0;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+ UCHAR SourceRoutingIdentifier;
+ ULONG HeaderSizeRequired;
+ PIPX_HEADER TempHeader;
+ USHORT PktLength;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ //
+ // Get the lock on the binding array
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ Binding = NIC_HANDLE_TO_BINDING(Device, &LocalTarget->NicHandle);
+
+ if (Binding == NULL) {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG(PNP, ("Invalid NIC handle: %lx\n", LocalTarget->NicHandle));
+ //
+ // [BUGBUGZZ] Return a unique error that NB/SPX see and re-query the NicId.
+ //
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ Adapter = Binding->Adapter;
+
+ IpxReferenceAdapter(Adapter);
+
+ //
+ // Release the lock
+ //
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+
+ //
+ // If this is on the loopback adapter (Nic 0), queue it on the LoopbackQueue;
+ // if the LoopbackRtn is not started, start it now.
+ //
+ if (LocalTarget->NicId == 0) {
+
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Mac.c: Packet: %x\n", Packet));
+
+ //
+ // Assume an 802_3802_2 header and use that length.
+ //
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ // NdisAdjustBufferLength (HeaderBuffer, 17);
+
+ NdisRecalculatePacketCounts (Packet);
+
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+
+ //
+ // The upper driver waits for the SendComplete.
+ //
+ return STATUS_PENDING;
+ }
+
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding == NULL) {
+ return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+ }
+ Adapter = Binding->Adapter;
+#endif _PNP_POWER
+
+ //
+ // For IPX and other protocols that are guaranteed to have allocated
+ // the header from non-paged pool, use the buffer directly. For others,
+ // query the packet for the pointer to the MDL.
+ //
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+ HeaderBuffer = Reserved->HeaderBuffer;
+ Header = Reserved->Header;
+
+ } else {
+ NdisQueryPacket (Packet, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+ }
+
+ CTEAssert (Reserved->PaddingBuffer == NULL);
+
+ //
+ // First move the packet around if needed.
+ //
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+
+ //
+ // Only RIP will have IncludedHeaderLength as 0. I don't know
+ // why we have the comment about RIP inside this if statement.
+ //
+ if (IncludedHeaderLength > 0) {
+
+ //
+ // Spx can handle a virtual net as long as it is
+ // not 0. Netbios always needs to use the real address.
+ // We need to hack the ipx source address for packets
+ // which are sent by spx if we have a fake virtual
+ // net, and packets sent by netbios unless we are
+ // bound to only one card.
+ //
+
+ //
+ // We handle binding sets as follows, based on who
+ // sent the frame to us:
+ //
+ // RIP: Since we only tell RIP about the masters at
+ // bind time, and hide slaves on indications, it should
+ // never be sending on a slave binding. Since RIP knows
+ // the real net and node of every binding we don't
+ // need to modify the packet at all.
+ //
+ // NB: For broadcasts we want to put the first card's
+ // address in the IPX source but round-robin the
+ // actual sends over all cards (broadcasts shouldn't
+ // be passed in with a slave's NIC ID). For directed
+ // packets, which may come in on a slave, we should
+ // put the slave's address in the IPX source.
+ //
+ // SPX: SPX does not send broadcasts. For directed
+ // frames we want to use the slave's net and node
+ // in the IPX source.
+ //
+
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ //
+ // Get the packet length from the ipx header. Compare with
+ // the max. allowed datagram size.
+ //
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+ PktLength = ((TempHeader->PacketLength[0] << 8) |
+ (TempHeader->PacketLength[1]));
+
+//
+// BUGBUG - Not the most efficient way to do this. NWLNKNB should do this.
+// Doing it in ipx means doing it for all packets (even those sent on
+// connections). Will remove this later when nwlnknb change has been
+// tested.
+//
+
+
+ if (PktLength > (Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER))) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ PktLength,
+ Binding->AnnouncedMaxDatagramSize + sizeof(IPX_HEADER)));
+
+#ifdef _PNP_POWER
+ //
+ // Dereference the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (Device->ValidBindings > 1) {
+
+
+ //
+ // Store this now, since even if we round-robin the
+ // actual send we want the binding set master's net
+ // and node in the IPX source address.
+ //
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ if (Binding->BindingSetMember) {
+
+ if (IPX_NODE_BROADCAST(LocalTarget->MacAddress)) {
+
+ //
+ // This is a broadcast, so we round-robin the
+ // sends through the binding set.
+ //
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+ Adapter = Binding->Adapter;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxReferenceAdapter(Adapter);
+#endif
+ }
+
+ }
+ }
+
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+
+ //
+ // Need to update this if we have multiple cards but
+ // a zero virtual net.
+ //
+
+ if (Device->MultiCardZeroVirtual) {
+
+ CTEAssert (IncludedHeaderLength >= sizeof(IPX_HEADER));
+
+ TempHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ *(UNALIGNED ULONG *)TempHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (TempHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ }
+
+ } else {
+
+ //
+ // For a rip packet it should not be in a binding set,
+ // or if it is it should be the master.
+ //
+#if DBG
+ CTEAssert ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding));
+#endif
+ }
+
+
+#if 0
+ //
+ // There is a header included, we need to adjust it.
+ // The header will be at Device->IncludedHeaderOffset.
+ //
+
+ if (LocalTarget->MacAddress[0] & Adapter->MacInfo.BroadcastMask) {
+ HeaderSizeRequired = Adapter->BcMcHeaderSizes[Binding->FrameType];
+ } else {
+ HeaderSizeRequired = Adapter->DefHeaderSizes[Binding->FrameType];
+ }
+
+ if (HeaderSizeRequired != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ &Header[HeaderSizeRequired],
+ &Header[Device->IncludedHeaderOffset],
+ IncludedHeaderLength);
+ }
+#endif
+ }
+ }
+
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+
+ if (!Binding->LineUp) {
+ //
+ // Bug #17273 return proper error message
+ //
+ // return STATUS_DEVICE_DOES_NOT_EXIST; // BUGBUG: Make this a separate switch that generally falls through?
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ IPX_HEADER UNALIGNED * IpxHeader;
+ PNDIS_BUFFER IpxNdisBuff;
+ UINT IpxHeaderLen;
+
+#if 0
+ //
+ // The header should have been moved here.
+ //
+
+ CTEAssert(Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] ==
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]);
+
+
+ IpxHeader = (IPX_HEADER UNALIGNED *)
+ (&Header[Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II]]);
+#endif
+ //
+ // The Ipx header is always the second ndis buffer in the mdl
+ // chain. Get it and then query the va of the same.
+ //
+ IpxNdisBuff = NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ NdisQueryBuffer (IpxNdisBuff, (PVOID *)&IpxHeader, &IpxHeaderLen);
+// IpxHeader = (IPX_HEADER UNALIGNED *) (&Header[MAC_HEADER_SIZE]);
+
+ //
+ // If this is a type 20 name frame from Netbios and we are
+ // on a dialin WAN line, drop it if configured to.
+ //
+ // The 0x01 bit of DisableDialinNetbios controls
+ // internal->WAN packets, which we handle here.
+ //
+ //
+
+ //
+ // SS# 33592: In case of iterative sends, the IncludedHeaderLength is not set properly
+ // since we dont keep track of the length that came in the first time (we track the PacketLength
+ // however). The included length field is used here for checking for NB_NAME_FRAMES, but elsewhere
+ // used only to distinguish between whether RIP or NB/SPX sent the packet (IncludedHeaderLen ==0 for RIP)
+ // The ideal solution here is to do way with this field altogether, but for the beta we will just use the
+ // PacketLength field for comparison here since we are assured that this will be equal to the InclHeaderLen
+ // for any type 0x14 packet that comes down from NB.
+ //
+ // BUGBUGZZ: Remove the IncludedHeaderLength field.
+ //
+ if ((!Binding->DialOutAsync) &&
+ (Reserved->Identifier == IDENTIFIER_NB) &&
+ // (IncludedHeaderLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ (PacketLength == sizeof(IPX_HEADER) + 50) && // 50 == sizeof(NB_NAME_FRAME)
+ ((Device->DisableDialinNetbios & 0x01) != 0) &&
+ (IpxHeader->PacketType == 0x14)) {
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact sap and ncp
+ // packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ IpxHeader,
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+
+ } else {
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ }
+
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+
+ case ISN_FRAME_TYPE_802_2:
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_802_3:
+ TwoBytes = PacketLength;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ TwoBytes = Adapter->BindSap;
+ HeaderLength = 14;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ //BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if ((((PacketLength + HeaderLength) & 1) != 0) &&
+ (Device->EthernetPadToEven) &&
+ (!Adapter->MacInfo.MediumAsync)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+ if ( CurBuffer == HeaderBuffer ) {
+ BufferLength++; // Just bump this length
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ if (TwoBytes != Adapter->BindSap) {
+ CTEAssert(TwoBytes & 1);
+ TwoBytes += 1;
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+ }
+
+ break;
+
+ case NdisMedium802_5:
+
+ if (Reserved->Identifier >= IDENTIFIER_IPX) {
+
+ DestinationType = Reserved->DestinationType;
+ SourceRoutingIdentifier = IDENTIFIER_IPX;
+
+ } else {
+
+ if (LocalTarget->MacAddress[0] & 0x80) {
+ if (*(UNALIGNED ULONG *)(&LocalTarget->MacAddress[2]) != 0xffffffff) {
+ DestinationType = DESTINATION_MCAST;
+ } else {
+ DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ DestinationType = DESTINATION_DEF;
+ }
+ SourceRoutingIdentifier = Reserved->Identifier;
+
+ }
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ SourceRoutingIdentifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Binding->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_802_3:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+ break;
+
+ case NdisMediumFddi:
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Binding->LocalMacAddress.Address, 6);
+
+ switch (Binding->FrameType) {
+ case ISN_FRAME_TYPE_802_3:
+ HeaderLength = 13;
+ break;
+ case ISN_FRAME_TYPE_802_2:
+ case ISN_FRAME_TYPE_ETHERNET_II:
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+ HeaderLength = 16;
+ break;
+ case ISN_FRAME_TYPE_SNAP:
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 21;
+ break;
+ }
+
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Binding->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+ //
+ // Binding->FrameType is not used.
+ //
+
+ HeaderLength = 3;
+// BufferLength = IncludedHeaderLength + HeaderLength;
+ BufferLength = HeaderLength;
+
+ break;
+
+ }
+
+ //
+ // Adjust the MAC header's length to the right value
+ //
+ NdisAdjustBufferLength (HeaderBuffer, BufferLength);
+ NdisRecalculatePacketCounts (Packet);
+
+#if 0
+ {
+ PMDL mdl;
+ mdl = (PMDL)NDIS_BUFFER_LINKAGE(HeaderBuffer);
+ if (mdl) {
+
+ KdPrint(("**Bytecount %x %x\n",mdl->ByteCount, mdl));
+ if ((LONG)mdl->ByteCount < 0) {
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+#if DBG
+ {
+ ULONG SendFlag;
+ ULONG Temp;
+ PNDIS_BUFFER FirstPacketBuffer;
+ PNDIS_BUFFER SecondPacketBuffer;
+ IPX_HEADER DumpHeader;
+ UCHAR DumpData[14];
+
+ NdisQueryPacket (Packet, NULL, NULL, &FirstPacketBuffer, NULL);
+ SecondPacketBuffer = NDIS_BUFFER_LINKAGE(FirstPacketBuffer);
+ TdiCopyMdlToBuffer(SecondPacketBuffer, 0, &DumpHeader, 0, sizeof(IPX_HEADER), &Temp);
+ if (Reserved->Identifier == IDENTIFIER_NB) {
+ SendFlag = IPX_PACKET_LOG_SEND_NB;
+ } else if (Reserved->Identifier == IDENTIFIER_SPX) {
+ SendFlag = IPX_PACKET_LOG_SEND_SPX;
+ } else if (Reserved->Identifier == IDENTIFIER_RIP) {
+ SendFlag = IPX_PACKET_LOG_SEND_RIP;
+ } else {
+ if (DumpHeader.SourceSocket == IpxPacketLogSocket) {
+ SendFlag = IPX_PACKET_LOG_SEND_SOCKET | IPX_PACKET_LOG_SEND_OTHER;
+ } else {
+ SendFlag = IPX_PACKET_LOG_SEND_OTHER;
+ }
+ }
+
+#if 0
+ if (PACKET_LOG(SendFlag)) {
+
+ TdiCopyMdlToBuffer(SecondPacketBuffer, sizeof(IPX_HEADER), &DumpData, 0, 14, &Temp);
+
+ IpxLogPacket(
+ TRUE,
+ LocalTarget->MacAddress,
+ Binding->LocalMacAddress.Address,
+ (USHORT)PacketLength,
+ &DumpHeader,
+ DumpData);
+
+ }
+#endif
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+#ifdef _PNP_POWER
+ if (Status != STATUS_PENDING) {
+
+ if (Reserved->PaddingBuffer) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+
+ //
+ // If this was an NB/SPX packet, and there was an
+ // iterative send going on, then call the SendComplete
+ // handler.
+ //
+ if ((Reserved->Identifier == IDENTIFIER_NB ||
+ Reserved->Identifier == IDENTIFIER_SPX) &&
+ (Reserved->CurrentNicId)) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ Status);
+
+ Status = STATUS_PENDING;
+ }
+ }
+#else
+ if ((Status != STATUS_PENDING) &&
+ (Reserved->PaddingBuffer)) {
+
+ //
+ // Remove padding if it was done.
+ //
+
+ if ( Reserved->PreviousTail ) {
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT LastBufferLength;
+
+ NdisQueryBuffer( LastBuffer, NULL, &LastBufferLength );
+ NdisAdjustBufferLength( LastBuffer, (LastBufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (Packet);
+ }
+ }
+#endif
+
+#ifdef _PNP_POWER
+ //
+ // Derefernce the binding and adapter
+ //
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IpxDereferenceAdapter(Adapter);
+#endif _PNP_POWER
+
+ return Status;
+
+} /* IpxSendFrame */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+ //
+ // BUGBUG: Remove the IncludedHeaderLength parameter from here
+ //
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+ LONG HeaderLength;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+ IPX_DEBUG(SEND,("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++PacketLength;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(PacketLength / 256);
+ Header[13] = (UCHAR)(PacketLength % 256);
+
+ //NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_3 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+ IPX_DEBUG(SEND, ("Backfill request 802_3802_3!! %x %x %x\n", Packet, Reserved, Reserved->HeaderBuffer));
+ IPX_DEBUG(SEND, ("packet=%x, usermdl %x\n",Packet,Reserved->HeaderBuffer));
+#endif
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 3;
+ Header[14] = 0xe0;
+ Header[15] = 0xe0;
+ Header[16] = 0x03;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0 ) {
+#if BACK_FILL
+ if (0) {
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 17);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 17);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_3EthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) != 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3EthernetII */
+
+
+NDIS_STATUS
+IpxSendFrame802_3Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_3 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ ULONG TwoBytes;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+6, Adapter->LocalMacAddress.Address, 6);
+
+ TwoBytes = PacketLength + 8;
+ Header[14] = 0xaa;
+ Header[15] = 0xaa;
+ Header[16] = 0x03;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ Header[19] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[20]) = Adapter->BindSapNetworkOrder;
+
+ //
+ // Pad odd-length packets if needed.
+ //
+
+ if (((PacketLength & 1) == 0) &&
+ (IpxDevice->EthernetPadToEven)) {
+
+ PNDIS_BUFFER CurBuffer;
+ PIPX_PADDING_BUFFER PaddingBuffer = IpxPaddingBuffer;
+ UINT Offset;
+ UINT LastBufferLength;
+
+ //
+ // Find the tail of the current packet.
+ //
+
+ CurBuffer = Reserved->HeaderBuffer;
+ while (NDIS_BUFFER_LINKAGE(CurBuffer) != NULL) {
+ CurBuffer = NDIS_BUFFER_LINKAGE(CurBuffer);
+ }
+
+ //
+ // If the last byte of the last NDIS_BUFFER is not at the end of
+ // the page, then we can simply increase the NDIS_BUFFER ByteCount
+ // by one.
+ // Otherwise, we must use the global padding buffer.
+ //
+
+ NdisQueryBufferOffset( CurBuffer, &Offset, &LastBufferLength );
+
+ if ( ((Offset + LastBufferLength) & (PAGE_SIZE - 1)) != 0) {
+
+#if BACK_FILL
+ if (0) {
+
+#else
+ if ( CurBuffer == Reserved->HeaderBuffer ) {
+ IncludedHeaderLength++; // Just bump this length
+#endif
+ } else {
+ NdisAdjustBufferLength( CurBuffer, (LastBufferLength + 1) );
+
+ Reserved->PreviousTail = NULL;
+ Reserved->PaddingBuffer = (PIPX_PADDING_BUFFER)CurBuffer;
+ }
+
+ } else {
+
+ CTEAssert (NDIS_BUFFER_LINKAGE(PaddingBuffer->NdisBuffer) == NULL);
+
+ Reserved->PreviousTail = CurBuffer;
+ NDIS_BUFFER_LINKAGE (CurBuffer) = PaddingBuffer->NdisBuffer;
+ Reserved->PaddingBuffer = PaddingBuffer;
+
+ }
+
+ ++TwoBytes;
+#if DBG
+ ++IpxPadCount;
+#endif
+
+ }
+
+ Header[12] = (UCHAR)(TwoBytes / 256);
+ Header[13] = (UCHAR)(TwoBytes % 256);
+
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 22);
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 22);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 22);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_3Snap */
+
+
+NDIS_STATUS
+IpxSendFrame802_5802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_802_2];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 17, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+ //PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+ PUCHAR IpxHeader = Header + MAC_HEADER_SIZE;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+// RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+ }
+
+#if 0
+ if (SourceRoutingLength != 0) {
+
+ PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+#endif
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xe0;
+ Header[1] = 0xe0;
+ Header[2] = 0x03;
+ HeaderLength = 17;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5802_2 */
+
+
+NDIS_STATUS
+IpxSendFrame802_5Snap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUM802_5 FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PBINDING Binding = Adapter->Bindings[ISN_FRAME_TYPE_SNAP];
+ PUCHAR Header;
+ ULONG HeaderLength;
+ UCHAR SourceRoutingBuffer[18];
+ PUCHAR SourceRouting;
+ ULONG SourceRoutingLength;
+ NDIS_STATUS Status;
+ ULONG BufferLength;
+ UCHAR DestinationType;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 22, Packet);
+#endif BACK_FILL
+
+ DestinationType = Reserved->DestinationType;
+
+ if (DestinationType == DESTINATION_DEF) {
+
+ MacLookupSourceRouting(
+ Reserved->Identifier,
+ Binding,
+ LocalTarget->MacAddress,
+ SourceRoutingBuffer,
+ &SourceRoutingLength);
+
+ if (SourceRoutingLength != 0) {
+
+// PUCHAR IpxHeader = Header + Binding->DefHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ SourceRouting = SourceRoutingBuffer;
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+
+ } else {
+
+ //
+ // For these packets we assume that the header is in the
+ // right place.
+ //
+
+ if (!Adapter->SourceRouting) {
+
+ SourceRoutingLength = 0;
+
+ } else {
+
+ if (DestinationType == DESTINATION_BCAST) {
+
+ if (Binding->AllRouteBroadcast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ } else {
+
+ CTEAssert (DestinationType == DESTINATION_MCAST);
+
+ if (Binding->AllRouteMulticast) {
+ SourceRouting = AllRouteSourceRouting;
+ } else {
+ SourceRouting = SingleRouteSourceRouting;
+ }
+ SourceRoutingLength = 2;
+
+ }
+
+ if (SourceRoutingLength != 0) {
+
+ // PUCHAR IpxHeader = Header + Binding->BcMcHeaderSize;
+
+ //
+ // Need to slide the header down to accomodate the SR.
+ //
+
+ // RtlMoveMemory (IpxHeader+SourceRoutingLength, IpxHeader, IncludedHeaderLength);
+ }
+ }
+ }
+
+ Header[0] = TR_PREAMBLE_AC;
+ Header[1] = TR_PREAMBLE_FC;
+ RtlCopyMemory (Header+2, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+8, Adapter->LocalMacAddress.Address, 6);
+
+ if (SourceRoutingLength != 0) {
+ Header[8] |= TR_SOURCE_ROUTE_FLAG;
+ RtlCopyMemory (Header+14, SourceRouting, SourceRoutingLength);
+ }
+
+ Header += (14 + SourceRoutingLength);
+
+ Header[0] = 0xaa;
+ Header[1] = 0xaa;
+ Header[2] = 0x03;
+ Header[3] = 0x00;
+ Header[4] = 0x00;
+ Header[5] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[6]) = Adapter->BindSapNetworkOrder;
+ HeaderLength = 22;
+
+ //BufferLength = IncludedHeaderLength + HeaderLength + SourceRoutingLength;
+ BufferLength = HeaderLength + SourceRoutingLength;
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, BufferLength);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, BufferLength);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrame802_5Snap */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_3(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_3 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 13, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 13);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 13);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 13);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_3 */
+
+
+NDIS_STATUS
+IpxSendFrameFddi802_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 16, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xe0;
+ Header[14] = 0xe0;
+ Header[15] = 0x03;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 16);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 16);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 16);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddi802_2 */
+
+
+NDIS_STATUS
+IpxSendFrameFddiSnap(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMFDDI FRAMES IN
+ THE ISN_FRAME_TYPE_SNAP FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 21, Packet);
+#endif BACK_FILL
+
+ Header[0] = FDDI_HEADER_BYTE;
+ RtlCopyMemory (Header+1, LocalTarget->MacAddress, 6);
+ RtlCopyMemory (Header+7, Adapter->LocalMacAddress.Address, 6);
+
+ Header[13] = 0xaa;
+ Header[14] = 0xaa;
+ Header[15] = 0x03;
+ Header[16] = 0x00;
+ Header[17] = 0x00;
+ Header[18] = 0x00;
+ *(UNALIGNED USHORT *)(&Header[19]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 21);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 21);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 21);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiSnap */
+
+
+NDIS_STATUS
+IpxSendFrameArcnet878_2(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMARCNET878_2 FRAMES IN
+ THE ISN_FRAME_TYPE_802_2 FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 3, Packet);
+#endif BACK_FILL
+ //
+ // Convert broadcast address to 0 (the arcnet broadcast).
+ //
+
+ Header[0] = Adapter->LocalMacAddress.Address[5];
+ if (LocalTarget->MacAddress[5] == 0xff) {
+ Header[1] = 0x00;
+ } else {
+ Header[1] = LocalTarget->MacAddress[5];
+ }
+ Header[2] = ARCNET_PROTOCOL_ID;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 3);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 3);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 3);
+#endif
+
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+
+ return Status;
+
+} /* IpxSendFrameFddiArcnet878_2 */
+
+
+NDIS_STATUS
+IpxSendFrameWanEthernetII(
+ IN PADAPTER Adapter,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN PNDIS_PACKET Packet,
+ IN ULONG PacketLength,
+ IN ULONG IncludedHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs a MAC header in a packet and submits
+ it to the appropriate NDIS driver.
+
+ It is assumed that the first buffer in the packet contains
+ an IPX header at an offset based on the media type. This
+ IPX header is moved around if needed.
+
+ THIS FUNCTION ONLY CONSTRUCT NDISMEDIUMWAN FRAMES IN
+ THE ISN_FRAME_TYPE_ETHERNET_II FORMAT.
+
+Arguments:
+
+ Adapter - The adapter on which we are sending.
+
+ LocalTarget - The local target of the send.
+
+ Packet - The NDIS packet.
+
+ PacketLength - The length of the packet, starting at the IPX header.
+
+ IncludedHeaderLength - The length of the header included in the
+ first buffer that needs to be moved if it does not wind up
+ MacHeaderOffset bytes into the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+#ifdef _PNP_POWER
+ PBINDING Binding;
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&IpxDevice->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(IpxDevice, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&IpxDevice->BindAccessLock, LockHandle1);
+
+#else
+ PBINDING Binding = IpxDevice->Bindings[LocalTarget->NicId];
+#endif _PNP_POWER
+
+ if (Binding->LineUp) {
+
+ Header = Reserved->Header;
+
+#if BACK_FILL
+ BACK_FILL_HEADER(Header, Reserved, 14, Packet);
+
+ //
+ // Call UpdateWanInactivity only if this is not a backfill packet, since
+ // SMB server does not do KeepAlives. In case, of backfilled packets, reset
+ // the counter regardless.
+ //
+ if (!Reserved->BackFill) {
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+ } else {
+ Binding->WanInactivityCounter = 0;
+ }
+
+#else
+ //
+ // We do checks to see if we should reset the inactivity
+ // counter. We normally need to check for netbios
+ // session alives, packets from rip, packets from
+ // sap, and ncp keep alives. In fact netbios packets
+ // and rip packets don't come through here.
+ //
+
+ IpxUpdateWanInactivityCounter(
+ Binding,
+ (IPX_HEADER UNALIGNED *)(Header + IpxDevice->IncludedHeaderOffset),
+ IncludedHeaderLength,
+ Packet,
+ PacketLength);
+#endif BACK_FILL
+
+ RtlCopyMemory (Header, Binding->RemoteMacAddress.Address, 6);
+ RtlCopyMemory (Header+6, Binding->LocalMacAddress.Address, 6);
+
+ *(UNALIGNED USHORT *)(&Header[12]) = Adapter->BindSapNetworkOrder;
+
+// NdisAdjustBufferLength (Reserved->HeaderBuffer, IncludedHeaderLength + 14);
+
+#if BACK_FILL
+ BACK_FILL_ADJUST_BUFFER_LENGTH(Reserved, 14);
+#else
+ NdisAdjustBufferLength (Reserved->HeaderBuffer, 14);
+#endif
+ NdisRecalculatePacketCounts (Packet);
+
+ NdisSend(
+ &Status,
+ Adapter->NdisBindingHandle,
+ Packet);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return Status;
+
+ } else {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+} /* IpxSendFrameWanEthernetII */
+
+
+VOID
+MacUpdateSourceRouting(
+ IN ULONG Database,
+ IN PADAPTER Adapter,
+ IN PUCHAR MacHeader,
+ IN ULONG MacHeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a valid IPX frame is received from
+ a remote. It gives the source routing database a change to
+ update itself to include information about this remote.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Adapter - The adapter the frame was received on.
+
+ MacHeader - The MAC header of the received frame.
+
+ MacHeaderLength - The length of the MAC header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ CTEAssert ((Database >= 0) && (Database <= 3));
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // need to do anything.
+ //
+
+ if (!Adapter->SourceRouting) {
+ return;
+ }
+
+ //
+ // See if this source routing is relevant. We don't
+ // care about two-byte source routing since that
+ // indicates it did not cross a router. If there
+ // is nothing in the database, then don't add
+ // this if it is minimal (if it is not, we need
+ // to add it so we will find it on sending).
+ //
+
+ if ((Adapter->SourceRoutingEmpty[Database]) &&
+ (MacHeaderLength <= 16)) {
+ return;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ //
+ // Try to find this address in the database.
+ //
+
+ Hash = MacSourceRoutingHash (MacHeader+8);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacHeader+8, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node. If the data is the
+ // same as what we have, update the time since used to
+ // prevent aging.
+ //
+
+ if ((Current->SourceRoutingLength == MacHeaderLength-14) &&
+ (RtlEqualMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength-14))) {
+
+ Current->TimeSinceUsed = 0;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+ }
+
+ }
+
+ //
+ // Not found, insert a new node at the front of the list.
+ //
+
+ Current = (PSOURCE_ROUTE)IpxAllocateMemory (SOURCE_ROUTE_SIZE(MacHeaderLength-14), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ if (Current == (PSOURCE_ROUTE)NULL) {
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+ }
+
+ Current->Next = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current;
+
+ Adapter->SourceRoutingEmpty[Database] = FALSE;
+
+ RtlCopyMemory (Current->MacAddress, MacHeader+8, 6);
+ Current->MacAddress[0] &= 0x7f;
+ Current->SourceRoutingLength = (UCHAR)(MacHeaderLength - 14);
+ RtlCopyMemory (Current->SourceRouting, MacHeader+14, MacHeaderLength - 14);
+
+ Current->TimeSinceUsed = 0;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Adding source route %lx for %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ Current, Current->MacAddress[0], Current->MacAddress[1],
+ Current->MacAddress[2], Current->MacAddress[3],
+ Current->MacAddress[4], Current->MacAddress[5]));
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacUpdateSourceRouting */
+
+
+VOID
+MacLookupSourceRouting(
+ IN ULONG Database,
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6],
+ IN OUT UCHAR SourceRouting[18],
+ OUT PULONG SourceRoutingLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a target address in the adapter's
+ source routing database to see if source routing information
+ needs to be added to the frame.
+
+Arguments:
+
+ Database - The "database" to use (IPX, SPX, NB, RIP).
+
+ Binding - The binding the frame is being sent on.
+
+ MacAddress - The destination address.
+
+ SourceRouting - Buffer to hold the returned source routing info.
+
+ SourceRoutingLength - The returned source routing length.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // If this adapter is configured for no source routing, don't
+ // insert any.
+ //
+
+ if (!Adapter->SourceRouting) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ //
+ // See if source routing has not been important so far.
+ //
+ // BUGBUG: This is wrong because we may be sending a directed
+ // packet to somebody on the other side of a router, without
+ // ever having received a routed packet. We fix this for the
+ // moment by only setting SourceRoutingEmpty for netbios
+ // which uses broadcasts for discovery.
+ //
+
+ if (Adapter->SourceRoutingEmpty[Database]) {
+ *SourceRoutingLength = 0;
+ return;
+ }
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ //
+ // We found routing for this node.
+ //
+
+ if (Current->SourceRoutingLength <= 2) {
+ *SourceRoutingLength = 0;
+ } else {
+ RtlCopyMemory (SourceRouting, Current->SourceRouting, Current->SourceRoutingLength);
+ SourceRouting[0] = (SourceRouting[0] & TR_LENGTH_MASK);
+ SourceRouting[1] = (SourceRouting[1] ^ TR_DIRECTION_MASK);
+ *SourceRoutingLength = Current->SourceRoutingLength;
+ }
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+ return;
+
+ } else {
+
+ Current = Current->Next;
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ //
+ // We did not find this node, use the default.
+ //
+
+ if (Binding->AllRouteDirected) {
+ RtlCopyMemory (SourceRouting, AllRouteSourceRouting, 2);
+ } else {
+ RtlCopyMemory (SourceRouting, SingleRouteSourceRouting, 2);
+ }
+ *SourceRoutingLength = 2;
+
+} /* MacLookupSourceRouting */
+
+
+VOID
+MacSourceRoutingTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the source routing timer expires.
+ It is called every minute.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PADAPTER Adapter;
+ PBINDING Binding;
+ PSOURCE_ROUTE Current, OldCurrent, Previous;
+ UINT i, j, k;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+#ifdef _PNP_POWER
+
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ //
+ // Get a lock on the access path.
+ //
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ ++Device->SourceRoutingTime;
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ if (Binding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ ++Device->SourceRoutingTime;
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ if (Binding = Device->Bindings[i]) {
+#endif _PNP_POWER
+
+ Adapter = Binding->Adapter;
+
+ if (Adapter->LastSourceRoutingTime != Device->SourceRoutingTime) {
+
+ //
+ // We need to scan this adapter's source routing
+ // tree for stale routes. To simplify the scan we
+ // only delete entries that have at least one
+ // child that is NULL.
+ //
+
+ Adapter->LastSourceRoutingTime = Device->SourceRoutingTime;
+
+ for (j = 0; j < IDENTIFIER_TOTAL; j++) {
+
+ for (k = 0; k < SOURCE_ROUTE_HASH_SIZE; k++) {
+
+ if (Adapter->SourceRoutingHeads[j][k] == (PSOURCE_ROUTE)NULL) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ Current = Adapter->SourceRoutingHeads[j][k];
+ Previous = (PSOURCE_ROUTE)NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ ++Current->TimeSinceUsed;
+
+ if (Current->TimeSinceUsed >= Device->SourceRouteUsageTime) {
+
+ //
+ // A stale entry needs to be aged.
+ //
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[j][k] = Current->Next;
+ }
+
+ OldCurrent = Current;
+ Current = Current->Next;
+
+ IPX_DEBUG (SOURCE_ROUTE, ("Aging out source-route entry %lx\n", OldCurrent));
+ IpxFreeMemory (OldCurrent, SOURCE_ROUTE_SIZE (OldCurrent->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+ } // for loop through the database's hash list
+
+ } // for loop through the adapter's four databases
+
+ } // if adapter's database needs to be checked
+
+ } // if binding exists
+
+ } // for loop through every binding
+ }
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Now restart the timer unless we should not (which means
+ // we are being unloaded).
+ //
+
+ if (Device->SourceRoutingUsed) {
+
+ CTEStartTimer(
+ &Device->SourceRoutingTimer,
+ 60000, // one minute timeout
+ MacSourceRoutingTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ IpxDereferenceDevice (Device, DREF_SR_TIMER);
+ }
+
+} /* MacSourceRoutingTimeout */
+
+
+VOID
+MacSourceRoutingRemove(
+ IN PBINDING Binding,
+ IN UCHAR MacAddress[6]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ MAC address should be removed.
+
+Arguments:
+
+ Binding - The binding to modify.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PSOURCE_ROUTE Current, Previous;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Hash;
+ ULONG Database;
+ LONG Result;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through to find the matching entry in each database.
+ //
+
+ Hash = MacSourceRoutingHash (MacAddress);
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Previous = NULL;
+
+ while (Current != (PSOURCE_ROUTE)NULL) {
+
+ IPX_NODE_COMPARE (MacAddress, Current->MacAddress, &Result);
+
+ if (Result == 0) {
+
+ if (Previous) {
+ Previous->Next = Current->Next;
+ } else {
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+ }
+
+ IPX_DEBUG (SOURCE_ROUTE, ("IPXROUTE freeing source-route entry %lx\n", Current));
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ break;
+
+ } else {
+
+ Previous = Current;
+ Current = Current->Next;
+
+ }
+
+ }
+
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingRemove */
+
+
+VOID
+MacSourceRoutingClear(
+ IN PBINDING Binding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the IPX action handler when an
+ IPXROUTE use has specified that source routing for a given
+ binding should be cleared entirely.
+
+Arguments:
+
+ Binding - The binding to be cleared.
+
+ MacAddress - The MAC address to remove.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSOURCE_ROUTE Current;
+ PADAPTER Adapter = Binding->Adapter;
+ ULONG Database, Hash;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Scan through and remove every entry in the database.
+ //
+
+ IPX_GET_LOCK (&Adapter->Lock, &LockHandle);
+
+ for (Database = 0; Database < IDENTIFIER_TOTAL; Database++) {
+
+ for (Hash = 0; Hash < SOURCE_ROUTE_HASH_SIZE; Hash++) {
+
+ while (Adapter->SourceRoutingHeads[Database][Hash]) {
+
+ Current = Adapter->SourceRoutingHeads[Database][Hash];
+ Adapter->SourceRoutingHeads[Database][Hash] = Current->Next;
+
+ IpxFreeMemory (Current, SOURCE_ROUTE_SIZE (Current->SourceRoutingLength), MEMORY_SOURCE_ROUTE, "SourceRouting");
+
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Adapter->Lock, LockHandle);
+
+} /* MacSourceRoutingClear */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/mac.h b/private/ntos/tdi/isnp/ipx/mac.h
new file mode 100644
index 000000000..a88e77ecd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mac.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ mac.h
+
+Abstract:
+
+ This header file defines manifest constants and necessary macros for use
+ by transports dealing with multiple MAC cards through the NDIS interface.
+
+Revision History:
+
+--*/
+
+
+//
+// We need this to define information about the MAC. Note that
+// it is a strange structure in that the first four elements
+// are for use internally by the mac.c routines, while the
+// DeviceContext knows about and uses the last two.
+//
+
+typedef struct _NDIS_INFORMATION {
+
+ NDIS_MEDIUM MediumType;
+ NDIS_MEDIUM RealMediumType;
+ BOOLEAN SourceRouting;
+ BOOLEAN MediumAsync;
+ UCHAR BroadcastMask;
+ ULONG CopyLookahead;
+ ULONG MacOptions;
+ ULONG MinHeaderLength;
+ ULONG MaxHeaderLength;
+
+} NDIS_INFORMATION, * PNDIS_INFORMATION;
+
+
+#define TR_SOURCE_ROUTE_FLAG 0x80
+
+#define ARCNET_PROTOCOL_ID 0xFA
+
diff --git a/private/ntos/tdi/isnp/ipx/mp/makefile b/private/ntos/tdi/isnp/ipx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/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/isnp/ipx/mp/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/mp/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/mp/sources b/private/ntos/tdi/isnp/ipx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/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/isnp/ipx/ndis.c b/private/ntos/tdi/isnp/ipx/ndis.c
new file mode 100644
index 000000000..14066a786
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/ndis.c
@@ -0,0 +1,2204 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ ndis.c
+
+Abstract:
+
+ This module contains code which implements the routines used to
+ initialize the IPX <-> NDIS interface, as well as most of the
+ interface routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) 3-Oct-1995
+ Changes to support transfer of buffer ownership to transports
+ 1. Added the ReceivePacketHandler to the ProtChars.
+
+ Sanjay Anand (SanjayAn) 27-Oct-1995
+ Changes to support Plug and Play (in _PNP_POWER)
+
+ Tony Bell (TonyBe) 10-Dec-1995
+ Changes to support new NdisWan Lineup.
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This is a one-per-driver variable used in binding
+// to the NDIS interface.
+//
+
+NDIS_HANDLE IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ );
+
+#ifndef _PNP_POWER
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,IpxRegisterProtocol)
+#pragma alloc_text(INIT,IpxInitializeNdis)
+#endif
+#endif
+
+
+NTSTATUS
+IpxRegisterProtocol(
+ IN PNDIS_STRING NameString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface.
+
+Arguments:
+
+ NameString - The name of the transport.
+
+Return Value:
+
+ The function value is the status of the operation.
+ STATUS_SUCCESS if all goes well,
+ Failure status if we tried to register and couldn't,
+ STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ NDIS_PROTOCOL_CHARACTERISTICS ProtChars; // Used temporarily to register
+
+
+ //
+ // Set up the characteristics of this protocol
+ //
+#if NDIS40
+ ProtChars.MajorNdisVersion = 4;
+
+ ProtChars.ReceivePacketHandler = IpxReceivePacket;
+#else
+ ProtChars.MajorNdisVersion = 3;
+#endif
+ ProtChars.MinorNdisVersion = 0;
+
+ ProtChars.Name = *NameString;
+
+ ProtChars.OpenAdapterCompleteHandler = IpxOpenAdapterComplete;
+ ProtChars.CloseAdapterCompleteHandler = IpxCloseAdapterComplete;
+ ProtChars.ResetCompleteHandler = IpxResetComplete;
+ ProtChars.RequestCompleteHandler = IpxRequestComplete;
+
+ ProtChars.SendCompleteHandler = IpxSendComplete;
+ ProtChars.TransferDataCompleteHandler = IpxTransferDataComplete;
+
+ ProtChars.ReceiveHandler = IpxReceiveIndication;
+ ProtChars.ReceiveCompleteHandler = IpxReceiveComplete;
+ ProtChars.StatusHandler = IpxStatus;
+ ProtChars.StatusCompleteHandler = IpxStatusComplete;
+
+#ifdef _PNP_POWER
+ ProtChars.BindAdapterHandler = IpxBindAdapter;
+ ProtChars.UnbindAdapterHandler = IpxUnbindAdapter;
+ ProtChars.TranslateHandler = IpxTranslate;
+#endif // _PNP_POWER
+
+ NdisRegisterProtocol (
+ &ndisStatus,
+ &IpxNdisProtocolHandle,
+ &ProtChars,
+ (UINT)sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + NameString->Length);
+
+ if (ndisStatus != NDIS_STATUS_SUCCESS) {
+ return (NTSTATUS)ndisStatus;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* IpxRegisterProtocol */
+
+
+VOID
+IpxDeregisterProtocol (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes this transport to the NDIS interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ if (IpxNdisProtocolHandle != (NDIS_HANDLE)NULL) {
+ NdisDeregisterProtocol (
+ &ndisStatus,
+ IpxNdisProtocolHandle);
+ IpxNdisProtocolHandle = (NDIS_HANDLE)NULL;
+ }
+
+} /* IpxDeregisterProtocol */
+
+
+NDIS_STATUS
+IpxSubmitNdisRequest(
+ IN PADAPTER Adapter,
+ IN PNDIS_REQUEST NdisRequest,
+ IN PNDIS_STRING AdapterString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine passed an NDIS_REQUEST to the MAC and waits
+ until it has completed before returning the final status.
+
+Arguments:
+
+ Adapter - Pointer to the device context for this driver.
+
+ NdisRequest - Pointer to the NDIS_REQUEST to submit.
+
+ AdapterString - The name of the adapter, in case an error needs
+ to be logged.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+{
+ NDIS_STATUS NdisStatus;
+
+ NdisRequest(
+ &NdisStatus,
+ Adapter->NdisBindingHandle,
+ NdisRequest);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx failed %lx\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid,
+ NdisStatus));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ NdisRequest->RequestType == NdisRequestSetInformation ?
+ EVENT_TRANSPORT_SET_OID_FAILED : EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NdisStatus,
+ AdapterString->Buffer,
+ NdisRequest->DATA.QUERY_INFORMATION.Oid);
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("%s on OID %8.8lx succeeded\n",
+ NdisRequest->RequestType == NdisRequestSetInformation ? "Set" : "Query",
+ NdisRequest->DATA.QUERY_INFORMATION.Oid));
+ }
+
+ return NdisStatus;
+
+} /* IpxSubmitNdisRequest */
+
+
+NTSTATUS
+IpxInitializeNdis(
+ IN PADAPTER Adapter,
+ IN PBINDING_CONFIG ConfigBinding
+ )
+
+/*++
+
+Routine Description:
+
+ This routine introduces this transport to the NDIS interface and sets up
+ any necessary NDIS data structures (Buffer pools and such). It will be
+ called for each adapter opened by this transport.
+
+Arguments:
+
+ Adapter - Structure describing this binding.
+
+ ConfigAdapter - Configuration information for this binding.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ NDIS_STATUS OpenErrorStatus;
+ NDIS_MEDIUM IpxSupportedMedia[] = { NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumArcnet878_2, NdisMediumWan };
+ UINT SelectedMedium;
+ NDIS_REQUEST IpxRequest;
+ ULONG MinimumLookahead;
+ UCHAR WanProtocolId[6] = { 0x80, 0x00, 0x00, 0x00, 0x81, 0x37 };
+ UCHAR FunctionalAddress[4] = { 0x00, 0x80, 0x00, 0x00 };
+ ULONG WanHeaderFormat = NdisWanHeaderEthernet;
+ NDIS_OID IpxOid;
+ ULONG MacOptions;
+ ULONG PacketFilter;
+ PNDIS_STRING AdapterString = &ConfigBinding->AdapterName;
+
+ //
+ // Initialize this adapter for IPX use through NDIS
+ //
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ Adapter->NdisBindingHandle = NULL;
+
+ OpenErrorStatus = 0;
+
+ NdisOpenAdapter (
+ &NdisStatus,
+ &OpenErrorStatus,
+ &Adapter->NdisBindingHandle,
+ &SelectedMedium,
+ IpxSupportedMedia,
+ sizeof (IpxSupportedMedia) / sizeof(NDIS_MEDIUM),
+ IpxNdisProtocolHandle,
+ (NDIS_HANDLE)Adapter,
+ &ConfigBinding->AdapterName,
+ 0,
+ NULL);
+
+ if (NdisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ NdisStatus = Adapter->NdisRequestStatus;
+ OpenErrorStatus = Adapter->OpenErrorStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (NDIS, ("Open %ws failed %lx\n", ConfigBinding->AdapterName.Buffer, NdisStatus));
+
+ IpxWriteGeneralErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 807,
+ NdisStatus,
+ AdapterString->Buffer,
+ 1,
+ &OpenErrorStatus);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ IPX_DEBUG (NDIS, ("Open %ws succeeded\n", ConfigBinding->AdapterName.Buffer));
+ }
+
+
+ //
+ // Get the information we need about the adapter, based on
+ // the media type.
+ //
+
+ MacInitializeMacInfo(
+ IpxSupportedMedia[SelectedMedium],
+ &Adapter->MacInfo);
+
+
+ switch (Adapter->MacInfo.RealMediumType) {
+
+ case NdisMedium802_3:
+
+ IpxOid = OID_802_3_CURRENT_ADDRESS;
+ break;
+
+ case NdisMedium802_5:
+
+ IpxOid = OID_802_5_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumFddi:
+
+ IpxOid = OID_FDDI_LONG_CURRENT_ADDR;
+ break;
+
+ case NdisMediumArcnet878_2:
+
+ IpxOid = OID_ARCNET_CURRENT_ADDRESS;
+ break;
+
+ case NdisMediumWan:
+
+ IpxOid = OID_WAN_CURRENT_ADDRESS;
+ break;
+
+ default:
+
+ NdisStatus = NDIS_STATUS_FAILURE;
+ break;
+
+ }
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = IpxOid;
+
+ if (IpxOid != OID_ARCNET_CURRENT_ADDRESS) {
+
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = Adapter->LocalMacAddress.Address;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ } else {
+
+ //
+ // We take the arcnet single-byte address and right-justify
+ // it in a field of zeros.
+ //
+
+ RtlZeroMemory (Adapter->LocalMacAddress.Address, 5);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->LocalMacAddress.Address[5];
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 1;
+
+ }
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the maximum packet sizes.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxReceivePacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MaxSendPacketSize);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Query the receive buffer space.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_RECEIVE_BUFFER_SPACE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->ReceiveBufferSpace);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now set the minimum lookahead size. The value we choose
+ // here is the 128 needed for TDI indications, plus the size
+ // of the IPX header, plus the largest extra header possible
+ // (a SNAP header, 8 bytes), plus the largest higher-level
+ // header (I think it is a Netbios datagram, 34 bytes).
+ //
+ // BETABUGBUG: Adapt this based on higher-level bindings and
+ // configured frame types.
+ //
+
+ MinimumLookahead = 128 + sizeof(IPX_HEADER) + 8 + 34;
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_CURRENT_LOOKAHEAD;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MinimumLookahead;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Now query the link speed
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_LINK_SPEED;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &(Adapter->MediumSpeed);
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For wan, specify our protocol ID and header format.
+ // We don't query the medium subtype because we don't
+ // case (since we require ethernet emulation).
+ //
+
+ if (Adapter->MacInfo.MediumAsync) {
+
+ if (Adapter->BindSap != 0x8137) {
+ *(UNALIGNED USHORT *)(&WanProtocolId[4]) = Adapter->BindSapNetworkOrder;
+ }
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_PROTOCOL_TYPE;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = WanProtocolId;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 6;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_HEADER_FORMAT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanHeaderFormat;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Now query the line count.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_LINE_COUNT;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &Adapter->WanNicIdCount;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ Adapter->WanNicIdCount = 1;
+ }
+
+ if (Adapter->WanNicIdCount == 0) {
+
+ IPX_DEBUG (NDIS, ("OID_WAN_LINE_COUNT returned 0 lines\n"));
+
+ IpxWriteOidErrorLog(
+ Adapter->Device->DeviceObject,
+ EVENT_TRANSPORT_QUERY_OID_FAILED,
+ NDIS_STATUS_INVALID_DATA,
+ AdapterString->Buffer,
+ OID_WAN_LINE_COUNT);
+
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ }
+
+
+ //
+ // For 802.5 adapter's configured that way, we enable the
+ // functional address (C0-00-00-80-00-00).
+ //
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) &&
+ (Adapter->EnableFunctionalAddress)) {
+
+ //
+ // For token-ring, we pass the last four bytes of the
+ // Netbios functional address.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_802_5_CURRENT_FUNCTIONAL;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = FunctionalAddress;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+
+ //
+ // Now query the MAC's optional characteristics.
+ //
+
+ IpxRequest.RequestType = NdisRequestQueryInformation;
+ IpxRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAC_OPTIONS;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBuffer = &MacOptions;
+ IpxRequest.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Adapter->MacInfo.CopyLookahead =
+ ((MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) != 0) ?
+ TDI_RECEIVE_COPY_LOOKAHEAD : 0;
+ Adapter->MacInfo.MacOptions = MacOptions;
+
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 14;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMedium802_5:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 17;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 22;
+ break;
+
+ case NdisMediumFddi:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 13;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 16;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 21;
+ break;
+
+ case NdisMediumArcnet878_2:
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->DefHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_2] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_802_3] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_ETHERNET_II] = 3;
+ Adapter->BcMcHeaderSizes[ISN_FRAME_TYPE_SNAP] = 3;
+ break;
+
+ }
+
+ //
+ // BUGBUG: If functional filtering is set, set the address
+ // for the appropriate binding.
+ //
+
+ //
+ // Now that everything is set up, we enable the filter
+ // for packet reception.
+ //
+
+ switch (Adapter->MacInfo.MediumType) {
+
+ case NdisMedium802_3:
+ case NdisMediumFddi:
+ case NdisMedium802_5:
+ case NdisMediumArcnet878_2:
+
+ //
+ // If we have a virtual network number we need to receive
+ // broadcasts (either the router will be bound in which
+ // case we want them, or we need to respond to rip requests
+ // ourselves).
+ //
+
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+
+ if (Adapter->Device->VirtualNetworkNumber != 0) {
+
+ Adapter->BroadcastEnabled = TRUE;
+ Adapter->Device->EnableBroadcastCount = 1;
+ PacketFilter |= NDIS_PACKET_TYPE_BROADCAST;
+
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter |= NDIS_PACKET_TYPE_FUNCTIONAL;
+ }
+
+ } else {
+
+ Adapter->BroadcastEnabled = FALSE;
+ Adapter->Device->EnableBroadcastCount = 0;
+
+ }
+
+ break;
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ NdisStatus = IpxSubmitNdisRequest (Adapter, &IpxRequest, AdapterString);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxCloseNdis (Adapter);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeNdis */
+
+
+VOID
+IpxAddBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when another reason for enabling
+ broadcast reception is added. If it is the first, then
+ reception on the card is enabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ++Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 1) {
+
+ //
+ // Broadcasts should be enabled.
+ //
+
+ if (!Device->EnableBroadcastPending) {
+
+ if (Device->DisableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxAddBroadcast */
+
+
+VOID
+IpxRemoveBroadcast(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a reason for enabling
+ broadcast reception is removed. If it is the last, then
+ reception on the card is disabled by queueing a call to
+ IpxBroadcastOperation.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD.
+
+Arguments:
+
+ Device - The IPX device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ --Device->EnableBroadcastCount;
+
+ if (Device->EnableBroadcastCount == 0) {
+
+ //
+ // Broadcasts should be disabled.
+ //
+
+ if (!Device->DisableBroadcastPending) {
+
+ if (Device->EnableBroadcastPending) {
+ Device->ReverseBroadcastOperation = TRUE;
+ } else {
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+ }
+ }
+
+} /* IpxRemoveBroadcast */
+
+
+VOID
+IpxBroadcastOperation(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to change whether broadcast reception
+ is enabled or disabled. It performs the requested operation
+ on every adapter bound to by IPX.
+
+ This routine is called by a worker thread queued when a
+ bind/unbind operation changes the broadcast state.
+
+Arguments:
+
+ Parameter - TRUE if broadcasts should be enabled, FALSE
+ if they should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ BOOLEAN Enable = (BOOLEAN)Parameter;
+ UINT i;
+ PBINDING Binding;
+ PADAPTER Adapter;
+ ULONG PacketFilter;
+ NDIS_REQUEST IpxRequest;
+ NDIS_STRING AdapterName;
+ CTELockHandle LockHandle;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ IPX_DEBUG (NDIS, ("%s operation started\n", Enable ? "Enable" : "Disable"));
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+#endif
+ if (Binding == NULL) {
+ continue;
+ }
+
+ Adapter = Binding->Adapter;
+ if (Adapter->BroadcastEnabled == Enable) {
+ continue;
+ }
+
+ if (Enable) {
+ if ((Adapter->MacInfo.MediumType == NdisMedium802_5) && (Adapter->EnableFunctionalAddress)) {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_FUNCTIONAL);
+ } else {
+ PacketFilter = (NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_BROADCAST);
+ }
+ } else {
+ PacketFilter = NDIS_PACKET_TYPE_DIRECTED;
+ }
+
+ //
+ // Now fill in the NDIS_REQUEST.
+ //
+
+ IpxRequest.RequestType = NdisRequestSetInformation;
+ IpxRequest.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;
+ IpxRequest.DATA.SET_INFORMATION.InformationBuffer = &PacketFilter;
+ IpxRequest.DATA.SET_INFORMATION.InformationBufferLength = sizeof(ULONG);
+
+ AdapterName.Buffer = Adapter->AdapterName;
+ AdapterName.Length = (USHORT)Adapter->AdapterNameLength;
+ AdapterName.MaximumLength = (USHORT)(Adapter->AdapterNameLength + sizeof(WCHAR));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ (VOID)IpxSubmitNdisRequest (Adapter, &IpxRequest, &AdapterName);
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Adapter->BroadcastEnabled = Enable;
+
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ if (Enable) {
+
+ CTEAssert (Device->EnableBroadcastPending);
+ Device->EnableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->DisableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)FALSE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ } else {
+
+ CTEAssert (Device->DisableBroadcastPending);
+ Device->DisableBroadcastPending = FALSE;
+
+ if (Device->ReverseBroadcastOperation) {
+ Device->ReverseBroadcastOperation = FALSE;
+ Device->EnableBroadcastPending = TRUE;
+ ExInitializeWorkItem(
+ &Device->BroadcastOperationQueueItem,
+ IpxBroadcastOperation,
+ (PVOID)TRUE);
+ ExQueueWorkItem(&Device->BroadcastOperationQueueItem, DelayedWorkQueue);
+ }
+
+ }
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+}/* IpxBroadcastOperation */
+
+
+VOID
+IpxCloseNdis(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unbinds the transport from the NDIS interface and does
+ any other work required to undo what was done in IpxInitializeNdis.
+ It is written so that it can be called from within IpxInitializeNdis
+ if it fails partway through.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NDIS_STATUS ndisStatus;
+
+ //
+ // Close the NDIS binding.
+ //
+
+ if (Adapter->NdisBindingHandle != (NDIS_HANDLE)NULL) {
+
+ //
+ // This event is used in case any of the NDIS requests
+ // pend; we wait until it is set by the completion
+ // routine, which also sets NdisRequestStatus.
+ //
+
+ KeInitializeEvent(
+ &Adapter->NdisRequestEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ NdisCloseAdapter(
+ &ndisStatus,
+ Adapter->NdisBindingHandle);
+
+ if (ndisStatus == NDIS_STATUS_PENDING) {
+
+ //
+ // The completion routine will set NdisRequestStatus.
+ //
+
+ KeWaitForSingleObject(
+ &Adapter->NdisRequestEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ ndisStatus = Adapter->NdisRequestStatus;
+
+ KeResetEvent(
+ &Adapter->NdisRequestEvent
+ );
+
+ }
+
+ //
+ // We ignore ndisStatus.
+ //
+
+ }
+
+#if 0
+ if (Adapter->SendPacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->SendPacketPoolHandle);
+ }
+
+ if (Adapter->ReceivePacketPoolHandle != NULL) {
+ NdisFreePacketPool (Adapter->ReceivePacketPoolHandle);
+ }
+
+ if (Adapter->NdisBufferPoolHandle != NULL) {
+ NdisFreeBufferPool (Adapter->NdisBufferPoolHandle);
+ }
+#endif
+
+} /* IpxCloseNdis */
+
+
+VOID
+IpxOpenAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that an open adapter
+ is complete. Since we only ever have one outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+ OpenErrorStatus - More status information.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+ Adapter->OpenErrorStatus = OpenErrorStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxOpenAdapterComplete */
+
+VOID
+IpxCloseAdapterComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a close adapter
+ is complete. Currently we don't close adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxCloseAdapterComplete */
+
+
+VOID
+IpxResetComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a reset adapter
+ is complete. Currently we don't reset adapters, so this is not
+ a problem.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BindingContext);
+ UNREFERENCED_PARAMETER(NdisStatus);
+
+} /* IpxResetComplete */
+
+
+VOID
+IpxRequestComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by NDIS to indicate that a request is complete.
+ Since we only ever have one request outstanding, and then only
+ during initialization, all we do is record the status and set
+ the event to signalled to unblock the initialization thread.
+
+Arguments:
+
+ BindingContext - Pointer to the device object for this driver.
+
+ NdisRequest - The object describing the request.
+
+ NdisStatus - The request completion code.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+
+ Adapter->NdisRequestStatus = NdisStatus;
+
+ KeSetEvent(
+ &Adapter->NdisRequestEvent,
+ 0L,
+ FALSE);
+
+} /* IpxRequestComplete */
+
+
+VOID
+IpxStatus(
+ IN NDIS_HANDLE NdisBindingContext,
+ IN NDIS_STATUS NdisStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+
+{
+ PADAPTER Adapter, TmpAdapter;
+
+ PNDIS_WAN_LINE_UP LineUp;
+ PNDIS_WAN_LINE_DOWN LineDown;
+ PIPXCP_CONFIGURATION Configuration; // contains ipx net and node
+
+ BOOLEAN UpdateLineUp;
+ PBINDING Binding, TmpBinding;
+ PDEVICE Device;
+ PADDRESS Address;
+ ULONG CurrentHash;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PNDIS_BUFFER NdisBuffer;
+ PNWLINK_ACTION NwlinkAction;
+ PIPX_ADDRESS_DATA IpxAddressData;
+ PREQUEST Request;
+ UINT BufferLength;
+ IPX_LINE_INFO LineInfo;
+ ULONG Segment;
+ ULONG LinkSpeed;
+ PLIST_ENTRY p;
+ NTSTATUS Status;
+ UINT i, j;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ NTSTATUS ntStatus;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ Adapter = (PADAPTER)NdisBindingContext;
+
+ IpxReferenceAdapter(Adapter);
+#else
+ Adapter = (PADAPTER)NdisBindingContext;
+#endif
+
+ Device = Adapter->Device;
+
+ switch (NdisStatus) {
+
+ case NDIS_STATUS_WAN_LINE_UP:
+
+
+ //
+ // If the line is already up, then we are just getting
+ // a change in line conditions, and the IPXCP_CONFIGURATION
+ // information is not included. If it turns out we need
+ // all the info, we check the size again later.
+ //
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_UP)) {
+ IPX_DEBUG (WAN, ("Line up, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_UP)));
+#ifdef _PNP_POWER
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ LineUp = (PNDIS_WAN_LINE_UP)StatusBuffer;
+
+ //
+ // We scan through the adapter's NIC ID range looking
+ // for an active binding with the same remote address.
+ //
+
+ UpdateLineUp = FALSE;
+
+ //
+ // See if this is a new lineup or not
+ //
+ *((ULONG UNALIGNED *)(&Binding)) =
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2]));
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ if (Binding != NULL) {
+ UpdateLineUp = TRUE;
+ }
+
+ if (LineUp->ProtocolType != Adapter->BindSap) {
+ IPX_DEBUG (WAN, ("Line up, wrong protocol type %lx\n", LineUp->ProtocolType));
+
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+
+ Configuration = (PIPXCP_CONFIGURATION)LineUp->ProtocolBuffer;
+
+ //
+ // PNP_POWER - We hold the exclusive lock to the binding array (thru both the device and adapter)
+ // and the reference to the adapter at this point.
+ //
+
+ //
+ // If this line was previously down, create a new binding
+ // if needed.
+ //
+
+ if (!UpdateLineUp) {
+
+ //
+ // We look for a binding that is allocated but down, if
+ // we can't find that then we look for any empty spot in
+ // the adapter's NIC ID range and allocate a binding in it.
+ // Since we always allocate this way, the allocated
+ // bindings are all clumped at the beginning and once
+ // we find a NULL spot we know there are no more
+ // allocated ones.
+ //
+ // We keep track of the first binding on this adapter
+ // in TmpBinding in case we need config info from it.
+ //
+
+ TmpBinding = NULL;
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (i = Adapter->FirstWanNicId;
+ i <= Adapter->LastWanNicId;
+ i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if (TmpBinding == NULL) {
+ TmpBinding = Binding;
+ }
+
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ break;
+ }
+ }
+
+ if (i > Adapter->LastWanNicId) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, no WAN binding available\n"));
+ return;
+ }
+
+ if (Binding == NULL) {
+
+ //
+ // We need to allocate one.
+ //
+
+ CTEAssert (TmpBinding != NULL);
+
+#ifdef _PNP_POWER
+ //
+ // CreateBinding does an InterLockedPop with the DeviceLock.
+ // So, release the lock here.
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ Status = IpxCreateBinding(
+ Device,
+ NULL,
+ 0,
+ Adapter->AdapterName,
+ &Binding);
+
+ if (Status != STATUS_SUCCESS) {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ goto error_no_lock;
+#else
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_DEBUG (WAN, ("Line up, could not create WAN binding\n"));
+ return;
+#endif
+ }
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ //
+ // Binding->AllRouteXXX doesn't matter for WAN.
+ //
+
+ Binding->FrameType = ISN_FRAME_TYPE_ETHERNET_II;
+ Binding->SendFrameHandler = IpxSendFrameWanEthernetII;
+ ++Adapter->BindingCount;
+ Binding->Adapter = Adapter;
+
+ Binding->NicId = i;
+#ifdef _PNP_POWER
+ INSERT_BINDING(Device, i, Binding);
+#else
+ Device->Bindings[i] = Binding;
+#endif
+
+ //
+ // Other fields are filled in below.
+ //
+
+ }
+
+ //
+ // This is not an update, so note that the line is active.
+ //
+
+ Binding->LineUp = TRUE;
+
+ if (Configuration->ConnectionClient == 1) {
+ Binding->DialOutAsync = TRUE;
+ } else {
+ Binding->DialOutAsync = FALSE;
+ }
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ if ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0)) {
+
+ Device->HighestType20NicId = i;
+ }
+ }
+
+ //
+ // We could error out below, trying to insert this network number. In RipShortTimeout
+ // we dont check for LineUp when calculating the tick counts; set this before the insert
+ // attempt.
+ //
+ Binding->MediumSpeed = LineUp->LinkSpeed;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Add a router entry for this net if there is no router.
+ // We want the number of ticks for a 576-byte frame,
+ // given the link speed in 100 bps units, so we calculate
+ // as:
+ //
+ // seconds 18.21 ticks 4608 bits
+ // --------------------- * ----------- * ---------
+ // link_speed * 100 bits second frame
+ //
+ // to get the formula
+ //
+ // ticks/frame = 839 / link_speed.
+ //
+ // We add link_speed to the numerator also to ensure
+ // that the value is at least 1.
+ //
+
+ if ((!Device->UpperDriverBound[IDENTIFIER_RIP]) &&
+ (*(UNALIGNED ULONG *)Configuration->Network != 0)) {
+ if (RipInsertLocalNetwork(
+ *(UNALIGNED ULONG *)Configuration->Network,
+ Binding->NicId,
+ Adapter->NdisBindingHandle,
+ (USHORT)((839 + LineUp->LinkSpeed) / LineUp->LinkSpeed)) != STATUS_SUCCESS) {
+ //
+ // This means we couldn't allocate memory, or
+ // the entry already existed. If it already
+ // exists we can ignore it for the moment.
+ //
+ // BUGBUG: Now it will succeed if the network
+ // exists.
+ //
+
+ IPX_DEBUG (WAN, ("Line up, could not insert local network\n"));
+ Binding->LineUp = FALSE;
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ goto error_no_lock;
+#else
+ return;
+#endif
+ }
+ }
+
+
+ //
+ // Update our addresses.
+ //
+ Binding->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Binding->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ RtlCopyMemory (Binding->WanRemoteNode, Configuration->RemoteNode, 6);
+
+ //
+ // Return the binding context for this puppy!
+ //
+ *((ULONG UNALIGNED *)(&LineUp->LocalAddress[2])) =
+ *((ULONG UNALIGNED *)(&Binding));
+
+ RtlCopyMemory (Binding->LocalMacAddress.Address, LineUp->LocalAddress, 6);
+ RtlCopyMemory (Binding->RemoteMacAddress.Address, LineUp->RemoteAddress, 6);
+
+ //
+ // Update the device node and all the address
+ // nodes if we have only one bound, or this is
+ // binding one.
+ //
+
+ if (!Device->VirtualNetwork) {
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+ Device->SourceAddress.NetworkAddress = *(UNALIGNED ULONG *)(Configuration->Network);
+ RtlCopyMemory (Device->SourceAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+
+ //
+ // Scan through all the addresses that exist and modify
+ // their pre-constructed local IPX address to reflect
+ // the new local net and node.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (CurrentHash = 0; CurrentHash < IPX_ADDRESS_HASH_COUNT; CurrentHash++) {
+
+ for (p = Device->AddressDatabases[CurrentHash].Flink;
+ p != &Device->AddressDatabases[CurrentHash];
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ Address->LocalAddress.NetworkAddress = *(UNALIGNED ULONG *)Configuration->Network;
+ RtlCopyMemory (Address->LocalAddress.NodeAddress, Configuration->LocalNode, 6);
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Reset this since the line just came up.
+ //
+
+ Binding->WanInactivityCounter = 0;
+
+ }
+
+ LinkSpeed = LineUp->LinkSpeed;
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count WAN
+ // bindings when doing this (although it is unlikely
+ // a LAN binding would be the winner).
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+#ifdef _PNP_POWER
+ //
+ // Release the lock after incrementing the reference count
+ //
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ Device->LinkSpeed = LinkSpeed;
+
+ if ((Adapter->ConfigMaxPacketSize == 0) ||
+ (LineUp->MaximumTotalSize < Adapter->ConfigMaxPacketSize)) {
+ Binding->MaxSendPacketSize = LineUp->MaximumTotalSize;
+ } else {
+ Binding->MaxSendPacketSize = Adapter->ConfigMaxPacketSize;
+ }
+ MacInitializeBindingInfo (Binding, Adapter);
+
+#ifdef _PNP_POWER
+
+ //
+ // We dont give lineups; instead indicate only if the PnP reserved address
+ // changed to SPX. NB gets all PnP indications with the reserved address case
+ // marked out.
+ //
+ {
+ IPX_PNP_INFO NBPnPInfo;
+
+ if ((!Device->MultiCardZeroVirtual) || (Binding->NicId == 1)) {
+
+ //
+ // NB's reserved address changed.
+ //
+ NBPnPInfo.NewReservedAddress = TRUE;
+
+ if (!Device->VirtualNetwork) {
+ //
+ // Let SPX know because it fills in its own headers.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_SPX]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_PNP_INFO IpxPnPInfo;
+
+ IpxPnPInfo.NewReservedAddress = TRUE;
+ IpxPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ IpxPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(IpxPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(IpxPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_SPX].PnPHandler) (
+ IPX_PNP_ADDRESS_CHANGE,
+ &IpxPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADDRESS_CHANGED to SPX: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+ }
+ } else {
+ NBPnPInfo.NewReservedAddress = FALSE;
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_ADD_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_ADD_DEVICE (lineup) to NB: net addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ }
+
+ //
+ // Register this address with the TDI clients.
+ //
+ RtlCopyMemory (Device->TdiRegistrationAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+
+ if ((ntStatus = TdiRegisterNetAddress(
+ Device->TdiRegistrationAddress,
+ &Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+
+ IPX_DEBUG(PNP, ("TdiRegisterNetAddress failed: %lx", ntStatus));
+ }
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+
+ //
+ // Give line up to RIP as it is not PnP aware.
+ //
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+#else
+ //
+ // Indicate to the upper drivers.
+ //
+ LineInfo.LinkSpeed = LineUp->LinkSpeed;
+ LineInfo.MaximumPacketSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MaximumSendSize = LineUp->MaximumTotalSize - 14;
+ LineInfo.MacOptions = Adapter->MacInfo.MacOptions;
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineUpHandler)(
+ Binding->NicId,
+ &LineInfo,
+ NdisMediumWan,
+ UpdateLineUp ? NULL : Configuration);
+ }
+ }
+#endif
+ if (!UpdateLineUp) {
+
+ if ((Device->SingleNetworkActive) &&
+ (Configuration->ConnectionClient == 1)) {
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = TRUE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ //
+ // If we have a virtual net, do a broadcast now so
+ // the router on the other end will know about us.
+ //
+ // BUGBUG: Use RipSendResponse, and do it even
+ // if SingleNetworkActive is FALSE??
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ // If WanGlobalNetworkNumber is TRUE, we only do
+ // this when the first dialin line comes up.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber ||
+ (!Device->GlobalNetworkIndicated && !Binding->DialOutAsync))
+ &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ if (Device->WanGlobalNetworkNumber) {
+ Device->GlobalWanNetwork = Binding->LocalAddress.NetworkAddress;
+ Device->GlobalNetworkIndicated = TRUE;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ if (Device->WanGlobalNetworkNumber) {
+ IpxAddressData->adapternum = Device->SapNicCount - 1;
+ } else {
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ }
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = TRUE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_LINE_DOWN:
+
+ if (StatusBufferSize < sizeof(NDIS_WAN_LINE_DOWN)) {
+ IPX_DEBUG (WAN, ("Line down, status buffer size wrong %d/%d\n", StatusBufferSize, sizeof(NDIS_WAN_LINE_DOWN)));
+ return;
+ }
+
+ LineDown = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
+
+ *((ULONG UNALIGNED*)(&Binding)) = *((ULONG UNALIGNED*)(&LineDown->LocalAddress[2]));
+
+ CTEAssert(Binding != NULL);
+
+ //
+ // Note that the WAN line is down.
+ //
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+
+ Binding->LineUp = FALSE;
+
+ //
+ // PNP_POWER - we hold the exclusive lock to the binding
+ // and reference to the adapter at this point.
+ //
+
+ //
+ // Keep track of the highest NIC ID that we should
+ // send type 20s out on.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Binding->NicId == MIN (Device->MaxBindings, Device->HighestType20NicId)) {
+
+ //
+ // This was the old limit, so we have to scan
+ // backwards to update it -- we stop when we hit
+ // a non-WAN binding, or a wan binding that is up and
+ // dialout, or any wan binding if bit 1 in
+ // DisableDialinNetbios is off.
+ //
+
+ for (i = Binding->NicId-1; i >= 1; i--) {
+#ifdef _PNP_POWER
+ TmpBinding = NIC_ID_TO_BINDING(Device, i);
+#else
+ TmpBinding = Device->Bindings[i];
+#endif
+
+ if ((TmpBinding != NULL) &&
+ ((!TmpBinding->Adapter->MacInfo.MediumAsync) ||
+ (TmpBinding->LineUp &&
+ ((Binding->DialOutAsync) ||
+ ((Device->DisableDialinNetbios & 0x01) == 0))))) {
+
+ break;
+ }
+ }
+
+ Device->HighestType20NicId = i;
+
+ }
+
+
+ //
+ // Scan through bindings to update Device->LinkSpeed.
+ // If SingleNetworkActive is set, we only count LAN
+ // bindings when doing this.
+ //
+ // BUGBUG: Update other device information?
+ //
+
+ LinkSpeed = 0xffffffff;
+ for (i = 1; i <= Device->ValidBindings; i++) {
+#ifdef _PNP_POWER
+ if (TmpBinding = NIC_ID_TO_BINDING(Device, i)) {
+#else
+ if (TmpBinding = Device->Bindings[i]) {
+#endif
+ TmpAdapter = TmpBinding->Adapter;
+ if (TmpBinding->LineUp &&
+ (!Device->SingleNetworkActive || !TmpAdapter->MacInfo.MediumAsync) &&
+ (TmpBinding->MediumSpeed < LinkSpeed)) {
+ LinkSpeed = TmpBinding->MediumSpeed;
+ }
+ }
+ }
+
+ if (LinkSpeed != 0xffffffff) {
+ Device->LinkSpeed = LinkSpeed;
+ }
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ //
+ // Remove our router entry for this net.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ Segment = RipGetSegment ((PUCHAR)&Binding->LocalAddress.NetworkAddress);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ RouteEntry = RipGetRoute (Segment, (PUCHAR)&Binding->LocalAddress.NetworkAddress);
+
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ }
+
+ RipAdjustForBindingChange (Binding->NicId, 0, IpxBindingDown);
+
+ }
+
+ //
+ // Indicate to the upper drivers.
+ //
+#ifdef _PNP_POWER
+
+ //
+ // DeRegister this address with the TDI clients.
+ //
+ {
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+
+ CTEAssert(Binding->TdiRegistrationHandle);
+
+ if ((ntStatus = TdiDeregisterNetAddress(Binding->TdiRegistrationHandle)) != STATUS_SUCCESS) {
+ IPX_DEBUG(PNP, ("TdiDeRegisterNetAddress failed: %lx", ntStatus));
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_NB]) {
+ IPX_PNP_INFO NBPnPInfo;
+
+ CTEAssert(Binding->IsnInformed[IDENTIFIER_NB]);
+
+ NBPnPInfo.LineInfo.LinkSpeed = Device->LinkSpeed;
+ NBPnPInfo.LineInfo.MaximumPacketSize =
+ Device->Information.MaximumLookaheadData + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MaximumSendSize =
+ Device->Information.MaxDatagramSize + sizeof(IPX_HEADER);
+ NBPnPInfo.LineInfo.MacOptions = Device->MacOptions;
+
+ NBPnPInfo.NewReservedAddress = FALSE;
+ NBPnPInfo.FirstORLastDevice = FALSE;
+
+ NBPnPInfo.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+
+ RtlCopyMemory(NBPnPInfo.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ NIC_HANDLE_FROM_NIC(NBPnPInfo.NicHandle, Binding->NicId);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // give the PnP indication
+ //
+ (*Device->UpperDrivers[IDENTIFIER_NB].PnPHandler) (
+ IPX_PNP_DELETE_DEVICE,
+ &NBPnPInfo);
+
+ IPX_DEBUG(AUTO_DETECT, ("IPX_PNP_DELETE_DEVICE (linedown) to NB: addr: %lx\n", Binding->LocalAddress.NetworkAddress));
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+ }
+ }
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ (*Device->UpperDrivers[IDENTIFIER_RIP].LineDownHandler)(
+ Binding->NicId);
+ }
+#else
+ for (i = 0; i < UPPER_DRIVER_COUNT; i++) {
+
+ if (Device->UpperDriverBound[i]) {
+ (*Device->UpperDrivers[i].LineDownHandler)(
+ Binding->NicId);
+ }
+ }
+#endif
+
+ if ((Device->SingleNetworkActive) &&
+ (Binding->DialOutAsync)) {
+
+ //
+ // Drop all entries in the database if rip is not bound.
+ //
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ RipDropRemoteEntries();
+ }
+
+ Device->ActiveNetworkWan = FALSE;
+
+ //
+ // Find a queued line change and complete it.
+ //
+
+ if ((p = ExInterlockedRemoveHeadList(
+ &Device->LineChangeQueue,
+ &Device->Lock)) != NULL) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_LINE_CHANGE);
+
+ }
+
+ }
+
+ //
+ // Find a queued address notify and complete it.
+ //
+
+ if ((!Device->WanGlobalNetworkNumber) &&
+ ((p = ExInterlockedRemoveHeadList(
+ &Device->AddressNotifyQueue,
+ &Device->Lock)) != NULL)) {
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ IpxAddressData = (PIPX_ADDRESS_DATA)(NwlinkAction->Data);
+
+ IpxAddressData->adapternum = Binding->NicId - 1;
+ *(UNALIGNED ULONG *)IpxAddressData->netnum = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory(IpxAddressData->nodenum, Binding->LocalAddress.NodeAddress, 6);
+ IpxAddressData->wan = TRUE;
+ IpxAddressData->status = FALSE;
+ IpxAddressData->maxpkt = Binding->AnnouncedMaxDatagramSize; // BUGBUG: Use real?
+ IpxAddressData->linkspeed = Binding->MediumSpeed;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+ IpxCompleteRequest (Request);
+ IpxFreeRequest (Device, Request);
+
+ IpxDereferenceDevice (Device, DREF_ADDRESS_NOTIFY);
+ }
+
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ break;
+
+ case NDIS_STATUS_WAN_FRAGMENT:
+
+ //
+ // No response needed, IPX is a datagram service.
+ //
+ // BUGBUG: What about telling Netbios/SPX?
+ //
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+#ifdef _PNP_POWER
+error_no_lock:
+ IpxDereferenceAdapter(Adapter);
+#endif
+
+} /* IpxStatus */
+
+
+VOID
+IpxStatusComplete(
+ IN NDIS_HANDLE NdisBindingContext
+ )
+{
+ UNREFERENCED_PARAMETER (NdisBindingContext);
+
+} /* IpxStatusComplete */
+
+
+
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.ini b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
new file mode 100644
index 000000000..416f0c6b7
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.ini
@@ -0,0 +1,191 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkIpx
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnkipx.sys
+ DisplayName = NWLINK2 IPX Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\Elnkii1"
+ Export = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Route = REG_MULTI_SZ ""Elnkii" "Elnkii1""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ NetConfig
+ Elnkii1
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard2
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard3
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard4
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Netcard5
+ NetworkNumber = REG_MULTI_SZ "0"
+ PktType = REG_MULTI_SZ "1"
+ BindSap = REG_DWORD 0x00008137
+ SourceRouting = REG_DWORD 0x00000001
+ SourceRouteDef = REG_DWORD 0x00000000
+ SourceRouteBcast = REG_DWORD 0x00000000
+ SourceRouteMcast = REG_DWORD 0x00000000
+ EnableFuncaddr = REG_DWORD 0x00000001
+ MaxPktSize = REG_DWORD 0x00000000
+ Parameters
+ DedicatedRouter = REG_DWORD 0x00000000
+ InitDatagrams = REG_DWORD 0x0000000a
+ MaxDatagrams = REG_DWORD 0x00000032
+ RipAgeTime = REG_DWORD 0x00000005
+ RipCount = REG_DWORD 0x00000005
+ RipTimeout = REG_DWORD 0x00000001
+ RipUsageTime = REG_DWORD 0x0000000f
+ SourceRouteUsageTime = REG_DWORD 0x0000000a
+ SocketUniqueness = REG_DWORD 0x00000008
+ VirtualNetworkNumber = REG_DWORD 0x00000000
+ VirtualNetworkOptional = REG_DWORD 0x00000001
+ Winsock
+ Mapping = REG_BINARY 0x00000c08
+ 0x00000100 0x00000003 0x00000006 0x00000002 0x000003e8 0x00000006 0x00000002 0x000003e9
+ 0x00000006 0x00000002 0x000003ea 0x00000006 0x00000002 0x000003eb 0x00000006 0x00000002
+ 0x000003ec 0x00000006 0x00000002 0x000003ed 0x00000006 0x00000002 0x000003ee 0x00000006
+ 0x00000002 0x000003ef 0x00000006 0x00000002 0x000003f0 0x00000006 0x00000002 0x000003f1
+ 0x00000006 0x00000002 0x000003f2 0x00000006 0x00000002 0x000003f3 0x00000006 0x00000002
+ 0x000003f4 0x00000006 0x00000002 0x000003f5 0x00000006 0x00000002 0x000003f6 0x00000006
+ 0x00000002 0x000003f7 0x00000006 0x00000002 0x000003f8 0x00000006 0x00000002 0x000003f9
+ 0x00000006 0x00000002 0x000003fa 0x00000006 0x00000002 0x000003fb 0x00000006 0x00000002
+ 0x000003fc 0x00000006 0x00000002 0x000003fd 0x00000006 0x00000002 0x000003fe 0x00000006
+ 0x00000002 0x000003ff 0x00000006 0x00000002 0x00000400 0x00000006 0x00000002 0x00000401
+ 0x00000006 0x00000002 0x00000402 0x00000006 0x00000002 0x00000403 0x00000006 0x00000002
+ 0x00000404 0x00000006 0x00000002 0x00000405 0x00000006 0x00000002 0x00000406 0x00000006
+ 0x00000002 0x00000407 0x00000006 0x00000002 0x00000408 0x00000006 0x00000002 0x00000409
+ 0x00000006 0x00000002 0x0000040a 0x00000006 0x00000002 0x0000040b 0x00000006 0x00000002
+ 0x0000040c 0x00000006 0x00000002 0x0000040d 0x00000006 0x00000002 0x0000040e 0x00000006
+ 0x00000002 0x0000040f 0x00000006 0x00000002 0x00000410 0x00000006 0x00000002 0x00000411
+ 0x00000006 0x00000002 0x00000412 0x00000006 0x00000002 0x00000413 0x00000006 0x00000002
+ 0x00000414 0x00000006 0x00000002 0x00000415 0x00000006 0x00000002 0x00000416 0x00000006
+ 0x00000002 0x00000417 0x00000006 0x00000002 0x00000418 0x00000006 0x00000002 0x00000419
+ 0x00000006 0x00000002 0x0000041a 0x00000006 0x00000002 0x0000041b 0x00000006 0x00000002
+ 0x0000041c 0x00000006 0x00000002 0x0000041d 0x00000006 0x00000002 0x0000041e 0x00000006
+ 0x00000002 0x0000041f 0x00000006 0x00000002 0x00000420 0x00000006 0x00000002 0x00000421
+ 0x00000006 0x00000002 0x00000422 0x00000006 0x00000002 0x00000423 0x00000006 0x00000002
+ 0x00000424 0x00000006 0x00000002 0x00000425 0x00000006 0x00000002 0x00000426 0x00000006
+ 0x00000002 0x00000427 0x00000006 0x00000002 0x00000428 0x00000006 0x00000002 0x00000429
+ 0x00000006 0x00000002 0x0000042a 0x00000006 0x00000002 0x0000042b 0x00000006 0x00000002
+ 0x0000042c 0x00000006 0x00000002 0x0000042d 0x00000006 0x00000002 0x0000042e 0x00000006
+ 0x00000002 0x0000042f 0x00000006 0x00000002 0x00000430 0x00000006 0x00000002 0x00000431
+ 0x00000006 0x00000002 0x00000432 0x00000006 0x00000002 0x00000433 0x00000006 0x00000002
+ 0x00000434 0x00000006 0x00000002 0x00000435 0x00000006 0x00000002 0x00000436 0x00000006
+ 0x00000002 0x00000437 0x00000006 0x00000002 0x00000438 0x00000006 0x00000002 0x00000439
+ 0x00000006 0x00000002 0x0000043a 0x00000006 0x00000002 0x0000043b 0x00000006 0x00000002
+ 0x0000043c 0x00000006 0x00000002 0x0000043d 0x00000006 0x00000002 0x0000043e 0x00000006
+ 0x00000002 0x0000043f 0x00000006 0x00000002 0x00000440 0x00000006 0x00000002 0x00000441
+ 0x00000006 0x00000002 0x00000442 0x00000006 0x00000002 0x00000443 0x00000006 0x00000002
+ 0x00000444 0x00000006 0x00000002 0x00000445 0x00000006 0x00000002 0x00000446 0x00000006
+ 0x00000002 0x00000447 0x00000006 0x00000002 0x00000448 0x00000006 0x00000002 0x00000449
+ 0x00000006 0x00000002 0x0000044a 0x00000006 0x00000002 0x0000044b 0x00000006 0x00000002
+ 0x0000044c 0x00000006 0x00000002 0x0000044d 0x00000006 0x00000002 0x0000044e 0x00000006
+ 0x00000002 0x0000044f 0x00000006 0x00000002 0x00000450 0x00000006 0x00000002 0x00000451
+ 0x00000006 0x00000002 0x00000452 0x00000006 0x00000002 0x00000453 0x00000006 0x00000002
+ 0x00000454 0x00000006 0x00000002 0x00000455 0x00000006 0x00000002 0x00000456 0x00000006
+ 0x00000002 0x00000457 0x00000006 0x00000002 0x00000458 0x00000006 0x00000002 0x00000459
+ 0x00000006 0x00000002 0x0000045a 0x00000006 0x00000002 0x0000045b 0x00000006 0x00000002
+ 0x0000045c 0x00000006 0x00000002 0x0000045d 0x00000006 0x00000002 0x0000045e 0x00000006
+ 0x00000002 0x0000045f 0x00000006 0x00000002 0x00000460 0x00000006 0x00000002 0x00000461
+ 0x00000006 0x00000002 0x00000462 0x00000006 0x00000002 0x00000463 0x00000006 0x00000002
+ 0x00000464 0x00000006 0x00000002 0x00000465 0x00000006 0x00000002 0x00000466 0x00000006
+ 0x00000002 0x00000467 0x00000006 0x00000002 0x00000468 0x00000006 0x00000002 0x00000469
+ 0x00000006 0x00000002 0x0000046a 0x00000006 0x00000002 0x0000046b 0x00000006 0x00000002
+ 0x0000046c 0x00000006 0x00000002 0x0000046d 0x00000006 0x00000002 0x0000046e 0x00000006
+ 0x00000002 0x0000046f 0x00000006 0x00000002 0x00000470 0x00000006 0x00000002 0x00000471
+ 0x00000006 0x00000002 0x00000472 0x00000006 0x00000002 0x00000473 0x00000006 0x00000002
+ 0x00000474 0x00000006 0x00000002 0x00000475 0x00000006 0x00000002 0x00000476 0x00000006
+ 0x00000002 0x00000477 0x00000006 0x00000002 0x00000478 0x00000006 0x00000002 0x00000479
+ 0x00000006 0x00000002 0x0000047a 0x00000006 0x00000002 0x0000047b 0x00000006 0x00000002
+ 0x0000047c 0x00000006 0x00000002 0x0000047d 0x00000006 0x00000002 0x0000047e 0x00000006
+ 0x00000002 0x0000047f 0x00000006 0x00000002 0x00000480 0x00000006 0x00000002 0x00000481
+ 0x00000006 0x00000002 0x00000482 0x00000006 0x00000002 0x00000483 0x00000006 0x00000002
+ 0x00000484 0x00000006 0x00000002 0x00000485 0x00000006 0x00000002 0x00000486 0x00000006
+ 0x00000002 0x00000487 0x00000006 0x00000002 0x00000488 0x00000006 0x00000002 0x00000489
+ 0x00000006 0x00000002 0x0000048a 0x00000006 0x00000002 0x0000048b 0x00000006 0x00000002
+ 0x0000048c 0x00000006 0x00000002 0x0000048d 0x00000006 0x00000002 0x0000048e 0x00000006
+ 0x00000002 0x0000048f 0x00000006 0x00000002 0x00000490 0x00000006 0x00000002 0x00000491
+ 0x00000006 0x00000002 0x00000492 0x00000006 0x00000002 0x00000493 0x00000006 0x00000002
+ 0x00000494 0x00000006 0x00000002 0x00000495 0x00000006 0x00000002 0x00000496 0x00000006
+ 0x00000002 0x00000497 0x00000006 0x00000002 0x00000498 0x00000006 0x00000002 0x00000499
+ 0x00000006 0x00000002 0x0000049a 0x00000006 0x00000002 0x0000049b 0x00000006 0x00000002
+ 0x0000049c 0x00000006 0x00000002 0x0000049d 0x00000006 0x00000002 0x0000049e 0x00000006
+ 0x00000002 0x0000049f 0x00000006 0x00000002 0x000004a0 0x00000006 0x00000002 0x000004a1
+ 0x00000006 0x00000002 0x000004a2 0x00000006 0x00000002 0x000004a3 0x00000006 0x00000002
+ 0x000004a4 0x00000006 0x00000002 0x000004a5 0x00000006 0x00000002 0x000004a6 0x00000006
+ 0x00000002 0x000004a7 0x00000006 0x00000002 0x000004a8 0x00000006 0x00000002 0x000004a9
+ 0x00000006 0x00000002 0x000004aa 0x00000006 0x00000002 0x000004ab 0x00000006 0x00000002
+ 0x000004ac 0x00000006 0x00000002 0x000004ad 0x00000006 0x00000002 0x000004ae 0x00000006
+ 0x00000002 0x000004af 0x00000006 0x00000002 0x000004b0 0x00000006 0x00000002 0x000004b1
+ 0x00000006 0x00000002 0x000004b2 0x00000006 0x00000002 0x000004b3 0x00000006 0x00000002
+ 0x000004b4 0x00000006 0x00000002 0x000004b5 0x00000006 0x00000002 0x000004b6 0x00000006
+ 0x00000002 0x000004b7 0x00000006 0x00000002 0x000004b8 0x00000006 0x00000002 0x000004b9
+ 0x00000006 0x00000002 0x000004ba 0x00000006 0x00000002 0x000004bb 0x00000006 0x00000002
+ 0x000004bc 0x00000006 0x00000002 0x000004bd 0x00000006 0x00000002 0x000004be 0x00000006
+ 0x00000002 0x000004bf 0x00000006 0x00000002 0x000004c0 0x00000006 0x00000002 0x000004c1
+ 0x00000006 0x00000002 0x000004c2 0x00000006 0x00000002 0x000004c3 0x00000006 0x00000002
+ 0x000004c4 0x00000006 0x00000002 0x000004c5 0x00000006 0x00000002 0x000004c6 0x00000006
+ 0x00000002 0x000004c7 0x00000006 0x00000002 0x000004c8 0x00000006 0x00000002 0x000004c9
+ 0x00000006 0x00000002 0x000004ca 0x00000006 0x00000002 0x000004cb 0x00000006 0x00000002
+ 0x000004cc 0x00000006 0x00000002 0x000004cd 0x00000006 0x00000002 0x000004ce 0x00000006
+ 0x00000002 0x000004cf 0x00000006 0x00000002 0x000004d0 0x00000006 0x00000002 0x000004d1
+ 0x00000006 0x00000002 0x000004d2 0x00000006 0x00000002 0x000004d3 0x00000006 0x00000002
+ 0x000004d4 0x00000006 0x00000002 0x000004d5 0x00000006 0x00000002 0x000004d6 0x00000006
+ 0x00000002 0x000004d7 0x00000006 0x00000002 0x000004d8 0x00000006 0x00000002 0x000004d9
+ 0x00000006 0x00000002 0x000004da 0x00000006 0x00000002 0x000004db 0x00000006 0x00000002
+ 0x000004dc 0x00000006 0x00000002 0x000004dd 0x00000006 0x00000002 0x000004de 0x00000006
+ 0x00000002 0x000004df 0x00000006 0x00000002 0x000004e0 0x00000006 0x00000002 0x000004e1
+ 0x00000006 0x00000002 0x000004e2 0x00000006 0x00000002 0x000004e3 0x00000006 0x00000002
+ 0x000004e4 0x00000006 0x00000002 0x000004e5 0x00000006 0x00000002 0x000004e6 0x00000006
+ 0x00000002 0x000004e7
+
+ HelperDllName = REG_EXPAND_SZ %SystemRoot%\system32\wshisn.dll
+ MinSockaddrLength = REG_DWORD 0x0000000e
+ MaxSockaddrLength = REG_DWORD 0x00000010
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkIpx
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isnp/ipx/nwlnkipx.rc b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
new file mode 100644
index 000000000..0f437a15d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/nwlnkipx.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnkipx.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnkipx.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/ipx/packet.c b/private/ntos/tdi/isnp/ipx/packet.c
new file mode 100644
index 000000000..f70154b03
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/packet.c
@@ -0,0 +1,1560 @@
+/*++
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+NTSTATUS
+IpxInitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisMacBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MAC_HEADER_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisIpxBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MAC_HEADER_SIZE,
+ IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ IpxFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisMacBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisIpxBuffer);
+
+ //
+ // This flag optimizes the virtual to physical address X-ln
+ // in the MAC drivers on x86
+ //
+ NdisMacBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+ NdisIpxBuffer->MdlFlags|=MDL_NETWORK_HEADER;
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisMacBuffer;
+ Reserved->PaddingBuffer = NULL;
+#if BACK_FILL
+ Reserved->BackFill = FALSE;
+#endif
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeSendPacket */
+
+#if BACK_FILL
+NTSTATUS
+IpxInitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet,
+ IN PUCHAR Header
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisMacBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet\n"));
+ IpxAllocateSendPacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->SendInProgress = FALSE;
+ Reserved->Header = NULL;
+ Reserved->HeaderBuffer = NULL;
+ Reserved->PaddingBuffer = NULL;
+ Reserved->BackFill = TRUE;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalBackFillPacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ IPX_DEBUG (PACKET, ("Initializing backfill packet Done\n"));
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeBackFillPacket */
+#endif
+
+
+NTSTATUS
+IpxInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PIPX_RECEIVE_RESERVED Reserved;
+
+ IpxAllocateReceivePacket (Device, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ Reserved->TransferInProgress = FALSE;
+ Reserved->SingleRequest = NULL;
+ Reserved->ReceiveBuffer = NULL;
+ InitializeListHead (&Reserved->Requests);
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceivePacket */
+
+
+NTSTATUS
+IpxInitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+ PDEVICE Device = Adapter->Device;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ ExInterlockedInsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage,
+ &Device->Lock);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializeReceiveBuffer */
+
+
+NTSTATUS
+IpxInitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a padding buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ PaddingBuffer - The receive buffer to initialize.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ PaddingBuffer->Data,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NDIS_BUFFER_LINKAGE(NdisBuffer) = (PNDIS_BUFFER)NULL;
+ PaddingBuffer->NdisBuffer = NdisBuffer;
+ PaddingBuffer->DataLength = DataBufferLength;
+ RtlZeroMemory (PaddingBuffer->Data, DataBufferLength);
+
+ return STATUS_SUCCESS;
+
+} /* IpxInitializePaddingBuffer */
+
+
+VOID
+IpxDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ //
+ // Free the packet in a slightly unconventional way; this
+ // allows us to not have to NULL out HeaderBuffer's linkage
+ // field during normal operations when we put it back in
+ // the free pool.
+ //
+
+ NdisBuffer = Reserved->HeaderBuffer;
+ NdisIpxBuffer = NDIS_BUFFER_LINKAGE(NdisBuffer);
+ NDIS_BUFFER_LINKAGE (NdisBuffer) = NULL;
+ NDIS_BUFFER_LINKAGE (NdisIpxBuffer) = NULL;
+
+#if 0
+ NdisAdjustBufferLength (NdisBuffer, PACKET_HEADER_SIZE);
+#endif
+ NdisAdjustBufferLength (NdisBuffer, MAC_HEADER_SIZE);
+ NdisAdjustBufferLength (NdisIpxBuffer, IPX_HEADER_SIZE + RIP_PACKET_SIZE);
+
+ NdisFreeBuffer (NdisBuffer);
+ NdisFreeBuffer (NdisIpxBuffer);
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+
+} /* IpxDeinitializeSendPacket */
+
+#if BACK_FILL
+VOID
+IpxDeinitializeBackFillPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a back fill packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisIpxBuffer;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet\n"));
+
+ Reserved = SEND_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+
+
+ NdisReinitializePacket (PACKET(Packet));
+ IpxFreeSendPacket (Device, Packet);
+ IPX_DEBUG (PACKET, ("DeInitializing backfill packet Done\n"));
+
+
+} /* IpxDeinitializeBackFillPacket */
+#endif
+
+
+VOID
+IpxDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PIPX_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ IpxFreeReceivePacket (Device, Packet);
+
+} /* IpxDeinitializeReceivePacket */
+
+
+VOID
+IpxDeinitializeReceiveBuffer(
+ IN PADAPTER Adapter,
+ IN PIPX_RECEIVE_BUFFER ReceiveBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+ DataBufferLength - The allocated length of the receive buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = Adapter->Device;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+ NdisAdjustBufferLength (ReceiveBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* IpxDeinitializeReceiveBuffer */
+
+
+VOID
+IpxDeinitializePaddingBuffer(
+ IN PDEVICE Device,
+ IN PIPX_PADDING_BUFFER PaddingBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a padding buffer.
+
+Arguments:
+
+ Device - The device.
+
+ PaddingBuffer - The padding buffer.
+
+ DataBufferLength - The allocated length of the padding buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NdisAdjustBufferLength (PaddingBuffer->NdisBuffer, DataBufferLength);
+ NdisFreeBuffer (PaddingBuffer->NdisBuffer);
+
+} /* IpxDeinitializePaddingBuffer */
+
+
+
+#ifdef IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+
+ SendPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams) +
+ (PACKET_HEADER_SIZE * Device->InitDatagrams);
+
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitDatagrams]);
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (IpxInitializeSendPacket (Device, Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedDatagrams += SendPool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateSendPool */
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PIPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ CTELockHandle LockHandle;
+
+ PIPX_SEND_POOL BackFillPool;
+ UINT BackFillPoolSize;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+
+ BackFillPoolSize = FIELD_OFFSET (IPX_SEND_POOL, Packets[0]) +
+ (sizeof(IPX_SEND_PACKET) * Device->InitDatagrams);
+
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (BackFillPoolSize, MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate BackFill pool memory\n"));
+ return;
+ }
+
+
+
+
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+
+ if (IpxInitializeBackFillPacket (Device, Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+
+ }
+
+ BackFillPool->PacketCount = PacketNum;
+ BackFillPool->PacketFree = PacketNum;
+
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < BackFillPool->PacketCount; PacketNum++) {
+
+ Packet = &BackFillPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+
+ IPX_DEBUG (PACKET, ("Allocation of backfill pool done\n"));
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PIPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ ReceivePoolSize = FIELD_OFFSET (IPX_RECEIVE_POOL, Packets[0]) +
+ (sizeof(IPX_RECEIVE_PACKET) * Device->InitReceivePackets);
+
+ ReceivePool = (PIPX_RECEIVE_POOL)IpxAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (IpxInitializeReceivePacket (Device, Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceivePool */
+
+
+#else // IPX_OWN_PACKETS
+VOID
+IpxAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_POOL SendPool;
+ UINT HeaderSize;
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ NDIS_STATUS Status;
+
+ CTELockHandle LockHandle;
+
+ SendPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "SendPool");
+
+ if (SendPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ HeaderSize = PACKET_HEADER_SIZE * Device->InitDatagrams;
+
+ Header = (PUCHAR)IpxAllocateMemory (HeaderSize, MEMORY_PACKET, "SendPool");
+
+ if (Header == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate header memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &SendPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ IPX_DEBUG (PACKET, ("Initializing send pool %lx, %d packets\n",
+ SendPool, Device->InitDatagrams));
+
+ SendPool->Header = Header;
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), SendPool->PoolHandle);
+
+ if (IpxInitializeSendPacket (Device, &Packet, Header) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ Header += PACKET_HEADER_SIZE;
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedDatagrams += PacketNum;
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateSendPool */
+
+
+#if BACK_FILL
+
+VOID
+IpxAllocateBackFillPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT PacketNum;
+ IPX_SEND_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ PIPX_SEND_POOL BackFillPool;
+ NDIS_STATUS Status;
+
+ IPX_DEBUG (PACKET, ("Allocating backfill pool\n"));
+
+ // Allocate pool for back fillable packets
+
+ BackFillPool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_SEND_POOL), MEMORY_PACKET, "BafiPool");
+
+ if (BackFillPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate backfill pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &BackFillPool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate Ndis pool memory\n"));
+ return;
+ }
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitDatagrams * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_SEND_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitDatagrams; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), BackFillPool->PoolHandle);
+
+ if (IpxInitializeBackFillPacket (Device, &Packet, NULL) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = BackFillPool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->BackFillPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ InsertTailList (&Device->BackFillPoolList, &BackFillPool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateBackFillPool */
+
+#endif
+
+
+VOID
+IpxAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive packets to the pool for this device.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_POOL ReceivePool;
+ UINT PacketNum;
+ IPX_RECEIVE_PACKET Packet;
+ PIPX_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ NDIS_STATUS Status;
+
+ ReceivePool = (PIPX_SEND_POOL)IpxAllocateMemory (sizeof(IPX_RECEIVE_POOL), MEMORY_PACKET, "ReceivePool");
+
+ if (ReceivePool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ NdisAllocatePacketPool(&Status, &ReceivePool->PoolHandle, Device->InitDatagrams, sizeof(IPX_SEND_RESERVED));
+
+ if (Status == NDIS_STATUS_RESOURCES) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitReceivePackets));
+
+ Device->MemoryUsage += (FIELD_OFFSET(NDIS_PACKET_POOL,Buffer[0]) +
+ Device->InitReceivePackets * (FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0]) + sizeof(IPX_RECEIVE_RESERVED)));
+
+ for (PacketNum = 0; PacketNum < Device->InitReceivePackets; PacketNum++) {
+
+ NdisAllocatePacket(&Status, &PACKET(&Packet), ReceivePool->PoolHandle);
+
+ if (IpxInitializeReceivePacket (Device, &Packet) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(&Packet);
+ Reserved->Address = NULL;
+ Reserved->OwnedByAddress = FALSE;
+#ifdef IPX_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ IPX_PUSH_ENTRY_LIST (&Device->ReceivePacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ Device->AllocatedReceivePackets += PacketNum;
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+} /* IpxAllocateReceivePool */
+#endif // IPX_OWN_PACKETS
+
+VOID
+IpxAllocateReceiveBufferPool(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this adapter.
+
+Arguments:
+
+ Adapter - The adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PIPX_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PDEVICE Device = Adapter->Device;
+ UINT DataLength;
+ PUCHAR Data;
+ CTELockHandle LockHandle;
+
+ DataLength = Adapter->MaxReceivePacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (IPX_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(IPX_RECEIVE_BUFFER) * Device->InitReceiveBuffers) +
+ (DataLength * Device->InitReceiveBuffers);
+
+ ReceiveBufferPool = (PIPX_RECEIVE_BUFFER_POOL)IpxAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ IPX_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ IPX_DEBUG (PACKET, ("Init recv buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitReceiveBuffers, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitReceiveBuffers]);
+
+
+ for (BufferNum = 0; BufferNum < Device->InitReceiveBuffers; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (IpxInitializeReceiveBuffer (Adapter, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ IPX_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef IPX_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ CTEGetLock (&Device->Lock, &LockHandle);
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ IPX_PUSH_ENTRY_LIST (&Adapter->ReceiveBufferList, &ReceiveBuffer->PoolLinkage, &Device->SListsLock);
+
+ }
+
+ InsertTailList (&Adapter->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Adapter->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+ CTEFreeLock (&Device->Lock, LockHandle);
+
+} /* IpxAllocateReceiveBufferPool */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopSendPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateSendPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopSendPacket */
+
+#if BACK_FILL
+
+PSINGLE_LIST_ENTRY
+IpxPopBackFillPacket(
+ PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet\n"));
+
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedDatagrams < Device->MaxDatagrams) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateBackFillPool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+
+ IPX_DEBUG (PACKET, ("Popping backfill packet done\n"));
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopBackFillPacket */
+#endif //BackFill
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxReceivePackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceivePool (Device);
+ s = IPX_POP_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+IpxPopReceiveBuffer(
+ IN PADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the adapter's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Adapter - Pointer to our adapter to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PDEVICE Device = Adapter->Device;
+
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Adapter->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ IpxAllocateReceiveBufferPool (Adapter);
+ s = IPX_POP_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Device->SListsLock);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* IpxPopReceiveBuffer */
+
+
+PIPX_PADDING_BUFFER
+IpxAllocatePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a padding buffer for use by all devices.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the allocated padding buffer.
+
+--*/
+
+{
+ PIPX_PADDING_BUFFER PaddingBuffer;
+ ULONG PaddingBufferSize;
+
+ //
+ // We are assuming that we can use 1 global padding buffer for ALL
+ // transmits! We must therefore test to make sure that EthernetExtraPadding
+ // is not greater than 1. Otherwise, we must assume that the extra padding
+ // is being used for something and we therefore cannot share across all
+ // transmit requests.
+ //
+
+ //
+ // We cannot support more than 1 byte padding space, since we allocate only
+ // one buffer for all transmit requests.
+ //
+
+ if ( Device->EthernetExtraPadding > 1 ) {
+ IPX_DEBUG (PACKET, ("Padding buffer cannot be more than 1 byte\n"));
+ DbgBreakPoint();
+ }
+
+ //
+ // Allocate a padding buffer if possible.
+ //
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+
+ PaddingBuffer = IpxAllocateMemory (PaddingBufferSize, MEMORY_PACKET, "PaddingBuffer");
+
+ if (PaddingBuffer != NULL) {
+
+ if (IpxInitializePaddingBuffer (Device, PaddingBuffer, Device->EthernetExtraPadding) !=
+ STATUS_SUCCESS) {
+ IpxFreeMemory (PaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer");
+ } else {
+ IPX_DEBUG (PACKET, ("Allocate padding buffer %lx\n", PaddingBuffer));
+ return PaddingBuffer;
+ }
+ }
+
+ return NULL;
+
+} /* IpxAllocatePaddingBuffer */
+
+
+VOID
+IpxFreePaddingBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates the padding buffer.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG PaddingBufferSize;
+
+ if ( IpxPaddingBuffer == (PIPX_PADDING_BUFFER)NULL ) {
+ return;
+ }
+
+ PaddingBufferSize = FIELD_OFFSET (IPX_PADDING_BUFFER, Data[0]) + Device->EthernetExtraPadding;
+ IpxFreeMemory( IpxPaddingBuffer, PaddingBufferSize, MEMORY_PACKET, "Padding Buffer" );
+ IpxPaddingBuffer = (PIPX_PADDING_BUFFER)NULL;
+
+} /* IpxFreePaddingBuffer */
+
diff --git a/private/ntos/tdi/isnp/ipx/precomp.h b/private/ntos/tdi/isnp/ipx/precomp.h
new file mode 100644
index 000000000..818629e5e
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/precomp.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnipx.h"
+#include "config.h"
+#include "mac.h"
+#include "ipxtypes.h"
+#include "ipxprocs.h"
+#include <wsnwlink.h>
diff --git a/private/ntos/tdi/isnp/ipx/query.c b/private/ntos/tdi/isnp/ipx/query.c
new file mode 100644
index 000000000..28b38df5c
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/query.c
@@ -0,0 +1,297 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Useful macro to obtain the total length of an MDL chain.
+//
+
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+
+
+
+NTSTATUS
+IpxTdiQueryInformation(
+ 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;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION query;
+ PADDRESS_FILE AddressFile;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PBINDING Binding;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_IPX_ADDRESS IpxAddress;
+ } AddressInfo;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ TDI_ADDRESS_IPX IpxAddress;
+ } TempBuffer;
+ UINT i;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // what type of status do we want?
+ //
+
+ query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ status = IpxVerifyAddressFile (AddressFile);
+
+ if (status == STATUS_SUCCESS) {
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ IpxBuildTdiAddress(
+ &TempBuffer.AddressInfo.IpxAddress,
+ Device->SourceAddress.NetworkAddress,
+ Device->SourceAddress.NodeAddress,
+ AddressFile->Address->Socket);
+
+ status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(TempBuffer.AddressInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ status = TdiCopyBufferToMdl (
+ &(Device->Information),
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+ TransportAddress = IpxAllocateMemory(sizeof(int) + (ElementSize * MIN (Device->MaxBindings, Device->ValidBindings)), MEMORY_QUERY, "NetworkAddress");
+
+ if (TransportAddress == NULL) {
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->ValidBindings);
+
+ for (i = 1; i <= Index; i++) {
+
+ Binding = NIC_ID_TO_BINDING(Device, i);
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+ }
+
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ for (i = 1; i <= Device->ValidBindings; i++) {
+
+ Binding = Device->Bindings[i];
+ if ((Binding == NULL) ||
+ (!Binding->LineUp)) {
+ continue;
+ }
+
+ if (query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = Binding->Adapter->MacInfo.RealMediumType;
+ RtlCopyMemory (CurAddress->Address, Binding->LocalAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &Binding->LocalAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+#endif
+ status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ CTEFreeMem (TransportAddress);
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return status;
+
+} /* IpxTdiQueryInformation */
+
+
+NTSTATUS
+IpxTdiSetInformation(
+ 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;
+
+} /* IpxTdiSetInformation */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/receive.c b/private/ntos/tdi/isnp/ipx/receive.c
new file mode 100644
index 000000000..ff9c68fbd
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/receive.c
@@ -0,0 +1,466 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiReceiveDatagram
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+IpxTransferDataComplete(
+ IN NDIS_HANDLE BindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine receives control from the physical provider as an
+ indication that an NdisTransferData has completed. We use this indication
+ to complete any pended requests to our clients.
+
+Arguments:
+
+ BindingContext - The Adapter Binding specified at initialization time.
+
+ NdisPacket/RequestHandle - An identifier for the request that completed.
+
+ NdisStatus - The completion status for the request.
+
+ BytesTransferred - Number of bytes actually transferred.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADAPTER Adapter = (PADAPTER)BindingContext;
+ PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
+ PREQUEST Request, LastRequest;
+ PADDRESS_FILE AddressFile;
+ ULONG ByteOffset;
+ PLIST_ENTRY p;
+ PDEVICE Device;
+
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+ if (Reserved->SingleRequest) {
+
+ //
+ // The transfer was directly into the client buffer,
+ // so simply complete the request.
+ //
+
+ Request = Reserved->SingleRequest;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
+ REQUEST_INFORMATION(Request) = BytesTransferred;
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ LastRequest = Request;
+ Reserved->SingleRequest = NULL;
+
+ } else {
+
+ //
+ // Multiple clients requested this datagram. Save
+ // the last one to delay queueing it for completion.
+ //
+
+ LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&Reserved->Requests);
+ if (p == &Reserved->Requests) {
+ break;
+ }
+
+ Request = LIST_ENTRY_TO_REQUEST(p);
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+
+ if (AddressFile->ReceiveIpxHeader) {
+ ByteOffset = 0;
+ } else {
+ ByteOffset = sizeof(IPX_HEADER);
+ }
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl(
+ Reserved->ReceiveBuffer->Data,
+ ByteOffset + REQUEST_INFORMATION(Request),
+ ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
+
+ }
+
+ if (Request != LastRequest) {
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(Request),
+ Adapter->DeviceLock);
+
+ }
+
+ }
+
+ //
+ // Now free the receive buffer back.
+ //
+
+ IPX_PUSH_ENTRY_LIST(
+ &Adapter->ReceiveBufferList,
+ &Reserved->ReceiveBuffer->PoolLinkage,
+ &Adapter->Device->SListsLock);
+
+ Reserved->ReceiveBuffer = NULL;
+
+ }
+
+
+ //
+ // Now free the packet.
+ //
+
+ NdisReinitializePacket (NdisPacket);
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->ReceivePacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
+
+ } else {
+
+ Device = Adapter->Device;
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ //
+ // We Delay inserting the last request (or the only one)
+ // until after we have put the packet back, to keep the
+ // address around if needed (the address won't go away
+ // until the last address file does, and the address file
+ // won't go away until the datagram is completed).
+ //
+
+ IPX_INSERT_TAIL_LIST(
+ &Adapter->RequestCompletionQueue,
+ REQUEST_LINKAGE(LastRequest),
+ Adapter->DeviceLock);
+
+ IpxReceiveComplete ((NDIS_HANDLE)Adapter);
+
+ break;
+
+ default:
+
+ Device = Adapter->Device;
+
+ (*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
+ NdisPacket,
+ NdisStatus,
+ BytesTransferred);
+
+ break;
+
+ }
+
+} /* IpxTransferDataComplete */
+
+
+VOID
+IpxTransferData(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by all tightly bound clients instead of NdisTransferData.
+ If this is a loopback packet, the transfer is done directly here, else NdisTransferData
+ is called.
+
+Arguments:
+
+ Status - status of operation
+ NdisBindingHandle - Loopback cookie or Ndis context
+ MacReceiveContext - Loopback packet or Mac context
+ ByteOffset - Source offset
+ BytesToTransfer - length of the transfer desired
+ Packet - dest packet
+ BytesTransferred - length of successful transfer
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ //
+ // If this is a loopback packet, copy the data directly
+ //
+ if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
+
+ IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
+ MacReceiveContext, Packet, BytesToTransfer));
+
+ NdisCopyFromPacketToPacket(
+ Packet, // Destination
+ 0, // DestinationOffset
+ BytesToTransfer, // BytesToCopy
+ (PNDIS_PACKET)MacReceiveContext, // Source
+ ByteOffset, // SourceOffset
+ BytesTransferred); // BytesCopied
+
+ *Status = NDIS_STATUS_SUCCESS;
+ } else {
+ NdisTransferData(
+ Status,
+ NdisBindingHandle,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+ }
+}
+
+
+
+NTSTATUS
+IpxTdiReceiveDatagram(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Irp - I/O Request Packet for this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ Address = AddressFile->Address;
+
+ if ((Address == NULL) ||
+ (Address->Size != sizeof (ADDRESS)) ||
+ (Address->Type != IPX_ADDRESS_SIGNATURE)) {
+
+ return STATUS_INVALID_HANDLE;
+ }
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
+
+ if (Request->Cancel) {
+
+ (VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IPX_END_SYNC (&SyncContext);
+ return STATUS_CANCELLED;
+ }
+
+ IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+} /* IpxTdiReceiveDatagram */
+
+
+VOID
+IpxCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ IpxCompleteRequest (Request);
+ ASSERT( DeviceObject->DeviceExtension == IpxDevice );
+ IpxFreeRequest(IpxDevice, Request);
+
+ IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* IpxCancelReceiveDatagram */
+
+
diff --git a/private/ntos/tdi/isnp/ipx/rip.c b/private/ntos/tdi/isnp/ipx/rip.c
new file mode 100644
index 000000000..d30770223
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/rip.c
@@ -0,0 +1,2655 @@
+/*++
+
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ rip.c
+
+Abstract:
+
+ This module contains code that implements the client-side
+ RIP support and simple router table support.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+
+NTSTATUS
+RipGetLocalTarget(
+ IN ULONG Segment,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN UCHAR Type,
+ OUT PIPX_LOCAL_TARGET LocalTarget,
+ OUT USHORT Counts[2] OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up the proper route for the specified remote
+ address. If a RIP request needs to be generated it does so.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD.
+ NOTE: IN THE CASE OF PnP, THIS COMES WITH THE BIND LOCK SHARED.
+
+Arguments:
+
+ Segment - The segment associate with the remote address.
+
+ RemoteAddress - The IPX address of the remote.
+
+ Type - One of IPX_FIND_ROUTE_NO_RIP, IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ or IPX_FIND_ROUTE_FORCE_RIP.
+
+ LocalTarget - Returns the next router information.
+
+ Counts - If specified, used to return the tick and hop count.
+
+Return Value:
+
+ STATUS_SUCCESS if a route is found, STATUS_PENDING if a
+ RIP request needs to be generated, failure status if a
+ RIP request packet cannot be allocated.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PBINDING Binding;
+ UINT i;
+
+
+ //
+ // Packets sent to network 0 go on the first adapter also.
+ //
+
+ if (RemoteAddress->NetworkAddress == 0) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 1);
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + NIC_ID_TO_BINDING(Device, 1)->MediumSpeed) /
+ NIC_ID_TO_BINDING(Device, 1)->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#else
+ LocalTarget->NicId = 1;
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = (USHORT)((839 + Device->Bindings[1]->MediumSpeed) /
+ Device->Bindings[1]->MediumSpeed); // tick count
+ Counts[1] = 1; // hop count
+ }
+#endif
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // See if this is a packet sent to our virtual network.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ //
+ // Send it through adapter 1.
+ // BUGBUG: Do real loopback.
+ //
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+ RtlCopyMemory (LocalTarget->MacAddress, NIC_ID_TO_BINDING(Device, 1)->LocalMacAddress.Address, 6);
+#else
+ //
+ // Loopback this packet
+ //
+ LocalTarget->NicId = 0;
+ RtlCopyMemory (LocalTarget->MacAddress, Device->Bindings[1]->LocalMacAddress.Address, 6);
+#endif
+
+ IPX_DEBUG (LOOPB, ("Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = 1; // tick count
+ Counts[1] = 1; // hop count
+ }
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Look up the route in the table. If the net is one
+ // of the ones we are directly attached to, this will
+ // return an entry with the correct flag set.
+ //
+
+ RouteEntry = RipGetRoute(Segment, (PUCHAR)&(RemoteAddress->NetworkAddress));
+
+ if (RouteEntry != NULL) {
+
+ RouteEntry->Timer = 0;
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, RouteEntry->NicId);
+#else
+ LocalTarget->NicId = RouteEntry->NicId;
+#endif
+ if (RouteEntry->Flags & IPX_ROUTER_LOCAL_NET) {
+
+ //
+ // The machine is on the same net, so send it directly.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RemoteAddress->NodeAddress, 6);
+
+ if (RouteEntry->Flags & IPX_ROUTER_GLOBAL_WAN_NET) {
+
+ //
+ // The NicId here is bogus, we have to scan through
+ // our bindings until we find one whose indicated
+ // IPX remote node matches the destination node of
+ // this frame. We don't scan into the duplicate
+ // binding set members since they won't be WANs.
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != (PBINDING)NULL) &&
+ (Binding->Adapter->MacInfo.MediumAsync) &&
+ (RtlEqualMemory(
+ Binding->WanRemoteNode,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ break;
+
+ }
+ }
+ }
+
+ if (i > (UINT)MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ } else {
+ //
+ // Find out if this is a loopback packet. If so, return NicId 0
+ //
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ //
+ // Self-directed - loopback
+ //
+ if ((Binding != (PBINDING)NULL) &&
+ (RtlEqualMemory(
+ Binding->LocalAddress.NodeAddress,
+ RemoteAddress->NodeAddress,
+ 6))) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, 0);
+#else
+ LocalTarget->NicId = 0;
+#endif
+
+ IPX_DEBUG (LOOPB, ("2.Loopback Nic returned for net: %lx\n", RemoteAddress->NetworkAddress));
+ break;
+
+ }
+ }
+ }
+ }
+
+ } else {
+
+ CTEAssert ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0);
+
+ //
+ // This is not a locally attached net, so if the caller
+ // is forcing a re-RIP then do that.
+ //
+
+ if (Type == IPX_FIND_ROUTE_FORCE_RIP) {
+ goto QueueUpRequest;
+ }
+
+ //
+ // Fill in the address of the next router in the route.
+ //
+
+ RtlCopyMemory (LocalTarget->MacAddress, RouteEntry->NextRouter, 6);
+
+ }
+
+ if (ARGUMENT_PRESENT(Counts)) {
+ Counts[0] = RouteEntry->TickCount;
+ Counts[1] = RouteEntry->HopCount;
+ }
+
+ return STATUS_SUCCESS;
+
+ }
+
+QueueUpRequest:
+
+ if (Type == IPX_FIND_ROUTE_NO_RIP) {
+
+ //
+ // Bug #17273 return proper error message
+ //
+
+ // return STATUS_DEVICE_DOES_NOT_EXIST;
+ return STATUS_NETWORK_UNREACHABLE;
+
+ } else {
+
+ return RipQueueRequest (RemoteAddress->NetworkAddress, RIP_REQUEST);
+
+ }
+
+} /* RipGetLocalTarget */
+
+
+NTSTATUS
+RipQueueRequest(
+ IN ULONG Network,
+ IN USHORT Operation
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queues up a request for a RIP route. It can be
+ used to find a specific route or to discover the locally
+ attached network (if Network is 0). It can also be used
+ to do a periodic announcement of the virtual net, which
+ we do once a minute if the router is not bound.
+
+ NOTE: THIS REQUEST IS CALLED WITH THE SEGMENT LOCK HELD
+ IF IT IS A REQUEST AND THE NETWORK IS NOT 0xffffffff.
+
+Arguments:
+
+ Network - The network to discover.
+
+ Operation - One of RIP_REQUEST, RIP_RESPONSE, or RIP_DOWN.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ PLIST_ENTRY p;
+ PRIP_PACKET RipPacket;
+ TDI_ADDRESS_IPX RemoteAddress;
+ TDI_ADDRESS_IPX LocalAddress;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PNDIS_BUFFER pNdisIpxBuff;
+
+
+ //
+ // Make sure we only queue a request for net 0xffffffff if we
+ // are auto-detecting, because we assume that in other places.
+ //
+
+ if ((Network == 0xffffffff) &&
+ (Device->AutoDetectState != AUTO_DETECT_STATE_RUNNING)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ //
+ // Try to get a packet to use for the RIP request. We
+ // allocate this now, but check if it succeeded later,
+ // to make the locking work better (we need to keep
+ // the lock between when we check for an existing
+ // request on this network and when we queue this
+ // request).
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ //
+ // There was no router table entry for this network, first see
+ // if there is already a pending request for this route.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Operation == RIP_REQUEST) {
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Skip responses.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (Reserved->u.SR_RIP.Network == Network &&
+ !Reserved->u.SR_RIP.RouteFound) {
+
+ //
+ // There is already one pending, put back the packet if
+ // we got one (we hold the lock already).
+ //
+
+ if (s != NULL) {
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, s, &Device->SListsLock);
+ }
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+ }
+ }
+
+ }
+
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_INTERNAL;
+ Reserved->SendInProgress = FALSE;
+ Reserved->DestinationType = DESTINATION_BCAST;
+ Reserved->u.SR_RIP.CurrentNicId = 0;
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ switch (Operation) {
+ case RIP_REQUEST: Reserved->u.SR_RIP.RetryCount = 0; break;
+ case RIP_RESPONSE: Reserved->u.SR_RIP.RetryCount = 0xfe; break;
+ case RIP_DOWN: Reserved->u.SR_RIP.RetryCount = 0xff; break;
+ }
+ Reserved->u.SR_RIP.RouteFound = FALSE;
+ Reserved->u.SR_RIP.Network = Network;
+ Reserved->u.SR_RIP.SendTime = Device->RipSendTime;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // Fill in the IPX header at the standard offset (for sending
+ // to actual bindings it will be moved around if needed). We
+ // have to construct the local and remote addresses so they
+ // are in the format that IpxConstructHeader expects.
+ //
+
+ RemoteAddress.NetworkAddress = Network;
+ RtlCopyMemory (RemoteAddress.NodeAddress, BroadcastAddress, 6);
+ RemoteAddress.Socket = RIP_SOCKET;
+
+ RtlCopyMemory (&LocalAddress, &Device->SourceAddress, FIELD_OFFSET(TDI_ADDRESS_IPX,Socket));
+ LocalAddress.Socket = RIP_SOCKET;
+
+ IpxConstructHeader(
+// &Reserved->Header[Device->IncludedHeaderOffset],
+ &Reserved->Header[MAC_HEADER_SIZE],
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ &RemoteAddress,
+ &LocalAddress);
+
+ //
+ // Fill in the RIP request also.
+ //
+
+#if 0
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[Device->IncludedHeaderOffset + sizeof(IPX_HEADER)]);
+#endif
+ RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+ RipPacket->Operation = Operation & 0x7fff;
+ RipPacket->NetworkEntry.NetworkNumber = Network;
+
+ if (Operation == RIP_REQUEST) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(0xffff);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(0xffff);
+ } else if (Operation == RIP_RESPONSE) {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(2); // will be modified when sent
+ } else {
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(16);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(16);
+ }
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now insert this packet in the queue of pending RIP
+ // requests and start the timer if needed (this is done
+ // to ensure the RIP_GRANULARITY milliseconds inter-RIP-packet
+ // delay).
+ //
+
+ IPX_DEBUG (RIP, ("RIP %s for network %lx\n",
+ (Operation == RIP_REQUEST) ? "request" : ((Operation == RIP_RESPONSE) ? "announce" : "down"),
+ REORDER_ULONG(Network)));
+
+ InsertHeadList(
+ &Device->WaitingRipPackets,
+ &Reserved->WaitLinkage);
+
+ ++Device->RipPacketCount;
+
+ if (!Device->RipShortTimerActive) {
+
+ Device->RipShortTimerActive = TRUE;
+ IpxReferenceDevice (Device, DREF_RIP_TIMER);
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ 1, // 1 ms, i.e. expire immediately
+ RipShortTimeout,
+ (PVOID)Device);
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_PENDING;
+
+} /* RipQueueRequest */
+
+
+VOID
+RipSendResponse(
+ IN PBINDING Binding,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a respond to a RIP request from a client --
+ this is only used if we have a virtual network and the router
+ is not bound, and somebody queries on the virtual network.
+
+Arguments:
+
+ Binding - The binding on which the request was received.
+
+ RemoteAddress - The IPX source address of the request.
+
+ LocalTarget - The local target of the received packet.
+
+Return Value:
+
+ STATUS_PENDING if the request is queued, failure status
+ if it could not be.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PIPX_SEND_RESERVED Reserved;
+ TDI_ADDRESS_IPX LocalAddress;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ PRIP_PACKET RipPacket;
+ PDEVICE Device = IpxDevice;
+ PBINDING MasterBinding;
+ NDIS_STATUS NdisStatus;
+ USHORT TickCount;
+ PNDIS_BUFFER pNdisIpxBuff;
+
+ //
+ // Get a packet to use for the RIP response.
+ //
+
+ s = IpxPopSendPacket (Device);
+
+ if (s == NULL) {
+ return;
+ }
+
+ IpxReferenceDevice (Device, DREF_RIP_PACKET);
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ Reserved->Identifier = IDENTIFIER_RIP_RESPONSE;
+ Reserved->DestinationType = DESTINATION_DEF;
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ //
+ // We aren't guaranteed that this is the case for packets
+ // on the free list.
+ //
+
+ pNdisIpxBuff = NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer);
+ NDIS_BUFFER_LINKAGE (pNdisIpxBuff) = NULL;
+
+ //
+ // If this binding is a binding set member, round-robin through
+ // the various bindings when responding. We will get some natural
+ // round-robinning because broadcast requests are received on
+ // binding set members in turn, but they are only rotated once
+ // a second.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // It's a binding set member, we round-robin the
+ // responses across all the cards to distribute
+ // the traffic.
+ //
+
+ MasterBinding = Binding->MasterBinding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+
+ //
+ // Fill in the IPX header at the correct offset.
+ //
+
+ LocalAddress.NetworkAddress = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (LocalAddress.NodeAddress, Binding->LocalAddress.NodeAddress, 6);
+ LocalAddress.Socket = RIP_SOCKET;
+#if 0
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[Binding->DefHeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ sizeof(IPX_HEADER) + sizeof (RIP_PACKET),
+ RIP_PACKET_TYPE,
+ RemoteAddress,
+ &LocalAddress);
+
+ //
+ // In case the request comes from net 0, fill that in too.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+
+
+ //
+ // Fill in the RIP request.
+ //
+
+ RipPacket = (PRIP_PACKET)(IpxHeader+1);
+
+ RipPacket->Operation = RIP_RESPONSE;
+ RipPacket->NetworkEntry.NetworkNumber = Device->VirtualNetworkNumber;
+
+ RipPacket->NetworkEntry.HopCount = REORDER_USHORT(1);
+ TickCount = (USHORT)(((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ IPX_DEBUG (RIP, ("RIP response for virtual network %lx\n",
+ REORDER_ULONG(Device->VirtualNetworkNumber)));
+
+ NdisAdjustBufferLength(pNdisIpxBuff, sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+#ifdef _PNP_POWER
+ if (Binding->BindingSetMember) {
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ }
+#endif
+ return;
+
+} /* RipSendResponse */
+
+
+VOID
+RipShortTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP short timer expires.
+ It is called every RIP_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p;
+ PIPX_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ USHORT OldNicId, NewNicId;
+ ULONG OldOffset, NewOffset;
+ PIPX_HEADER IpxHeader;
+ PBINDING Binding, MasterBinding;
+ NDIS_STATUS NdisStatus;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+#ifdef _PNP_LATER
+ static IPX_LOCAL_TARGET BroadcastTarget = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, {0, 0, 0} };
+#else
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif
+
+ static ULONG ZeroNetwork = 0;
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->RipSendTime;
+
+ if (Device->RipPacketCount == 0) {
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+
+ while (TRUE) {
+
+ p = Device->WaitingRipPackets.Flink;
+ if (p == &Device->WaitingRipPackets) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if ((Reserved->u.SR_RIP.RouteFound) && (!Reserved->SendInProgress)) {
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+ }
+
+ if ((((SHORT)(Device->RipSendTime - Reserved->u.SR_RIP.SendTime)) < 0) ||
+ Reserved->SendInProgress) {
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingRipPackets);
+
+ //
+ // Find the right binding to send to. If NoIdAdvance
+ // is set, then the binding doesn't need to be changed
+ // this time (this means we wrapped last time).
+ //
+
+ OldNicId = Reserved->u.SR_RIP.CurrentNicId;
+
+ if (!Reserved->u.SR_RIP.NoIdAdvance) {
+
+ BOOLEAN FoundNext = FALSE;
+
+#ifdef _PNP_POWER
+//
+// To maintain the lock order, release Device lock here and re-acquire later
+//
+ USHORT StartId;
+
+ if (Device->ValidBindings == 0) {
+ IPX_DEBUG(PNP, ("ValidBindings 0 in RipShortTimeOut\n"));
+
+ Device->RipShortTimerActive = FALSE;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceDevice (Device, DREF_RIP_TIMER);
+ return;
+ }
+
+ StartId = (USHORT)((OldNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+
+ NewNicId = StartId;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#else
+
+ USHORT StartId = (USHORT)((OldNicId % Device->BindingCount) + 1);
+
+ NewNicId = StartId;
+#endif
+ do {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+ if (Reserved->u.SR_RIP.Network != 0xffffffff) {
+
+ //
+ // We are looking for a real net; check that
+ // the next binding is valid. If it is a WAN
+ // binding, we don't send queries if the router
+ // is bound. If it is a LAN binding, we don't
+ // send queries if we are configured for
+ // SingleNetworkActive and the WAN is up.
+ // We also don't send queries on binding set
+ // members which aren't masters.
+ //
+
+ if ((Binding != NULL)
+ &&
+ ((!Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->UpperDriverBound[IDENTIFIER_RIP]))
+ &&
+ ((Binding->Adapter->MacInfo.MediumAsync) ||
+ (!Device->SingleNetworkActive) ||
+ (!Device->ActiveNetworkWan))
+ &&
+ ((!Binding->BindingSetMember) ||
+ (Binding->CurrentSendBinding))) {
+
+ FoundNext = TRUE;
+ break;
+ }
+
+ } else {
+
+ //
+ // We are sending out the initial request to net
+ // 0xffffffff, to generate traffic so we can figure
+ // out our real network number. We don't do this
+ // to nets that already have a number and we don't
+ // do it on WAN links. We also don't do it on
+ // auto-detect nets if we have found the default.
+ //
+
+
+ if ((Binding != NULL) &&
+ (Binding->TentativeNetworkAddress == 0) &&
+ (!Binding->Adapter->MacInfo.MediumAsync) &&
+ (!Binding->AutoDetect || !Binding->Adapter->DefaultAutoDetected)) {
+ FoundNext = TRUE;
+ break;
+ }
+ }
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ] Why cycle thru the entire list?
+ //
+ NewNicId = (USHORT)((NewNicId % MIN (Device->MaxBindings, Device->ValidBindings)) + 1);
+#else
+ NewNicId = (USHORT)((NewNicId % Device->BindingCount) + 1);
+#endif
+ } while (NewNicId != StartId);
+
+ if (!FoundNext) {
+
+ //
+ // Nothing more needs to be done with this packet,
+ // leave it off the queue and since we didn't send
+ // a packet we can check for more.
+ //
+#ifndef _PNP_POWER
+ //
+ // This was released above (before the BindAccessLock was taken
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ RipCleanupPacket(Device, Reserved);
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ continue;
+
+ }
+
+#ifdef _PNP_POWER
+
+ IPX_DEBUG(RIP, ("RIP: FoundNext: %lx, StartId: %lx, OldNicId: %lx, NewNicId: %lx\n", FoundNext, StartId, OldNicId, NewNicId));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Re-acquire the Device lock
+ //
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+
+ Reserved->u.SR_RIP.CurrentNicId = NewNicId;
+
+ //
+ // Move the data around if needed.
+ //
+
+#if 0
+ if (OldNicId != NewNicId) {
+
+ if (OldNicId == 0) {
+ OldOffset = Device->IncludedHeaderOffset;
+ } else {
+ OldOffset = Device->Bindings[OldNicId]->BcMcHeaderSize;
+ }
+
+ NewOffset = Binding->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER) + sizeof(RIP_PACKET));
+
+ }
+
+ }
+#endif
+
+ if (NewNicId <= OldNicId) {
+
+ //
+ // We found a new binding but we wrapped, so increment
+ // the counter. If we have done all the resends, or
+ // this is a response (indicated by retry count of 0xff;
+ // they are only sent once) then clean up.
+ //
+
+ if ((Reserved->u.SR_RIP.RetryCount >= 0xfe) ||
+ ((++Reserved->u.SR_RIP.RetryCount) == Device->RipCount)) {
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ RipCleanupPacket(Device, Reserved);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &Reserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ //
+ // We wrapped, so put ourselves back in the queue
+ // at the end.
+ //
+
+ Reserved->u.SR_RIP.SendTime = (USHORT)(Device->RipSendTime + Device->RipTimeout - 1);
+ Reserved->u.SR_RIP.NoIdAdvance = TRUE;
+ InsertTailList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+#ifdef _PNP_POWER
+ //
+ // Free the Device lock before deref'ing the Binding so we maintain
+ // the lock order: BindingAccess > GlobalInterLock > Device
+ //
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+#endif
+ }
+
+ continue;
+
+ }
+#ifdef _PNP_POWER
+//
+// To prevent the re-acquire of the device lock, this is moved up...
+//
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ } else {
+
+ //
+ // Next time we need to advance the binding.
+ //
+
+ Reserved->u.SR_RIP.NoIdAdvance = FALSE;
+ NewNicId = OldNicId;
+#ifdef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NewNicId);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ Binding = Device->Bindings[NewNicId];
+#endif
+
+ }
+#ifndef _PNP_POWER
+ //
+ // Send it again as soon as possible (it we just wrapped, then
+ // we will have put ourselves at the tail and won't get here).
+ //
+
+ InsertHeadList (&Device->WaitingRipPackets, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_RIP_INTERNAL);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+#endif
+ //
+ // This packet should be sent on binding NewNicId; first
+ // move the data to the right location for the current
+ // binding.
+ //
+#ifdef _PNP_POWER
+ CTEAssert (Binding == NIC_ID_TO_BINDING(Device, NewNicId)); // temp, just to make sure
+#else
+ CTEAssert (Binding == Device->Bindings[NewNicId]); // temp, just to make sure
+#endif
+// NewOffset = Binding->BcMcHeaderSize;
+
+ //
+ // Now submit the packet to NDIS.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&BroadcastTarget, NewNicId);
+#else
+ BroadcastTarget.NicId = NewNicId;
+#endif
+
+ //
+ // Modify the header so the packet comes from this
+ // specific adapter, not the virtual network.
+ //
+
+ // IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+ if (Reserved->u.SR_RIP.Network == 0xffffffff) {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = 0;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ }
+
+ if (Reserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ //
+ // This is an outgoing query. We round-robin these through
+ // binding sets.
+ //
+
+ if (Binding->BindingSetMember) {
+
+ //
+ // Shouldn't have any binding sets during initial
+ // discovery.
+ //
+
+ CTEAssert (Reserved->u.SR_RIP.Network != 0xffffffff);
+
+ //
+ // If we are in a binding set, then use the current binding
+ // in the set for this send, and advance the current binding.
+ // The places we have used Binding before here will be fine
+ // since the binding set members all have the same media
+ // and frame type.
+ //
+
+ CTEAssert (Binding->CurrentSendBinding); // should be a master.
+ MasterBinding = Binding;
+ Binding = MasterBinding->CurrentSendBinding;
+ MasterBinding->CurrentSendBinding = Binding->NextBinding;
+#ifdef _PNP_POWER
+ //
+ // [BUGBUGZZ]: We dont have a lock here - the masterbinding could be bogus
+ //
+ IpxDereferenceBinding1(MasterBinding, BREF_DEVICE_ACCESS);
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ }
+ }
+
+
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+
+ //
+ // Bug# 6485
+ // Rip request, general or specific, is putting the network of the
+ // node to which the route has to be found in the ipx header remote
+ // network field. Some novell routers don't like that. This network
+ // field should be 0.
+ //
+ {
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(&Reserved->Header[MAC_HEADER_SIZE + sizeof(IPX_HEADER)]);
+
+ if (RipPacket->Operation != RIP_REQUEST) {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = Binding->LocalAddress.NetworkAddress;
+ } else {
+ *(UNALIGNED ULONG *)IpxHeader->DestinationNetwork = 0;
+ }
+ }
+
+ //
+ // If this is a RIP_RESPONSE, set the tick count for this
+ // binding.
+ //
+
+ if (Reserved->u.SR_RIP.RetryCount == 0xfe) {
+
+ PRIP_PACKET RipPacket = (PRIP_PACKET)(IpxHeader+1);
+ USHORT TickCount = (USHORT)
+ (((839 + Binding->MediumSpeed) / Binding->MediumSpeed) + 1);
+
+ RipPacket->NetworkEntry.TickCount = REORDER_USHORT(TickCount);
+
+ }
+
+ if ((NdisStatus = IpxSendFrame(
+ &BroadcastTarget,
+ Packet,
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER),
+ sizeof(RIP_PACKET) + sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+
+ break;
+
+ }
+
+ CTEStartTimer(
+ &Device->RipShortTimer,
+ RIP_GRANULARITY,
+ RipShortTimeout,
+ (PVOID)Device);
+
+} /* RipShortTimeout */
+
+
+VOID
+RipLongTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the RIP long timer expires.
+ It is called every minute and handles periodic re-RIPping
+ to ensure that entries are accurate, as well as aging out
+ of entries if the rip router is not bound.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ UINT i;
+ PBINDING Binding;
+ IPX_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ //
+ // Rotate the broadcast receiver on all binding sets.
+ // We can loop up to HighestExternal only since we
+ // are only interested in finding binding set masters.
+ //
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+#endif
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (i = 1; i <= Index; i++) {
+
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, i);
+#else
+ Binding = Device->Bindings[i];
+#endif
+ if ((Binding != NULL) &&
+ (Binding->CurrentSendBinding)) {
+
+ //
+ // It is a master, so find the current broadcast
+ // receiver, then advance it.
+ //
+
+ while (TRUE) {
+ if (Binding->ReceiveBroadcast) {
+ Binding->ReceiveBroadcast = FALSE;
+ Binding->NextBinding->ReceiveBroadcast = TRUE;
+ break;
+ } else {
+ Binding = Binding->NextBinding;
+ }
+ }
+ }
+ }
+ }
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+
+ //
+ // If RIP is bound, we don't do any of this, and
+ // we stop the timer from running.
+ //
+
+ if (Device->UpperDriverBound[IDENTIFIER_RIP]) {
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+ return;
+ }
+
+
+ //
+ // If we have a virtual net, do our periodic broadcast.
+ //
+
+ if (Device->RipResponder) {
+ (VOID)RipQueueRequest (Device->VirtualNetworkNumber, RIP_RESPONSE);
+ }
+
+
+ //
+ // Update the real counters from the temp ones.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Device->TempDatagramBytesSent);
+ Device->Statistics.DatagramsSent += Device->TempDatagramsSent;
+
+ Device->TempDatagramBytesSent = 0;
+ Device->TempDatagramsSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ Device->TempDatagramBytesReceived);
+ Device->Statistics.DatagramsReceived += Device->TempDatagramsReceived;
+
+ Device->TempDatagramBytesReceived = 0;
+ Device->TempDatagramsReceived = 0;
+
+
+ //
+ // We need to scan each hash bucket to see if there
+ // are any active entries which need to be re-RIPped
+ // for. We also scan for entries that should be timed
+ // out.
+ //
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ //
+ // Don't take the lock if the bucket is empty.
+ //
+
+ if (RouterSegment->Entries.Flink == &RouterSegment->Entries) {
+ continue;
+ }
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry looking for ones to age.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) {
+ continue;
+ }
+
+ ++RouteEntry->Timer;
+ if (RouteEntry->Timer >= Device->RipUsageTime) {
+
+ RipDeleteRoute (Segment, RouteEntry);
+ IpxFreeMemory(RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ continue;
+
+ }
+
+ //
+ // See if we should re-RIP for this segment. It has
+ // to have been around for RipAgeTime, and we also
+ // make sure that the Timer is not too high to
+ // prevent us from re-RIPping on unused routes.
+ //
+
+ ++RouteEntry->PRIVATE.Reserved[0];
+
+ if ((RouteEntry->PRIVATE.Reserved[0] >= Device->RipAgeTime) &&
+ (RouteEntry->Timer <= Device->RipAgeTime)) {
+
+ //
+ // If we successfully queue a request, then reset
+ // Reserved[0] so we don't re-RIP for a while.
+ //
+
+ if (RipQueueRequest (*(UNALIGNED ULONG *)RouteEntry->Network, RIP_REQUEST) == STATUS_PENDING) {
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ }
+ }
+ }
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+
+ //
+ // Now restart the timer for the next timeout.
+ //
+
+ if (Device->State == DEVICE_STATE_OPEN) {
+
+ CTEStartTimer(
+ &Device->RipLongTimer,
+ 60000, // one minute timeout
+ RipLongTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ //
+ // Send a DOWN packet if needed, then stop ourselves.
+ //
+
+ if (Device->RipResponder) {
+
+ if (RipQueueRequest (Device->VirtualNetworkNumber, RIP_DOWN) != STATUS_PENDING) {
+
+ //
+ // We need to kick this event because the packet completion
+ // won't.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+ }
+
+ IpxDereferenceDevice (Device, DREF_LONG_TIMER);
+
+ }
+
+} /* RipLongTimeout */
+
+
+VOID
+RipCleanupPacket(
+ IN PDEVICE Device,
+ IN PIPX_SEND_RESERVED RipReserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up when a RIP packet times out.
+
+Arguments:
+
+ Device - The device.
+
+ RipReserved - The ProtocolReserved section of the RIP packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ if (RipReserved->u.SR_RIP.RetryCount < 0xfe) {
+
+ if (RipReserved->u.SR_RIP.Network != 0xffffffff) {
+
+ IPX_DEBUG (RIP, ("Timing out RIP for network %lx\n",
+ REORDER_ULONG(RipReserved->u.SR_RIP.Network)));
+
+ Segment = RipGetSegment ((PUCHAR)&RipReserved->u.SR_RIP.Network);
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipReserved->u.SR_RIP.Network),
+ LockHandle,
+ FALSE,
+ NULL,
+ 0,
+ 0);
+
+ } else {
+
+ //
+ // This was the initial query looking for networks --
+ // signal the init thread which is waiting.
+ //
+
+ IPX_DEBUG (AUTO_DETECT, ("Signalling auto-detect event\n"));
+ KeSetEvent(
+ &Device->AutoDetectEvent,
+ 0L,
+ FALSE);
+
+ }
+
+ } else if (RipReserved->u.SR_RIP.RetryCount == 0xff) {
+
+ //
+ // This is a DOWN message, set the device event that
+ // is waiting for it to complete.
+ //
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+ }
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ RipReserved->Identifier = IDENTIFIER_IPX;
+
+} /* RipCleanupPacket */
+
+
+VOID
+RipProcessResponse(
+ IN PDEVICE Device,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN RIP_PACKET UNALIGNED * RipPacket
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes a RIP response from the specified
+ local target, indicating a route to the network in the RIP
+ header.
+
+Arguments:
+
+ Device - The device.
+
+ LocalTarget - The router that the frame was received from.
+
+ RipPacket - The RIP response header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPX_SEND_RESERVED RipReserved; // ProtocolReserved of RIP packet
+ ULONG Segment;
+ PIPX_ROUTE_ENTRY RouteEntry, OldRouteEntry;
+ PLIST_ENTRY p;
+ IPX_DEFINE_LOCK_HANDLE_PARAM (LockHandle)
+
+ //
+ // Since we have received a RIP response for this network.
+ // kill the waiting RIP packets for it if it exists.
+ //
+
+ IPX_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingRipPackets.Flink;
+ p != &Device->WaitingRipPackets;
+ p = p->Flink) {
+
+ RipReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+
+ if (RipReserved->u.SR_RIP.RetryCount >= 0xfe) {
+ continue;
+ }
+
+ if (RipReserved->u.SR_RIP.Network ==
+ RipPacket->NetworkEntry.NetworkNumber) {
+ break;
+ }
+
+ }
+
+ if (p == &Device->WaitingRipPackets) {
+
+ //
+ // No packets pending on this, return.
+ //
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Put the RIP packet back in the pool.
+ //
+
+ IPX_DEBUG (RIP, ("Got RIP response for network %lx\n",
+ REORDER_ULONG(RipPacket->NetworkEntry.NetworkNumber)));
+
+ RipReserved->u.SR_RIP.RouteFound = TRUE;
+ if (!RipReserved->SendInProgress) {
+
+ //
+ // If the send is done destroy it now, otherwise
+ // when it pops up in RipShortTimeout it will get
+ // destroyed because RouteFound is TRUE.
+ //
+
+ RemoveEntryList (p);
+ RipReserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST (&Device->SendPacketList, &RipReserved->PoolLinkage, &Device->SListsLock);
+ --Device->RipPacketCount;
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+
+ //
+ // Try to allocate and add a router segment unless the
+ // RIP router is active...if we don't that is fine, we'll
+ // just re-RIP later.
+ //
+
+ Segment = RipGetSegment ((PUCHAR)&RipPacket->NetworkEntry.NetworkNumber);
+
+ if (!Device->UpperDriverBound[IDENTIFIER_RIP]) {
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry != (PIPX_ROUTE_ENTRY)NULL) {
+
+ *(UNALIGNED LONG *)RouteEntry->Network = RipPacket->NetworkEntry.NetworkNumber;
+#ifdef _PNP_POWER
+ RouteEntry->NicId = NIC_FROM_LOCAL_TARGET(LocalTarget);
+ RouteEntry->NdisBindingContext = NIC_ID_TO_BINDING(Device, RouteEntry->NicId)->Adapter->NdisBindingHandle;
+ // BUGBUG: What if this is NULL??
+#else
+ RouteEntry->NicId = LocalTarget->NicId;
+ RouteEntry->NdisBindingContext = Device->Bindings[LocalTarget->NicId]->Adapter->NdisBindingHandle; // BUGBUG: What if this is NULL??
+#endif
+ RouteEntry->Flags = 0;
+ RouteEntry->Timer = 0;
+ RouteEntry->PRIVATE.Reserved[0] = 0;
+ RouteEntry->Segment = Segment;
+ RouteEntry->HopCount = REORDER_USHORT(RipPacket->NetworkEntry.HopCount);
+ RouteEntry->TickCount = REORDER_USHORT(RipPacket->NetworkEntry.TickCount);
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+ RtlCopyMemory (RouteEntry->NextRouter, LocalTarget->MacAddress, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Replace any existing routes. This is OK because once
+ // we get the first response to a RIP packet on a given
+ // route, we will take the packet out of the queue and
+ // ignore further responses. We will only get a bad route
+ // if we do two requests really quickly and there
+ // are two routes, and the second response to the first
+ // request is picked up as the first response to the second
+ // request.
+ //
+
+ if ((OldRouteEntry = RipGetRoute (Segment, (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber))) != NULL) {
+
+ //
+ // These are saved so timeouts etc. happen right.
+ //
+
+ RouteEntry->Flags = OldRouteEntry->Flags;
+ RouteEntry->Timer = OldRouteEntry->Timer;
+
+ RipDeleteRoute (Segment, OldRouteEntry);
+ IpxFreeMemory(OldRouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+
+ }
+
+ RipAddRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ } else {
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+ }
+
+ //
+ // Complete all datagrams etc. that were waiting
+ // for this route. This call releases the lock.
+ //
+
+ RipHandleRoutePending(
+ Device,
+ (PUCHAR)&(RipPacket->NetworkEntry.NetworkNumber),
+ LockHandle,
+ TRUE,
+ LocalTarget,
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.HopCount)),
+ (USHORT)(REORDER_USHORT(RipPacket->NetworkEntry.TickCount))
+ );
+
+} /* RipProcessResponse */
+
+VOID
+RipHandleRoutePending(
+ IN PDEVICE Device,
+ IN UCHAR Network[4],
+ IN CTELockHandle LockHandle,
+ IN BOOLEAN Success,
+ IN OPTIONAL PIPX_LOCAL_TARGET LocalTarget,
+ IN OPTIONAL USHORT HopCount,
+ IN OPTIONAL USHORT TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams, find route
+ requests, and GET_LOCAL_TARGET ioctls that were
+ waiting for a route to be found.
+
+ THIS ROUTINE IS CALLED WITH THE SEGMENT LOCK HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ Network - The network in question.
+
+ LockHandle - The handle used to acquire the lock.
+
+ Success - TRUE if the route was successfully found.
+
+ LocalTarget - If Success is TRUE, the local target for the route.
+
+ HopCount - If Success is TRUE, the hop count for the route,
+ in machine order.
+
+ TickCount - If Success is TRUE, the tick count for the route,
+ in machine order.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY FindRouteList;
+ LIST_ENTRY GetLocalTargetList;
+ LIST_ENTRY ReripNetnumList;
+ PIPX_SEND_RESERVED WaitReserved; // ProtocolReserved of waiting packet
+ PIPX_FIND_ROUTE_REQUEST FindRouteRequest;
+ PREQUEST GetLocalTargetRequest;
+ PREQUEST ReripNetnumRequest;
+ PISN_ACTION_GET_LOCAL_TARGET GetLocalTarget;
+ PIPX_NETNUM_DATA NetnumData;
+ ULONG Segment;
+ PBINDING Binding, SendBinding;
+ PLIST_ENTRY p;
+ PNDIS_PACKET Packet;
+ PIPX_HEADER IpxHeader;
+ ULONG HeaderSize;
+ NDIS_STATUS NdisStatus;
+ ULONG NetworkUlong = *(UNALIGNED ULONG *)Network;
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&FindRouteList);
+ InitializeListHead (&GetLocalTargetList);
+ InitializeListHead (&ReripNetnumList);
+
+
+ //
+ // Put all packets that were waiting for a route to
+ // this network on DatagramList. They will be sent
+ // or failed later in the routine.
+ //
+
+ Segment = RipGetSegment (Network);
+
+ p = Device->Segments[Segment].WaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingForRoute) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+#if 0
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[Device->IncludedHeaderOffset]))->DestinationNetwork) ==
+ NetworkUlong) {
+#endif
+ if (*(UNALIGNED ULONG *)(((PIPX_HEADER)(&WaitReserved->Header[MAC_HEADER_SIZE]))->DestinationNetwork) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&WaitReserved->WaitLinkage);
+ InsertTailList (&DatagramList, &WaitReserved->WaitLinkage);
+ }
+
+ }
+
+ //
+ // Put all find route requests for this network on
+ // FindRouteList. They will be completed later in the
+ // routine.
+ //
+
+ p = Device->Segments[Segment].FindWaitingForRoute.Flink;
+
+ while (p != &Device->Segments[Segment].FindWaitingForRoute) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+ if (*(UNALIGNED ULONG *)(FindRouteRequest->Network) ==
+ NetworkUlong) {
+
+ RemoveEntryList (&FindRouteRequest->Linkage);
+ InsertTailList (&FindRouteList, &FindRouteRequest->Linkage);
+ }
+
+ }
+
+ //
+ // Put all get local target action requests for this
+ // network on GetLocalTargetList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingLocalTarget.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingLocalTarget) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+ if (GetLocalTarget->IpxAddress.NetworkAddress == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(GetLocalTargetRequest));
+ InsertTailList (&GetLocalTargetList, REQUEST_LINKAGE(GetLocalTargetRequest));
+ }
+
+ }
+
+ //
+ // Put all MIPX_RERIPNETNUM action requests for this
+ // network on ReripNetnumList. They will be completed
+ // later in the routine.
+ //
+
+ p = Device->Segments[Segment].WaitingReripNetnum.Flink;
+
+ while (p != &Device->Segments[Segment].WaitingReripNetnum) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+ if (*(UNALIGNED ULONG *)NetnumData->netnum == NetworkUlong) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ReripNetnumRequest));
+ InsertTailList (&ReripNetnumList, REQUEST_LINKAGE(ReripNetnumRequest));
+ }
+
+ }
+
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+
+ //
+ // For sends we will use the master binding of a binding
+ // set, but we'll return the real NicId for people who
+ // want that.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, SendBinding->NicId));
+ } else {
+ SendBinding = Binding;
+ }
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+
+ if (Binding->BindingSetMember) {
+ SendBinding = Binding->MasterBinding;
+ LocalTarget->NicId = SendBinding->NicId;
+ } else {
+ SendBinding = Binding;
+ }
+#endif
+ }
+
+
+ //
+ // Now that the lock is free, process all packets on
+ // DatagramList.
+ //
+ // NOTE: May misorder packets if they come in right now...
+ //
+
+ for (p = DatagramList.Flink; p != &DatagramList ; ) {
+
+ WaitReserved = CONTAINING_RECORD (p, IPX_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+ Packet = CONTAINING_RECORD (WaitReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+#if DBG
+ CTEAssert (!WaitReserved->SendInProgress);
+ WaitReserved->SendInProgress = TRUE;
+#endif
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued packet %lx\n", WaitReserved));
+
+ if (REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) >
+ SendBinding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Queued send %d bytes too large (%d)\n",
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request),
+ SendBinding->RealMaxDatagramSize));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_INVALID_BUFFER_SIZE);
+
+ } else {
+
+#if 0
+ if (WaitReserved->DestinationType == DESTINATION_DEF) {
+ HeaderSize = SendBinding->DefHeaderSize;
+ } else {
+ HeaderSize = SendBinding->BcMcHeaderSize;
+ }
+
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[HeaderSize]);
+#endif
+ IpxHeader = (PIPX_HEADER)
+ (&WaitReserved->Header[MAC_HEADER_SIZE]);
+
+ //
+ // Move the header to the correct location now that
+ // we know the NIC ID to send to.
+ //
+#if 0
+ if (HeaderSize != Device->IncludedHeaderOffset) {
+
+ RtlMoveMemory(
+ IpxHeader,
+ &WaitReserved->Header[Device->IncludedHeaderOffset],
+ sizeof(IPX_HEADER));
+
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // These frames need to look like they come from the
+ // local network, not the virtual one.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = SendBinding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, SendBinding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ LocalTarget,
+ Packet,
+ REQUEST_INFORMATION(WaitReserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)SendBinding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+
+ }
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out packet %lx\n", WaitReserved));
+
+ IpxSendComplete(
+ (NDIS_HANDLE)NULL,
+ Packet,
+ STATUS_BAD_NETWORK_PATH);
+
+ }
+
+ }
+
+
+ //
+ // Since we round-robin outgoing rip packets, we just use the
+ // real NicId here for find route and get local target requests.
+ // We changed LocalTarget->NicId to be the master above.
+ //
+
+ if (Success) {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(LocalTarget, MIN( Device->MaxBindings, Binding->NicId));
+#else
+ LocalTarget->NicId = Binding->NicId;
+#endif
+ }
+
+ for (p = FindRouteList.Flink; p != &FindRouteList ; ) {
+
+ FindRouteRequest = CONTAINING_RECORD (p, IPX_FIND_ROUTE_REQUEST, Linkage);
+ p = p->Flink;
+
+ if (Success) {
+
+ PUSHORT Counts;
+
+ IPX_DEBUG (RIP, ("Found queued find route %lx\n", FindRouteRequest));
+ FindRouteRequest->LocalTarget = *LocalTarget;
+
+ Counts = (PUSHORT)&FindRouteRequest->Reserved2;
+ Counts[0] = TickCount;
+ Counts[1] = HopCount;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out find route %lx\n", FindRouteRequest));
+
+ }
+
+ (*Device->UpperDrivers[FindRouteRequest->Identifier].FindRouteCompleteHandler)(
+ FindRouteRequest,
+ Success);
+
+ }
+
+ for (p = GetLocalTargetList.Flink; p != &GetLocalTargetList ; ) {
+
+ GetLocalTargetRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ GetLocalTarget = (PISN_ACTION_GET_LOCAL_TARGET)REQUEST_INFORMATION(GetLocalTargetRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ GetLocalTarget->LocalTarget = *LocalTarget;
+ REQUEST_INFORMATION(GetLocalTargetRequest) = sizeof(ISN_ACTION_GET_LOCAL_TARGET);
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out LOCAL_TARGET action %lx\n", GetLocalTargetRequest));
+ REQUEST_INFORMATION(GetLocalTargetRequest) = 0;
+ REQUEST_STATUS(GetLocalTargetRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(GetLocalTargetRequest);
+ IpxFreeRequest(Device, GetLocalTargetRequest);
+
+ }
+
+ //
+ // NOTE: LocalTarget->NicId now points to the real binding
+ // not the master, so we use SendBinding->NicId below.
+ //
+
+ for (p = ReripNetnumList.Flink; p != &ReripNetnumList ; ) {
+
+ ReripNetnumRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+ NetnumData = (PIPX_NETNUM_DATA)REQUEST_INFORMATION(ReripNetnumRequest);
+
+ if (Success) {
+
+ IPX_DEBUG (RIP, ("Found queued MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ NetnumData->hopcount = HopCount;
+ NetnumData->netdelay = TickCount;
+ NetnumData->cardnum = (INT)(MIN( Device->MaxBindings, SendBinding->NicId) - 1);
+ RtlMoveMemory (NetnumData->router, LocalTarget->MacAddress, 6);
+
+ REQUEST_INFORMATION(ReripNetnumRequest) =
+ FIELD_OFFSET(NWLINK_ACTION, Data[0]) + sizeof(IPX_NETNUM_DATA);
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_SUCCESS;
+
+ } else {
+
+ IPX_DEBUG (RIP, ("Timing out MIPX_RERIPNETNUM action %lx\n", ReripNetnumRequest));
+ REQUEST_INFORMATION(ReripNetnumRequest) = 0;
+ REQUEST_STATUS(ReripNetnumRequest) = STATUS_BAD_NETWORK_PATH;
+ }
+
+ IpxCompleteRequest(ReripNetnumRequest);
+ IpxFreeRequest(Device, ReripNetnumRequest);
+
+ }
+
+} /* RipHandleRoutePending */
+
+
+NTSTATUS
+RipInsertLocalNetwork(
+ IN ULONG Network,
+ IN USHORT NicId,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN USHORT Count
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a router entry for a local network
+ and inserts it in the table.
+
+Arguments:
+
+ Network - The network.
+
+ NicId - The NIC ID used to route packets
+
+ NdisBindingHandle - The binding handle used for NdisSend
+
+ Count - The tick and hop count for this network (will be
+ 0 for the virtual net and 1 for attached nets)
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY RouteEntry;
+ PDEVICE Device = IpxDevice;
+ ULONG Segment;
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // BUGBUG: We should allocate the memory in the binding/device
+ // structure itself.
+ //
+
+ RouteEntry = IpxAllocateMemory(sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ if (RouteEntry == (PIPX_ROUTE_ENTRY)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Segment = RipGetSegment ((PUCHAR)&Network);
+
+ *(UNALIGNED LONG *)RouteEntry->Network = Network;
+ RouteEntry->NicId = NicId;
+ RouteEntry->NdisBindingContext = NdisBindingContext;
+
+ if (NicId == 0) {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY;
+ } else {
+ RouteEntry->Flags = IPX_ROUTER_PERMANENT_ENTRY | IPX_ROUTER_LOCAL_NET;
+ }
+ RouteEntry->Segment = Segment;
+ RouteEntry->TickCount = Count;
+ RouteEntry->HopCount = 1;
+ InitializeListHead (&RouteEntry->AlternateRoute);
+ InitializeListHead (&RouteEntry->NicLinkage);
+
+ //
+ // RouteEntry->NextRouter is not used for the virtual net or
+ // when LOCAL_NET is set (i.e. every net that we will add here).
+ //
+
+ RtlZeroMemory (RouteEntry->NextRouter, 6);
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Make sure one doesn't exist.
+ //
+
+ if (RipGetRoute(Segment, (PUCHAR)&Network) != NULL) {
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_DUPLICATE_NAME;
+ }
+
+ //
+ // Add this new entry.
+ //
+
+ if (RipAddRoute (Segment, RouteEntry)) {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ return STATUS_SUCCESS;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IpxFreeMemory (RouteEntry, sizeof(IPX_ROUTE_ENTRY), MEMORY_RIP, "RouteEntry");
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+} /* RipInsertLocalNetwork */
+
+
+VOID
+RipAdjustForBindingChange(
+ IN USHORT NicId,
+ IN USHORT NewNicId,
+ IN IPX_BINDING_CHANGE_TYPE ChangeType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an auto-detect binding is
+ deleted or moved, or a WAN line goes down.
+
+ It scans the RIP database for routes equal to this NIC ID
+ and modifies them appropriately. If ChangeType is
+ IpxBindingDeleted it will subract one from any NIC IDs
+ in the database that are higher than NicId. It is assumed
+ that other code is readjusting the Device->Bindings
+ array.
+
+Arguments:
+
+ NicId - The NIC ID of the deleted binding.
+
+ NewNicId - The new NIC ID, for IpxBindingMoved changes.
+
+ ChangeType - Either IpxBindingDeleted, IpxBindingMoved,
+ or IpxBindingDown.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through each entry comparing the NIC ID.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if (RouteEntry->NicId == NicId) {
+
+ if (ChangeType != IpxBindingMoved) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, binding deleted\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ } else {
+
+ IPX_DEBUG (AUTO_DETECT, ("Changing NIC ID for route entry %lx\n", RouteEntry));
+ RouteEntry->NicId = NewNicId;
+
+ }
+#ifdef _PNP_POWER
+ //
+ // If the NicId is 0, we dont adjust the other entries' NicId's - this is to support the removal
+ // of the Virtual Net # which resides at NicId=0.
+ //
+ } else if (NicId && (ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#else
+ } else if ((ChangeType != IpxBindingDown) && (RouteEntry->NicId > NicId)) {
+#endif
+ IPX_DEBUG (AUTO_DETECT, ("Decrementing NIC ID for route entry %lx\n", RouteEntry));
+ --RouteEntry->NicId;
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipAdjustForBindingChange */
+
+
+UINT
+RipGetSegment(
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the correct segment for the specified
+ network.
+
+Arguments:
+
+ Network - The network.
+
+Return Value:
+
+ The segment.
+
+--*/
+
+{
+
+ ULONG Total;
+
+ Total = Network[0] ^ Network[1] ^ Network[2] ^ Network[3];
+ return (Total % IpxDevice->SegmentCount);
+
+} /* RipGetSegment */
+
+
+PIPX_ROUTE_ENTRY
+RipGetRoute(
+ IN UINT Segment,
+ IN UCHAR Network[4]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the router table entry for the given
+ network, which is in the specified segment of the table.
+ THE SEGMENT LOCK MUST BE HELD. The returned data is valid
+ until the segment lock is released or other operations
+ (add/delete) are performed on the segment.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ Network - The network.
+
+Return Value:
+
+ The router table entry, or NULL if none exists for this network.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PROUTER_SEGMENT RouterSegment;
+ PIPX_ROUTE_ENTRY RouteEntry;
+
+ RouterSegment = &IpxDevice->Segments[Segment];
+
+ for (p = RouterSegment->Entries.Flink;
+ p != &RouterSegment->Entries;
+ p = p->Flink) {
+
+ RouteEntry = CONTAINING_RECORD(
+ p,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ if ((*(UNALIGNED LONG *)RouteEntry->Network) ==
+ (*(UNALIGNED LONG *)Network)) {
+ return RouteEntry;
+ }
+ }
+
+ return NULL;
+
+} /* RipGetRoute */
+
+
+BOOLEAN
+RipAddRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is allocated and filled in by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully inserted.
+
+--*/
+
+{
+
+ IPX_DEBUG (RIP, ("Adding route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+ InsertTailList(
+ &IpxDevice->Segments[Segment].Entries,
+ &RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipAddRoute */
+
+
+BOOLEAN
+RipDeleteRoute(
+ IN UINT Segment,
+ IN PIPX_ROUTE_ENTRY RouteEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a router table entry in the
+ table, which must belong in the specified segment.
+ THE SEGMENT LOCK MUST BE HELD. Storage for the entry
+ is freed by the caller.
+
+Arguments:
+
+ Segment - The segment corresponding to the network.
+
+ RouteEntry - The router table entry.
+
+Return Value:
+
+ TRUE if the entry was successfully deleted.
+
+--*/
+
+{
+
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ IPX_DEBUG (RIP, ("Deleting route for network %lx (%d)\n",
+ REORDER_ULONG(*(UNALIGNED ULONG *)RouteEntry->Network), Segment));
+
+ //
+ // If the current enumeration point for this segment is here,
+ // adjust the pointer before deleting the entry. We make it
+ // point to the previous entry so GetNextRoute will work.
+ //
+
+ if (RouterSegment->EnumerateLocation == &RouteEntry->PRIVATE.Linkage) {
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Blink;
+ }
+
+ RemoveEntryList (&RouteEntry->PRIVATE.Linkage);
+
+ return TRUE;
+
+} /* RipDeleteRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetFirstRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the first router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetNextRoute to enumerate all the
+ entries in a segment.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The first router table entry, or NULL if the segment is empty.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY FirstEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->Entries.Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ FirstEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return FirstEntry;
+
+ }
+
+} /* RipGetFirstRoute */
+
+
+PIPX_ROUTE_ENTRY
+RipGetNextRoute(
+ IN UINT Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the next router table entry in the
+ segment. THE SEGMENT LOCK MUST BE HELD. It is used in
+ conjunction with RipGetFirstRoute to enumerate all the
+ entries in a segment.
+
+ It is illegal to call RipGetNextRoute on a segment
+ without first calling RipGetFirstRoute. The segment
+ lock must be held for the duration of the enumeration
+ of a single segment. It is legal to stop enumerating
+ the segment in the middle.
+
+Arguments:
+
+ Segment - The segment being enumerated.
+
+Return Value:
+
+ The next router table entry, or NULL if the end of the
+ segment is reached.
+
+--*/
+
+{
+ PIPX_ROUTE_ENTRY NextEntry;
+ PROUTER_SEGMENT RouterSegment = &IpxDevice->Segments[Segment];
+
+ RouterSegment->EnumerateLocation = RouterSegment->EnumerateLocation->Flink;
+
+ if (RouterSegment->EnumerateLocation == &RouterSegment->Entries) {
+
+ return NULL;
+
+ } else {
+
+ NextEntry = CONTAINING_RECORD(
+ RouterSegment->EnumerateLocation,
+ IPX_ROUTE_ENTRY,
+ PRIVATE.Linkage);
+
+ return NextEntry;
+
+ }
+
+} /* RipGetNextRoute */
+
+
+VOID
+RipDropRemoteEntries(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes all non-local entries from the
+ RIP database. It is called when the WAN line goes up
+ or down and we want to remove all existing entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = IpxDevice;
+ PIPX_ROUTE_ENTRY RouteEntry;
+ UINT Segment;
+ CTELockHandle LockHandle;
+
+ for (Segment = 0; Segment < Device->SegmentCount; Segment++) {
+
+ CTEGetLock (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // Scan through, deleting everything but local entries.
+ //
+
+ for (RouteEntry = RipGetFirstRoute (Segment);
+ RouteEntry != (PIPX_ROUTE_ENTRY)NULL;
+ RouteEntry = RipGetNextRoute (Segment)) {
+
+ if ((RouteEntry->Flags & IPX_ROUTER_PERMANENT_ENTRY) == 0) {
+
+ IPX_DEBUG (AUTO_DETECT, ("Deleting route entry %lx, dropping remote entries\n", RouteEntry));
+ RipDeleteRoute (Segment, RouteEntry);
+
+ }
+ }
+
+ CTEFreeLock (&Device->SegmentLocks[Segment], LockHandle);
+
+ }
+
+} /* RipDropRemoteEntries */
+
diff --git a/private/ntos/tdi/isnp/ipx/send.c b/private/ntos/tdi/isnp/ipx/send.c
new file mode 100644
index 000000000..fd9a62a7d
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/send.c
@@ -0,0 +1,1651 @@
+
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains code that implements the send engine for the
+ IPX transport provider.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Sanjay Anand (SanjayAn) - August-25-1995
+ Bug Fixes - tagged [SA]
+ Sanjay Anand (SanjayAn) - 22-Sept-1995
+ BackFill optimization changes added under #if BACK_FILL
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// BUGBUG Using the macro for performance reasons. Should be taken out
+// when NdisQueryPacket is optimized. In the near future (after PPC release)
+// move this to a header file and use it at other places.
+//
+#define IPX_PACKET_HEAD(Pkt) (Pkt)->Private.Head
+
+#if 0
+#define IpxGetMdlChainLength(Mdl, Length) { \
+ PMDL _Mdl = (Mdl); \
+ *(Length) = 0; \
+ while (_Mdl) { \
+ *(Length) += MmGetMdlByteCount(_Mdl); \
+ _Mdl = _Mdl->Next; \
+ } \
+}
+#endif
+
+VOID
+IpxSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET NdisPacket,
+ IN NDIS_STATUS NdisStatus
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to indicate that a connection-
+ oriented packet has been shipped and is no longer needed by the Physical
+ Provider.
+
+Arguments:
+
+ 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.
+
+--*/
+
+{
+
+ PIPX_SEND_RESERVED Reserved = (PIPX_SEND_RESERVED)(NdisPacket->ProtocolReserved);
+ PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
+ PREQUEST Request;
+ PADDRESS_FILE AddressFile;
+ PDEVICE Device = IpxDevice;
+ PBINDING Binding;
+ USHORT NewId, OldId;
+ ULONG NewOffset, OldOffset;
+ PIPX_HEADER IpxHeader;
+ IPX_LOCAL_TARGET LocalTarget;
+ PIO_STACK_LOCATION irpSp;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+#if DBG
+ if (Adapter != NULL) {
+ ASSERT_ADAPTER(Adapter);
+ }
+#endif
+
+ //
+ // See if this send was padded.
+ //
+
+ if (Reserved->PaddingBuffer) {
+
+ UINT Offset;
+ //
+ // Check if we simply need to re-adjust the buffer length. This will
+ // happen if we incremented the buffer length in MAC.C.
+ //
+
+ if (Reserved->PreviousTail) {
+ CTEAssert (NDIS_BUFFER_LINKAGE(Reserved->PaddingBuffer->NdisBuffer) == NULL);
+ NDIS_BUFFER_LINKAGE (Reserved->PreviousTail) = (PNDIS_BUFFER)NULL;
+ } else {
+ PNDIS_BUFFER LastBuffer = (PNDIS_BUFFER)Reserved->PaddingBuffer;
+ UINT BufferLength;
+
+ NdisQueryBufferOffset( LastBuffer, &Offset, &BufferLength );
+ NdisAdjustBufferLength( LastBuffer, (BufferLength - 1) );
+ }
+
+ Reserved->PaddingBuffer = NULL;
+
+ if (Reserved->Identifier < IDENTIFIER_IPX) {
+ NdisRecalculatePacketCounts (NdisPacket);
+ }
+ }
+
+FunctionStart:;
+
+ switch (Reserved->Identifier) {
+
+ case IDENTIFIER_IPX:
+
+// #if DBG
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+// #endif
+
+ //
+ // Check if this packet should be sent to all
+ // networks.
+ //
+
+ if (Reserved->u.SR_DG.CurrentNicId) {
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->u.SR_DG.Net0SendSucceeded = TRUE;
+ }
+
+ OldId = Reserved->u.SR_DG.CurrentNicId;
+
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if ((Binding = NIC_ID_TO_BINDING(Device, NewId))
+#else
+ for (NewId = OldId+1; NewId <= Device->HighestExternalNicId; NewId++) {
+ if ((Binding = Device->Bindings[NewId])
+#endif _PNP_POWER
+ &&
+ ((!Device->SingleNetworkActive) ||
+ (Device->ActiveNetworkWan == Binding->Adapter->MacInfo.MediumAsync))
+ &&
+ ((!Device->DisableDialoutSap) ||
+ (!Binding->DialOutAsync) ||
+ (!Reserved->u.SR_DG.OutgoingSap))) {
+
+ //
+ // The binding exists, and we either are not configured
+ // for "SingleNetworkActive", or we are and this binding
+ // is the right type (i.e. the active network is wan and
+ // this is a wan binding, or the active network is not
+ // wan and this is not a wan binding), and this is not
+ // an outgoing sap that we are trying to send with
+ // "DisableDialoutSap" set.
+ //
+
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+#ifdef _PNP_POWER
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = NewId;
+ CTEAssert ((Reserved->DestinationType == DESTINATION_BCAST) ||
+ (Reserved->DestinationType == DESTINATION_MCAST));
+
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+#endif
+
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[MAC_HEADER_SIZE]);
+
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&LocalTarget, NewId);
+#else
+ LocalTarget.NicId = NewId;
+#endif
+ RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ if (Device->MultiCardZeroVirtual ||
+ (IpxHeader->DestinationSocket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual net.
+ //
+
+ *(UNALIGNED ULONG *)IpxHeader->SourceNetwork = Binding->LocalAddress.NetworkAddress;
+ RtlCopyMemory (IpxHeader->SourceNode, Binding->LocalAddress.NodeAddress, 6);
+ }
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+
+ if ((NdisStatus = IpxSendFrame(
+ &LocalTarget,
+ NdisPacket,
+ REQUEST_INFORMATION(Reserved->u.SR_DG.Request) + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+ goto FunctionStart;
+ }
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif _PNP_POWER
+
+ return;
+
+ } else {
+#ifdef _PNP_POWER
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif _PNP_POWER
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+
+ if (Reserved->u.SR_DG.Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+
+ }
+
+
+#if 0
+ //
+ // NOTE: We don't NULL out the linkage field of the
+ // HeaderBuffer, which will leave the old buffer chain
+ // hanging off it; but that is OK because if we reuse
+ // this packet we will replace that chain with the new
+ // one, and before we free it we NULL it out.
+ //
+ // I.e. we don't do this:
+ //
+
+ NDIS_BUFFER_LINKAGE (Reserved->HeaderBuffer) = NULL;
+ NdisRecalculatePacketCounts (NdisPacket);
+#endif
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer), &ActualLength);
+ if (ActualLength != REQUEST_INFORMATION(Reserved->u.SR_DG.Request)) {
+ DbgPrint ("IPX: At completion, IRP %lx has parameter length %d, buffer chain length %d\n",
+ Reserved->u.SR_DG.Request, REQUEST_INFORMATION(Reserved->u.SR_DG.Request), ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ //
+ // Save these so we can free the packet.
+ //
+
+ Request = Reserved->u.SR_DG.Request;
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+
+
+#if BACK_FILL
+ // Check if this is backfilled. If so restore users Mdl back to its original shape
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer->MappedSystemVa = Reserved->MappedSystemVa;
+ Reserved->HeaderBuffer->ByteCount = Reserved->UserLength;
+ Reserved->HeaderBuffer->StartVa = (PCHAR)((ULONG)Reserved->HeaderBuffer->MappedSystemVa & ~(PAGE_SIZE-1));
+ Reserved->HeaderBuffer->ByteOffset = (ULONG)Reserved->HeaderBuffer->MappedSystemVa & (PAGE_SIZE-1);
+
+ IPX_DEBUG(SEND, ("completeing back filled userMdl %x\n",Reserved->HeaderBuffer));
+
+ NdisPacket->Private.ValidCounts = FALSE;
+
+ NdisPacket->Private.Head = NULL;
+ NdisPacket->Private.Tail = NULL;
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ }
+ // not a back fill packet. Push it on sendpacket pool
+ else {
+
+ if (Reserved->OwnedByAddress) {
+
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+
+
+ }
+
+#else
+
+ if (Reserved->OwnedByAddress) {
+
+
+ Reserved->Address->SendPacketInUse = FALSE;
+
+ } else {
+
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+#endif
+
+ ++Device->Statistics.PacketsSent;
+
+ //
+ // If this is a fast send irp, we bypass the file system and
+ // call the completion routine directly.
+ //
+
+ REQUEST_STATUS(Request) = NdisStatus;
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ } else {
+ IpxCompleteRequest (Request);
+ }
+
+ IpxFreeRequest(Device, Request);
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+ break;
+
+ case IDENTIFIER_RIP_INTERNAL:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ break;
+
+ case IDENTIFIER_RIP_RESPONSE:
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Reserved->Identifier = IDENTIFIER_IPX;
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ IpxDereferenceDevice (Device, DREF_RIP_PACKET);
+ break;
+
+#ifdef _PNP_POWER
+ case IDENTIFIER_NB:
+ case IDENTIFIER_SPX:
+
+ //
+ // See if this is an iterative send
+ //
+ if (OldId = Reserved->CurrentNicId) {
+
+ PNDIS_BUFFER HeaderBuffer;
+ UINT TempHeaderBufferLength;
+ PUCHAR Header;
+ PIPX_HEADER IpxHeader;
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+ Reserved->Net0SendSucceeded = TRUE;
+ }
+
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ {
+ ULONG Index = MIN (Device->MaxBindings, Device->HighestExternalNicId);
+
+ for (NewId = OldId+1; NewId <= Index; NewId++) {
+ if (Binding = NIC_ID_TO_BINDING(Device, NewId)) {
+ //
+ // Found next NIC to send on
+ //
+ break;
+ }
+ }
+ }
+
+ if (NewId <= MIN (Device->MaxBindings, Device->HighestExternalNicId)) {
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // Yes, we found another net to send it on, so
+ // move the header around if needed and do so.
+ //
+ IPX_DEBUG(SEND, ("ISN iteration: OldId: %lx, NewId: %lx\n", OldId, NewId));
+ Reserved->CurrentNicId = NewId;
+#if 0
+ NewOffset = Binding->BcMcHeaderSize;
+ OldOffset = Device->Bindings[OldId]->BcMcHeaderSize;
+
+ if (OldOffset != NewOffset) {
+
+ RtlMoveMemory(
+ &Reserved->Header[NewOffset],
+ &Reserved->Header[OldOffset],
+ sizeof(IPX_HEADER));
+
+ }
+
+ IpxHeader = (PIPX_HEADER)(&Reserved->Header[NewOffset]);
+
+
+#if BACK_FILL
+ // This should be a normal packet. Backfill packet is never used for
+ // reserved other than IPX type
+
+ CTEAssert(!Reserved->BackFill);
+#endif
+#endif
+
+ NdisQueryPacket (NdisPacket, NULL, NULL, &HeaderBuffer, NULL);
+ NdisQueryBuffer(HeaderBuffer, &Header, &TempHeaderBufferLength);
+
+ IpxHeader = (PIPX_HEADER)(&Header[Device->IncludedHeaderOffset]);
+
+ IPX_DEBUG(SEND, ("SendComplete: IpxHeader: %lx\n", IpxHeader));
+ FILL_LOCAL_TARGET(&Reserved->LocalTarget, NewId);
+
+ //
+ // We don't need to so this since the macaddress is replaced in
+ // IpxSendFrame anyway. The LocalTarget is the same as the one on
+ // the original send - this is passed down for further sends.
+ //
+ // RtlCopyMemory(LocalTarget.MacAddress, IpxHeader->DestinationNode, 6);
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+ if ((NdisStatus = IpxSendFrame(
+ &Reserved->LocalTarget,
+ NdisPacket,
+ Reserved->PacketLength,
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ Adapter = Binding->Adapter;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ goto FunctionStart;
+ }
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ return;
+
+ } else {
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ //
+ // If any of the sends succeeded then return
+ // success on the datagram send, otherwise
+ // use the most recent failure status.
+ //
+ if (Reserved->Net0SendSucceeded) {
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ }
+
+ }
+ }
+
+ //
+ // fall thru'
+ //
+#endif
+ default:
+
+ (*Device->UpperDrivers[Reserved->Identifier].SendCompleteHandler)(
+ NdisPacket,
+ NdisStatus);
+ break;
+ }
+
+} /* IpxSendComplete */
+
+
+NTSTATUS
+IpxTdiSendDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSendDatagram request for the transport
+ provider.
+
+Arguments:
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PNDIS_PACKET Packet;
+ PIPX_SEND_RESERVED Reserved;
+ PSINGLE_LIST_ENTRY s;
+ TDI_ADDRESS_IPX UNALIGNED * RemoteAddress;
+ TDI_ADDRESS_IPX TempAddress;
+ TA_ADDRESS UNALIGNED * AddressName;
+ PTDI_CONNECTION_INFORMATION Information;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PBINDING Binding;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = IpxDevice;
+ UCHAR PacketType;
+ NTSTATUS Status;
+ PIPX_HEADER IpxHeader;
+ NDIS_STATUS NdisStatus;
+ USHORT LengthIncludingHeader;
+ IPX_DEFINE_SYNC_CONTEXT (SyncContext)
+ IPX_DEFINE_LOCK_HANDLE (LockHandle)
+ PIO_STACK_LOCATION irpSp; \
+ BOOLEAN IsLoopback = FALSE;
+
+#ifdef _PNP_POWER
+ IPX_DEFINE_LOCK_HANDLE(LockHandle1)
+#endif
+
+ //
+ // Do a quick check of the validity of the address.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ IPX_BEGIN_SYNC (&SyncContext);
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == IPX_ADDRESSFILE_SIGNATURE) &&
+ ((Address = AddressFile->Address) != NULL)) {
+
+ IPX_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_CLOSING) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ Information = Parameters->SendDatagramInformation;
+
+ //
+ // Do a quick check if this address has only one entry.
+ //
+
+ AddressName = &((TRANSPORT_ADDRESS UNALIGNED *)(Information->RemoteAddress))->Address[0];
+
+ if ((AddressName->AddressType == TDI_ADDRESS_TYPE_IPX) &&
+ (AddressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))) {
+
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)(AddressName->Address);
+
+ } else if ((RemoteAddress = IpxParseTdiAddress (Information->RemoteAddress)) == NULL) {
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_ADDRESS;
+ goto error_send_no_packet;
+ }
+
+ IPX_DEBUG (SEND, ("Send on %lx, network %lx socket %lx\n",
+ Address, RemoteAddress->NetworkAddress, RemoteAddress->Socket));
+
+#if 0
+ if (Parameters->SendLength > IpxDevice->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ IpxDevice->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_no_packet;
+ }
+#endif
+ //
+ // Every address has one packet committed to it, use that
+ // if possible, otherwise take one out of the pool.
+ //
+
+
+#if BACK_FILL
+
+ // If the request is coming from the server, which resrves transport header space
+ // build the header in its space. Allocate a special packet to which does not contain
+ // mac and ipx headers in its reserved space.
+
+ if ((PMDL)REQUEST_NDIS_BUFFER(Request) &&
+ (((PMDL)REQUEST_NDIS_BUFFER(Request))->MdlFlags & MDL_NETWORK_HEADER) &&
+ (!(Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS))) &&
+ (RemoteAddress->NodeAddress[0] != 0xff)) {
+
+ //if (!Address->BackFillPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->BackFillPacketInUse, 0) == 0) {
+ //Address->BackFillPacketInUse = TRUE;
+ InterlockedIncrement(&Address->BackFillPacketInUse);
+
+ Packet = PACKET(&Address->BackFillPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+ IPX_DEBUG(SEND, ("Getting owned backfill %x %x \n", Packet,Reserved));
+
+ }else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotBackFillPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopBackFillPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotBackFillPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ IPX_DEBUG(SEND, ("getting backfill packet %x %x %x\n", s, Reserved, RemoteAddress->NodeAddress));
+ if(!Reserved->BackFill)DbgBreakPoint();
+
+ }
+
+ }else {
+
+ // if (!Address->SendPacketInUse) {
+ if (InterlockedExchangeAdd(&Address->SendPacketInUse, 0) == 0) {
+ // Address->SendPacketInUse = TRUE;
+ InterlockedIncrement(&Address->SendPacketInUse);
+
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ Reserved->BackFill = FALSE;
+
+ }
+
+ }
+
+
+#else
+
+ if (!Address->SendPacketInUse) {
+
+ Address->SendPacketInUse = TRUE;
+ Packet = PACKET(&Address->SendPacket);
+ Reserved = (PIPX_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = IPX_POP_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Device->SListsLock);
+
+ if (s != NULL) {
+ goto GotPacket;
+ }
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = IpxPopSendPacket(Device);
+
+ //
+ // Possibly we should queue the packet up to wait
+ // for one to become free.
+ //
+
+ if (s == NULL) {
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto error_send_no_packet;
+ }
+
+GotPacket:
+
+ Reserved = CONTAINING_RECORD (s, IPX_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+
+#endif
+
+ IpxReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // Save this now while we have Parameters available.
+ //
+
+ REQUEST_INFORMATION(Request) = Parameters->SendLength;
+ LengthIncludingHeader = (USHORT)(Parameters->SendLength + sizeof(IPX_HEADER));
+
+#if 0
+ {
+ ULONG ActualLength;
+ IpxGetMdlChainLength(REQUEST_NDIS_BUFFER(Request), &ActualLength);
+ if (ActualLength != Parameters->SendLength) {
+ DbgPrint ("IPX: IRP %lx has parameter length %d, buffer chain length %d\n",
+ Request, Parameters->SendLength, ActualLength);
+ DbgBreakPoint();
+ }
+ }
+#endif
+
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.Request = Request;
+ CTEAssert (Reserved->Identifier == IDENTIFIER_IPX);
+
+
+ //
+ // Set this to 0; this means the packet is not one that
+ // should be broadcast on all nets. We will change it
+ // later if it turns out this is the case.
+ //
+
+ Reserved->u.SR_DG.CurrentNicId = 0;
+
+ //
+ // We need this to track these packets specially.
+ //
+
+ Reserved->u.SR_DG.OutgoingSap = AddressFile->IsSapSocket;
+
+ //
+ // Add the MDL chain after the pre-allocated header buffer.
+ // NOTE: THIS WILL ONLY WORK IF WE EVENTUALLY CALL
+ // NDISRECALCULATEPACKETCOUNTS (which we do in IpxSendFrame).
+ //
+ //
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->HeaderBuffer = REQUEST_NDIS_BUFFER(Request);
+
+ //remove the ipx mdl from the packet.
+ Reserved->UserLength = Reserved->HeaderBuffer->ByteCount;
+
+ IPX_DEBUG(SEND, ("back filling userMdl Reserved %x %x\n", Reserved->HeaderBuffer, Reserved));
+ } else {
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+ }
+#else
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = REQUEST_NDIS_BUFFER(Request);
+#endif
+
+
+ if (Information->OptionsLength < sizeof(IPX_DATAGRAM_OPTIONS)) {
+
+ //
+ // The caller did not supply the local target for this
+ // send, so we look it up ourselves.
+ //
+
+ UINT Segment;
+
+ //
+ // We calculate this now since we need to know
+ // if it is directed below.
+ //
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+ }
+
+ //
+ // If there are no options, then check if the
+ // caller is passing the packet type as a final byte
+ // in the remote address; if not use the default.
+ //
+
+ if (Information->OptionsLength == 0) {
+ if (AddressFile->ExtendedAddressing) {
+ PacketType = ((PUCHAR)(RemoteAddress+1))[0];
+ } else {
+ PacketType = AddressFile->DefaultPacketType;
+ }
+ } else {
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ }
+
+ if ((Reserved->DestinationType != DESTINATION_DEF) &&
+ ((RemoteAddress->NetworkAddress == 0) ||
+ (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)))) {
+
+ //
+ // This packet needs to be broadcast to all networks.
+ // Make sure it is not too big for any of them.
+ //
+
+ if (Parameters->SendLength > Device->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength, Device->RealMaxDatagramSize));
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ //
+ // If this is a broadcast to the virtual net, we
+ // need to construct a fake remote address which
+ // has network 0 in there instead.
+ //
+
+ if (Device->VirtualNetwork &&
+ (RemoteAddress->NetworkAddress == Device->SourceAddress.NetworkAddress)) {
+
+ RtlCopyMemory (&TempAddress, (PVOID)RemoteAddress, sizeof(TDI_ADDRESS_IPX));
+ TempAddress.NetworkAddress = 0;
+ RemoteAddress = (TDI_ADDRESS_IPX UNALIGNED *)&TempAddress;
+ }
+
+ //
+ // If someone is sending to the SAP socket and
+ // we are running with multiple cards without a
+ // virtual network, AND this packet is a SAP response,
+ // then we log an error to warn them that the
+ // system may not work as they like (since there
+ // is no virtual network to advertise, we use
+ // the first card's net/node as our local address).
+ // We only do this once per boot, using the
+ // SapWarningLogged variable to control that.
+ //
+
+ if ((RemoteAddress->Socket == SAP_SOCKET) &&
+ (!Device->SapWarningLogged) &&
+ (Device->MultiCardZeroVirtual)) {
+
+ PNDIS_BUFFER FirstBuffer;
+ UINT FirstBufferLength;
+ USHORT UNALIGNED * FirstBufferData;
+
+ if ((FirstBuffer = REQUEST_NDIS_BUFFER(Request)) != NULL) {
+
+ NdisQueryBuffer(
+ FirstBuffer,
+ (PVOID *)&FirstBufferData,
+ &FirstBufferLength);
+
+ //
+ // The first two bytes of a SAP packet are the
+ // operation, 0x2 (in network order) is response.
+ //
+
+ if ((FirstBufferLength >= sizeof(USHORT)) &&
+ (*FirstBufferData == 0x0200)) {
+
+ Device->SapWarningLogged = TRUE;
+
+ IpxWriteGeneralErrorLog(
+ Device->DeviceObject,
+ EVENT_IPX_SAP_ANNOUNCE,
+ 777,
+ STATUS_NOT_SUPPORTED,
+ NULL,
+ 0,
+ NULL);
+ }
+ }
+ }
+
+
+ //
+ // In this case we do not RIP but instead set the
+ // packet up so it is sent to each network in turn.
+ //
+ // Special case: If this packet is from the SAP
+ // socket and we are running with multiple cards
+ // without a virtual network, we only send this
+ // on the card with NIC ID 1, so we leave
+ // CurrentNicId set to 0.
+ //
+
+ //
+ // BUGBUG: What if NicId 1 is invalid? Should scan
+ // for first valid one, fail send if none.
+ //
+
+ if ((Address->Socket != SAP_SOCKET) ||
+ (!Device->MultiCardZeroVirtual)) {
+
+ if (Device->SingleNetworkActive) {
+
+ if (Device->ActiveNetworkWan) {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstWanNicId;
+ } else {
+ Reserved->u.SR_DG.CurrentNicId = Device->FirstLanNicId;
+ }
+
+ } else {
+
+ Reserved->u.SR_DG.CurrentNicId = 1;
+
+ }
+
+ Reserved->u.SR_DG.Net0SendSucceeded = FALSE;
+
+ //
+ // In this case, we need to scan for the first
+ // non-dialout wan socket.
+ //
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET)) {
+
+ PBINDING TempBinding;
+
+ CTEAssert (Reserved->u.SR_DG.CurrentNicId <= Device->ValidBindings);
+ while (Reserved->u.SR_DG.CurrentNicId <= MIN (Device->MaxBindings, Device->ValidBindings)) {
+#ifdef _PNP_POWER
+// No need to lock the access path since he just looks at it
+//
+ TempBinding = NIC_ID_TO_BINDING(Device, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempBinding = Device->Bindings[Reserved->u.SR_DG.CurrentNicId];
+#endif _PNP_POWER
+ if ((TempBinding != NULL) &&
+ (!TempBinding->DialOutAsync)) {
+ break;
+ }
+ ++Reserved->u.SR_DG.CurrentNicId;
+ }
+ if (Reserved->u.SR_DG.CurrentNicId > MIN (Device->MaxBindings, Device->ValidBindings)) {
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+
+ goto error_send_with_packet;
+ }
+ }
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, Reserved->u.SR_DG.CurrentNicId);
+#else
+ TempLocalTarget.NicId = Reserved->u.SR_DG.CurrentNicId;
+#endif
+
+ } else {
+#ifdef _PNP_POWER
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+#else
+ TempLocalTarget.NicId = 1;
+#endif
+ }
+
+ RtlCopyMemory(TempLocalTarget.MacAddress, RemoteAddress->NodeAddress, 6);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#endif
+
+ } else {
+
+ Segment = RipGetSegment((PUCHAR)&RemoteAddress->NetworkAddress);
+
+
+ IPX_GET_LOCK (&Device->SegmentLocks[Segment], &LockHandle);
+
+ //
+ // This call will return STATUS_PENDING if we need to
+ // RIP for the packet.
+ //
+
+ Status = RipGetLocalTarget(
+ Segment,
+ RemoteAddress,
+ IPX_FIND_ROUTE_RIP_IF_NEEDED,
+ &TempLocalTarget,
+ NULL);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // We found the route, TempLocalTarget is filled in.
+ //
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+#ifdef _PNP_POWER
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ if (NIC_FROM_LOCAL_TARGET(&TempLocalTarget) == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ FILL_LOCAL_TARGET(&TempLocalTarget, 1);
+ }
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(&TempLocalTarget));
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+
+ if (Parameters->SendLength >
+ Binding->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Binding->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+
+ goto error_send_with_packet;
+ }
+#else
+ if (TempLocalTarget.NicId == 0) {
+ IPX_DEBUG(LOOPB, ("Loopback TDI packet: remoteaddr: %lx\n", RemoteAddress));
+ IsLoopback = TRUE;
+ TempLocalTarget.NicId = 1;
+ }
+
+ if (Parameters->SendLength >
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize) {
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Device->Bindings[TempLocalTarget.NicId]->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+ if ((Device->DisableDialoutSap) &&
+ (Address->Socket == SAP_SOCKET) &&
+ (Device->Bindings[TempLocalTarget.NicId]->DialOutAsync)) {
+
+ REQUEST_INFORMATION(Request) = 0;
+ //
+ // [SA] Bug #17273 return proper error mesg.
+ //
+
+ // Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto error_send_with_packet;
+ }
+#endif _PNP_POWER
+
+ } else if (Status == STATUS_PENDING) {
+
+ //
+ // A RIP request went out on the network; we queue
+ // this packet for transmission when the RIP
+ // response arrives. First we fill in the IPX
+ // header; the only thing we don't know is where
+ // exactly to fill it in, so we choose
+ // the most common location.
+ //
+
+ IpxConstructHeader(
+ &Reserved->Header[Device->IncludedHeaderOffset],
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ //
+ // Adjust the 2nd mdl's size
+ //
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+
+ IPX_DEBUG (RIP, ("Queueing packet %lx\n", Reserved));
+
+ InsertTailList(
+ &Device->Segments[Segment].WaitingForRoute,
+ &Reserved->WaitLinkage);
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ IPX_END_SYNC (&SyncContext);
+
+ return STATUS_PENDING;
+
+ } else {
+
+ IPX_FREE_LOCK (&Device->SegmentLocks[Segment], LockHandle);
+ goto error_send_with_packet;
+
+ }
+ }
+
+ LocalTarget = &TempLocalTarget;
+
+ //
+ // Now we know the local target, we can figure out
+ // the offset for the IPX header.
+ //
+#ifdef _PNP_POWER
+// Remember that we have got the binding with ref above....
+
+#else
+ Binding = Device->Bindings[LocalTarget->NicId];
+#endif
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+#if 0
+ if (Reserved->DestinationType == DESTINATION_DEF) {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ } else {
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ }
+#endif
+
+ } else {
+
+ PacketType = ((PUCHAR)(Information->Options))[0];
+ LocalTarget = &((PIPX_DATAGRAM_OPTIONS)(Information->Options))->LocalTarget;
+
+ //
+ // Calculate the binding and the correct location
+ // for the IPX header. We can do this at the same
+ // time as we calculate the DestinationType which
+ // saves an if like the one 15 lines up.
+ //
+
+#ifdef _PNP_POWER
+// Get lock to ref.
+ IPX_GET_LOCK1(&Device->BindAccessLock, &LockHandle1);
+ //
+ // If a loopback packet, use the first binding as place holder
+ //
+ if (NIC_FROM_LOCAL_TARGET(LocalTarget) == 0) {
+ Binding = NIC_ID_TO_BINDING(Device, 1);
+ IsLoopback = TRUE;
+ } else {
+ Binding = NIC_ID_TO_BINDING(Device, NIC_FROM_LOCAL_TARGET(LocalTarget));
+ }
+
+ IpxReferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+ IPX_FREE_LOCK1(&Device->BindAccessLock, LockHandle1);
+#else
+ if (LocalTarget->NicId == 0) {
+ Binding = Device->Bindings[1];
+ IsLoopback = TRUE;
+ } else {
+ Binding = Device->Bindings[LocalTarget->NicId];
+ }
+#endif _PNP_POWER
+ if (Parameters->SendLength > Binding->RealMaxDatagramSize) {
+
+ IPX_DEBUG (SEND, ("Send %d bytes too large (%d)\n",
+ Parameters->SendLength,
+ Binding->RealMaxDatagramSize));
+
+ REQUEST_INFORMATION(Request) = 0;
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto error_send_with_packet;
+ }
+
+#if 0
+ //
+ // This shouldn't be needed because even WAN bindings
+ // don't go away once they are added.
+ //
+
+ if (Binding == NULL) {
+ Status = STATUS_DEVICE_DOES_NOT_EXIST;
+ goto error_send_with_packet;
+ }
+#endif
+
+ if (RemoteAddress->NodeAddress[0] == 0xff) {
+ // BUGBUG: What about multicast?
+ if ((*(UNALIGNED ULONG *)(RemoteAddress->NodeAddress) != 0xffffffff) ||
+ (*(UNALIGNED USHORT *)(RemoteAddress->NodeAddress+4) != 0xffff)) {
+ Reserved->DestinationType = DESTINATION_MCAST;
+ } else {
+ Reserved->DestinationType = DESTINATION_BCAST;
+ }
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->BcMcHeaderSize];
+ } else {
+ Reserved->DestinationType = DESTINATION_DEF; // directed send
+// IpxHeader = (PIPX_HEADER)&Reserved->Header[Binding->DefHeaderSize];
+ }
+ IpxHeader = (PIPX_HEADER)&Reserved->Header[MAC_HEADER_SIZE];
+
+ }
+
+
+ ++Device->TempDatagramsSent;
+ Device->TempDatagramBytesSent += Parameters->SendLength;
+
+
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ Reserved->MappedSystemVa = Reserved->HeaderBuffer->MappedSystemVa;
+ IpxHeader = (PIPX_HEADER)((PCHAR)Reserved->HeaderBuffer->MappedSystemVa - sizeof(IPX_HEADER));
+ Reserved->HeaderBuffer->ByteOffset -= sizeof(IPX_HEADER);
+ (ULONG)Reserved->HeaderBuffer->MappedSystemVa-= sizeof(IPX_HEADER);
+ IPX_DEBUG(SEND, ("Adjusting backfill userMdl Ipxheader %x %x \n",Reserved->HeaderBuffer,IpxHeader));
+ }
+#endif
+
+ if (Device->MultiCardZeroVirtual ||
+ (Address->LocalAddress.Socket == SAP_SOCKET) ||
+ (RemoteAddress->Socket == SAP_SOCKET)) {
+
+ //
+ // SAP frames need to look like they come from the
+ // local network, not the virtual one. The same is
+ // true if we are running multiple nets without
+ // a virtual network number.
+ //
+ // If this is a binding set member and a local target
+ // was provided we will send using the real node of
+ // the binding, even if it was a slave. This is
+ // intentional. If no local target was provided then
+ // this will not be a binding slave.
+ //
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Binding->LocalAddress);
+
+ IpxHeader->SourceSocket = Address->SendSourceSocket;
+
+ } else {
+
+ IpxConstructHeader(
+ (PUCHAR)IpxHeader,
+ LengthIncludingHeader,
+ PacketType,
+ RemoteAddress,
+ &Address->LocalAddress);
+
+ }
+
+
+ //
+ // Fill in the MAC header and submit the frame to NDIS.
+ //
+
+// #if DBG
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+// #endif
+ //
+ // Adjust the 2nd mdl's size
+ //
+#if BACK_FILL
+ if (Reserved->BackFill) {
+ NdisAdjustBufferLength(Reserved->HeaderBuffer, (Reserved->HeaderBuffer->ByteCount+sizeof(IPX_HEADER)));
+ } else {
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+ }
+#else
+ NdisAdjustBufferLength(NDIS_BUFFER_LINKAGE(IPX_PACKET_HEAD(Packet)), sizeof(IPX_HEADER));
+#endif
+
+ IPX_DEBUG(SEND, ("Packet Head %x\n",IPX_PACKET_HEAD(Packet)));
+
+ if (IsLoopback) {
+ //
+ // Enque this packet to the LoopbackQueue on the binding.
+ // If the LoopbackRtn is not already scheduled, schedule it.
+ //
+
+ IPX_DEBUG(LOOPB, ("Packet: %lx, Addr: %lx, Addr->SendPacket: %lx\n", Packet, Address, Address->SendPacket));
+
+ //
+ // Recalculate packet counts here.
+ //
+ // NdisAdjustBufferLength (Reserved->HeaderBuffer, 17);
+#if BACK_FILL
+
+ if (Reserved->BackFill) {
+ //
+ // Set the Header pointer and chain the first MDL
+ //
+ Reserved->Header = (PCHAR)Reserved->HeaderBuffer->MappedSystemVa;
+ NdisChainBufferAtFront(Packet,(PNDIS_BUFFER)Reserved->HeaderBuffer);
+ }
+#endif
+ NdisRecalculatePacketCounts (Packet);
+#ifdef _PNP_POWER
+ IpxLoopbackEnque(Packet, NIC_ID_TO_BINDING(Device, 1)->Adapter);
+#else
+ IpxLoopbackEnque(Packet, Device->Bindings[1]->Adapter);
+#endif
+
+ } else {
+ if ((NdisStatus = (*Binding->SendFrameHandler)(
+ Binding->Adapter,
+ LocalTarget,
+ Packet,
+ Parameters->SendLength + sizeof(IPX_HEADER),
+ sizeof(IPX_HEADER))) != NDIS_STATUS_PENDING) {
+
+ IpxSendComplete(
+ (NDIS_HANDLE)Binding->Adapter,
+ Packet,
+ NdisStatus);
+ }
+ }
+
+ IPX_END_SYNC (&SyncContext);
+#ifdef _PNP_POWER
+ IpxDereferenceBinding1(Binding, BREF_DEVICE_ACCESS);
+#endif
+ return STATUS_PENDING;
+
+ } else {
+
+ //
+ // The address file state was closing.
+ //
+
+ IPX_FREE_LOCK (&Address->Lock, LockHandle);
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+
+ }
+
+ } else {
+
+ //
+ // The address file didn't look like one.
+ //
+
+ Status = STATUS_INVALID_HANDLE;
+ goto error_send_no_packet;
+ }
+
+ //
+ // Jump here if we want to fail the send and we have already
+ // allocated the packet and ref'ed the address file.
+ //
+
+error_send_with_packet:
+
+#if BACK_FILL
+ //
+ // Check if this is backfilled. If so, set the headerbuffer to NULL. Note that we dont need
+ // restore to restore the user's MDL since it was never touched when this error occurred.
+ // Also, push the packet on to backfillpacket queue if the packet is not owned by the address
+ //
+ if (Reserved->BackFill) {
+
+ Reserved->HeaderBuffer = NULL;
+
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->BackFillPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->BackFillPacketInUse);
+
+ IPX_DEBUG(SEND, ("Freeing owned backfill %x\n", Reserved));
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->BackFillPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+ } else {
+ // not a back fill packet. Push it on sendpacket pool
+ if (Reserved->OwnedByAddress) {
+ // Reserved->Address->SendPacketInUse = FALSE;
+ InterlockedDecrement(&Reserved->Address->SendPacketInUse);
+
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+
+ }
+ }
+#else
+ if (Reserved->OwnedByAddress) {
+ Reserved->Address->SendPacketInUse = FALSE;
+ } else {
+ IPX_PUSH_ENTRY_LIST(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &Device->SListsLock);
+ }
+#endif
+
+ IpxDereferenceAddressFileSync (AddressFile, AFREF_SEND_DGRAM);
+
+error_send_no_packet:
+
+ //
+ // Jump here if we fail before doing any of that.
+ //
+
+ IPX_END_SYNC (&SyncContext);
+
+ irpSp = IoGetCurrentIrpStackLocation( Request );
+ if ( irpSp->MinorFunction == TDI_DIRECT_SEND_DATAGRAM ) {
+
+ REQUEST_STATUS(Request) = Status;
+ Request->CurrentLocation++,
+ Request->Tail.Overlay.CurrentStackLocation++;
+
+ (VOID) irpSp->CompletionRoutine(
+ NULL,
+ Request,
+ irpSp->Context
+ );
+
+ IpxFreeRequest (DeviceObject, Request);
+ }
+
+ return Status;
+
+} /* IpxTdiSendDatagram */
+
+
+#if DBG
+VOID
+IpxConstructHeader(
+ IN PUCHAR Header,
+ IN USHORT PacketLength,
+ IN UCHAR PacketType,
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PTDI_ADDRESS_IPX LocalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs an IPX header in a packet.
+
+Arguments:
+
+ Header - The location at which the header should be built.
+
+ PacketLength - The length of the packet, including the IPX header.
+
+ PacketType - The packet type of the frame.
+
+ RemoteAddress - The remote IPX address.
+
+ LocalAddress - The local IPX address.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PIPX_HEADER IpxHeader = (PIPX_HEADER)Header;
+
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = (UCHAR)(PacketLength / 256);
+ IpxHeader->PacketLength[1] = (UCHAR)(PacketLength % 256);
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = PacketType;
+
+ //
+ // These copies depend on the fact that the destination
+ // network is the first field in the 12-byte address.
+ //
+
+ RtlCopyMemory(IpxHeader->DestinationNetwork, (PVOID)RemoteAddress, 12);
+ RtlCopyMemory(IpxHeader->SourceNetwork, LocalAddress, 12);
+
+} /* IpxConstructHeader */
+#endif
+
+
diff --git a/private/ntos/tdi/isnp/ipx/sources.inc b/private/ntos/tdi/isnp/ipx/sources.inc
new file mode 100644
index 000000000..449026087
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/sources.inc
@@ -0,0 +1,74 @@
+!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=nwlnkipx
+
+TARGETNAME=nwlnkipx
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+NTPROFILEINPUT=yes
+
+
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -DBACK_FILL=1 -DNDIS40=1 -D_PNP_POWER=1
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES=$(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\adapter.c \
+ ..\address.c \
+ ..\config.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\ind.c \
+ ..\internal.c \
+ ..\nwlnkipx.rc \
+ ..\mac.c \
+ ..\ndis.c \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\rip.c \
+ ..\send.c \
+ ..\loopback.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+
+SOURCES_USED=..\sources.inc
+
+
diff --git a/private/ntos/tdi/isnp/ipx/up/makefile b/private/ntos/tdi/isnp/ipx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/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/isnp/ipx/up/nwlnkipx.prf b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
new file mode 100644
index 000000000..0c4359235
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/up/nwlnkipx.prf
@@ -0,0 +1,89 @@
+IpxTdiSendDatagram@8
+IpxReceiveIndicationNew@36
+IpxSendFrame@16
+IpxReceiveComplete@4
+IpxSendFrame802_3802_2@20
+IpxReceivePacket@8
+IpxDerefAddressSync@4
+IpxSendComplete@12
+IpxSendFramePreFwd@16
+IpxReceiveIndication@28
+IpxInitializeBackFillPacket@12
+IpxpAllocateMemory@12
+IpxPopBackFillPacket@4
+IpxAllocateBackFillPool@4
+RipLongTimeout@8
+CTEStartTimer@16
+TdiCopyBufferToMdl@24
+IpxTdiQueryInformation@8
+IpxVerifyAddressFile@4
+IpxDispatchInternal@8
+IpxTransferData@28
+IpxInitLoopback@0
+RipGetFirstRoute@4
+IpxCreateAddress@8
+MacReturnMaxDataSize@20
+IpxLookupAddress@8
+IpxAbortLineChanges@4
+MacMapFrameType@12
+IpxInitializeReceiveBuffer@16
+IpxDispatchOpenClose@8
+IpxTdiSetEventHandler@4
+IpxCreateAddressFile@4
+IpxInternalBind@8
+IpxInitializeReceivePacket@8
+IpxIsAddressLocal@4
+IpxOpenAddress@8
+IpxAllocateReceiveBufferPool@4
+IpxSubmitNdisRequest@12
+IpxAddBroadcast@4
+IpxDestroyBinding@4
+RipAdjustForBindingChange@12
+IpxDispatchDeviceControl@8
+IpxAllocatePaddingBuffer@4
+TdiMapUserRequest@12
+CTEInitialize@0
+IpxInitializeSendPacket@12
+IpxpFreeMemory@12
+IpxInitializePaddingBuffer@12
+IpxAllocateSendPool@4
+RipCleanupPacket@8
+TdiRegisterDeviceObject@8
+TdiRegisterNetAddress@8
+IpxTdiAction@8
+IpxCreateBinding@20
+IpxDerefDevice@4
+MacInitializeBindingInfo@8
+IpxRegisterProtocol@4
+IpxInitializeNdis@8
+IpxGetConfigValue@24
+IpxCreateAdapter@12
+IpxResolveBindingSets@8
+IpxGetFrameType@24
+MacInitializeMacInfo@8
+IpxGetBindingValue@24
+RipQueueRequest@8
+RipShortTimeout@8
+IpxPopSendPacket@4
+IpxAllocateBindingPool@4
+IpxInternalQuery@20
+CTEInitTimer@4
+IpxRequestComplete@12
+IpxBroadcastOperation@4
+CTEInitEvent@8
+IpxPnPGetVirtualNetworkNumber@4
+IpxPnPGetAdapterParameters@12
+IpxOpenAdapterComplete@12
+IpxResolveAutoDetect@16
+IpxBindToAdapter@16
+TdiInitialize@0
+IpxPnPIsnIndicate@4
+IpxPnPUpdateBindingArray@12
+IpxBindAdapter@20
+IpxPnPUpdateDevice@4
+IpxGetConfiguration@12
+IpxAddExport@24
+IpxCreateDevice@16
+DriverEntry@8
+IpxReadLinkageInformation@4
+IpxFreeConfiguration@4
diff --git a/private/ntos/tdi/isnp/ipx/up/sources b/private/ntos/tdi/isnp/ipx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/ipx/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
diff --git a/private/ntos/tdi/isnp/nb/action.c b/private/ntos/tdi/isnp/nb/action.c
new file mode 100644
index 000000000..9ff843a76
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/action.c
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains code which implements the TDI action
+ dispatch routines.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles action requests.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the action.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ UINT BufferLength;
+ UINT DataLength;
+ PNDIS_BUFFER NdisBuffer;
+ CTELockHandle LockHandle;
+ union {
+ PNB_ACTION_GET_COUNTS GetCounts;
+ } u; // BUGBUG: Make these unaligned??
+ PNWLINK_ACTION NwlinkAction;
+ UINT i;
+ static UCHAR BogusId[4] = { 0x01, 0x00, 0x00, 0x00 }; // old nwrdr uses this
+
+
+ //
+ // To maintain some compatibility with the NWLINK streams-
+ // based transport, we use the streams header format for
+ // our actions. The old transport expected the action header
+ // to be in InputBuffer and the output to go in OutputBuffer.
+ // We follow the TDI spec, which states that OutputBuffer
+ // is used for both input and output. Since IOCTL_TDI_ACTION
+ // is method out direct, this means that the output buffer
+ // is mapped by the MDL chain; for action the chain will
+ // only have one piece so we use it for input and output.
+ //
+
+ NdisBuffer = REQUEST_NDIS_BUFFER(Request);
+ if (NdisBuffer == NULL) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ NdisQueryBuffer (REQUEST_NDIS_BUFFER(Request), (PVOID *)&NwlinkAction, &BufferLength);
+
+ if ((!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MISN", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "MIPX", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), "XPIM", 4)) &&
+ (!RtlEqualMemory ((PVOID)(&NwlinkAction->Header.TransportId), BogusId, 4))) {
+
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Make sure we have enough room for just the header not
+ // including the data.
+ //
+
+ if (BufferLength < (UINT)(FIELD_OFFSET(NWLINK_ACTION, Data[0]))) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, buffer too small\n"));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DataLength = BufferLength - FIELD_OFFSET(NWLINK_ACTION, Data[0]);
+
+
+ //
+ // Make sure that the correct file object is being used.
+ //
+
+ if (NwlinkAction->OptionType == NWLINK_OPTION_ADDRESS) {
+
+ if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+ NB_DEBUG (QUERY, ("Nwlink action failed, not address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
+ (AddressFile->Type != NB_ADDRESSFILE_SIGNATURE)) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, bad address file\n"));
+ return STATUS_INVALID_HANDLE;
+ }
+
+ } else if (NwlinkAction->OptionType != NWLINK_OPTION_CONTROL) {
+
+ NB_DEBUG (QUERY, ("Nwlink action failed, option type %d\n", NwlinkAction->OptionType));
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Handle the requests based on the action code. For these
+ // requests ActionHeader->ActionCode is 0, we use the
+ // Option field in the streams header instead.
+ //
+
+
+ Status = STATUS_SUCCESS;
+
+ switch (NwlinkAction->Option) {
+
+ case (I_MIPX | 351):
+
+ //
+ // A request for details on every binding.
+ //
+
+ if (DataLength < sizeof(NB_ACTION_GET_COUNTS)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ u.GetCounts = (PNB_ACTION_GET_COUNTS)(NwlinkAction->Data);
+
+ u.GetCounts->MaximumNicId = NbiDevice->MaximumNicId;
+
+ for (i = 0; i < 32 ; i++) {
+ u.GetCounts->NicIdCounts[i] = 0;
+ }
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[i].Connections;
+
+ while (Connection != NULL) {
+#if defined(_PNP_POWER)
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicHandle.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicHandle.NicId];
+ }
+#else
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->LocalTarget.NicId < 32)) {
+
+ ++u.GetCounts->NicIdCounts[Connection->LocalTarget.NicId];
+ }
+#endif _PNP_POWER
+ Connection = Connection->NextConnection;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ //
+ // The Option was not supported, so fail.
+ //
+
+ default:
+
+ Status = STATUS_NOT_SUPPORTED;
+ break;
+
+
+ } // end of the long switch on NwlinkAction->Option
+
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ NB_DEBUG (QUERY, ("Nwlink action %lx failed, status %lx\n", NwlinkAction->Option, Status));
+ }
+#endif
+
+ return Status;
+
+} /* NbiTdiAction */
+
diff --git a/private/ntos/tdi/isnp/nb/address.c b/private/ntos/tdi/isnp/nb/address.c
new file mode 100644
index 000000000..2eb882b80
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/address.c
@@ -0,0 +1,2406 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ address.c
+
+Abstract:
+
+ This module contains code which implements the ADDRESS object.
+ Routines are provided to create, destroy, reference, and dereference,
+ transport address objects.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Map all generic accesses to the same one.
+//
+
+static GENERIC_MAPPING AddressGenericMapping =
+ { READ_CONTROL, READ_CONTROL, READ_CONTROL, READ_CONTROL };
+
+
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, looking for an address
+ of type TDI_ADDRESS_TYPE_NETBIOS.
+
+Arguments:
+
+ Transport - The generic TDI address.
+
+ BroadcastAddressOk - TRUE if we should return the broadcast
+ address if found. If so, a value of (PVOID)-1 indicates
+ the broadcast address.
+
+Return Value:
+
+ A pointer to the Netbios address, or NULL if none is found,
+ or (PVOID)-1 if the broadcast address is found.
+
+--*/
+
+{
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ addressName = &TransportAddress->Address[0];
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the Netbios one.
+ //
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->AddressType == TDI_ADDRESS_TYPE_NETBIOS) {
+ if ((addressName->AddressLength == 0) &&
+ BroadcastAddressOk) {
+ return (PVOID)-1;
+ } else if (addressName->AddressLength == sizeof(TDI_ADDRESS_NETBIOS)) {
+ return ((TDI_ADDRESS_NETBIOS UNALIGNED *)(addressName->Address));
+ }
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+ return NULL;
+
+} /* NbiParseTdiAddress */
+
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans a TRANSPORT_ADDRESS, verifying that the
+ components of the address do not extend past the specified
+ length.
+
+Arguments:
+
+ TransportAddress - The generic TDI address.
+
+ TransportAddressLength - The specific length of TransportAddress.
+
+Return Value:
+
+ TRUE if the address is valid, FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
+ TA_ADDRESS UNALIGNED * addressName;
+ INT i;
+
+ if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) {
+ NbiPrint0 ("NbfValidateTdiAddress: runt address\n");
+ return FALSE;
+ }
+
+ addressName = &TransportAddress->Address[0];
+
+ for (i=0;i<TransportAddress->TAAddressCount;i++) {
+ if (addressName->Address > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ addressName = (TA_ADDRESS UNALIGNED *)(addressName->Address +
+ addressName->AddressLength);
+ }
+
+ if ((PUCHAR)addressName > AddressEnd) {
+ NbiPrint0 ("NbiValidateTdiAddress: address too short\n");
+ return FALSE;
+ }
+ return TRUE;
+
+} /* NbiValidateTdiAddress */
+
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens a file that points to an existing address object, or, if
+ the object doesn't exist, creates it (note that creation of the address
+ object includes registering the address, and may take many seconds to
+ complete, depending upon system configuration).
+
+ If the address already exists, and it has an ACL associated with it, the
+ ACL is checked for access rights before allowing creation of the address.
+
+Arguments:
+
+ Device - pointer to the device describing the Netbios transport.
+
+ Request - a pointer to the request used for the creation of the address.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PFILE_FULL_EA_INFORMATION ea;
+ TRANSPORT_ADDRESS UNALIGNED *name;
+ TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress;
+ ULONG DesiredShareAccess;
+ CTELockHandle LockHandle;
+ PACCESS_STATE AccessState;
+ ACCESS_MASK GrantedAccess;
+ BOOLEAN AccessAllowed;
+ BOOLEAN found = FALSE;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+#if 0
+ TA_NETBIOS_ADDRESS FakeAddress;
+#endif
+
+
+ //
+ // The network name is in the EA, passed in the request.
+ //
+
+ ea = OPEN_REQUEST_EA_INFORMATION(Request);
+ if (ea == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no EA\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // this may be a valid name; parse the name from the EA and use it if OK.
+ //
+
+ name = (PTRANSPORT_ADDRESS)&ea->EaName[ea->EaNameLength+1];
+#if 0
+ TdiBuildNetbiosAddress(
+ "ADAMBA67 ",
+ FALSE,
+ &FakeAddress);
+ name = (PTRANSPORT_ADDRESS)&FakeAddress;
+#endif
+
+ //
+ // The name can be passed with multiple entries; we'll take and use only
+ // the first one of type Netbios. This call returns (PVOID)-1 if the
+ // address is the broadcast address.
+ //
+
+ NetbiosAddress = NbiParseTdiAddress (name, TRUE);
+
+ if (NetbiosAddress == NULL) {
+ NbiPrint1("OpenAddress: REQUEST %lx has no Netbios Address\n", Request);
+ return STATUS_INVALID_ADDRESS_COMPONENT;
+ }
+
+ //
+ // get an address file structure to represent this address.
+ //
+
+ AddressFile = NbiCreateAddressFile (Device);
+
+ if (AddressFile == (PADDRESS_FILE)NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // See if this address is already established. This call automatically
+ // increments the reference count on the address so that it won't disappear
+ // from underneath us after this call but before we have a chance to use it.
+ //
+ // To ensure that we don't create two address objects for the
+ // same address, we hold the device context addressResource until
+ // we have found the address or created a new one.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+
+#if defined(_PNP_POWER)
+
+ Address = NbiFindAddress (
+ Device,
+ ( NetbiosAddress == (PVOID)-1 ) ? (PVOID)-1 : NetbiosAddress->NetbiosName
+ );
+
+ if (Address == NULL) {
+
+#else
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Address = NbiLookupAddress (Device, NetbiosAddress);
+
+ if (Address == NULL) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif _PNP_POWER
+
+ //
+ // This address doesn't exist. Create it.
+ // This initializes the address with a ref
+ // of type ADDRESS_FILE, so if we fail here
+ // we need to remove that.
+ //
+
+ Address = NbiCreateAddress (
+ Device,
+ NetbiosAddress);
+
+ if (Address != (PADDRESS)NULL) {
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+#ifdef ISN_NT
+
+ //
+ // Initialize the shared access now. We use read access
+ // to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ IoSetShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess);
+
+
+ //
+ // Assign the security descriptor (need to do this with
+ // the spinlock released because the descriptor is not
+ // mapped).
+ //
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ status = SeAssignSecurity(
+ NULL, // parent descriptor
+ AccessState->SecurityDescriptor,
+ &Address->SecurityDescriptor,
+ FALSE, // is directory
+ &AccessState->SubjectSecurityContext,
+ &AddressGenericMapping,
+ NonPagedPool);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Error, return status.
+ //
+
+ IoRemoveShareAccess (IrpSp->FileObject, &Address->u.ShareAccess);
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ return status;
+
+ }
+
+#endif
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // if the adapter isn't ready, we can't do any of this; get out
+ //
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+#else
+ if (Device->State == DEVICE_STATE_STOPPING) {
+#endif _PNP_POWER
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DEVICE_NOT_READY;
+
+ } else {
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+ AddressFile->Address = Address;
+
+ NB_INSERT_TAIL_LIST(
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage,
+ &Address->Lock);
+
+ if (NetbiosAddress == (PVOID)-1) {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ NbiStartRegistration (Address);
+ }
+
+ }
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ //
+ // If the address could not be created, and is not in the
+ // process of being created, then we can't open up an address.
+ // Since we can't use the AddressLock to deref, we just destroy
+ // the address file.
+ //
+
+ NbiDestroyAddressFile (AddressFile);
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+#if !defined(_PNP_POWER)
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#endif !_PNP_POWER
+ NB_DEBUG2 (ADDRESS, ("Add to address %lx\n", Address));
+
+ //
+ // Set this now in case we have to deref.
+ //
+
+ AddressFile->AddressLock = &Address->Lock;
+
+ //
+ // Make sure the types do not conflict.
+ //
+
+ if ((NetbiosAddress != (PVOID)-1) &&
+ (NetbiosAddress->NetbiosNameType != Address->NetbiosAddress.NetbiosNameType)) {
+
+ NB_DEBUG (ADDRESS, ("Address types conflict %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ //
+ // The address already exists. Check the ACL and see if we
+ // can access it. If so, simply use this address as our address.
+ //
+
+#ifdef ISN_NT
+
+ AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState;
+
+ AccessAllowed = SeAccessCheck(
+ Address->SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ FALSE, // tokens locked
+ IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
+ (ACCESS_MASK)0, // previously granted
+ NULL, // privileges
+ &AddressGenericMapping,
+ Irp->RequestorMode,
+ &GrantedAccess,
+ &status);
+
+#else // ISN_NT
+
+ AccessAllowed = TRUE;
+
+#endif // ISN_NT
+
+ if (!AccessAllowed) {
+
+ NB_DEBUG (ADDRESS, ("Address access not allowed %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+#ifdef ISN_NT
+
+ //
+ // Now check that we can obtain the desired share
+ // access. We use read access to control all access.
+ //
+
+ DesiredShareAccess = (ULONG)
+ (((IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
+ (IrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE)) ?
+ FILE_SHARE_READ : 0);
+
+ status = IoCheckShareAccess(
+ FILE_READ_DATA,
+ DesiredShareAccess,
+ IrpSp->FileObject,
+ &Address->u.ShareAccess,
+ TRUE);
+
+#else // ISN_NT
+
+ status = STATUS_SUCCESS;
+
+#endif // ISN_NT
+
+ if (!NT_SUCCESS (status)) {
+
+ NB_DEBUG (ADDRESS, ("Address share access wrong %lx\n", Address));
+ ExReleaseResource (&Device->AddressResource);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ ExReleaseResource (&Device->AddressResource);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // Insert the address file on the address
+ // list; we will pend this open if the address
+ // is still registering. If the address has
+ // already failed as duplicate, then we
+ // fail the open.
+ //
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Address duplicated %lx\n", Address));
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+ status = STATUS_DUPLICATE_NAME;
+
+ } else {
+
+ InsertTailList (
+ &Address->AddressFileDatabase,
+ &AddressFile->Linkage);
+
+ //
+ // Start registration unless it is registered or
+ // it is the broadcast address.
+ //
+
+ if ((Address->State == ADDRESS_STATE_REGISTERING) &&
+ (NetbiosAddress != (PVOID)-1)) {
+
+ AddressFile->OpenRequest = Request;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ status = STATUS_PENDING;
+
+ } else {
+
+ AddressFile->OpenRequest = NULL;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+ status = STATUS_SUCCESS;
+ }
+
+ AddressFile->Address = Address;
+#ifdef ISN_NT
+ AddressFile->FileObject = IrpSp->FileObject;
+#endif
+
+ NbiReferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)AddressFile;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ }
+
+ }
+ }
+ }
+
+ //
+ // Remove the reference from NbiLookupAddress.
+ //
+
+ NbiDereferenceAddress (Address, AREF_LOOKUP);
+ }
+
+ return status;
+
+} /* NbiOpenAddress */
+
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the registration process for a netbios name
+ by sending out the first add name packet and starting the timer
+ so that NbiRegistrationTimeout is called after the correct timeout.
+
+Arguments:
+
+ Address - The address which is to be registered.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NB_DEBUG2 (ADDRESS, ("StartRegistration of %lx\n", Address));
+
+ //
+ // First send out an add name packet.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ Address->RegistrationCount = 0;
+
+ //
+ // Now start the timer.
+ //
+
+ NbiReferenceAddress (Address, AREF_TIMER);
+
+ CTEInitTimer (&Address->RegistrationTimer);
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+} /* NbiStartRegistration */
+
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the address registration
+ timer expires. It sends another add name if needed, or
+ checks the result if the correct number have been sent.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the address pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Context;
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PLIST_ENTRY p;
+
+ ++Address->RegistrationCount;
+
+ if ((Address->RegistrationCount < Address->Device->BroadcastCount) &&
+ ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0)) {
+
+ NB_DEBUG2 (ADDRESS, ("Send add name %d for %lx\n", Address->RegistrationCount+1, Address));
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED),
+ NB_CMD_ADD_NAME,
+ NULL,
+ NULL);
+
+ CTEStartTimer(
+ &Address->RegistrationTimer,
+ Address->Device->BroadcastTimeout,
+ NbiRegistrationTimeout,
+ (PVOID)Address);
+
+ } else {
+
+ //
+ // The correct number of frames have been sent, see what
+ // happened.
+ //
+
+ NB_DEBUG2 (ADDRESS, ("Done with add names for %lx\n", Address));
+
+ ReferencedAddressFile = NULL;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if ((Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) == 0) {
+ Address->State = ADDRESS_STATE_OPEN;
+ } else {
+ Address->State = ADDRESS_STATE_STOPPING;
+ }
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ CTEAssert (AddressFile->State == ADDRESSFILE_STATE_OPENING);
+ CTEAssert (AddressFile->OpenRequest != NULL);
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_TIMEOUT);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ //
+ // Now see what to do with this address file.
+ //
+
+ REQUEST_INFORMATION(AddressFile->OpenRequest) = 0;
+
+ if (Address->Flags & ADDRESS_FLAGS_DUPLICATE_NAME) {
+
+ NB_DEBUG (ADDRESS, ("Open of address file %lx failed, duplicate\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_DUPLICATE_NAME;
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ } else {
+
+ NB_DEBUG2 (ADDRESS, ("Complete open of address file %lx\n", AddressFile));
+ REQUEST_STATUS(AddressFile->OpenRequest) = STATUS_SUCCESS;
+ AddressFile->State = ADDRESSFILE_STATE_OPEN;
+
+ }
+
+ NbiCompleteRequest (AddressFile->OpenRequest);
+ NbiFreeRequest (Address->Device, AddressFile->OpenRequest);
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ ReferencedAddressFile = AddressFile;
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_TIMEOUT);
+ }
+
+ NbiDereferenceAddress (Address, AREF_TIMER);
+
+ }
+
+} /* NbiRegistrationTimeout */
+
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_FIND_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Quick check for any names starting with this character.
+ //
+
+ if (Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] == 0) {
+ return;
+ }
+
+ //
+ // Always respond to broadcast requests.
+ //
+#if defined(_PNP_POWER)
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ } else if ( NbiFindAdapterAddress( NbConnectionless->NameFrame.Name, LOCK_NOT_ACQUIRED ) ) {
+
+ NbiSendNameFrame(
+ NULL,
+ (UCHAR)(NB_NAME_UNIQUE | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ NbConnectionless);
+ }
+#else
+ if (RtlEqualMemory (NetbiosBroadcastName, NbConnectionless->NameFrame.Name, 16)) {
+
+ NbiSendNameFrame(
+ NULL,
+ NB_NAME_DUPLICATED, // this is what Novell machines use
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ } else if (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag | NB_NAME_USED | NB_NAME_REGISTERED),
+ NB_CMD_NAME_RECOGNIZED,
+ RemoteAddress,
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+#endif _PNP_POWER
+} /* NbiProcessFindName */
+
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_ADD_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PADDRESS Address;
+ NB_CONNECTIONLESS UNALIGNED * NbConnectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ BOOLEAN LocalFrame;
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // Ignore any frame that came from us, except for the purpose
+ // of updating the cache.
+ //
+
+ if ((Device->Bind.QueryHandler)(
+ IPX_QUERY_IS_ADDRESS_LOCAL,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ NbConnectionless->IpxHeader.SourceNetwork,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) == STATUS_SUCCESS) {
+
+ LocalFrame = TRUE;
+
+ } else {
+
+ LocalFrame = FALSE;
+
+ }
+
+ if (!LocalFrame) {
+
+ if ((Device->AddressCounts[NbConnectionless->NameFrame.Name[0]] != 0) &&
+ (Address = NbiFindAddress(Device, (PUCHAR)NbConnectionless->NameFrame.Name))) {
+
+ if (NB_NODE_BROADCAST(NbConnectionless->IpxHeader.DestinationNode)) {
+
+ //
+ // If this frame is an add name (identified because it is a
+ // broadcast frame) then respond if we have it registered
+ // unique, or we have it group and someone is trying to add
+ // it unique.
+ //
+
+ if ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) ||
+ ((Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP) &&
+ ((NbConnectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0))) {
+
+ //
+ // According to GeorgeJ's doc, on a name in use we just
+ // echo back the name type flags from the request.
+ //
+
+ NbiSendNameFrame(
+ Address,
+ NbConnectionless->NameFrame.NameTypeFlag,
+ NB_CMD_NAME_IN_USE,
+ RemoteAddress,
+#if defined(_PNP_POWER)
+ NbConnectionless);
+#else
+ (PTDI_ADDRESS_IPX)(NbConnectionless->IpxHeader.SourceNetwork));
+#endif _PNP_POWER
+ }
+
+ } else if ((*(UNALIGNED ULONG *)NbConnectionless->IpxHeader.DestinationNetwork ==
+ *(UNALIGNED ULONG *)Device->Bind.Network) &&
+ NB_NODE_EQUAL(NbConnectionless->IpxHeader.DestinationNode, Device->Bind.Node)) {
+
+ //
+ // If this is an add name response (which will be sent
+ // directly to us) then we need to mark the address
+ // as such.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+ Address->Flags |= ADDRESS_FLAGS_DUPLICATE_NAME;
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ }
+
+
+ //
+ // Pass this frame over to the netbios cache management
+ // routines to check if they need to update their cache.
+ //
+
+ CacheUpdateFromAddName (RemoteAddress, NbConnectionless, LocalFrame);
+
+} /* NbiProcessAddName */
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport address and associates it with
+ the specified transport device context. The reference count in the
+ address is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ NetbiosAddress - The name to assign to this address, or -1 if it
+ is the broadcast address.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+
+--*/
+
+{
+ PADDRESS Address;
+
+ Address = (PADDRESS)NbiAllocateMemory (sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+ if (Address == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address %.16s failed\n",
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address %lx (%.16s)\n", Address,
+ (NetbiosAddress == (PVOID)-1) ? "<broadcast>" : NetbiosAddress->NetbiosName));
+ RtlZeroMemory (Address, sizeof(ADDRESS));
+
+ Address->Type = NB_ADDRESS_SIGNATURE;
+ Address->Size = sizeof (ADDRESS);
+ Address->State = ADDRESS_STATE_REGISTERING;
+ Address->Flags = 0;
+
+ Address->Device = Device;
+ Address->DeviceLock = &Device->Lock;
+ CTEInitLock (&Address->Lock.Lock);
+
+ InitializeListHead (&Address->AddressFileDatabase);
+
+ Address->ReferenceCount = 1;
+#if DBG
+ Address->RefTypes[AREF_ADDRESS_FILE] = 1;
+#endif
+
+ if (NetbiosAddress == (PVOID)-1) {
+ Address->NetbiosAddress.Broadcast = TRUE;
+ } else {
+ Address->NetbiosAddress.Broadcast = FALSE;
+ Address->NetbiosAddress.NetbiosNameType = NetbiosAddress->NetbiosNameType;
+ RtlCopyMemory (Address->NetbiosAddress.NetbiosName, NetbiosAddress->NetbiosName, 16);
+ ++Device->AddressCounts[NetbiosAddress->NetbiosName[0]];
+ }
+
+ if (Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_UNIQUE) {
+ Address->NameTypeFlag = NB_NAME_UNIQUE;
+ } else {
+ Address->NameTypeFlag = NB_NAME_GROUP;
+ }
+
+ //
+ // Now link this address into the specified device context's
+ // address database. To do this, we need to acquire the spin lock
+ // on the device context.
+ //
+
+ InsertTailList (&Device->AddressDatabase, &Address->Linkage);
+ ++Device->AddressCount;
+
+ NbiReferenceDevice (Device, DREF_ADDRESS);
+
+ return Address;
+
+} /* NbiCreateAddress */
+
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid address file object. We also verify that the
+ address object pointed to by it is a valid address object, and reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ AddressFile - potential pointer to a ADDRESS_FILE object
+
+ ConflictIsOk - TRUE if we should succeed the verify even if the
+ corresponding address is in CONFLICT. ( For Close and
+ cleanup we return STATUS_SUCCESS even if we are in conflict
+ so that the addressfile can be destroyed)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_ADDRESS otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PADDRESS Address;
+ BOOLEAN LockHeld = FALSE;
+
+ //
+ // try to verify the address file signature. If the signature is valid,
+ // verify the address pointed to by it and get the address spinlock.
+ // check the address's state, and increment the reference count if it's
+ // ok to use it. Note that the only time we return an error for state is
+ // if the address is closing.
+ //
+
+ try {
+
+ if ((AddressFile->Size == sizeof (ADDRESS_FILE)) &&
+ (AddressFile->Type == NB_ADDRESSFILE_SIGNATURE) ) {
+// (AddressFile->State != ADDRESSFILE_STATE_CLOSING) ) {
+
+ Address = AddressFile->Address;
+
+ if ((Address->Size == sizeof (ADDRESS)) &&
+ (Address->Type == NB_ADDRESS_SIGNATURE) ) {
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+#if defined(_PNP_POWER)
+ if (Address->State != ADDRESS_STATE_STOPPING &&
+ ( ConflictIsOk || ( !(Address->Flags & ADDRESS_FLAGS_CONFLICT) )) ) {
+#else
+ if (Address->State != ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx closing\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: A %lx bad signature\n", Address);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } else {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx bad signature\n", AddressFile);
+ status = STATUS_INVALID_ADDRESS;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyAddressFile: AF %lx exception\n", Address);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyAddressFile */
+
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport address and removes all references
+ made by it to other objects in the transport. The address structure
+ is returned to nonpaged system pool. It is assumed
+ that the caller has already removed all addressfile structures associated
+ with this address.
+
+ It is called from a worker thread queue by NbiDerefAddress when
+ the reference count goes to 0.
+
+ This thread is only queued by NbiDerefAddress. The reason for
+ this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ Address - Pointer to a transport address structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS Address = (PADDRESS)Parameter;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address %lx <%.16s>\n", Address,
+ Address->NetbiosAddress.Broadcast ? "<broadcast>" : Address->NetbiosAddress.NetbiosName));
+
+ SeDeassignSecurity (&Address->SecurityDescriptor);
+
+ //
+ // Delink this address from its associated device context's address
+ // database. To do this we must spin lock on the device context object,
+ // not on the address.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!Address->NetbiosAddress.Broadcast) {
+ --Device->AddressCounts[Address->NetbiosAddress.NetbiosName[0]];
+ }
+ --Device->AddressCount;
+ RemoveEntryList (&Address->Linkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeMemory (Address, sizeof(ADDRESS), MEMORY_ADDRESS, "Address");
+
+ NbiDereferenceDevice (Device, DREF_ADDRESS);
+
+} /* NbiDestroyAddress */
+
+
+#if DBG
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+} /* NbiRefAddress */
+
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport address
+ when the device lock is already held.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (Address->ReferenceCount > 0); // not perfect, but...
+
+ InterlockedIncrement( &Address->ReferenceCount );
+
+} /* NbiRefAddressLock */
+#endif
+
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport address by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddress to remove it from the system.
+
+Arguments:
+
+ Address - Pointer to a transport address object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &Address->ReferenceCount );
+ //
+ // If we have deleted all references to this address, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+
+#if ISN_NT
+ ExInitializeWorkItem(
+ &Address->u.DestroyAddressQueueItem,
+ NbiDestroyAddress,
+ (PVOID)Address);
+ ExQueueWorkItem(&Address->u.DestroyAddressQueueItem, DelayedWorkQueue);
+#else
+ NbiDestroyAddress(Address);
+#endif
+
+ }
+
+} /* NbiDerefAddress */
+
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an address file from the pool of ther
+ specified device context. The reference count in the
+ address is automatically set to 1.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+Return Value:
+
+ The allocate address file or NULL.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PADDRESS_FILE AddressFile;
+ UINT i;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ AddressFile = (PADDRESS_FILE)NbiAllocateMemory (sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+ if (AddressFile == NULL) {
+ NB_DEBUG (ADDRESS, ("Create address file failed\n"));
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Create address file %lx\n", AddressFile));
+
+ RtlZeroMemory (AddressFile, sizeof(ADDRESS_FILE));
+
+ AddressFile->Type = NB_ADDRESSFILE_SIGNATURE;
+ AddressFile->Size = sizeof (ADDRESS_FILE);
+
+ InitializeListHead (&AddressFile->ReceiveDatagramQueue);
+ InitializeListHead (&AddressFile->ConnectionDatabase);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ AddressFile->Address = NULL;
+#ifdef ISN_NT
+ AddressFile->FileObject = NULL;
+#endif
+ AddressFile->Device = Device;
+ AddressFile->State = ADDRESSFILE_STATE_OPENING;
+ AddressFile->ReferenceCount = 1;
+#if DBG
+ AddressFile->RefTypes[AFREF_CREATE] = 1;
+#endif
+ AddressFile->CloseRequest = (PREQUEST)NULL;
+
+ //
+ // Initialize the request handlers.
+ //
+
+ for (i = 0; i < 6; i++) {
+ AddressFile->RegisteredHandler[i] = FALSE;
+ AddressFile->HandlerContexts[i] = NULL;
+ AddressFile->Handlers[i] = TdiDefaultHandlers[i];
+ }
+
+ CTEAssert (AddressFile->ConnectionHandler == TdiDefaultConnectHandler);
+ CTEAssert (AddressFile->DisconnectHandler == TdiDefaultDisconnectHandler);
+ CTEAssert (AddressFile->ErrorHandler == TdiDefaultErrorHandler);
+ CTEAssert (AddressFile->ReceiveHandler == TdiDefaultReceiveHandler);
+ CTEAssert (AddressFile->ReceiveDatagramHandler == TdiDefaultRcvDatagramHandler);
+ CTEAssert (AddressFile->ExpeditedDataHandler == TdiDefaultRcvExpeditedHandler);
+
+ return AddressFile;
+
+} /* NbiCreateAddressFile */
+
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys an address file and removes all references
+ made by it to other objects in the transport.
+
+ This routine is only called by NbiDereferenceAddressFile. The reason
+ for this is that there may be multiple streams of execution which are
+ simultaneously referencing the same address file object, and it should
+ not be deleted out from under an interested stream of execution.
+
+Arguments:
+
+ AddressFile Pointer to a transport address file structure to be destroyed.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle, LockHandle1;
+ PADDRESS Address;
+ PDEVICE Device;
+ PREQUEST CloseRequest;
+ BOOLEAN StopAddress;
+
+ NB_DEBUG2 (ADDRESS, ("Destroy address file %lx\n", AddressFile));
+
+ Address = AddressFile->Address;
+ Device = AddressFile->Device;
+
+ if (Address) {
+
+ //
+ // This addressfile was associated with an address.
+ //
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ //
+ // remove this addressfile from the address list and disassociate it from
+ // the file handle.
+ //
+
+ RemoveEntryList (&AddressFile->Linkage);
+ InitializeListHead (&AddressFile->Linkage);
+
+ if (Address->AddressFileDatabase.Flink == &Address->AddressFileDatabase) {
+
+ //
+ // This is the last open of this address, it will close
+ // due to normal dereferencing but we have to set the
+ // CLOSING flag too to stop further references.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle1);
+ Address->State = ADDRESS_STATE_STOPPING;
+ NB_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ StopAddress = TRUE;
+
+ } else {
+
+ StopAddress = FALSE;
+ }
+
+ AddressFile->Address = NULL;
+
+#ifdef ISN_NT
+ AddressFile->FileObject->FsContext = NULL;
+ AddressFile->FileObject->FsContext2 = NULL;
+#endif
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ //
+ // We will already have been removed from the ShareAccess
+ // of the owning address.
+ //
+
+ if (StopAddress && (!Address->NetbiosAddress.Broadcast)) {
+
+ NbiSendNameFrame(
+ Address,
+ (UCHAR)(Address->NameTypeFlag |
+ NB_NAME_USED | NB_NAME_REGISTERED | NB_NAME_DEREGISTERED),
+ NB_CMD_DELETE_NAME,
+ NULL,
+ NULL);
+ }
+
+ //
+ // Now dereference the owning address.
+ //
+
+ NbiDereferenceAddress (Address, AREF_ADDRESS_FILE);
+
+ }
+
+ //
+ // Save this for later completion.
+ //
+
+ CloseRequest = AddressFile->CloseRequest;
+
+ //
+ // return the addressFile to the pool of address files
+ //
+
+ NbiFreeMemory (AddressFile, sizeof(ADDRESS_FILE), MEMORY_ADDRESS, "AddressFile");
+
+ if (CloseRequest != (PREQUEST)NULL) {
+ REQUEST_INFORMATION(CloseRequest) = 0;
+ REQUEST_STATUS(CloseRequest) = STATUS_SUCCESS;
+ NbiCompleteRequest (CloseRequest);
+ NbiFreeRequest (Device, CloseRequest);
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiDestroyAddressFile */
+
+
+#if DBG
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+} /* NbiRefAddressFile */
+
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on an address file.
+ IT IS CALLED WITH THE ADDRESS LOCK HELD.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ CTEAssert (AddressFile->ReferenceCount > 0); // not perfect, but...
+
+
+ InterlockedIncrement( &AddressFile->ReferenceCount );
+
+} /* NbiRefAddressFileLock */
+
+#endif
+
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences an address file by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiDestroyAddressFile to remove it from the system.
+
+Arguments:
+
+ AddressFile - Pointer to a transport address file object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG newvalue;
+
+ newvalue = InterlockedDecrement( &AddressFile->ReferenceCount );
+
+ //
+ // If we have deleted all references to this address file, then we can
+ // destroy the object. It is okay to have already released the spin
+ // lock at this point because there is no possible way that another
+ // stream of execution has access to the address any longer.
+ //
+
+ CTEAssert (newvalue >= 0);
+
+ if (newvalue == 0) {
+ NbiDestroyAddressFile (AddressFile);
+ }
+
+} /* NbiDerefAddressFile */
+
+#if !defined(_PNP_POWER)
+
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NETWORK
+ NAME values. If an exact match is found, then a pointer to the
+ ADDRESS object is returned, and as a side effect, the reference
+ count to the address object is incremented. If the address is not
+ found, then NULL is returned.
+
+ NOTE: This routine must be called with the Device
+ spinlock held.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosAddress - The name to look up, or -1 if the broadcast
+ address is being searched for.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosAddress != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if (NetbiosAddress == (PVOID)-1) {
+ continue;
+ }
+
+ if (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+ }
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_LOOKUP);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ return NULL;
+
+} /* NbiLookupAddress */
+#endif !_PNP_POWER
+
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the transport addresses defined for the given
+ device context and compares them with the specified NetbiosName
+ values. If a match is found, the address is referenced and the
+ pointer is returned.
+
+ We ignore any addresses which are either STOPPING or are under
+ CONFLICT state.
+
+ A name in CONFLICT is dead for all practical purposes
+ except Close. This routine is called by various name service,
+ datagram and session sevice routines. We hide any names in CONFLICT
+ from these routines.
+
+ This routine is also called by NbiTdiOpenAddress().
+ A name could have been marked in CONFLICT ages ago(but is not closed
+ yet). We must allow another open of the same name as that might
+ succeed now.
+
+Arguments:
+
+ Device - Pointer to the device object and its extension.
+
+ NetbiosName - The name to look up, or -1 for the broadcast name.
+
+Return Value:
+
+ Pointer to the ADDRESS object found, or NULL if not found.
+
+--*/
+
+{
+ PADDRESS Address;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->AddressDatabase.Flink;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+#if defined(_PNP_POWER)
+ if ( ( Address->State == ADDRESS_STATE_STOPPING ) ||
+ ( Address->Flags & ADDRESS_FLAGS_CONFLICT ) ) {
+#else
+ if (Address->State == ADDRESS_STATE_STOPPING) {
+#endif _PNP_POWER
+ continue;
+ }
+
+ if (Address->NetbiosAddress.Broadcast) {
+
+ //
+ // This address is the broadcast one, so no match
+ // unless we are looking for that.
+ //
+
+ if (NetbiosName != (PVOID)-1) {
+ continue;
+ }
+
+ } else {
+
+ //
+ // This address is not the broadcast, so if we are
+ // looking for that then no match, else compare the
+ // two names.
+ //
+
+ if ((NetbiosName == (PVOID)-1) ||
+ (!RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ NetbiosName,
+ 16))) {
+ continue;
+ }
+ }
+
+
+ //
+ // We found the match. Bump the reference count on the address, and
+ // return a pointer to the address object for the caller to use.
+ //
+
+ NbiReferenceAddressLock (Address, AREF_FIND);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Address;
+
+ } /* for */
+
+ //
+ // The specified address was not found.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return NULL;
+
+} /* NbiFindAddress */
+
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to terminate all activity on an AddressFile and
+ destroy the object. We remove every connection and datagram associated
+ with this addressfile from the address database and terminate their
+ activity. Then, if there are no other outstanding addressfiles open on
+ this address, the address will go away.
+
+Arguments:
+
+ AddressFile - pointer to the addressFile to be stopped
+
+ Address - the owning address for this addressFile (we do not depend upon
+ the pointer in the addressFile because we want this routine to be safe)
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the request
+ is not for a real address.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = Address->Device;
+ CTELockHandle LockHandle1, LockHandle2;
+ LIST_ENTRY SendDatagramList;
+ PNB_SEND_RESERVED Reserved;
+ PREQUEST DatagramRequest;
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ LIST_ENTRY DatagramQ;
+
+
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ if (AddressFile->State == ADDRESSFILE_STATE_CLOSING) {
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ return STATUS_SUCCESS;
+ }
+
+
+ //
+ // This prevents anybody else from being put on the
+ // ConnectionDatabase.
+ //
+
+ AddressFile->State = ADDRESSFILE_STATE_CLOSING;
+
+ while (!IsListEmpty (&AddressFile->ConnectionDatabase)) {
+
+ p = RemoveHeadList (&AddressFile->ConnectionDatabase);
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ CTEAssert (Connection->AddressFile == AddressFile);
+ Connection->AddressFileLinked = FALSE;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // The refcount is already 0, so we can just
+ // NULL out this field to complete the disassociate.
+ //
+
+ Connection->AddressFile = NULL;
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ //
+ // Mark this so we know to disassociate when the
+ // count goes to 0, but that there is no specific
+ // request pending on it. We also stop the connection
+ // to shut it down.
+ //
+
+ Connection->DisassociatePending = (PVOID)-1;
+ NbiReferenceConnectionLock (Connection, CREF_DISASSOC);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle3);
+
+ //
+ // This call frees the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle3));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_DISASSOC);
+
+ }
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Abort all pending send datagrams.
+ //
+ // BUGBUG: Also make them cancellable.
+ //
+
+ InitializeListHead (&SendDatagramList);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ if (Reserved->u.SR_DG.AddressFile == AddressFile) {
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&SendDatagramList, &Reserved->WaitLinkage);
+
+ }
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ for (p = SendDatagramList.Flink; p != &SendDatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Aborting datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+
+ //
+ // Abort all pending receive datagrams.
+ //
+
+ InitializeListHead( &DatagramQ );
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ while (!IsListEmpty(&AddressFile->ReceiveDatagramQueue)) {
+
+ p = RemoveHeadList (&AddressFile->ReceiveDatagramQueue);
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ // Insert it on a private Q, so it can be completed later.
+ InsertTailList( &DatagramQ, p);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_NETWORK_NAME_DELETED;
+
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ for( p = DatagramQ.Flink; p != &DatagramQ; ) {
+ Request = LIST_ENTRY_TO_REQUEST ( p );
+
+ p = p->Flink;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ }
+
+
+ return STATUS_SUCCESS;
+
+} /* NbiStopAddressFile */
+
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close the addressfile pointed to by a file
+ object. If there is any activity to be run down, we will run it down
+ before we terminate the addressfile. We remove every connection and
+ datagram associated with this addressfile from the address database
+ and terminate their activity. Then, if there are no other outstanding
+ addressfiles open on this address, the address will go away.
+
+Arguments:
+
+ Request - the close request.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well, STATUS_INVALID_HANDLE if the
+ request does not point to a real address.
+
+--*/
+
+{
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ AddressFile->CloseRequest = Request;
+
+ //
+ // We assume that addressFile has already been verified
+ // at this point.
+ //
+
+ Address = AddressFile->Address;
+ CTEAssert (Address);
+
+ //
+ // Remove us from the access info for this address.
+ //
+
+ ExAcquireResourceExclusive (&Device->AddressResource, TRUE);
+#ifdef ISN_NT
+ IoRemoveShareAccess (AddressFile->FileObject, &Address->u.ShareAccess);
+#endif
+ ExReleaseResource (&Device->AddressResource);
+
+ NbiStopAddressFile (AddressFile, Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_CREATE);
+
+ return STATUS_PENDING;
+
+} /* NbiCloseAddressFile */
+
+#if defined(_PNP_POWER)
+
+
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an adapter address sttuctures which stores
+ the netbios name of an adapter. the netbios name has 12 0's
+ followed by the mac address of the adapter.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ address.
+
+ AdapterMacAddress - pointer to the adapter mac address given to us
+ by IPX.
+
+Return Value:
+
+ The newly created address, or NULL if none can be allocated.
+ THIS ROUTINE MUST BE CALLED WITH THE DEVICE LOCK HELD.
+
+--*/
+
+{
+ PADAPTER_ADDRESS AdapterAddress;
+ CTELockHandle LockHandle;
+ PDEVICE Device = NbiDevice;
+
+ AdapterAddress = (PADAPTER_ADDRESS)NbiAllocateMemory (sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "Adapter Address");
+ if (AdapterAddress == NULL) {
+ NB_DEBUG (ADDRESS, ("Create Adapter Address %<2.2x><2.2x><2.2x><2.2x><2.2x><2.2x> failed\n",
+ AdapterMacAddress[0],
+ AdapterMacAddress[1],
+ AdapterMacAddress[2],
+ AdapterMacAddress[3],
+ AdapterMacAddress[4],
+ AdapterMacAddress[5]
+ ));
+ return NULL;
+ }
+
+ AdapterAddress->Type = NB_ADAPTER_ADDRESS_SIGNATURE;
+ AdapterAddress->Size = sizeof (ADDRESS);
+
+ RtlZeroMemory(AdapterAddress->NetbiosName, 10);
+ RtlCopyMemory(&AdapterAddress->NetbiosName[10], AdapterMacAddress, 6);
+
+
+ InsertTailList (&Device->AdapterAddressDatabase, &AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ return AdapterAddress;
+
+} /* NbiCreateAdapterAddress */
+
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the adapter address structure and removes it
+ from the list.
+
+Arguments:
+
+ AdapterAddress - Pointer to an adapter address structure to be destroyed
+ NULL if AdapterMacAddress is given.
+
+ AdapterMacAddress - Mac Address of the adapter which just got deleted. so find
+ the corresponding adapter address structure and remove it.
+ NULL if AdapterAddress is supplied.
+
+Return Value:
+
+ STATUS_SUCCESS or STATUS_UNSUCCESSFUL if address not found.
+
+ THIS ROUTINE ASSUMES THE THE DEVICE IS LOCK IS HELD BY THE CALLER
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ UCHAR NetbiosName[NB_NETBIOS_NAME_SIZE];
+
+
+ //
+
+ CTEAssert( AdapterAddress || AdapterMacAddress );
+ if ( !AdapterAddress ) {
+ RtlZeroMemory( NetbiosName, 10);
+ RtlCopyMemory( &NetbiosName[10], AdapterMacAddress, 6 );
+
+ AdapterAddress = NbiFindAdapterAddress( NetbiosName, LOCK_ACQUIRED );
+
+ if ( !AdapterAddress ) {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ NB_DEBUG2 (ADDRESS, ("Destroy Adapter address %lx <%.16s>\n", AdapterAddress,AdapterAddress->NetbiosName));
+ RemoveEntryList (&AdapterAddress->Linkage);
+ ++Device->AddressCounts[AdapterAddress->NetbiosName[0]];
+
+ NbiFreeMemory (AdapterAddress, sizeof(ADAPTER_ADDRESS), MEMORY_ADAPTER_ADDRESS, "AdapterAddress");
+
+ return STATUS_SUCCESS;
+} /* NbiDestroyAdapterAddress */
+
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds an adapter address ( netbios name ) for the given
+ AdapterMacAddress and returns a pointer to it. Note that no reference
+ is done on this address, so if this routine is called without the device
+ lock, the caller must not use this pointer directly.
+
+Arguments:
+
+ NetbiosName - NetbiosName to be found.
+
+ LockHeld - is device lock already held or not.
+
+Return Value:
+
+ Pointer to the adapter address if found, NULL otherwise.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+ PADAPTER_ADDRESS AdapterAddress;
+ PDEVICE Device = NbiDevice;
+
+
+ if ( !LockHeld ) {
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ }
+ for ( p = Device->AdapterAddressDatabase.Flink;
+ p != &Device->AdapterAddressDatabase;
+ p = p->Flink ) {
+
+ AdapterAddress = CONTAINING_RECORD( p, ADAPTER_ADDRESS, Linkage );
+ if ( RtlEqualMemory(
+ NetbiosName,
+ AdapterAddress->NetbiosName,
+ NB_NETBIOS_NAME_SIZE ) ) {
+ break;
+ }
+ }
+
+
+ if ( !LockHeld ) {
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+ }
+
+ if ( p == &Device->AdapterAddressDatabase ) {
+ return NULL;
+ } else {
+ return AdapterAddress;
+ }
+
+} /* NbiFindAdapterAddress */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/nb/autodial.c b/private/ntos/tdi/isnp/nb/autodial.c
new file mode 100644
index 000000000..ec56e2351
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/autodial.c
@@ -0,0 +1,526 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ autodial.c
+
+Abstract:
+
+ NT specific routines for interfacing with the
+ RAS AutoDial driver (rasacd.sys).
+
+Author:
+
+ Anthony Discolo (adiscolo) Aug 30, 1995
+
+Revision History:
+
+ Who When What
+ -------- -------- ----------------------------------------------
+ adiscolo 08-30-95 created
+
+Notes:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+
+#include <acd.h>
+#include <acdapi.h>
+
+//
+// Global variables
+//
+BOOLEAN fAcdLoadedG;
+ACD_DRIVER AcdDriverG;
+ULONG ulDriverIdG = 'Nbi ';
+
+
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called indirectly by the automatic
+ connection driver to continue the connection process
+ after an automatic connection has been made.
+
+Arguments:
+
+ fSuccess - TRUE if the connection attempt was successful.
+
+ pArgs - a pointer to the argument vector
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE pDevice = pArgs[0];
+ PCONNECTION pConnection = pArgs[1];
+ PREQUEST pRequest = pArgs[2];
+ CTELockHandle ConnectionLH, DeviceLH;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+#if notdef // DBG
+ DbgPrint("NbiRetryTdiConnect: fSuccess=%d, pConnection=0x%x\n", fSuccess, pConnection);
+#endif
+
+ status = NbiVerifyConnection(pConnection);
+ if (!NT_SUCCESS(status)) {
+ DbgPrint(
+ "NbiRetryTdiConnect: NbiVerifyConnection failed on connection 0x%x (status=0x%x)\n",
+ pConnection,
+ status);
+ return;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&pConnection->Lock, &ConnectionLH);
+ NB_GET_LOCK (&pDevice->Lock, &DeviceLH);
+
+#if notdef // DBG
+ DbgPrint(
+ "NbiRetryTdiConnect: AddressFile=0x%x, DisassociatePending=0x%x, ClosePending=0x%x\n",
+ pConnection->AddressFile,
+ pConnection->DisassociatePending,
+ pConnection->ClosePending);
+#endif
+
+ if ((pConnection->AddressFile != NULL) &&
+ (pConnection->AddressFile != (PVOID)-1) &&
+ (pConnection->DisassociatePending == NULL) &&
+ (pConnection->ClosePending == NULL))
+ {
+ NbiReferenceConnectionLock(pConnection, CREF_CONNECT);
+ //
+ // Clear the AUTOCONNECTING flag since we
+ // done with the automatic connection attempt.
+ // Set the AUTOCONNECTED flag to prevent us
+ // from attempting an automatic connection
+ // for this connection again.
+ //
+ pConnection->Flags &= ~CONNECTION_FLAGS_AUTOCONNECTING;
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTED;
+
+ pConnection->State = CONNECTION_STATE_CONNECTING;
+ pConnection->Retries = pDevice->ConnectionCount;
+ status = NbiTdiConnectFindName(
+ pDevice,
+ pRequest,
+ pConnection,
+ CancelLH,
+ ConnectionLH,
+ DeviceLH,
+ &bLockFreed);
+ }
+ else {
+ DbgPrint("NbiRetryTdiConnect: Connect on invalid connection 0x%x\n", pConnection);
+
+ pConnection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&pDevice->Lock, DeviceLH);
+ status = STATUS_INVALID_CONNECTION;
+ }
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&pConnection->Lock, ConnectionLH);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+ }
+ //
+ // Complete the irp if necessary.
+ //
+ if (status != STATUS_PENDING) {
+ REQUEST_INFORMATION(pRequest) = 0;
+ REQUEST_STATUS(pRequest) = status;
+
+ NbiCompleteRequest(pRequest);
+ NbiFreeRequest(pDevice, pRequest);
+ }
+ NbiDereferenceConnection(pConnection, CREF_VERIFY);
+} /* NbiRetryTdiConnect */
+
+
+
+BOOLEAN
+NbiCancelAutoDialRequest(
+ IN PVOID pArg,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN USHORT nArgs,
+ IN PVOID *pArgs
+ )
+{
+#if notdef // DBG
+ DbgPrint("NbiCancelAutodialRequest: pArg=0x%x\n", pArg);
+#endif
+ if (nArgs != 2)
+ return FALSE;
+
+ return (pArgs[1] == pArg);
+} // NbiCancelAutoDialRequest
+
+
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ )
+
+/*++
+
+DESCRIPTION
+ This routine is called by the I/O system to cancel a connection
+ when we are attempting to restore an automatic connection.
+
+ARGUMENTS
+ pDevice: a pointer to the device object for this driver
+
+ pRequest: a pointer to the irp to be cancelled
+
+ pConnection: a pointer to the connnection to be cancelled
+
+RETURN VALUE
+ TRUE if the request was canceled; FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint(
+ "NbiCancelTdiConnect: pIrp=0x%x, RemoteName=%-15.15s, pConnection=0x%x\n",
+ pRequest,
+ addr.cNetbios,
+ pConnection);
+#endif
+ //
+ // Cancel the autodial request.
+ //
+ return (*AcdDriverG.lpfnCancelConnection)(
+ ulDriverIdG,
+ &addr,
+ NbiCancelAutoDialRequest,
+ pConnection);
+} // NbiCancelTdiConnect
+
+
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ )
+
+/*++
+
+Routine Description:
+
+ Call the automatic connection driver to attempt an
+ automatic connection.
+
+Arguments:
+
+ pDevice - a pointer to the DEVICE structure for this connection
+
+ pConnection - a pointer to the CONNECTION block for this connection
+
+ ulFlags - connection flags to pass to the automatic
+ connection driver
+
+ pProc - a callback procedure when the automatic connection completes
+
+ pRequest - a pointer to the request irp
+
+Return Value:
+
+ TRUE if the automatic connection was started successfully,
+ FALSE otherwise.
+
+--*/
+
+{
+ ACD_ADDR addr;
+ PVOID pArgs[3];
+ BOOLEAN bSuccess;
+
+ //
+ // If we've already attempted an automatic connection
+ // on this connection, don't try it again.
+ //
+ if (pConnection->Flags & CONNECTION_FLAGS_AUTOCONNECTED)
+ return FALSE;
+ //
+ // Get the address of the connection.
+ //
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+#ifdef notdef // DBG
+ DbgPrint("NbiAttemptAutoDial: szAddr=%15.15s\n", addr.cNetbios);
+#endif
+ //
+ // Attempt to start the connection.
+ // NbiRetryTdiConnect() will be called
+ // when the connection process has completed.
+ //
+ pArgs[0] = pDevice;
+ pArgs[1] = pConnection;
+ pArgs[2] = pRequest;
+ bSuccess = (*AcdDriverG.lpfnStartConnection)(
+ ulDriverIdG,
+ &addr,
+ ulFlags,
+ pProc,
+ 3,
+ pArgs);
+ if (bSuccess) {
+ //
+ // Set the AUTOCONNECTING flag so we know
+ // to also cancel the connection in the
+ // automatic connection driver if this
+ // request gets canceled.
+ //
+ pConnection->Flags |= CONNECTION_FLAGS_AUTOCONNECTING;
+ }
+} // NbiAttemptAutoDial
+
+
+
+VOID
+NbiNoteNewConnection(
+ IN PCONNECTION pConnection
+ )
+{
+ NTSTATUS status;
+ ACD_ADDR addr;
+ ACD_ADAPTER adapter;
+ ULONG i;
+ TDI_ADDRESS_IPX tdiIpxAddress;
+
+ addr.fType = ACD_ADDR_NB;
+ RtlCopyMemory(&addr.cNetbios, pConnection->RemoteName, 16);
+ //
+ // Determine the mac address of the adapter
+ // over which the connection has been made.
+ //
+ status = (pConnection->Device->Bind.QueryHandler)(
+ IPX_QUERY_IPX_ADDRESS,
+#if defined(_PNP_POWER)
+ &pConnection->LocalTarget.NicHandle,
+#else
+ pConnection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &tdiIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+ if (status != STATUS_SUCCESS) {
+#if notdef // DBG
+ DbgPrint("NbiNoteNewConnection: QueryHandler(IPX_QUERY_IPX_ADDRESS) failed (status=0x%x)\n", status);
+ return;
+#endif
+ }
+ //
+ // Copy the source mac address to identify
+ // the adapter.
+ //
+ adapter.fType = ACD_ADAPTER_MAC;
+ for (i = 0; i < 6; i++)
+ adapter.cMac[i] = tdiIpxAddress.NodeAddress[i];
+#if notdef // DBG
+ DbgPrint(
+ "NbiNoteNewConnection: address=%-15.15s, remote mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr.cNetbios,
+ adapter.cMac[0],
+ adapter.cMac[1],
+ adapter.cMac[2],
+ adapter.cMac[3],
+ adapter.cMac[4],
+ adapter.cMac[5]);
+#endif
+ //
+ // Simply notify the automatic connection driver
+ // that a successful connection has been made.
+ //
+ (*AcdDriverG.lpfnNewConnection)(
+ &addr,
+ &adapter);
+} // NbiNoteNewConnection
+
+
+
+VOID
+NbiAcdBind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Initialize our part of the ACD_DRIVER
+ // structure.
+ //
+ KeInitializeSpinLock(&AcdDriverG.SpinLock);
+ AcdDriverG.ulDriverId = ulDriverIdG;
+ AcdDriverG.fEnabled = FALSE;
+ //
+ // Build a request to get the automatic
+ // connection driver entry points.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_BIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ fAcdLoadedG = (status == STATUS_SUCCESS);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdBind
+
+
+
+VOID
+NbiAcdUnbind()
+{
+ NTSTATUS status;
+ UNICODE_STRING nameString;
+ IO_STATUS_BLOCK ioStatusBlock;
+ PIRP pIrp;
+ PFILE_OBJECT pAcdFileObject;
+ PDEVICE_OBJECT pAcdDeviceObject;
+ PACD_DRIVER pDriver = &AcdDriverG;
+
+ //
+ // Don't bother to unbind if we
+ // didn't successfully bind in the
+ // first place.
+ //
+ if (!fAcdLoadedG)
+ return;
+ //
+ // Initialize the name of the automatic
+ // connection device.
+ //
+ RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
+ //
+ // Get the file and device objects for the
+ // device.
+ //
+ status = IoGetDeviceObjectPointer(
+ &nameString,
+ SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
+ &pAcdFileObject,
+ &pAcdDeviceObject);
+ if (status != STATUS_SUCCESS)
+ return;
+ //
+ // Reference the device object.
+ //
+ ObReferenceObject(pAcdDeviceObject);
+ //
+ // Remove the reference IoGetDeviceObjectPointer()
+ // put on the file object.
+ //
+ ObDereferenceObject(pAcdFileObject);
+ //
+ // Build a request to unbind from
+ // the automatic connection driver.
+ //
+ pIrp = IoBuildDeviceIoControlRequest(
+ IOCTL_INTERNAL_ACD_UNBIND,
+ pAcdDeviceObject,
+ (PVOID)&pDriver,
+ sizeof (pDriver),
+ NULL,
+ 0,
+ TRUE,
+ NULL,
+ &ioStatusBlock);
+ if (pIrp == NULL) {
+ ObDereferenceObject(pAcdDeviceObject);
+ return;
+ }
+ //
+ // Submit the request to the
+ // automatic connection driver.
+ //
+ status = IoCallDriver(pAcdDeviceObject, pIrp);
+ //
+ // Close the device.
+ //
+ ObDereferenceObject(pAcdDeviceObject);
+} // NbiAcdUnbind
+
+#endif // RASAUTODIAL
diff --git a/private/ntos/tdi/isnp/nb/bind.c b/private/ntos/tdi/isnp/nb/bind.c
new file mode 100644
index 000000000..7dc20d0d5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/bind.c
@@ -0,0 +1,593 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiBind)
+#endif
+
+#if defined(_PNP_POWER)
+//
+// local functions.
+//
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine binds the Netbios module of ISN to the IPX
+ module, which provides the NDIS binding services.
+
+Arguments:
+
+ Device - Pointer to the Netbios device.
+
+ Config - Pointer to the configuration information.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+/* union {
+ IPX_INTERNAL_BIND_INPUT Input;
+ IPX_INTERNAL_BIND_OUTPUT Output;
+ } Bind;
+*/
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &Config->BindName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = ZwCreateFile(
+ &Device->BindHandle,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0L);
+
+ if (!NT_SUCCESS(Status)) {
+
+ NB_DEBUG (BIND, ("Could not open IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ return Status;
+ }
+
+ //
+ // Fill in our bind data.
+ //
+
+#if defined(_PNP_POWER)
+ Device->BindInput.Version = ISN_VERSION;
+#else
+ Device->BindInput.Version = 1;
+#endif _PNP_POWER
+ Device->BindInput.Identifier = IDENTIFIER_NB;
+ Device->BindInput.BroadcastEnable = TRUE;
+ Device->BindInput.LookaheadRequired = 192;
+ Device->BindInput.ProtocolOptions = 0;
+ Device->BindInput.ReceiveHandler = NbiReceive;
+ Device->BindInput.ReceiveCompleteHandler = NbiReceiveComplete;
+ Device->BindInput.StatusHandler = NbiStatus;
+ Device->BindInput.SendCompleteHandler = NbiSendComplete;
+ Device->BindInput.TransferDataCompleteHandler = NbiTransferDataComplete;
+ Device->BindInput.FindRouteCompleteHandler = NbiFindRouteComplete;
+ Device->BindInput.LineUpHandler = NbiLineUp;
+ Device->BindInput.LineDownHandler = NbiLineDown;
+ Device->BindInput.ScheduleRouteHandler = NULL;
+#if defined(_PNP_POWER)
+ Device->BindInput.PnPHandler = NbiPnPNotification;
+#endif _PNP_POWER
+
+
+ Status = ZwDeviceIoControlFile(
+ Device->BindHandle, // HANDLE to File
+ NULL, // HANDLE to Event
+ NULL, // ApcRoutine
+ NULL, // ApcContext
+ &IoStatusBlock, // IO_STATUS_BLOCK
+ IOCTL_IPX_INTERNAL_BIND, // IoControlCode
+ &Device->BindInput, // Input Buffer
+ sizeof(Device->BindInput), // Input Buffer Length
+ &Device->Bind, // OutputBuffer
+ sizeof(Device->Bind)); // OutputBufferLength
+
+ //
+ // We open synchronous, so this shouldn't happen.
+ //
+
+ CTEAssert (Status != STATUS_PENDING);
+
+ //
+ // Save the bind data.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (BIND, ("Successfully bound to IPX (%ws)\n",
+ Config->BindName.Buffer));
+// RtlCopyMemory (&Device->Bind, &Bind.Output, sizeof(IPX_INTERNAL_BIND_OUTPUT));
+
+#if !defined(_PNP_POWER)
+ RtlZeroMemory (Device->ReservedNetbiosName, 16);
+ RtlCopyMemory (&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAXIMUM_NIC_ID,
+ (USHORT)0,
+ &Device->MaximumNicId,
+ sizeof(Device->MaximumNicId),
+ NULL);
+ CTEAssert (Status == STATUS_SUCCESS);
+#endif !_PNP_POWER
+
+ } else {
+
+ NB_DEBUG (BIND, ("Could not bind to IPX (%ws) %lx\n",
+ Config->BindName.Buffer, Status));
+ NbiWriteGeneralErrorLog(
+ Device,
+ EVENT_TRANSPORT_BINDING_FAILED,
+ 1,
+ Status,
+ Config->BindName.Buffer,
+ 0,
+ NULL);
+ ZwClose(Device->BindHandle);
+ }
+
+ return Status;
+
+} /* NbiBind */
+
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the binding between the Netbios over
+ IPX module and the IPX module previously established by
+ NbiBind.
+
+Arguments:
+
+ Device - The netbios device object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ZwClose (Device->BindHandle);
+
+} /* NbiUnbind */
+
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives a status indication from IPX,
+ corresponding to a status indication from an underlying
+ NDIS driver.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ GeneralStatus - The general status code.
+
+ StatusBuffer - The status buffer.
+
+ StatusBufferLength - The length of the status buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiStatus */
+
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line up indications from IPX,
+ indicating that the specified adapter is now up with
+ the characteristics shown.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+ LineInfo - Information about the adapter's medium.
+
+ DeviceType - The type of the adapter.
+
+ ConfigurationData - IPX-specific configuration data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIPXCP_CONFIGURATION Configuration = (PIPXCP_CONFIGURATION)ConfigurationData;
+
+ //
+ // Update queries have NULL as the ConfigurationData. These
+ // only indicate changes in LineInfo. BUGBUG Ignore these
+ // for the moment.
+ //
+
+ if (Configuration == NULL) {
+ return;
+ }
+
+#if !defined(_PNP_POWER)
+ //
+ // Since Netbios outgoing queries only go out on network 1,
+ // we ignore this (BUGBUG for the moment) unless that is
+ // the NIC it is on.
+ //
+
+ if (NicId == 1) {
+
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNetwork, Configuration->Network, 4);
+ RtlCopyMemory(NbiDevice->ConnectionlessHeader.SourceNode, Configuration->LocalNode, 6);
+
+ }
+#endif !_PNP_POWER
+} /* NbiLineUp */
+
+
+VOID
+NbiLineDown(
+ IN USHORT NicId
+ )
+
+
+/*++
+
+Routine Description:
+
+ This function receives line down indications from IPX,
+ indicating that the specified adapter is no longer
+ up.
+
+Arguments:
+
+ NicId - The NIC ID of the underlying adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+} /* NbiLineDown */
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiPnPNotification(
+ IN IPX_PNP_OPCODE OpCode,
+ IN PVOID PnPData
+ )
+
+/*++
+
+Routine Description:
+
+ This function receives the notification about PnP events from IPX.
+
+Arguments:
+
+ OpCode - Type of the PnP event
+
+ PnPData - Data associated with this event.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT MaximumNicId = 0;
+ CTELockHandle LockHandle;
+ UCHAR PrevReservedName[NB_NETBIOS_NAME_SIZE];
+ UNICODE_STRING UnicodeDeviceName;
+
+
+ NB_DEBUG2( DEVICE, ("Received a pnp notification, opcode %d\n",OpCode ));
+
+ switch( OpCode ) {
+ case IPX_PNP_ADD_DEVICE : {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ BOOLEAN ReallocReceiveBuffers = FALSE;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ if ( PnPInfo->NewReservedAddress ) {
+
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+// RtlZeroMemory(Device->ReservedNetbiosName, NB_NETBIOS_NAME_SIZE);
+// RtlCopyMemory(&Device->ReservedNetbiosName[10], Device->Bind.Node, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+ }
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ CTEAssert( PnPInfo->NewReservedAddress );
+ CTEAssert( Device->State != DEVICE_STATE_OPEN );
+
+
+ //
+ // we must do this while we still have the device lock.
+ //
+ if ( !Device->LongTimerRunning ) {
+ Device->LongTimerRunning = TRUE;
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ }
+
+ Device->State = DEVICE_STATE_OPEN;
+
+ CTEAssert( !Device->MaximumNicId );
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize;
+ ReallocReceiveBuffers = TRUE;
+ } else {
+ if ( PnPInfo->LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+ ReallocReceiveBuffers = TRUE;
+ }
+ //
+ // MaxSendSize could become smaller.
+ //
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+ }
+
+ Device->MaximumNicId++;
+
+
+ //
+ //
+ NbiCreateAdapterAddress( PnPInfo->NodeAddress );
+
+ //
+ // And finally remove all the failed cache entries since we might
+ // find those routes using this new adapter
+ //
+ FlushFailedNetbiosCacheEntries(Device->NameCache);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ if ( ReallocReceiveBuffers ) {
+ PWORK_QUEUE_ITEM WorkItem;
+
+ WorkItem = NbiAllocateMemory( sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buffer work item");
+
+ if ( WorkItem ) {
+ ExInitializeWorkItem( WorkItem, NbiReAllocateReceiveBufferPool, (PVOID) WorkItem );
+ ExQueueWorkItem( WorkItem, DelayedWorkQueue );
+ } else {
+ NB_DEBUG( DEVICE, ("Cannt schdule work item to realloc receive buffer pool\n"));
+ }
+ }
+ //
+ // Notify the TDI clients about the device creation
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ UnicodeDeviceName.Buffer = Device->DeviceName;
+ UnicodeDeviceName.MaximumLength = Device->DeviceNameLength;
+ UnicodeDeviceName.Length = Device->DeviceNameLength - sizeof(WCHAR);
+
+ if ( !NT_SUCCESS( TdiRegisterDeviceObject(
+ &UnicodeDeviceName,
+ &Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to register nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_DELETE_DEVICE : {
+
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ CTEAssert( Device->MaximumNicId );
+ Device->MaximumNicId--;
+
+ if ( PnPInfo->FirstORLastDevice ) {
+ Device->State = DEVICE_STATE_LOADED;
+ Device->MaximumNicId = 0;
+
+ }
+
+
+ //
+ // MaximumSendSize could change if the card with the smallest send size just
+ // got removed. MaximumPacketSize could only become smaller and we ignore that
+ // since we dont need to(want to) realloc ReceiveBuffers.
+ //
+
+ Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+ RemoveInvalidRoutesFromNetbiosCacheTable( Device->NameCache, &PnPInfo->NicHandle );
+
+ NbiDestroyAdapterAddress( NULL, PnPInfo->NodeAddress );
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+/* //
+ // Now mark the previous reserved name in conflict if it has
+ // been registered by any of our client
+ //
+ if ( Address = NbiFindAddress( Device, PrevReservedName ) ) {
+ NB_GET_LOCK( &Address->Lock, &LockHandle );
+ Address->Flags |= ADDRESS_FLAGS_CONFLICT;
+ NB_FREE_LOCK( &Address->Lock, LockHandle );
+
+ NB_DEBUG( ADDRESS, ("Reserved Address %lx<%.16s> is marked CONFLICT\n",Address,Address->NetbiosAddress.NetbiosName));
+ //
+ // nbifindaddress added a reference, so deref
+ //
+ NbiDereferenceAddress( Address, AREF_FIND );
+ }
+*/
+
+ //
+ // inform tdi clients about the device deletion
+ //
+ if ( PnPInfo->FirstORLastDevice ) {
+ if ( !NT_SUCCESS( TdiDeregisterDeviceObject(
+ Device->TdiRegistrationHandle ) )) {
+ NB_DEBUG( DEVICE, ("Failed to Deregister nwlnknb with TDI\n"));
+ }
+ }
+
+ break;
+ }
+ case IPX_PNP_ADDRESS_CHANGE: {
+ IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
+ PADDRESS Address;
+ BOOLEAN ReservedNameClosing = FALSE;
+
+ CTEAssert( PnPInfo->NewReservedAddress );
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+ *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress;
+ RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
+
+ *(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network;
+ RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+
+ break;
+ }
+ case IPX_PNP_TRANSLATE_DEVICE:
+ break;
+ case IPX_PNP_TRANSLATE_ADDRESS:
+ break;
+ default:
+ CTEAssert( FALSE );
+ }
+} /* NbiPnPNotification */
+
+#endif _PNP_POWER
diff --git a/private/ntos/tdi/isnp/nb/cache.c b/private/ntos/tdi/isnp/nb/cache.c
new file mode 100644
index 000000000..cbd27ad67
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/cache.c
@@ -0,0 +1,2746 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ cache.c
+
+Abstract:
+
+ This module contains the name cache routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 20-December-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+BOOLEAN
+NbiAttemptAutoDial(
+ IN PDEVICE pDevice,
+ IN PCONNECTION pConnection,
+ IN ULONG ulFlags,
+ IN ACD_CONNECT_CALLBACK pProc,
+ IN PREQUEST pRequest
+ );
+
+VOID
+NbiRetryTdiConnect(
+ IN BOOLEAN fSuccess,
+ IN PVOID *pArgs
+ );
+#endif // RASAUTODIAL
+
+//
+// BUGBUG: We should change to monitor add name packets better,
+// so if we get an add for a different place we attempt to determine
+// if it is real or bogus and update if possible.
+//
+
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+)
+
+/*++
+
+Routine Description:
+
+ This routine looks up a particular remote name in the
+ Netbios name cache. If it cannot find it, a find name
+ request is queued up.
+
+ THIS REQUEST IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Type - Defines the type. The effect this has is:
+ FindNameConnect - On connects we will ignore an existing
+ cache entry if it got no response before.
+ FindNameNetbiosFindName - For these we ignore an existing
+ cache entry if it is for a group name -- this is
+ because the find name wants the address of every
+ machine, not just the network list.
+ FindNameOther - Normal handling is done.
+
+ RemoteName - The name to be discovered -- will be NULL if it
+ is the broadcast address.
+
+ CacheName - Returns the cache entry that was discovered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE FoundCacheName;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR RealRemoteName; // RemoteName or NetbiosBroadcastName
+
+ //
+ // First scan the netbios name cache to see if we know
+ // about this remote.
+ //
+
+ if (RemoteName) {
+ RealRemoteName = RemoteName;
+ } else {
+ RealRemoteName = NetbiosBroadcastName;
+ }
+
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ RealRemoteName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // If this is a netbios find name, we only can use unique
+ // names in the cache; for the group ones we need to requery
+ // because the cache only lists networks, not individual machines.
+ // For connect requests, if we find an empty cache entry we
+ // remove it and requery.
+ //
+
+ if ( FoundCacheName->Unique || (Type != FindNameNetbiosFindName) ) {
+
+ if (FoundCacheName->NetworksUsed > 0) {
+
+ *CacheName = FoundCacheName;
+ NB_DEBUG2 (CACHE, ("Found cache name <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_SUCCESS;
+
+ } else {
+
+ if (Type != FindNameConnect) {
+
+ if (FoundCacheName->FailedOnDownWan) {
+ NB_DEBUG2 (CACHE, ("Found cache name, but down wan <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ } else {
+ NB_DEBUG2 (CACHE, ("Found cache name, but no nets <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ } else {
+
+ //
+ // This is a connect and the current cache entry
+ // has zero names; delete it.
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+ CTEAssert (FoundCacheName->ReferenceCount == 1);
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free unneeded empty cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+ }
+
+ }
+ }
+ }
+ }
+
+
+ //
+ // There was no suitable cache entry for this network, first see
+ // if there is one pending.
+ //
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // For this purpose we ignore a packet if a route
+ // has been found and it was for a unique name. This
+ // is because the cache information has already been
+ // inserted for this name. Otherwise if the name has
+ // since been deleted from the cache, the request
+ // that is looking for this name will starve because
+ // FindNameTimeout will just destroy the packet.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+ continue;
+ }
+
+ if (RtlEqualMemory(
+ Reserved->u.SR_FN.NetbiosName,
+ RealRemoteName, 16)) {
+
+ NB_DEBUG2 (CACHE, ("Cache name already pending <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+
+ //
+ // There is already one pending. If it is for a group
+ // name and this is a netbios find name, we make sure
+ // the retry count is such that at least one more
+ // query will be sent, so the netbios find name
+ // buffer can be filled with the responses from this.
+ //
+
+ if ((Type == FindNameNetbiosFindName) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) &&
+ (Reserved->u.SR_FN.RetryCount == Device->BroadcastCount)) {
+
+ --Reserved->u.SR_FN.RetryCount;
+ }
+
+ return STATUS_PENDING;
+ }
+ }
+
+ s = NbiPopSendPacket(Device, TRUE);
+
+ if (s == NULL) {
+ NB_DEBUG (CACHE, ("Couldn't get packet to find <%.16s>\n", RemoteName ? RemoteName : "<broadcast>"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+
+ //
+ // We have the packet, fill it in for this request.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = FALSE;
+ Reserved->Type = SEND_TYPE_FIND_NAME;
+ RtlCopyMemory (Reserved->u.SR_FN.NetbiosName, RealRemoteName, 16);
+ Reserved->u.SR_FN.StatusAndSentOnUpLine = FNStatusNoResponse; // SentOnUpLine is FALSE
+ Reserved->u.SR_FN.RetryCount = 0;
+ Reserved->u.SR_FN.NewCache = NULL;
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+#if !defined(_PNP_POWER)
+ Reserved->u.SR_FN.CurrentNicId = 1;
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_MAX_TYPE_20_NIC_ID,
+ (USHORT)0,
+ &Reserved->u.SR_FN.MaximumNicId,
+ sizeof(USHORT),
+ NULL);
+
+ if (Reserved->u.SR_FN.MaximumNicId == 0) {
+ Reserved->u.SR_FN.MaximumNicId = 1; // code assumes at least one
+ }
+#endif !_PNP_POWER
+ NB_DEBUG2 (CACHE, ("Queued FIND_NAME %lx for <%.16s>\n",
+ Reserved, RemoteName ? RemoteName : "<broadcast>"));
+
+
+ InsertHeadList(
+ &Device->WaitingFindNames,
+ &Reserved->WaitLinkage);
+
+ ++Device->FindNamePacketCount;
+
+ if (!Device->FindNameTimerActive) {
+
+ Device->FindNameTimerActive = TRUE;
+ NbiReferenceDevice (Device, DREF_FN_TIMER);
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ 1, // 1 ms, i.e. expire immediately
+ FindNameTimeout,
+ (PVOID)Device);
+ }
+
+ NbiReferenceDevice (Device, DREF_FIND_NAME);
+
+ return STATUS_PENDING;
+
+} /* CacheFindName */
+
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the find name timer expires.
+ It is called every FIND_NAME_GRANULARITY milliseconds unless there
+ is nothing to do.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the device pointer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, q;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PNETBIOS_CACHE FoundCacheName;
+ NDIS_STATUS NdisStatus;
+#if !defined(_PNP_POWER)
+ static IPX_LOCAL_TARGET BroadcastTarget = { 0, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif !_PNP_POWER
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ ++Device->FindNameTime;
+
+ if (Device->FindNamePacketCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout exiting\n"));
+
+ Device->FindNameTimerActive = FALSE;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDereferenceDevice (Device, DREF_FN_TIMER);
+
+ return;
+ }
+
+ //
+ // Check what is on the queue; this is set up as a
+ // loop but in fact it rarely does (under no
+ // circumstances can we send more than one packet
+ // each time this function executes).
+ //
+#if defined(_PNP_POWER)
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ //
+
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // If this is the first retry, we need to initialize the packet
+ //
+ if ( Reserved->u.SR_FN.RetryCount == 1 ) {
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+
+ }
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx\n", Reserved));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+
+ break;
+
+ }
+#else
+ while (TRUE) {
+
+ p = Device->WaitingFindNames.Flink;
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ if (Reserved->SendInProgress) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // This was a find name for a unique name which got a
+ // response but was not freed at the time (because
+ // SendInProgress was still TRUE) so we free it now.
+ //
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ --Device->FindNamePacketCount;
+
+ //
+ // It is OK to do this with the lock held because
+ // it won't be the last one (we have the RIP_TIMER ref).
+ //
+
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ if (((SHORT)(Device->FindNameTime - Reserved->u.SR_FN.SendTime)) < 0) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ break;
+ }
+
+ (VOID)RemoveHeadList (&Device->WaitingFindNames);
+
+ //
+ // Save this now, then change it if needed.
+ //
+
+ BroadcastTarget.NicId = Reserved->u.SR_FN.CurrentNicId;
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+
+ //
+ // Increment the counter and see if we have sent
+ // all the frames we need to (we will age out
+ // here if we got no response for a unique query,
+ // or if we are doing a global name or broadcast
+ // search). We also kill the query right now if
+ // we have not found anything but down wan lines
+ // to send it on.
+ //
+
+ if ((++Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) ||
+ ((Reserved->u.SR_FN.RetryCount > 1) && (!NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved)))) {
+
+#if DBG
+ if (Reserved->u.SR_FN.RetryCount > Device->BroadcastCount) {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout aging out %lx\n", Reserved));
+ } else {
+ NB_DEBUG2 (CACHE, ("FindNameTimeout no active nets %lx\n", Reserved));
+ }
+#endif
+
+ //
+ // This packet is stale, clean it up and continue.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup) {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache != NULL);
+
+ //
+ // If this was a group name and we have a new
+ // cache entry that we have been building for it,
+ // then insert that in the queue and use it
+ // to succeed any pending connects. Because
+ // netbios find name requests can cause cache
+ // requests for group names to be queued even
+ // if we already have on in the database, we
+ // first scan for old ones and remove them.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+ NB_DEBUG2 (CACHE, ("Found old group cache name <%.16s>\n", FoundCacheName->NetbiosName));
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, FoundCacheName );
+
+ if (--FoundCacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", FoundCacheName));
+ NbiFreeMemory(
+ FoundCacheName,
+ sizeof(NETBIOS_CACHE) + ((FoundCacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free due to replacement");
+
+ }
+ }
+
+ Reserved->u.SR_FN.NewCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ Reserved->u.SR_FN.NewCache);
+
+ //
+ // Reference it for the moment since CacheHandlePending
+ // uses it after releasing the lock. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++Reserved->u.SR_FN.NewCache->ReferenceCount;
+
+ //
+ // This call releases the locks
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ Reserved->u.SR_FN.NewCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ CTEAssert (Reserved->u.SR_FN.NewCache == NULL);
+
+ //
+ // Allocate an empty cache entry to record the
+ // fact that we could not find this name, unless
+ // there is already an entry for this name.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Reserved->u.SR_FN.NetbiosName,
+ &FoundCacheName ) == STATUS_SUCCESS ) {
+
+
+ NB_DEBUG2 (CACHE, ("Don't replace old group cache name with empty <%.16s>\n", FoundCacheName->NetbiosName));
+
+ } else {
+
+ PNETBIOS_CACHE EmptyCache;
+
+ //
+ // Nothing found.
+ //
+
+ EmptyCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (EmptyCache != NULL) {
+
+ RtlZeroMemory (EmptyCache, sizeof(NETBIOS_CACHE));
+
+ NB_DEBUG2 (CACHE, ("Allocate new empty cache %lx for <%.16s>\n",
+ EmptyCache, Reserved->u.SR_FN.NetbiosName));
+
+ RtlCopyMemory (EmptyCache->NetbiosName, Reserved->u.SR_FN.NetbiosName, 16);
+ EmptyCache->Unique = TRUE; // so we'll delete it if we see an add name
+ EmptyCache->ReferenceCount = 1;
+ EmptyCache->NetworksAllocated = 1;
+ EmptyCache->TimeStamp = Device->CacheTimeStamp;
+ EmptyCache->NetworksUsed = 0;
+ EmptyCache->FailedOnDownWan = (BOOLEAN)
+ !NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved);
+
+ InsertInNetbiosCacheTable (
+ Device->NameCache,
+ EmptyCache);
+ }
+ }
+
+ //
+ // Fail all datagrams, etc. that were waiting for
+ // this route. This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NB_GET_SR_FN_SENT_ON_UP_LINE(Reserved) ?
+ NetbiosNameNotFoundNormal :
+ NetbiosNameNotFoundWanDown,
+ NULL
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+ --Device->FindNamePacketCount;
+ NbiDereferenceDevice (Device, DREF_FIND_NAME);
+ continue;
+ }
+
+ }
+
+
+ //
+ // Increment the current NIC ID for next time.
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId >= Reserved->u.SR_FN.MaximumNicId) {
+ Reserved->u.SR_FN.CurrentNicId = 1;
+ } else {
+ ++Reserved->u.SR_FN.CurrentNicId;
+ }
+
+
+ //
+ // Send the packet out again. We first set the time so
+ // it won't be sent again until the appropriate timeout.
+ // If we are going to wrap around the maximum NIC ID
+ // after sending this packet we wait the full configured
+ // amount, otherwise we wait almost the minimum (but still
+ // insert ourselves at the back of the queue to be fair).
+ //
+
+ if (Reserved->u.SR_FN.CurrentNicId == 1) {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + Device->FindNameTimeout);
+ } else {
+ Reserved->u.SR_FN.SendTime = (USHORT)(Device->FindNameTime + 2);
+ }
+ InsertTailList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+
+ CTEAssert (Reserved->Identifier == IDENTIFIER_NB);
+ CTEAssert (!Reserved->SendInProgress);
+ Reserved->SendInProgress = TRUE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, which is
+ // what we want.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = NB_CMD_FIND_NAME;
+ Header->NameFrame.DataStreamType2 = NB_CMD_FIND_NAME;
+ Header->NameFrame.NameTypeFlag = 0x00;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Reserved->u.SR_FN.NetbiosName,
+ 16);
+
+ //
+ // Now submit the packet to IPX.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout sending %lx to %d\n", Reserved, BroadcastTarget.NicId));
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &BroadcastTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ if (NdisStatus == STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ //
+ // This send was done on a down wan line. To avoid
+ // extensive delays sending find names on systems
+ // with a lot of wan lines, we loop around immediately
+ // and do the next send. We put this packet back on
+ // the head of the list and change its SendTime so
+ // it will be resent immediately.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NB_DEBUG2 (CACHE, ("FindNameTimeout resending %lx, wan send failed\n", Reserved));
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertHeadList (&Device->WaitingFindNames, &Reserved->WaitLinkage);
+ Reserved->u.SR_FN.SendTime = Device->FindNameTime;
+
+ continue;
+
+ } else {
+
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ }
+
+
+ break;
+
+ }
+#endif _PNP_POWER
+
+ //
+ // Since we did something this time, we restart the timer.
+ //
+
+ CTEStartTimer(
+ &Device->FindNameTimer,
+ FIND_NAME_GRANULARITY,
+ FindNameTimeout,
+ (PVOID)Device);
+
+} /* FindNameTimeout */
+
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up pending datagrams and connects
+ that were waiting for a route to be discovered to a
+ given Netbios NAME. THIS ROUTINE IS CALLED WITH
+ DEVICE->LOCK ACQUIRED AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Device - The device.
+
+ RemoteName - The netbios name that was being searched for.
+
+ Result - Indicates if the name was found, or not found due
+ to no response or wan lines being down.
+
+ CacheName - If Result is NetbiosNameFound, the cache entry for this name.
+ This entry has been referenced and this routine will deref it.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LIST_ENTRY DatagramList;
+ LIST_ENTRY ConnectList;
+ LIST_ENTRY AdapterStatusList;
+ LIST_ENTRY NetbiosFindNameList;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ PLIST_ENTRY p;
+ PREQUEST ConnectRequest, DatagramRequest, AdapterStatusRequest, NetbiosFindNameRequest;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ InitializeListHead (&DatagramList);
+ InitializeListHead (&ConnectList);
+ InitializeListHead (&AdapterStatusList);
+ InitializeListHead (&NetbiosFindNameList);
+
+ //
+ // Put all connect requests on ConnectList. They will
+ // be continued or failed later.
+ //
+
+ p = Device->WaitingConnects.Flink;
+
+ while (p != &Device->WaitingConnects) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+ p = p->Flink;
+
+ if (RtlEqualMemory (Connection->RemoteName, RemoteName, 16)) {
+
+ RemoveEntryList (REQUEST_LINKAGE(ConnectRequest));
+ InsertTailList (&ConnectList, REQUEST_LINKAGE(ConnectRequest));
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+ }
+
+ }
+
+
+ //
+ // Put all the datagrams on Datagram list. They will be
+ // sent or failed later.
+ //
+
+ p = Device->WaitingDatagrams.Flink;
+
+ while (p != &Device->WaitingDatagrams) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ p = p->Flink;
+
+ //
+ // Check differently based on whether we were looking for
+ // the broadcast address or not.
+ //
+
+ if (Reserved->u.SR_DG.RemoteName == (PVOID)-1) {
+ if (!RtlEqualMemory (RemoteName, NetbiosBroadcastName, 16)) {
+ continue;
+ }
+ } else {
+
+ if (!RtlEqualMemory (RemoteName, Reserved->u.SR_DG.RemoteName->NetbiosName, 16)) {
+ continue;
+ }
+ }
+
+ RemoveEntryList (&Reserved->WaitLinkage);
+ InsertTailList (&DatagramList, &Reserved->WaitLinkage);
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the adapter status requests on AdapterStatus
+ // list. They will be sent or failed later.
+ //
+
+ p = Device->WaitingAdapterStatus.Flink;
+
+ while (p != &Device->WaitingAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(AdapterStatusRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // Reference this here with the lock held.
+ //
+
+ if (Result == NetbiosNameFound) {
+ ++CacheName->ReferenceCount;
+ }
+
+ }
+
+
+ //
+ // Put all the netbios find name requests on NetbiosFindName
+ // list. They will be completed later.
+ //
+
+ p = Device->WaitingNetbiosFindName.Flink;
+
+ while (p != &Device->WaitingNetbiosFindName) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ RemoteAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ RemoteName,
+ RemoteAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ RemoveEntryList (REQUEST_LINKAGE(NetbiosFindNameRequest));
+ InsertTailList (&NetbiosFindNameList, REQUEST_LINKAGE(NetbiosFindNameRequest));
+
+ }
+
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ //
+ // Now that the lock is free, process all the packets on
+ // the various lists.
+ //
+
+ for (p = ConnectList.Flink; p != &ConnectList; ) {
+
+ ConnectRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(ConnectRequest);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (CONNECTION, ("Found queued connect %lx on %lx\n", ConnectRequest, Connection));
+
+ //
+ // Continue with the connection sequence.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!ConnectRequest->Cancel) {
+
+ IoSetCancelRoutine (ConnectRequest, NbiCancelConnectWaitResponse);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1 );
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelling connect %lx on %lx\n", ConnectRequest, Connection));
+
+ goto AbortConnect;
+
+ //
+ // Jumps down into the else below.
+ //
+
+ }
+
+ } else {
+ BOOLEAN bAutodialAttempt = FALSE;
+
+ NB_DEBUG2 (CONNECTION, ("Timing out connect %lx on %lx\n", ConnectRequest, Connection));
+AbortConnect:
+
+ ASSERT (Connection->ConnectRequest == ConnectRequest);
+
+#ifdef RASAUTODIAL
+ if (fAcdLoadedG) {
+ CTELockHandle adirql;
+ BOOLEAN fEnabled;
+
+ //
+ // See if the automatic connection driver knows
+ // about this address before we search the
+ // network. If it does, we return STATUS_PENDING,
+ // and we will come back here via NbfRetryTdiConnect().
+ //
+ CTEGetLock(&AcdDriverG.SpinLock, &adirql);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, adirql);
+ if (fEnabled && NbiAttemptAutoDial(
+ Device,
+ Connection,
+ 0,
+ NbiRetryTdiConnect,
+ ConnectRequest))
+ {
+ NB_SYNC_FREE_LOCK(&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK(CancelLH);
+
+ bAutodialAttempt = TRUE;
+ }
+ }
+#endif // RASAUTODIAL
+
+ if (!bAutodialAttempt) {
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ IoSetCancelRoutine( ConnectRequest, (PDRIVER_CANCEL)NULL );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS(ConnectRequest) = STATUS_BAD_NETWORK_PATH;
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ } else {
+
+ // BUGBUG What happens to the IRP? Who completes it?
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+
+ }
+
+
+ for (p = DatagramList.Flink; p != &DatagramList; ) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (DATAGRAM, ("Found queued datagram %lx on %lx\n", Reserved->u.SR_DG.DatagramRequest, Reserved->u.SR_DG.AddressFile));
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER( Reserved->u.SR_DG.DatagramRequest )) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Reserved->u.SR_DG.DatagramRequest));
+ }
+
+ NbiTransmitDatagram (Reserved);
+
+ } else {
+
+ //
+ // BETABUGBUG: Should we send it once as a broadcast
+ // on net 0, just in case??
+ //
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Timing out datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // If the failure was due to a down wan line indicate
+ // that, otherwise return success (so the browser won't
+ // confuse this with a down wan line).
+ //
+
+ if (Result == NetbiosNameNotFoundWanDown) {
+ REQUEST_STATUS(DatagramRequest) = STATUS_DEVICE_DOES_NOT_EXIST;
+ REQUEST_INFORMATION(DatagramRequest) = 0;
+ } else {
+ REQUEST_STATUS(DatagramRequest) = STATUS_SUCCESS;
+ }
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ }
+
+ }
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ if (Result == NetbiosNameFound) {
+
+ NB_DEBUG2 (QUERY, ("Found queued AdapterStatus %lx\n", AdapterStatusRequest));
+
+ //
+ // Continue with the AdapterStatus sequence. We put
+ // it in ActiveAdapterStatus, it will either get
+ // completed when a response is received or timed
+ // out by the long timeout.
+ //
+
+ REQUEST_STATUS(AdapterStatusRequest) = (NTSTATUS)CacheName;
+
+ //
+ // CacheName was referenced above.
+ //
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (AdapterStatusRequest),
+ &Device->Lock);
+
+ NbiSendStatusQuery (AdapterStatusRequest);
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Timing out AdapterStatus %lx\n", AdapterStatusRequest));
+
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ }
+
+
+ for (p = NetbiosFindNameList.Flink; p != &NetbiosFindNameList; ) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ //
+ // In fact there is not much difference between success or
+ // failure, since in the successful case the information
+ // will already have been written to the buffer. Just
+ // complete the request with the appropriate status,
+ // which will already be stored in the request.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ if (CacheName->Unique) {
+
+ NB_DEBUG2 (QUERY, ("Found queued unique NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ } else {
+
+ NB_DEBUG2 (QUERY, ("Found queued group NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ } else {
+
+ CTEAssert (REQUEST_STATUS(NetbiosFindNameRequest) == STATUS_IO_TIMEOUT);
+ NB_DEBUG2 (QUERY, ("Timed out NetbiosFindName %lx\n", NetbiosFindNameRequest));
+
+ }
+
+ //
+ // This sets REQUEST_INFORMATION(Request) to the correct value.
+ //
+
+ NbiSetNetbiosFindNameInformation (NetbiosFindNameRequest);
+
+ NbiCompleteRequest(NetbiosFindNameRequest);
+ NbiFreeRequest (Device, NetbiosFindNameRequest);
+
+ NbiDereferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ }
+
+
+ //
+ // We referenced this temporarily so we could use it in here,
+ // deref and check if we need to delete it.
+ //
+
+ if (Result == NetbiosNameFound) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free newly allocated cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free in CacheHandlePending");
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+
+ }
+
+} /* CacheHandlePending */
+
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_NAME_RECOGNIZED frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ PNETBIOS_CACHE NameCache;
+ PREQUEST NetbiosFindNameRequest;
+ PNB_SEND_RESERVED Reserved;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteNetbiosAddress;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+#if 0
+ //
+ // BETABUGBUG: We should handle responses from network 0
+ // differently -- if they are for a group name, we should
+ // keep them around but only until we get a non-zero
+ // response from the same card.
+ //
+
+ if (*(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork) == 0) {
+ return;
+ }
+#endif
+
+
+ //
+ // We need to scan our queue of pending find name packets
+ // to see if someone is waiting for this name.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ for (p = Device->WaitingFindNames.Flink;
+ p != &Device->WaitingFindNames;
+ p = p->Flink) {
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+
+ //
+ // Find names which have already found unique names are
+ // "dead", waiting for FindNameTimeout to remove them,
+ // and should be ignored when scanning the list.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ continue;
+ }
+
+ if (RtlEqualMemory (Reserved->u.SR_FN.NetbiosName, Connectionless->NameFrame.Name, 16)) {
+ break;
+ }
+ }
+
+ if (p == &Device->WaitingFindNames) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // Scan for any netbios find name requests on the queue, and
+ // inform them about this remote. We need to do this on every
+ // response because group names need every computer recorded,
+ // but the normal cache only includes one entry per network.
+ //
+
+ for (p = Device->WaitingNetbiosFindName.Flink;
+ p != &Device->WaitingNetbiosFindName;
+ p = p->Flink) {
+
+ NetbiosFindNameRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ RemoteNetbiosAddress = (TDI_ADDRESS_NETBIOS UNALIGNED *)REQUEST_INFORMATION(NetbiosFindNameRequest);
+
+ if (!RtlEqualMemory(
+ Connectionless->NameFrame.Name,
+ RemoteNetbiosAddress->NetbiosName,
+ 16)) {
+ continue;
+ }
+
+ //
+ // This will update the request status if needed.
+ //
+
+ NbiUpdateNetbiosFindName(
+ NetbiosFindNameRequest,
+#if defined(_PNP_POWER)
+ &RemoteAddress->NicHandle,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ (TDI_ADDRESS_IPX UNALIGNED *)Connectionless->IpxHeader.SourceNetwork,
+ (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0));
+
+ }
+
+
+ //
+ // See what is up with this pending find name packet.
+ //
+
+ if (Reserved->u.SR_FN.NewCache == NULL) {
+
+ //
+ // This is the first response we have received, so we
+ // allocate the initial entry with room for a single
+ // entry.
+ //
+
+ NameCache = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (NameCache == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Alloc new cache %lx for <%.16s>, net %lx\n",
+ NameCache, Reserved->u.SR_FN.NetbiosName,
+ *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork)));
+
+ RtlCopyMemory (NameCache->NetbiosName, Connectionless->NameFrame.Name, 16);
+ NameCache->Unique = (BOOLEAN)((Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) == 0);
+ NameCache->ReferenceCount = 1;
+ RtlCopyMemory (&NameCache->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ NameCache->NetworksAllocated = 1;
+ NameCache->NetworksUsed = 1;
+ NameCache->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+
+ if (RtlEqualMemory (Connectionless->NameFrame.Name, NetbiosBroadcastName, 16)) {
+
+ NB_SET_SR_FN_STATUS (Reserved, FNStatusResponseGroup);
+ NameCache->Unique = FALSE;
+
+ } else {
+
+ NB_SET_SR_FN_STATUS(
+ Reserved,
+ NameCache->Unique ? FNStatusResponseUnique : FNStatusResponseGroup);
+
+ }
+
+ Reserved->u.SR_FN.NewCache = NameCache;
+
+ //
+ // If this packet was not routed to us and is for a group name,
+ // rather than use whatever local target it happened to come
+ // from we set it up so that it is broadcast on that net.
+ //
+
+ if ((RtlEqualMemory (RemoteAddress->MacAddress, Connectionless->IpxHeader.SourceNode, 6)) &&
+ (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseGroup)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[0].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[0].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[0].LocalTarget.MacAddress, BroadcastAddress, 6);
+ RtlCopyMemory (NameCache->FirstResponse.NodeAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[0].LocalTarget = *RemoteAddress;
+ }
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // Complete pending requests now, since it is a unique
+ // name we have all the information we will get.
+ //
+
+ NameCache->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ NameCache);
+
+ //
+ // Reference it since CacheHandlePending uses it
+ // with the lock released. CacheHandlePending
+ // will dereference it.
+ //
+
+ ++NameCache->ReferenceCount;
+
+ //
+ // This call releases the lock.
+ //
+
+ CacheHandlePending(
+ Device,
+ Reserved->u.SR_FN.NetbiosName,
+ NetbiosNameFound,
+ NameCache
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We already have a response to this frame.
+ //
+
+ if (NB_GET_SR_FN_STATUS(Reserved) == FNStatusResponseUnique) {
+
+ //
+ // BUGBUG: Should we check that the response is also
+ // unique? Not much to do since I don't know of an
+ // equivalent to the netbeui NAME_IN_CONFLICT.
+ //
+
+ } else {
+
+ //
+ // This is a group name.
+ //
+
+ if (Connectionless->NameFrame.NameTypeFlag & NB_NAME_GROUP) {
+
+ //
+ // Update our information about this network if needed.
+ // This may free the existing cache and allocate a new one.
+ //
+
+ Reserved->u.SR_FN.NewCache =
+ CacheUpdateNameCache(
+ Reserved->u.SR_FN.NewCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)
+ Connectionless->IpxHeader.SourceNetwork,
+ FALSE);
+
+ } else {
+
+ //
+ // BUGBUG: This respondent thinks it is a unique name
+ // but we think it is group, should we do something?
+ //
+
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessNameRecognized */
+
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to update a netbios cache entry
+ with a new network, if it is does not already contain
+ information about the network. It is called when a frame
+ is received advertising the appropriate cache entry, which
+ is either a group name or the broadcast name.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH IT HELD.
+
+Arguments:
+
+ NameCache - The name cache entry to update.
+
+ RemoteAddress - The remote address on which a frame was received.
+
+ IpxAddress - The source IPX address of the frame.
+
+ ModifyQueue - TRUE if we should update the queue which this
+ cache entry is in, if we reallocate it.
+
+Return Value:
+
+ The netbios cache entry, either the original or a reallocated one.
+
+--*/
+
+{
+
+ PDEVICE Device = NbiDevice;
+ USHORT NewNetworks;
+ PNETBIOS_CACHE NewNameCache;
+ PLIST_ENTRY OldPrevious;
+ UINT i;
+
+ //
+ // See if we already know about this network.
+ //
+
+ for (i = 0; i < NameCache->NetworksUsed; i++) {
+ if (NameCache->Networks[i].Network == SourceAddress->NetworkAddress) {
+ return NameCache;
+ }
+ }
+
+ //
+ // We need to add information about this network
+ // to the name cache entry. If we have to allocate
+ // a new one we do that.
+ //
+
+ NB_DEBUG2 (CACHE, ("Got new net %lx for <%.16s>\n",
+ SourceAddress->NetworkAddress,
+ NameCache->NetbiosName));
+
+ if (NameCache->NetworksUsed == NameCache->NetworksAllocated) {
+
+ //
+ // We double the number of entries allocated until
+ // we hit 16, then add 8 at a time.
+ //
+
+ if (NameCache->NetworksAllocated < 16) {
+ NewNetworks = NameCache->NetworksAllocated * 2;
+ } else {
+ NewNetworks = NameCache->NetworksAllocated + 8;
+ }
+
+
+ NewNameCache = NbiAllocateMemory(
+ sizeof(NETBIOS_CACHE) + ((NewNetworks-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge cache entry");
+
+ if (NewNameCache == NULL) {
+ return NameCache;
+ }
+
+ NB_DEBUG2 (CACHE, ("Expand cache %lx to %lx for <%.16s>\n",
+ NameCache, NewNameCache, NameCache->NetbiosName));
+
+ //
+ // Copy the new current data to the new one.
+ //
+
+ RtlCopyMemory(
+ NewNameCache,
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)));
+
+ NewNameCache->NetworksAllocated = NewNetworks;
+ NewNameCache->ReferenceCount = 1;
+
+ if (ModifyQueue) {
+
+ //
+ // Insert at the same place as the old one. The time
+ // stamp is the same as the old one.
+ //
+
+
+ ReinsertInNetbiosCacheTable( Device->NameCache, NameCache, NewNameCache );
+
+ }
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free replaced cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ NameCache = NewNameCache;
+
+ }
+
+ NameCache->Networks[NameCache->NetworksUsed].Network =
+ SourceAddress->NetworkAddress;
+
+ //
+ // If this packet was not routed to us, then store the local
+ // target for a correct broadcast.
+ //
+
+ if (RtlEqualMemory (RemoteAddress->MacAddress, SourceAddress->NodeAddress, 6)) {
+#if defined(_PNP_POWER)
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicHandle = RemoteAddress->NicHandle;
+#else
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget.NicId = RemoteAddress->NicId;
+#endif _PNP_POWER
+ RtlCopyMemory (NameCache->Networks[NameCache->NetworksUsed].LocalTarget.MacAddress, BroadcastAddress, 6);
+ } else {
+ NameCache->Networks[NameCache->NetworksUsed].LocalTarget = *RemoteAddress;
+ }
+
+ ++NameCache->NetworksUsed;
+
+ return NameCache;
+
+} /* CacheUpdateNameCache */
+
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an add name frame is received.
+ If it is for a group name it checks if our cache entry for
+ that group name needs to be updated to include a new network;
+ for all frames it checks if our broadcast cache entry needs
+ to be updated to include a new network.
+
+Arguments:
+
+ RemoteAddress - The address the frame was received from.
+
+ Connectionless - The header of the received add name.
+
+ LocalFrame - TRUE if the frame was sent locally.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE NameCache;
+ PLIST_ENTRY p;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ //
+ // First look up the broadcast name.
+ //
+ // BUGBUG: We should cache a pointer to the cache name
+ // for the broadcast entry, if there is one.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (!LocalFrame) {
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosBroadcastName,
+ &NameCache ) == STATUS_SUCCESS ) {
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+ }
+
+ }
+
+
+ //
+ // Now see if our database needs to be updated based on this.
+ //
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ Connectionless->NameFrame.Name,
+ &NameCache ) == STATUS_SUCCESS ) {
+
+
+ if (!NameCache->Unique) {
+
+ if (!LocalFrame) {
+
+ //
+ // This will reallocate a cache entry and update the
+ // queue if necessary.
+ //
+
+ (VOID)CacheUpdateNameCache(
+ NameCache,
+ RemoteAddress,
+ (TDI_ADDRESS_IPX UNALIGNED *)(Connectionless->IpxHeader.SourceNetwork),
+ TRUE);
+
+ }
+
+ } else {
+
+ //
+ // To be safe, delete any unique names we get add
+ // names for (we will requery next time we need it).
+ // BUGBUG: Update the database instead -- but then
+ // we may not get the best route??
+ //
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, NameCache );
+
+ if (--NameCache->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free add named cache entry %lx\n", NameCache));
+ NbiFreeMemory(
+ NameCache,
+ sizeof(NETBIOS_CACHE) + ((NameCache->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Enlarge existing");
+
+ }
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+} /* CacheUpdateFromAddName */
+
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_DELETE_NAME frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+ PUCHAR NetbiosName;
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ if (PacketSize != sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME)) {
+ return;
+ }
+
+ //
+ // We want to update our netbios cache to reflect the
+ // fact that this name is no longer valid.
+ //
+
+ NetbiosName = (PUCHAR)Connectionless->NameFrame.Name;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ( FindInNetbiosCacheTable( Device->NameCache,
+ NetbiosName,
+ &CacheName ) == STATUS_SUCCESS ) {
+
+ //
+ // We don't track group names since we don't know if
+ // this is the last person that owns it. We also drop
+ // the frame if does not come from the person we think
+ // owns this name.
+ //
+
+ if ((!CacheName->Unique) ||
+ (CacheName->NetworksUsed == 0) ||
+ (!RtlEqualMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12))) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (CACHE, ("Found cache name to delete <%.16s>\n", NetbiosName));
+
+ }else {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+
+ //
+ // We have a cache entry, take it out of the list. If no
+ // one else is using it, delete it; if not, they will delete
+ // it when they are done.
+ //
+
+
+ RemoveFromNetbiosCacheTable ( Device->NameCache, CacheName);
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessDeleteName */
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry in the hash table
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ USHORT HashIndex;
+
+ //
+ // Keep a threshold of how many entries do we keep in the table.
+ // If it crosses the threshold, just remove the oldest entry
+ //
+ if ( CacheTable->CurrentEntries >= CacheTable->MaxHashIndex * NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET ) {
+ PNETBIOS_CACHE OldestCacheEntry = NULL;
+ PNETBIOS_CACHE NextEntry;
+ PLIST_ENTRY p;
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ if ( (p = CacheTable->Bucket[ HashIndex ].Blink ) != &CacheTable->Bucket[ HashIndex ] ) {
+ NextEntry = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ if ( OldestCacheEntry ) {
+ if ( NextEntry->TimeStamp < OldestCacheEntry->TimeStamp ) {
+ OldestCacheEntry = NextEntry;
+ }
+ } else {
+ OldestCacheEntry = NextEntry;
+ }
+ }
+ }
+
+ CTEAssert( OldestCacheEntry );
+
+ NB_DEBUG2 (CACHE, ("Threshold exceeded, removing oldest cache entry %lx\n", OldestCacheEntry));
+ RemoveEntryList (&OldestCacheEntry->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--OldestCacheEntry->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed cache entry %lx\n", OldestCacheEntry));
+
+ NbiFreeMemory(
+ OldestCacheEntry,
+ sizeof(NETBIOS_CACHE) + ((OldestCacheEntry->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ }
+ HashIndex = ( ( CacheEntry->NetbiosName[0] & 0x0f ) << 4 ) + ( CacheEntry->NetbiosName[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ InsertHeadList( &CacheTable->Bucket[HashIndex], &CacheEntry->Linkage );
+ CacheTable->CurrentEntries++;
+} /* InsertInNetbiosCacheTable */
+
+
+__inline
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine inserts a new cache entry at the same place where
+ the old entry was.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be inserted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PLIST_ENTRY OldPrevious;
+
+ OldPrevious = OldEntry->Linkage.Blink;
+ RemoveEntryList (&OldEntry->Linkage);
+ InsertHeadList (OldPrevious, &NewEntry->Linkage);
+} /* ReinsertInNetbiosCacheTable */
+
+__inline
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes an entry from the cache table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Entry to be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ RemoveEntryList( &CacheEntry->Linkage );
+ CacheTable->CurrentEntries--;
+} /* RemoveFromNetbiosCacheTable */
+
+
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the old entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ AgeLimit - All the entries older than AgeLimit will be removed.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // see if any entries have been around for more than agelimit
+ //
+
+ if ((USHORT)(NbiDevice->CacheTimeStamp - CacheName->TimeStamp) >= AgeLimit ) {
+
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Aging out name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+
+ } else {
+
+ break;
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushOldFromNetbiosCacheTable */
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all the failed entries from the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // run the hash table looking for old entries. Since new entries
+ // are stored at the head and all entries are time stamped when
+ // they are inserted, we scan backwards and stop once we find
+ // an entry which does not need to be aged.
+ // we repeat this for each bucket.
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ for (p = CacheTable->Bucket[ HashIndex ].Blink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Blink;
+
+ //
+ // flush all the failed cache entries.
+ // We do this when a new adapter appears, and there's a possiblity that
+ // the failed entries might succeed now on the new adapter.
+ //
+
+ if (CacheName->NetworksUsed == 0) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+ CTEAssert( CacheName->ReferenceCount == 1 );
+ CTEAssert( CacheName->NetworksAllocated == 1 );
+
+ NB_DEBUG2 (CACHE, ("Flushing out failed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ } // for loop
+ } // for loop
+} /* FlushFailedNetbiosCacheEntries */
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all invalid route entries from the hash table.
+ Routes become invalid when the binding is deleted in Ipx due to PnP
+ event.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ InvalidRouteNicId - NicId of the invalid routes.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+ USHORT i,j,NetworksRemoved;
+ USHORT HashIndex;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Flush all the cache entries that are using this NicId in the local
+ // target.
+ //
+
+ for ( HashIndex = 0; HashIndex < Device->NameCache->MaxHashIndex; HashIndex++) {
+ for (p = Device->NameCache->Bucket[ HashIndex ].Flink;
+ p != &Device->NameCache->Bucket[ HashIndex ];
+ ) {
+
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+ p = p->Flink;
+
+
+ //
+ // Remove each of those routes which is using this NicId.
+ // if no routes left, then flush the cache entry also.
+ // ( unique names have only one route anyways )
+ //
+ for ( i = 0, NetworksRemoved = 0; i < CacheName->NetworksUsed; i++ ) {
+ if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId == InvalidNicHandle->NicId ) {
+ CTEAssert( RtlEqualMemory( &CacheName->Networks[i].LocalTarget.NicHandle, InvalidNicHandle, sizeof(NIC_HANDLE)));
+ for ( j = i+1; j < CacheName->NetworksUsed; j++ ) {
+ CacheName->Networks[j-1] = CacheName->Networks[j];
+ }
+ NetworksRemoved++;
+ } else if ( CacheName->Networks[i].LocalTarget.NicHandle.NicId > InvalidNicHandle->NicId ) {
+ CacheName->Networks[i].LocalTarget.NicHandle.NicId--;
+ }
+ }
+ CTEAssert( NetworksRemoved <= CacheName->NetworksUsed );
+ if ( ! ( CacheName->NetworksUsed -= NetworksRemoved ) ) {
+ RemoveEntryList (&CacheName->Linkage);
+ CacheTable->CurrentEntries--;
+
+ NB_DEBUG2 (CACHE, ("Removed cache entry %lx bcoz route(NicId %d) deleted\n", CacheName, InvalidNicHandle->NicId ));
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Freed name cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Aged out");
+
+ }
+ }
+ } // for loop
+ } // for loop
+} /* RemoveInvalidRoutesFromNetbiosCacheTable */
+
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds a netbios name in the Hash Table and returns
+ the corresponding cache entry.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+ CacheEntry - Pointer to the netbios cache entry if found.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_UNSUCCESSFUL - otherwise.
+
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE FoundCacheName;
+
+
+ HashIndex = ( ( NameToBeFound[0] & 0x0f ) << 4 ) + ( NameToBeFound[1] & 0x0f );
+ HashIndex = HashIndex % CacheTable->MaxHashIndex;
+
+ for (p = ( CacheTable->Bucket[ HashIndex ] ).Flink;
+ p != &CacheTable->Bucket[ HashIndex ];
+ p = p->Flink) {
+
+ FoundCacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ //
+ // See if this entry is for the same name we are looking for.
+
+ if ( RtlEqualMemory (FoundCacheName->NetbiosName, NameToBeFound, 16) ) {
+ *CacheEntry = FoundCacheName;
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_UNSUCCESSFUL;
+} /* FindInNetbiosCacheTable */
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new hash table for netbios cache
+ and initializes it.
+
+ THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND RETURNS
+ WITH THE LOCK HELD.
+
+Arguments:
+
+ NewTable - The pointer of the table to be created.
+
+ MaxHashIndex - Number of buckets in the hash table.
+
+Return Value:
+
+ STATUS_SUCCESS - if successful.
+
+ STATUS_INSUFFICIENT_RESOURCES - If cannot allocate memory.
+
+--*/
+
+{
+ USHORT i;
+
+ *NewTable = NbiAllocateMemory (sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Cache Table");
+
+ if ( *NewTable ) {
+ for ( i = 0; i < MaxHashIndex; i++ ) {
+ InitializeListHead(& (*NewTable)->Bucket[i] );
+ }
+
+ (*NewTable)->MaxHashIndex = MaxHashIndex;
+ (*NewTable)->CurrentEntries = 0;
+ return STATUS_SUCCESS;
+ }
+ else {
+ NB_DEBUG( CACHE, ("Cannot create Netbios Cache Table\n") );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+} /* CreateNetbiosCacheTable */
+
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes all entries from the hash table.
+ and free up the hash table.
+
+Arguments:
+
+ CacheTable - The pointer of the Hash Table.
+
+Return Value:
+
+ None.
+--*/
+
+{
+ USHORT HashIndex;
+ PLIST_ENTRY p;
+ PNETBIOS_CACHE CacheName;
+
+
+ for ( HashIndex = 0; HashIndex < CacheTable->MaxHashIndex; HashIndex++) {
+ while (!IsListEmpty ( &( CacheTable->Bucket[ HashIndex ] ) ) ) {
+
+ p = RemoveHeadList ( &( CacheTable->Bucket[ HashIndex ] ));
+ CacheTable->CurrentEntries--;
+ CacheName = CONTAINING_RECORD (p, NETBIOS_CACHE, Linkage);
+
+ NB_DEBUG2 (CACHE, ("Free cache entry %lx\n", CacheName));
+
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free entries");
+
+ }
+ } // for loop
+
+ CTEAssert( CacheTable->CurrentEntries == 0 );
+
+ NbiFreeMemory (CacheTable, sizeof(NETBIOS_CACHE_TABLE) + sizeof(LIST_ENTRY) * ( CacheTable->MaxHashIndex - 1) ,
+ MEMORY_CACHE, "Free Cache Table");
+
+} /* DestroyNetbiosCacheTable */
+
+
diff --git a/private/ntos/tdi/isnp/nb/config.c b/private/ntos/tdi/isnp/nb/config.c
new file mode 100644
index 000000000..8689c5d20
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/config.c
@@ -0,0 +1,661 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This contains all routines necessary for the support of the dynamic
+ configuration of the ISN Netbios module.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Local functions used to access the registry.
+//
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiGetConfiguration)
+#pragma alloc_text(INIT,NbiFreeConfiguration)
+#pragma alloc_text(INIT,NbiGetConfigValue)
+#pragma alloc_text(INIT,NbiAddBind)
+#pragma alloc_text(INIT,NbiAddExport)
+#pragma alloc_text(INIT,NbiReadLinkageInformation)
+#endif
+
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get information from the configuration
+ management routines. We read the registry, starting at RegistryPath,
+ to get the parameters. If they don't exist, we use the defaults
+ set in ipxcnfg.h file. A list of adapters to bind to is chained
+ on to the config information.
+
+Arguments:
+
+ DriverObject - Used for logging errors.
+
+ RegistryPath - The name of Netbios' node in the registry.
+
+ ConfigPtr - Returns the configuration information.
+
+Return Value:
+
+ Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES
+ otherwise.
+
+--*/
+{
+ PWSTR RegistryPathBuffer;
+ PCONFIG Config;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2];
+ NTSTATUS Status;
+ ULONG One = 1;
+ ULONG Two = 2;
+ ULONG Three = 3;
+ ULONG Four = 4;
+ ULONG Five = 5;
+ ULONG Eight = 8;
+ ULONG FortyEight = 48;
+ ULONG Sixty = 60;
+ ULONG TwoFifty = 250;
+ ULONG FiveHundred = 500;
+ ULONG MaxMTU = 0xffffffff;
+
+ PWSTR Parameters = L"Parameters";
+ struct {
+ PWSTR KeyName;
+ PULONG DefaultValue;
+ } ParameterValues[CONFIG_PARAMETERS] = {
+ { L"AckDelayTime", &TwoFifty } , // milliseconds
+ { L"AckWindow", &Two } ,
+ { L"AckWindowThreshold", &FiveHundred } , // milliseconds
+ { L"EnablePiggyBackAck", &One } ,
+ { L"Extensions", &One } ,
+ { L"RcvWindowMax", &Four } ,
+ { L"BroadcastCount", &Three } ,
+ { L"BroadcastTimeout", &One } , // half-seconds
+ { L"ConnectionCount", &Five } ,
+ { L"ConnectionTimeout", &Two } , // half-seconds
+ { L"InitPackets", &Eight } ,
+ { L"MaxPackets", &FortyEight } ,
+ { L"InitialRetransmissionTime", &FiveHundred } , // milliseconds
+ { L"Internet", &One } ,
+ { L"KeepAliveCount", &Eight } ,
+ { L"KeepAliveTimeout", &Sixty } , // half-seconds
+ { L"RetransmitMax", &Eight } ,
+ { L"RouterMTU", &MaxMTU } };
+ UINT i;
+
+
+ //
+ // Allocate memory for the main config structure.
+ //
+
+ Config = NbiAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config");
+ if (Config == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, sizeof(CONFIG), MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Config->DeviceName.Buffer = NULL;
+ Config->BindName.Buffer = NULL;
+ Config->DriverObject = DriverObject; // save this to log errors
+
+ //
+ // Read in the NDIS binding information (if none is present
+ // the array will be filled with all known drivers).
+ //
+ // NbiReadLinkageInformation expects a null-terminated path,
+ // so we have to create one from the UNICODE_STRING.
+ //
+
+ RegistryPathBuffer = (PWSTR)NbiAllocateMemory(RegistryPath->Length + sizeof(WCHAR),
+ MEMORY_CONFIG, "RegistryPathBuffer");
+ if (RegistryPathBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)DriverObject, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG);
+ NbiFreeConfiguration(Config);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length);
+ *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0';
+
+ Config->RegistryPathBuffer = RegistryPathBuffer;
+
+
+ //
+ // Determine what name to export and who to bind to.
+ //
+
+ Status = NbiReadLinkageInformation (Config);
+
+ if (Status != STATUS_SUCCESS) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ return Status;
+ }
+
+
+ //
+ // Read the per-transport (as opposed to per-binding)
+ // parameters.
+ //
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Parameters key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Parameters;
+
+ //
+ // 2-18) Call NbiSetBindingValue for each of the keys we
+ // care about.
+ //
+
+ for (i = 0; i < CONFIG_PARAMETERS; i++) {
+
+ QueryTable[i+1].QueryRoutine = NbiGetConfigValue;
+ QueryTable[i+1].Flags = 0;
+ QueryTable[i+1].Name = ParameterValues[i].KeyName;
+ QueryTable[i+1].EntryContext = (PVOID)i;
+ QueryTable[i+1].DefaultType = REG_DWORD;
+ QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue);
+ QueryTable[i+1].DefaultLength = sizeof(ULONG);
+
+ }
+
+ //
+ // 19) Stop
+ //
+
+ QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL;
+ QueryTable[CONFIG_PARAMETERS+1].Flags = 0;
+ QueryTable[CONFIG_PARAMETERS+1].Name = NULL;
+
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+
+ NbiFreeConfiguration(Config);
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 701,
+ Status,
+ Parameters,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ NbiFreeMemory (RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer");
+ *ConfigPtr = Config;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfiguration */
+
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to get free any storage that was allocated
+ by NbiGetConfiguration in producing the specified CONFIG structure.
+
+Arguments:
+
+ Config - A pointer to the configuration information structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Config->BindName.Buffer) {
+ NbiFreeMemory (Config->BindName.Buffer, Config->BindName.MaximumLength, MEMORY_CONFIG, "BindName");
+ }
+
+ if (Config->DeviceName.Buffer) {
+ NbiFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName");
+ }
+
+ NbiFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config");
+
+} /* NbiFreeConfig */
+
+
+NTSTATUS
+NbiGetConfigValue(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each entry in the Parameters
+ node to set the config values. The table is set up
+ so that this function will be called with correct default
+ values for keys that are not present.
+
+Arguments:
+
+ ValueName - The name of the value (ignored).
+
+ ValueType - The type of the value (REG_DWORD -- ignored).
+
+ ValueData - The data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the CONFIG structure.
+
+ EntryContext - The index in Config->Parameters to save the value.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ ULONG Data = *(UNALIGNED ULONG *)ValueData;
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+ UNREFERENCED_PARAMETER(ValueLength);
+
+ if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+
+ switch ( (ULONG) EntryContext ) {
+ case CONFIG_ROUTER_MTU:
+ if ( ( Data - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER) ) <= 0 ) {
+ Config->Parameters[CONFIG_ROUTER_MTU] = 0xffffffff;
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 704,
+ STATUS_INVALID_PARAMETER,
+ ValueName,
+ 0,
+ NULL);
+ return STATUS_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ NB_DEBUG2 (CONFIG, ("Config parameter %d, value %lx\n",
+ (ULONG)EntryContext, Data));
+ Config->Parameters[(ULONG)EntryContext] = Data;
+
+ return STATUS_SUCCESS;
+
+} /* NbiGetConfigValue */
+
+
+NTSTATUS
+NbiAddBind(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Bind" multi-string and
+ saves the information in a Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Bind" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a count of binds that is incremented.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read bind value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "BindName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->BindName.Buffer = NameBuffer;
+ Config->BindName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->BindName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddBind */
+
+
+NTSTATUS
+NbiAddExport(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues
+ It is called for each piece of the "Export" multi-string. It
+ saves the first callback string in the Config structure.
+
+Arguments:
+
+ ValueName - The name of the value ("Export" -- ignored).
+
+ ValueType - The type of the value (REG_SZ -- ignored).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData.
+
+ Context - A pointer to the Config structure.
+
+ EntryContext - A pointer to a ULONG that goes to 1 after the
+ first call to this routine (so we know to ignore other ones).
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PCONFIG Config = (PCONFIG)Context;
+ PULONG ValueReadOk = ((PULONG)EntryContext);
+ PWCHAR NameBuffer;
+
+ UNREFERENCED_PARAMETER(ValueName);
+ UNREFERENCED_PARAMETER(ValueType);
+
+ if (*ValueReadOk == 0) {
+
+ NB_DEBUG2 (CONFIG, ("Read export value %ws\n", ValueData));
+
+ NameBuffer = (PWCHAR)NbiAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName");
+ if (NameBuffer == NULL) {
+ NbiWriteResourceErrorLog ((PVOID)Config->DriverObject, ValueLength, MEMORY_CONFIG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory (NameBuffer, ValueData, ValueLength);
+ Config->DeviceName.Buffer = NameBuffer;
+ Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR));
+ Config->DeviceName.MaximumLength = (USHORT)ValueLength;
+
+ //
+ // Set this to ignore any other callbacks and let the
+ // caller know we read something.
+ //
+
+ *ValueReadOk = 1;
+
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiAddExport */
+
+
+NTSTATUS
+NbiReadLinkageInformation(
+ IN PCONFIG Config
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to read its linkage information
+ from the registry.
+
+Arguments:
+
+ Config - The config structure which will have per-binding information
+ linked on to it.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+ PWSTR Subkey = L"Linkage";
+ PWSTR Bind = L"Bind";
+ PWSTR Export = L"Export";
+ ULONG ValueReadOk; // set to TRUE when a value is read correctly
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Switch to the Linkage key below Netbios
+ //
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
+ QueryTable[0].Name = Subkey;
+
+ //
+ // 1) Call NbiAddExport for each string in "Export"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddExport;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = Export;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 2) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 702,
+ Status,
+ Export,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+
+ //
+ // 1) Change to call NbiAddBind for each string in "Bind"
+ //
+
+ QueryTable[1].QueryRoutine = NbiAddBind;
+ QueryTable[1].Flags = 0; // not required
+ QueryTable[1].Name = Bind;
+ QueryTable[1].EntryContext = (PVOID)&ValueReadOk;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ ValueReadOk = 0;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Config->RegistryPathBuffer,
+ QueryTable,
+ (PVOID)Config,
+ NULL);
+
+ if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)Config->DriverObject,
+ EVENT_IPX_ILLEGAL_CONFIG,
+ 703,
+ Status,
+ Bind,
+ 0,
+ NULL);
+ return STATUS_DEVICE_CONFIGURATION_ERROR;
+ }
+
+ return STATUS_SUCCESS;
+
+} /* NbiReadLinkageInformation */
+
diff --git a/private/ntos/tdi/isnp/nb/config.h b/private/ntos/tdi/isnp/nb/config.h
new file mode 100644
index 000000000..99b6c6357
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/config.h
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ config.h
+
+Abstract:
+
+ Private include file for the ISN Netbios module.
+ file defines all constants and structures necessary for support of
+ the dynamic configuration of ST.
+
+Revision History:
+
+--*/
+
+
+//
+// These are used to index into the Parameters array in CONFIG.
+//
+
+#define CONFIG_ACK_DELAY_TIME 0
+#define CONFIG_ACK_WINDOW 1
+#define CONFIG_ACK_WINDOW_THRESHOLD 2
+#define CONFIG_ENABLE_PIGGYBACK_ACK 3
+#define CONFIG_EXTENSIONS 4
+#define CONFIG_RCV_WINDOW_MAX 5
+#define CONFIG_BROADCAST_COUNT 6
+#define CONFIG_BROADCAST_TIMEOUT 7
+#define CONFIG_CONNECTION_COUNT 8
+#define CONFIG_CONNECTION_TIMEOUT 9
+#define CONFIG_INIT_PACKETS 10
+#define CONFIG_MAX_PACKETS 11
+#define CONFIG_INIT_RETRANSMIT_TIME 12
+#define CONFIG_INTERNET 13
+#define CONFIG_KEEP_ALIVE_COUNT 14
+#define CONFIG_KEEP_ALIVE_TIMEOUT 15
+#define CONFIG_RETRANSMIT_MAX 16
+#define CONFIG_ROUTER_MTU 17
+#define CONFIG_PARAMETERS 18
+
+//
+// Main configuration structure.
+//
+
+typedef struct _CONFIG {
+
+ ULONG Parameters[CONFIG_PARAMETERS]; // index defined above
+ NDIS_STRING DeviceName; // device name exported
+ NDIS_STRING BindName; // device to bind to
+ PWSTR RegistryPathBuffer; // path to config info
+ PDRIVER_OBJECT DriverObject; // used for logging errors
+
+} CONFIG, * PCONFIG;
+
+
+NTSTATUS
+NbiGetConfiguration (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ OUT PCONFIG * ConfigPtr
+ );
+
+VOID
+NbiFreeConfiguration (
+ IN PCONFIG Config
+ );
+
diff --git a/private/ntos/tdi/isnp/nb/connect.c b/private/ntos/tdi/isnp/nb/connect.c
new file mode 100644
index 000000000..7ee7204b5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/connect.c
@@ -0,0 +1,3628 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ connect.c
+
+Abstract:
+
+ This routine contains the code to handle connect requests
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+
+BOOLEAN
+NbiCancelTdiConnect(
+ IN PDEVICE pDevice,
+ IN PREQUEST pRequest,
+ IN PCONNECTION pConnection
+ );
+#endif // RASAUTODIAL
+
+
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a find route request
+ previously issued to IPX completes.
+
+Arguments:
+
+ FindRouteRequest - The find route request that was issued.
+
+ FoundRoute - TRUE if the route was found.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ UINT i;
+ BOOLEAN LocalRoute;
+ USHORT TickCount;
+ PREQUEST RequestToComplete;
+ PUSHORT Counts;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ Connection = CONTAINING_RECORD (FindRouteRequest, CONNECTION, FindRouteRequest);
+
+ NB_GET_CANCEL_LOCK(&CancelLH);
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection->FindRouteInProgress = FALSE;
+
+ if (FoundRoute) {
+
+ //
+ // See if the route is local or not (for local routes
+ // we use the real MAC address in the local target, but
+ // the NIC ID may not be what we expect.
+ //
+
+ LocalRoute = TRUE;
+
+ for (i = 0; i < 6; i++) {
+ if (FindRouteRequest->LocalTarget.MacAddress[i] != 0x00) {
+ LocalRoute = FALSE;
+ }
+ }
+
+ if (LocalRoute) {
+
+#if defined(_PNP_POWER)
+ Connection->LocalTarget.NicHandle = FindRouteRequest->LocalTarget.NicHandle;
+#else
+ Connection->LocalTarget.NicId = FindRouteRequest->LocalTarget.NicId;
+#endif _PNP_POWER
+
+ } else {
+
+ Connection->LocalTarget = FindRouteRequest->LocalTarget;
+
+ }
+
+ Counts = (PUSHORT)(&FindRouteRequest->Reserved2);
+ TickCount = Counts[0];
+
+ if (TickCount > 1) {
+
+ //
+ // Each tick is 55 ms, and for our timeout we use 10 ticks
+ // worth (this makes tick count of 1 be about 500 ms, the
+ // default).
+ //
+ // We get 55 milliseconds from
+ //
+ // 1 second * 1000 milliseconds 55 ms
+ // -------- ----------------- = -----
+ // 18.21 ticks 1 second tick
+ //
+
+ Connection->TickCount = TickCount;
+ Connection->BaseRetransmitTimeout = (TickCount * 550) / SHORT_TIMER_DELTA;
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+ }
+
+ Connection->HopCount = Counts[1];
+
+ }
+
+ //
+ // If the call failed we just use whatever route we had before
+ // (on a connect it will be from the name query response, on
+ // a listen from whatever the incoming connect frame had).
+ //
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_W_ROUTE)) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // Continue on with the session init frame.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+ // Maximum packet size is the lower of RouterMtu and MaximumSendSize.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER) , Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION) ;
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ //
+ // Don't set RcvSequenceMax yet because we don't know
+ // if the connection is old or new netbios.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
+
+ //
+ // We found a route, we need to start the connect
+ // process by sending out the session initialize
+ // frame. We start the timer to handle retries.
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiSendSessionInitialize (Connection);
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ROUTE)) {
+
+ if (Connection->ListenRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_ACTIVE);
+ RequestToComplete = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+
+ } else if (Connection->AcceptRequest != NULL) {
+
+ NbiTransferReferenceConnection (Connection, CREF_ACCEPT, CREF_ACTIVE);
+ RequestToComplete = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ } else {
+
+ CTEAssert (FALSE);
+ RequestToComplete = NULL;
+
+ }
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+#if defined(_PNP_POWER)
+ &Connection->LocalTarget.NicHandle,
+#else
+ Connection->LocalTarget.NicId,
+#endif _PNP_POWER
+ &Connection->LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+
+
+ // Take the lowest of MaximumPacketSize ( set from the sessionInit
+ // frame ), MaximumSendSize and RouterMtu.
+
+ if (Connection->MaximumPacketSize > Connection->LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)) {
+
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER), Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION);
+
+ } else {
+
+ // Connection->MaximumPacketSize is what was set by the sender so already
+ // accounts for the header.
+ Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER), Connection->MaximumPacketSize ) ;
+
+ }
+
+ Connection->ReceiveWindowSize = 6;
+ Connection->SendWindowSize = 2;
+ Connection->MaxSendWindowSize = 6; // BUGBUG: Base on what he sent
+
+ if (Connection->NewNetbios) {
+ CTEAssert (Connection->LocalRcvSequenceMax == 4); // should have been set
+ Connection->LocalRcvSequenceMax = Connection->ReceiveWindowSize;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ ++Device->Statistics.OpenConnections;
+
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // StartWatchdog acquires TimerLock, so we have to
+ // free Lock first.
+ //
+
+
+ NbiStartWatchdog (Connection);
+
+ //
+ // This releases the connection lock, so that SessionInitAckData
+ // can't be freed before it is copied.
+ //
+
+ NbiSendSessionInitAck(
+ Connection,
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ &LockHandle1);
+
+ if (RequestToComplete != NULL) {
+
+ REQUEST_STATUS(RequestToComplete) = STATUS_SUCCESS;
+
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_FIND_ROUTE);
+
+} /* NbiFindRouteComplete */
+
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to open a connection. Note that the connection that
+ is open is of little use until associated with an address; until then,
+ the only thing that can be done with it is close it.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PFILE_FULL_EA_INFORMATION ea;
+#ifdef ISN_NT
+ PIRP Irp = (PIRP)Request;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+#endif
+
+ //
+ // First, try to make a connection object to represent this pending
+ // connection. Then fill in the relevant fields.
+ // In addition to the creation, if successful NbfCreateConnection
+ // will create a second reference which is removed once the request
+ // references the connection, or if the function exits before that.
+
+ if (!(Connection = NbiCreateConnection (Device))) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // set the connection context so we can connect the user to this data
+ // structure
+ //
+
+ ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
+ RtlCopyMemory (
+ &Connection->Context,
+ &ea->EaName[ea->EaNameLength+1],
+ sizeof (PVOID));
+
+ //
+ // let file object point at connection and connection at file object
+ //
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)Connection;
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONNECTION_FILE;
+#ifdef ISN_NT
+ Connection->FileObject = IrpSp->FileObject;
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* NbiOpenConnection */
+
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to stop an active connection.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection to be stopped.
+
+ DisconnectStatus - The reason for the disconnect. One of:
+ STATUS_LINK_FAILED: We timed out trying to probe the remote.
+ STATUS_REMOTE_DISCONNECT: The remote sent a session end.
+ STATUS_LOCAL_DISCONNECT: The local side disconnected.
+ STATUS_CANCELLED: A send or receive on this connection was cancelled.
+ STATUS_INVALID_CONNECTION: The local side closed the connection.
+ STATUS_INVALID_ADDRESS: The local side closed the address.
+
+ LockHandle - The handle which the connection lock was acquired with.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST ListenRequest, AcceptRequest, SendRequest, ReceiveRequest,
+ DisconnectWaitRequest, ConnectRequest;
+ PREQUEST Request, TmpRequest;
+ BOOLEAN DerefForPacketize;
+ BOOLEAN DerefForWaitPacket;
+ BOOLEAN DerefForActive;
+ BOOLEAN DerefForWaitCache;
+ BOOLEAN SendSessionEnd;
+ BOOLEAN ActiveReceive;
+ BOOLEAN IndicateToClient;
+ BOOLEAN ConnectionWasActive;
+ PDEVICE Device = NbiDevice;
+ PADDRESS_FILE AddressFile;
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+
+ NB_DEBUG2 (CONNECTION, ("Stop connection %lx (%lx)\n", Connection, DisconnectStatus));
+
+ //
+ // These flags control our actions after we set the state to
+ // DISCONNECT.
+ //
+
+ DerefForPacketize = FALSE;
+ DerefForWaitPacket = FALSE;
+ DerefForActive = FALSE;
+ DerefForWaitCache = FALSE;
+ SendSessionEnd = FALSE;
+ ActiveReceive = FALSE;
+ IndicateToClient = FALSE;
+ ConnectionWasActive = FALSE;
+
+ //
+ // These contain requests or queues of request to complete.
+ //
+
+ ListenRequest = NULL;
+ AcceptRequest = NULL;
+ SendRequest = NULL;
+ ReceiveRequest = NULL;
+ DisconnectWaitRequest = NULL;
+ ConnectRequest = NULL;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ --Device->Statistics.OpenConnections;
+
+ ConnectionWasActive = TRUE;
+
+ Connection->Status = DisconnectStatus;
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_LOCAL_DISCONNECT)) {
+
+ //
+ // Send out session end frames, but fewer if
+ // we timed out.
+ //
+ // BUGBUG: What about STATUS_CANCELLED?
+ //
+
+ Connection->Retries = (DisconnectStatus == STATUS_LOCAL_DISCONNECT) ?
+ Device->ConnectionCount :
+ (Device->ConnectionCount / 2);
+
+ SendSessionEnd = TRUE;
+ Connection->SubState = CONNECTION_SUBSTATE_D_W_ACK;
+
+ //
+ // CTEStartTimer doesn't deal with changing the
+ // expiration time of a running timer, so we have
+ // to stop it first. If we succeed in stopping the
+ // timer, then the CREF_TIMER reference from the
+ // previous starting of the timer remains, so we
+ // don't need to reference the connection again.
+ //
+
+ if (!CTEStopTimer (&Connection->Timer)) {
+ NbiReferenceConnectionLock (Connection, CREF_TIMER);
+ }
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_TRANSFER) {
+ ActiveReceive = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_DISCONNECT;
+ DerefForActive = TRUE;
+
+ if (Connection->DisconnectWaitRequest != NULL) {
+ DisconnectWaitRequest = Connection->DisconnectWaitRequest;
+ Connection->DisconnectWaitRequest = NULL;
+ }
+
+ if ((DisconnectStatus == STATUS_LINK_FAILED) ||
+ (DisconnectStatus == STATUS_REMOTE_DISCONNECT) ||
+ (DisconnectStatus == STATUS_CANCELLED)) {
+
+ IndicateToClient = TRUE;
+
+ }
+
+ //
+ // If we are inside NbiAssignSequenceAndSend, add
+ // a reference so the connection won't go away during it.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+ *(Connection->NdisSendReference) = TRUE;
+ NB_DEBUG2 (SEND, ("Adding CREF_NDIS_SEND to %lx\n", Connection));
+ NbiReferenceConnectionLock (Connection, CREF_NDIS_SEND);
+ }
+
+ //
+ // Clean up some other stuff.
+ //
+
+ Connection->ReceiveUnaccepted = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ //
+ // Update our counters. BUGBUG: Some of these we
+ // never use.
+ //
+
+ switch (DisconnectStatus) {
+
+ case STATUS_LOCAL_DISCONNECT:
+ ++Device->Statistics.LocalDisconnects;
+ break;
+ case STATUS_REMOTE_DISCONNECT:
+ ++Device->Statistics.RemoteDisconnects;
+ break;
+ case STATUS_LINK_FAILED:
+ ++Device->Statistics.LinkFailures;
+ break;
+ case STATUS_IO_TIMEOUT:
+ ++Device->Statistics.SessionTimeouts;
+ break;
+ case STATUS_CANCELLED:
+ ++Device->Statistics.CancelledConnections;
+ break;
+ case STATUS_REMOTE_RESOURCES:
+ ++Device->Statistics.RemoteResourceFailures;
+ break;
+ case STATUS_INVALID_CONNECTION:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INSUFFICIENT_RESOURCES:
+ ++Device->Statistics.LocalResourceFailures;
+ break;
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_REMOTE_NOT_LISTENING:
+ ++Device->Statistics.NotFoundFailures;
+ break;
+ default:
+ CTEAssert(FALSE);
+ break;
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ //
+ // There is a connect in progress. We have to find ourselves
+ // in the pending connect queue if we are there.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) {
+ RemoveEntryList (REQUEST_LINKAGE(Connection->ConnectRequest));
+ DerefForWaitCache = TRUE;
+ }
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) {
+
+ ConnectRequest = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ }
+
+ }
+
+
+ //
+ // If we allocated this memory, free it.
+ //
+
+ if (Connection->SessionInitAckDataLength > 0) {
+
+ NbiFreeMemory(
+ Connection->SessionInitAckData,
+ Connection->SessionInitAckDataLength,
+ MEMORY_CONNECTION,
+ "SessionInitAckData");
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+
+ }
+
+
+ if (Connection->ListenRequest != NULL) {
+
+ ListenRequest = Connection->ListenRequest;
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(ListenRequest)); // take out of Device->ListenQueue
+
+ }
+
+ if (Connection->AcceptRequest != NULL) {
+
+ AcceptRequest = Connection->AcceptRequest;
+ Connection->AcceptRequest = NULL;
+
+ }
+
+
+ //
+ // BUGBUG: Do we need to stop the connection timer?
+ // I don't think so.
+ //
+
+
+
+ //
+ // A lot of this we only have to tear down if we were
+ // active before this, because once we are stopping nothing
+ // new will get started. BUGBUG: Some of the other stuff
+ // can be put inside this if also.
+ //
+
+ if (ConnectionWasActive) {
+
+ //
+ // Stop any receives. If there is one that is actively
+ // transferring we leave it and just run down the rest
+ // of the queue. If not, we queue the rest of the
+ // queue on the back of the current one and run
+ // down them all.
+ //
+
+ if (ActiveReceive) {
+
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+
+ //
+ // Connection->ReceiveRequest will get set to NULL
+ // when the transfer completes.
+ //
+
+ } else {
+
+ ReceiveRequest = Connection->ReceiveRequest;
+ if (ReceiveRequest) {
+ REQUEST_SINGLE_LINKAGE (ReceiveRequest) = Connection->ReceiveQueue.Head;
+ } else {
+ ReceiveRequest = Connection->ReceiveQueue.Head;
+ }
+ Connection->ReceiveRequest = NULL;
+
+ }
+
+ Connection->ReceiveQueue.Head = NULL;
+
+
+ if ((Request = Connection->FirstMessageRequest) != NULL) {
+
+ //
+ // If the current request has some sends outstanding, then
+ // we dequeue it from the queue to let it complete when
+ // the sends complete. In that case we set SendRequest
+ // to be the rest of the queue, which will be aborted.
+ // If the current request has no sends, then we put
+ // queue everything to SendRequest to be aborted below.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ //
+ // NOTE: If this is a multi-request message, then
+ // the linkage of Request will already point to the
+ // send queue head, but we don't bother checking.
+ //
+
+ SendRequest = Request;
+ REQUEST_SINGLE_LINKAGE (Request) = Connection->SendQueue.Head;
+
+ } else {
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->FirstMessageRequest = NULL;
+
+ } else {
+
+ //
+ // This may happen if we were sending a probe when a
+ // send was submitted, and the probe timed out.
+ //
+
+ SendRequest = Connection->SendQueue.Head;
+
+ }
+
+ Connection->SendQueue.Head = NULL;
+
+ }
+
+
+ if (Connection->OnWaitPacketQueue) {
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+ DerefForWaitPacket = TRUE;
+ }
+
+ if (Connection->OnPacketizeQueue) {
+ Connection->OnPacketizeQueue = FALSE;
+ RemoveEntryList (&Connection->PacketizeLinkage);
+ DerefForPacketize = TRUE;
+ }
+
+ //
+ // BUGBUG: Should we check if DataAckPending is TRUE and
+ // send an ack??
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // We can't acquire TimerLock with Lock held, since
+ // we sometimes call ReferenceConnection (which does an
+ // interlocked add using Lock) with TimerLock held.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle3);
+
+ if (Connection->OnShortList) {
+ Connection->OnShortList = FALSE;
+ RemoveEntryList (&Connection->ShortList);
+ }
+
+ if (Connection->OnLongList) {
+ Connection->OnLongList = FALSE;
+ RemoveEntryList (&Connection->LongList);
+ }
+
+ if (Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = FALSE;
+ RemoveEntryList (&Connection->DataAckLinkage);
+ Device->DataAckQueueChanged = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle3);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+
+ if (IndicateToClient) {
+
+ AddressFile = Connection->AddressFile;
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_DISCONNECT]) {
+
+ NB_DEBUG2 (CONNECTION, ("Session end indicated on connection %lx\n", Connection));
+
+ (*AddressFile->DisconnectHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_DISCONNECT],
+ Connection->Context,
+ 0, // DisconnectData
+ NULL,
+ 0, // DisconnectInformation
+ NULL,
+ TDI_DISCONNECT_RELEASE); // DisconnectReason. BUGBUG: Clean it up?
+
+ }
+
+ }
+
+
+ if (DisconnectWaitRequest != NULL) {
+
+ //
+ // Make the TDI tester happy by returning CONNECTION_RESET
+ // here.
+ //
+
+ if (DisconnectStatus == STATUS_REMOTE_DISCONNECT) {
+ REQUEST_STATUS(DisconnectWaitRequest) = STATUS_CONNECTION_RESET;
+ } else {
+ REQUEST_STATUS(DisconnectWaitRequest) = DisconnectStatus;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (DisconnectWaitRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (DisconnectWaitRequest);
+ NbiFreeRequest (Device, DisconnectWaitRequest);
+
+ }
+
+ if (ConnectRequest != NULL) {
+
+ REQUEST_STATUS (ConnectRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ConnectRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest(ConnectRequest);
+ NbiFreeRequest (Device, ConnectRequest);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ }
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION(ListenRequest) = 0;
+ REQUEST_STATUS(ListenRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest(Device, ListenRequest);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ }
+
+ if (AcceptRequest != NULL) {
+
+ REQUEST_INFORMATION(AcceptRequest) = 0;
+ REQUEST_STATUS(AcceptRequest) = STATUS_LOCAL_DISCONNECT;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest(Device, AcceptRequest);
+
+ NbiDereferenceConnection (Connection, CREF_ACCEPT);
+
+ }
+
+ while (ReceiveRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (ReceiveRequest);
+
+ REQUEST_STATUS (ReceiveRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (ReceiveRequest) = 0;
+
+ NB_DEBUG2 (RECEIVE, ("StopConnection aborting receive %lx\n", ReceiveRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (ReceiveRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (ReceiveRequest);
+ NbiFreeRequest (Device, ReceiveRequest);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ ReceiveRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ }
+
+ while (SendRequest != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+
+ REQUEST_STATUS (SendRequest) = DisconnectStatus;
+ REQUEST_INFORMATION (SendRequest) = 0;
+
+ NB_DEBUG2 (SEND, ("StopConnection aborting send %lx\n", SendRequest));
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+
+ SendRequest = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ if (SendSessionEnd) {
+ NbiSendSessionEnd (Connection);
+ }
+
+ if (DerefForWaitCache) {
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ }
+
+ if (DerefForPacketize) {
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+ }
+
+ if (DerefForWaitPacket) {
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+ }
+
+ if (DerefForActive) {
+ NbiDereferenceConnection (Connection, CREF_ACTIVE);
+ }
+
+} /* NbiStopConnection */
+
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to close a connection.
+
+Arguments:
+
+ Device - Pointer to the device for this driver.
+
+ Request - Pointer to the request representing the open.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (CONNECTION, ("Close connection %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and some thread has already done cleanup,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ if ( Connection->CanBeDestroyed && ( Connection->ThreadsInHandleConnectionZero == 0 ) ) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NbiDestroyConnection(Connection);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ Connection->ClosePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ return Status;
+
+} /* NbiCloseConnection */
+
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the association of the connection and
+ the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject;
+#endif
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
+ CTELockHandle LockHandle;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+
+ //
+ // The request request parameters hold
+ // get a pointer to the address FileObject, which points us to the
+ // transport's address object, which is where we want to put the
+ // connection.
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)REQUEST_PARAMETERS(Request);
+
+#ifdef ISN_NT
+
+ Status = ObReferenceObjectByHandle (
+ Parameters->AddressHandle,
+ 0L,
+ 0,
+ KernelMode,
+ (PVOID *)&FileObject,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ AddressFile = (PADDRESS_FILE)(FileObject->FsContext);
+
+#else
+
+ //
+ // I don't know how this works in a VxD.
+ //
+
+ AddressFile = (PADDRESS_FILE)(Parameters->AddressHandle);
+
+#endif
+
+ //
+ // Make sure the address file is valid, and reference it.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+
+#ifdef ISN_NT
+ ObDereferenceObject (FileObject);
+#endif
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Associate connection %lx with address file %lx\n",
+ Connection, AddressFile));
+
+
+ //
+ // Now insert the connection into the database of the address.
+ //
+
+ Address = AddressFile->Address;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFile != NULL) {
+
+ //
+ // The connection is already associated with
+ // an address file.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ if (AddressFile->State == ADDRESSFILE_STATE_OPEN) {
+
+ Connection->AddressFile = AddressFile;
+ Connection->AddressFileLinked = TRUE;
+ InsertHeadList (&AddressFile->ConnectionDatabase, &Connection->AddressFileLinkage);
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_INVALID_ADDRESS;
+ }
+
+ }
+
+#ifdef ISN_NT
+
+ //
+ // We don't need the reference to the file object, we just
+ // used it to get from the handle to the object.
+ //
+
+ ObDereferenceObject (FileObject);
+
+#endif
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAssociateAddress */
+
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the disassociation of the connection
+ and the address for the user.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the associate.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ NTSTATUS Status;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ CTELockHandle LockHandle;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Disassociate connection %lx\n", Connection));
+
+
+ //
+ // First check if the connection is still active.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if (Connection->State != CONNECTION_STATE_INACTIVE) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_ADDRESS
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ //
+ // BUGBUG: Keep the sync through the function??
+ //
+
+ NB_END_SYNC (&SyncContext);
+
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is associated and is not in the
+ // middle of disassociating.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL)) {
+
+ if (Connection->ReferenceCount == 0) {
+
+ //
+ // Because the connection still has a reference to
+ // the address file, we know it is still valid. We
+ // set the connection address file to the temporary
+ // value of -1, which prevents somebody else from
+ // disassociating it and also prevents a new association.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ //
+ // Set this so when the count goes to 0 it will
+ // be disassociated and the request completed.
+ //
+
+ Connection->DisassociatePending = Request;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisassociateAddress */
+
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine posts a listen on a connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the listen.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_WAITING;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+
+ if (!Request->Cancel) {
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen %lx on %lx\n", Request, Connection));
+ InsertTailList (&Device->ListenQueue, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelListen);
+ Connection->ListenRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_LISTEN);
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen %lx on %lx\n", Request, Connection));
+ Connection->State = CONNECTION_STATE_INACTIVE;
+ Status = STATUS_CANCELLED;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiListen */
+
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine accepts a connection to a remote machine. The
+ connection must previously have completed a listen with
+ the TDI_QUERY_ACCEPT flag on.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the accept.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_ACCEPT, CREF_ACCEPT);
+ Connection->AcceptRequest = Request;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Accept received on %lx\n", Connection));
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Accept received on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiAccept */
+
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_CONNECT Parameters;
+#if 0
+ PLARGE_INTEGER RequestedTimeout;
+ LARGE_INTEGER RealTimeout;
+#endif
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle1, LockHandle2;
+ CTELockHandle CancelLH;
+ BOOLEAN bLockFreed = FALSE;
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ //
+ // The connection must be inactive, but associated and
+ // with no disassociate or close pending.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->RequestConnectionInformation->RemoteAddress), FALSE);
+
+ if (RemoteName == NULL) {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ } else {
+
+ NbiReferenceConnectionLock (Connection, CREF_CONNECT);
+ Connection->State = CONNECTION_STATE_CONNECTING;
+ RtlCopyMemory (Connection->RemoteName, RemoteName->NetbiosName, 16);
+
+ Connection->Retries = Device->ConnectionCount;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+
+ Status = NbiTdiConnectFindName(
+ Device,
+ Request,
+ Connection,
+ CancelLH,
+ LockHandle1,
+ LockHandle2,
+ &bLockFreed);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Connect on invalid connection %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ if (!bLockFreed) {
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiConnect */
+
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ )
+{
+ NTSTATUS Status;
+ PNETBIOS_CACHE CacheName;
+
+ //
+ // See what is up with this Netbios name.
+ //
+
+ Status = CacheFindName(
+ Device,
+ FindNameConnect,
+ Connection->RemoteName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this connect
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_FIND_NAME;
+
+
+ if (!Request->Cancel) {
+
+ InsertTailList( &Device->WaitingConnects, REQUEST_LINKAGE(Request));
+ IoSetCancelRoutine (Request, NbiCancelConnectFindName);
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_WAIT_CACHE);
+ NB_DEBUG2 (CONNECTION, ("Queueing up connect %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // We don't need to worry about referencing CacheName
+ // because we stop using it before we release the lock.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelConnectWaitResponse);
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SWAP_IRQL( CancelLH, ConnectionLH);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ Connection->ConnectRequest = Request;
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_DEBUG2 (CONNECTION, ("Found connect cached %lx on %lx\n",
+ Request, Connection));
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+ NB_FREE_LOCK (&Connection->Lock, ConnectionLH);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
+
+ //
+ // When this completes, we will send the session init.
+ // We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (CacheName->FirstResponse.NetworkAddress != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ Status = STATUS_PENDING;
+
+ //
+ // This jump is like falling out of the if, except
+ // it skips over freeing the connection lock since
+ // we just did that.
+ //
+
+ *pbLockFreed = TRUE;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We could not find or queue a request for
+ // this remote, fail it. When the refcount
+ // drops the state will go to INACTIVE and
+ // the connection ID will be deassigned.
+ //
+
+ if (Status == STATUS_DEVICE_DOES_NOT_EXIST) {
+ Status = STATUS_BAD_NETWORK_PATH;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, DeviceLH);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ }
+
+ return Status;
+} /* NbiTdiConnectFindName */
+
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine connects to a remote machine.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the connect.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PCONNECTION Connection;
+ BOOLEAN DisconnectWait;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ CTELockHandle CancelLH;
+
+
+ //
+ // Check that the connection is valid. This references
+ // the connection.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ DisconnectWait = (BOOLEAN)
+ ((((PTDI_REQUEST_KERNEL_DISCONNECT)(REQUEST_PARAMETERS(Request)))->RequestFlags &
+ TDI_DISCONNECT_WAIT) != 0);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+
+ //
+ // We need to be inside a sync because NbiStopConnection
+ // expects that.
+ //
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (DisconnectWait) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // This disconnect wait will get completed by
+ // NbiStopConnection.
+ //
+
+ if (Connection->DisconnectWaitRequest == NULL) {
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelDisconnectWait);
+ NB_DEBUG2 (CONNECTION, ("Disconnect wait queued on connection %lx\n", Connection));
+ Connection->DisconnectWaitRequest = Request;
+ Status = STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled disconnect wait on connection %lx\n", Connection));
+ Status = STATUS_CANCELLED;
+ }
+
+ } else {
+
+ //
+ // We got a second disconnect request and we already
+ // have one pending.
+ //
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, already queued on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait submitted on disconnected connection %lx\n", Connection));
+ Status = Connection->Status;
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Disconnect wait failed, bad state on connection %lx\n", Connection));
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ } else {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of active connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ //
+ // This call releases the connection lock, sets
+ // the state to DISCONNECTING, and sends out
+ // the first session end.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // There is already a disconnect pending. Queue
+ // this one up so it completes when the refcount
+ // goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of disconnecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
+
+ //
+ // We were waiting for an accept, but instead we got
+ // a disconnect. Remove the reference and the teardown
+ // will proceed. The disconnect will complete when the
+ // refcount goes to zero.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of accept pending connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK ( CancelLH );
+
+ NbiDereferenceConnection (Connection, CREF_W_ACCEPT);
+
+ } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
+
+ // we dont need to hold CancelSpinLock so release it,
+ // since we are releasing the locks out of order, we must
+ // swap the irql to get the priorities right.
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // We are connecting, and got a disconnect. We call
+ // NbiStopConnection which will handle this case
+ // and abort the connect.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of connecting connection %lx\n", Connection));
+
+ if (Connection->DisconnectRequest == NULL) {
+ Connection->DisconnectRequest = Request;
+ Status = STATUS_PENDING;
+ } else {
+ Status = STATUS_SUCCESS;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ //
+ // This call releases the connection lock and
+ // aborts the connect request.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LOCAL_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Disconnect of invalid connection (%d) %lx\n",
+ Connection->State, Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ }
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiDisconnect */
+
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to assign a connection ID. It picks
+ one whose hash table has the fewest entries.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD. THE CONNECTION IS INSERTED INTO THE CORRECT HASH
+ ENTRY BY THIS CALL.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ TRUE if it could be successfully assigned.
+
+--*/
+
+{
+ UINT Hash;
+ UINT i;
+ USHORT ConnectionId, HashId;
+ PCONNECTION CurConnection;
+
+
+ CTEAssert (Connection->LocalConnectionId == 0xffff);
+
+ //
+ // Find the hash bucket with the fewest entries.
+ //
+
+ Hash = 0;
+ for (i = 1; i < CONNECTION_HASH_COUNT; i++) {
+ if (Device->ConnectionHash[i].ConnectionCount < Device->ConnectionHash[Hash].ConnectionCount) {
+ Hash = i;
+ }
+ }
+
+
+ //
+ // Now find a valid connection ID within that bucket.
+ //
+
+ ConnectionId = Device->ConnectionHash[Hash].NextConnectionId;
+
+ while (TRUE) {
+
+ //
+ // Scan through the list to see if this ID is in use.
+ //
+
+ HashId = (USHORT)(ConnectionId | (Hash << CONNECTION_HASH_SHIFT));
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+
+ while (CurConnection != NULL) {
+ if (CurConnection->LocalConnectionId != HashId) {
+ CurConnection = CurConnection->NextConnection;
+ } else {
+ break;
+ }
+ }
+
+ if (CurConnection == NULL) {
+ break;
+ }
+
+ if (ConnectionId >= CONNECTION_MAXIMUM_ID) {
+ ConnectionId = 1;
+ } else {
+ ++ConnectionId;
+ }
+
+ //
+ // BUGBUG: What if we have 64K-1 sessions and loop forever?
+ //
+ }
+
+ if (Device->ConnectionHash[Hash].NextConnectionId >= CONNECTION_MAXIMUM_ID) {
+ Device->ConnectionHash[Hash].NextConnectionId = 1;
+ } else {
+ ++Device->ConnectionHash[Hash].NextConnectionId;
+ }
+
+ Connection->LocalConnectionId = HashId;
+ Connection->RemoteConnectionId = 0xffff;
+ NB_DEBUG2 (CONNECTION, ("Assigned ID %lx to %x\n", Connection->LocalConnectionId, Connection));
+
+ Connection->NextConnection = Device->ConnectionHash[Hash].Connections;
+ Device->ConnectionHash[Hash].Connections = Connection;
+ ++Device->ConnectionHash[Hash].ConnectionCount;
+
+ return TRUE;
+
+} /* NbiAssignConnectionId */
+
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to deassign a connection ID. It removes
+ the connection from the hash bucket for its ID.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
+ IT HELD.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Connection - The connection that needs an ID assigned.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT Hash;
+ PCONNECTION CurConnection;
+ PCONNECTION * PrevConnection;
+
+ //
+ // Make sure the connection has a valid ID.
+ //
+
+ CTEAssert (Connection->LocalConnectionId != 0xffff);
+
+ Hash = (Connection->LocalConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ CurConnection = Device->ConnectionHash[Hash].Connections;
+ PrevConnection = &Device->ConnectionHash[Hash].Connections;
+
+ while (TRUE) {
+
+ CTEAssert (CurConnection != NULL);
+
+ //
+ // We can loop until we find it because it should be
+ // on here.
+ //
+
+ if (CurConnection == Connection) {
+ *PrevConnection = Connection->NextConnection;
+ --Device->ConnectionHash[Hash].ConnectionCount;
+ break;
+ }
+
+ PrevConnection = &CurConnection->NextConnection;
+ CurConnection = CurConnection->NextConnection;
+
+ }
+
+ Connection->LocalConnectionId = 0xffff;
+
+} /* NbiDeassignConnectionId */
+
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection timer expires.
+ This is either because we need to send the next session
+ initialize, or because our listen has timed out.
+
+Arguments:
+
+ Event - The event used to queue the timer.
+
+ Context - The context, which is the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONNECTION Connection = (PCONNECTION)Context;
+ PDEVICE Device = NbiDevice;
+ PREQUEST Request;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (CancelLH)
+
+ //
+ // Take the lock and see what we need to do.
+ //
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ if (--Connection->Retries == 0) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out session initializes on %lx\n", Connection));
+
+ //
+ // We have just timed out this connect, we fail the
+ // request. When the reference count goes to 0 we
+ // will set the state to INACTIVE and deassign
+ // the connection ID.
+ //
+
+ Request = Connection->ConnectRequest;
+ Connection->ConnectRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_BAD_NETWORK_PATH;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session initialize.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionInitialize (Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ if ((Connection->SubState != CONNECTION_SUBSTATE_D_W_ACK) ||
+ (--Connection->Retries == 0)) {
+
+ NB_DEBUG2 (CONNECTION, ("Timing out disconnect of %lx\n", Connection));
+
+ //
+ // Just dereference the connection, that will cause the
+ // disconnect to be completed, the state to be set
+ // to INACTIVE, and our connection ID deassigned.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ } else {
+
+ //
+ // Send the next session end.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiSendSessionEnd(Connection);
+
+ CTEStartTimer(
+ &Connection->Timer,
+ Device->ConnectionTimeout,
+ NbiConnectionTimeout,
+ (PVOID)Connection);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+
+ }
+
+} /* NbiConnectionTimeout */
+
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ listen.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_LISTEN));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_LISTENING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_L_WAITING) &&
+ (Connection->ListenRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled listen on %lx\n", Connection));
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+ Connection->ListenRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_LISTEN);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel listen on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelListen */
+
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for the name to be found.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ PLIST_ENTRY p;
+ BOOLEAN fCanceled = TRUE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // Make sure the request is still on the queue
+ // before cancelling it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ for (p = Device->WaitingConnects.Flink;
+ p != &Device->WaitingConnects;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+ break;
+ }
+ }
+
+ if (p != &Device->WaitingConnects) {
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled find name connect on %lx\n", Connection));
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ Connection->ConnectRequest = NULL;
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+#ifdef RASAUTODIAL
+ if (Connection->Flags & CONNECTION_FLAGS_AUTOCONNECTING)
+ fCanceled = NbiCancelTdiConnect(Device, Request, Connection);
+#endif // RASAUTODIAL
+
+ if (fCanceled) {
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect not found on queue %lx\n", Connection));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectFindName */
+
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a connect
+ request which is waiting for a rip or session init response
+ from the remote.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN TimerWasStopped = FALSE;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) &&
+ (Connection->ConnectRequest == Request)) {
+
+ //
+ // When the reference count goes to 0, we will set the
+ // state to INACTIVE and deassign the connection ID.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Cancelled wait response connect on %lx\n", Connection));
+
+ Connection->ConnectRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ NbiDereferenceConnection (Connection, CREF_CONNECT);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelConnectWaitResponse */
+
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a posted
+ disconnect wait.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ CTELockHandle LockHandle1, LockHandle2;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request = (PREQUEST)Irp;
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_DISCONNECT));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->DisconnectWaitRequest == Request) {
+
+ Connection->DisconnectWaitRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest(Device, Request);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle1);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ }
+
+} /* NbiCancelDisconnectWait */
+
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks up a connection based on the context.
+ The connection is assumed to be associated with the
+ specified address file.
+
+Arguments:
+
+ AddressFile - Pointer to an address file.
+
+ ConnectionContext - Connection context to find.
+
+Return Value:
+
+ A pointer to the connection we found
+
+--*/
+
+{
+ CTELockHandle LockHandle1, LockHandle2;
+ PLIST_ENTRY p;
+ PADDRESS Address = AddressFile->Address;
+ PCONNECTION Connection;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p=AddressFile->ConnectionDatabase.Flink;
+ p != &AddressFile->ConnectionDatabase;
+ p=p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
+
+ NB_GET_LOCK (&Connection->Lock, &LockHandle2);
+
+ //
+ // BUGBUG: Does this spinlock ordering hurt us
+ // somewhere else?
+ //
+
+ if (Connection->Context == ConnectionContext) {
+
+ NbiReferenceConnection (Connection, CREF_BY_CONTEXT);
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return Connection;
+ }
+
+ NB_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ return NULL;
+
+} /* NbiLookupConnectionByContext */
+
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a transport connection and associates it with
+ the specified transport device context. The reference count in the
+ connection is automatically set to 1, and the reference count of the
+ device context is incremented.
+
+Arguments:
+
+ Device - Pointer to the device context (which is really just
+ the device object with its extension) to be associated with the
+ connection.
+
+Return Value:
+
+ The newly created connection, or NULL if none can be allocated.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PNB_SEND_RESERVED SendReserved;
+ ULONG ConnectionSize;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION);
+ ConnectionSize = FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) + HeaderLength;
+
+ Connection = (PCONNECTION)NbiAllocateMemory (ConnectionSize, MEMORY_CONNECTION, "Connection");
+ if (Connection == NULL) {
+ NB_DEBUG (CONNECTION, ("Create connection failed\n"));
+ return NULL;
+ }
+
+ NB_DEBUG2 (CONNECTION, ("Create connection %lx\n", Connection));
+ RtlZeroMemory (Connection, ConnectionSize);
+
+
+#if defined(NB_OWN_PACKETS)
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+
+#else // !NB_OWN_PACKETS
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &Connection->SendPacketPoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (CONNECTION, ("Could not allocatee connection packet %lx\n", Status));
+ Connection->SendPacketInUse = TRUE;
+ } else {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if (NbiInitializeSendPacket(
+ Device,
+ Connection->SendPacketPoolHandle,
+ &Connection->SendPacket,
+ Connection->SendPacketHeader,
+ HeaderLength) != STATUS_SUCCESS) {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
+ Connection->SendPacketInUse = TRUE;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ SendReserved = SEND_RESERVED(&Connection->SendPacket);
+ SendReserved->u.SR_CO.Connection = Connection;
+ SendReserved->OwnedByConnection = TRUE;
+#ifdef NB_TRACK_POOL
+ SendReserved->Pool = NULL;
+#endif
+ }
+ }
+
+#endif NB_OWN_PACKETS
+
+ Connection->Type = NB_CONNECTION_SIGNATURE;
+ Connection->Size = (USHORT)ConnectionSize;
+
+#if 0
+ Connection->AddressFileLinked = FALSE;
+ Connection->AddressFile = NULL;
+#endif
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+#if 0
+ Connection->SubState = 0;
+ Connection->ReferenceCount = 0;
+#endif
+
+ Connection->CanBeDestroyed = TRUE;
+
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+
+ //
+ // Device->InitialRetransmissionTime is in milliseconds, as is
+ // SHORT_TIMER_DELTA.
+ //
+
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ //
+ // Device->KeepAliveTimeout is in half-seconds, while LONG_TIMER_DELTA
+ // is in milliseconds.
+ //
+
+ Connection->WatchdogTimeout = (Device->KeepAliveTimeout * 500) / LONG_TIMER_DELTA;
+
+
+ Connection->LocalConnectionId = 0xffff;
+
+ //
+ // When the connection becomes active we will replace the
+ // destination address of this header with the correct
+ // information.
+ //
+
+ RtlCopyMemory(&Connection->RemoteHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ Connection->Device = Device;
+ Connection->DeviceLock = &Device->Lock;
+ CTEInitLock (&Connection->Lock.Lock);
+
+ CTEInitTimer (&Connection->Timer);
+
+ InitializeListHead (&Connection->NdisSendQueue);
+#if 0
+ Connection->NdisSendsInProgress = 0;
+ Connection->DisassociatePending = NULL;
+ Connection->ClosePending = NULL;
+ Connection->SessionInitAckData = NULL;
+ Connection->SessionInitAckDataLength = 0;
+ Connection->PiggybackAckTimeout = FALSE;
+ Connection->ReceivesWithoutAck = 0;
+#endif
+ Connection->Flags = 0;
+
+ NbiReferenceDevice (Device, DREF_CONNECTION);
+
+ return Connection;
+
+} /* NbiCreateConnection */
+
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to verify that the pointer given us in a file
+ object is in fact a valid connection object. We reference
+ it to keep it from disappearing while we use it.
+
+Arguments:
+
+ Connection - potential pointer to a CONNECTION object
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ NTSTATUS status = STATUS_SUCCESS;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN LockHeld = FALSE;
+
+ try {
+
+ if ((Connection->Size == FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) +
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) &&
+ (Connection->Type == NB_CONNECTION_SIGNATURE)) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LockHeld = TRUE;
+
+ if (Connection->State != CONNECTION_STATE_CLOSING) {
+
+ NbiReferenceConnectionLock (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx closing\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else {
+
+ NbiPrint1("NbiVerifyConnection: C %lx bad signature\n", Connection);
+ status = STATUS_INVALID_CONNECTION;
+ }
+
+ } except(EXCEPTION_EXECUTE_HANDLER) {
+
+ NbiPrint1("NbiVerifyConnection: C %lx exception\n", Connection);
+ if (LockHeld) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return GetExceptionCode();
+ }
+
+ return status;
+
+} /* NbiVerifyConnection */
+
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a transport connection and removes all references
+ made by it to other objects in the transport. The connection structure
+ is returned to nonpaged system pool.
+
+Arguments:
+
+ Connection - Pointer to a transport connection structure to be destroyed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = Connection->Device;
+#if 0
+ CTELockHandle LockHandle;
+#endif
+
+ NB_DEBUG2 (CONNECTION, ("Destroy connection %lx\n", Connection));
+
+ if (!Connection->SendPacketInUse) {
+ NbiDeinitializeSendPacket (Device, &Connection->SendPacket, Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(Connection->SendPacketPoolHandle);
+#endif
+ }
+
+ NbiFreeMemory (Connection, (ULONG)Connection->Size, MEMORY_CONNECTION, "Connection");
+
+ NbiDereferenceDevice (Device, DREF_CONNECTION);
+
+} /* NbiDestroyConnection */
+
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ (VOID)ExInterlockedAddUlong (
+ &Connection->ReferenceCount,
+ 1,
+ &Connection->DeviceLock->Lock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnection */
+
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when the device lock is already held.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ ++Connection->ReferenceCount;
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionLock */
+
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a transport connection
+ when we are in a sync routine.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ (VOID)NB_ADD_ULONG (
+ &Connection->ReferenceCount,
+ 1,
+ Connection->DeviceLock);
+
+ Connection->CanBeDestroyed = FALSE;
+
+ CTEAssert (Connection->ReferenceCount > 0);
+
+} /* NbiRefConnectionSync */
+
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a transport connection by decrementing the
+ reference count contained in the structure. If, after being
+ decremented, the reference count is zero, then this routine calls
+ NbiHandleConnectionZero to complete any disconnect, disassociate,
+ or close requests that have pended on the connection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ ULONG oldvalue;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( Connection->DeviceLock, &LockHandle );
+ CTEAssert( Connection->ReferenceCount );
+ if ( !(--Connection->ReferenceCount) ) {
+
+ Connection->ThreadsInHandleConnectionZero++;
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+
+ //
+ // If the refcount has dropped to 0, then the connection can
+ // become inactive. We reacquire the spinlock and if it has not
+ // jumped back up then we handle any disassociates and closes
+ // that have pended.
+ //
+
+ NbiHandleConnectionZero (Connection);
+ } else {
+
+ NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
+ }
+
+
+} /* NbiDerefConnection */
+
+
+#endif
+
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a connection's refcount going to 0.
+
+ BUGBUG: If two threads are in this at the same time and
+ the close has already come through, one of them might
+ destroy the connection while the other one is looking
+ at it. We minimize the chance of this by not derefing
+ the connection after calling CloseConnection.
+
+Arguments:
+
+ Connection - Pointer to a transport connection object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST DisconnectPending;
+ PREQUEST DisassociatePending;
+ PREQUEST ClosePending;
+
+
+ Device = Connection->Device;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+#if DBG
+ //
+ // Make sure if our reference count is zero, all the
+ // sub-reference counts are also zero.
+ //
+
+ if (Connection->ReferenceCount == 0) {
+
+ UINT i;
+ for (i = 0; i < CREF_TOTAL; i++) {
+ if (Connection->RefTypes[i] != 0) {
+ DbgPrint ("NBI: Connection reftype mismatch on %lx\n", Connection);
+ DbgBreakPoint();
+ }
+ }
+ }
+#endif
+
+ //
+ // If the connection was assigned an ID, then remove it
+ // (it is assigned one when it leaves INACTIVE).
+ //
+
+ if (Connection->LocalConnectionId != 0xffff) {
+ NbiDeassignConnectionId (Device, Connection);
+ }
+
+ //
+ // Complete any pending disconnects.
+ //
+
+ if (Connection->DisconnectRequest != NULL) {
+
+ DisconnectPending = Connection->DisconnectRequest;
+ Connection->DisconnectRequest = NULL;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_STATUS(DisconnectPending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisconnectPending);
+ NbiFreeRequest (Device, DisconnectPending);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ }
+
+ //
+ // This should have been completed by NbiStopConnection,
+ // or else not allowed to be queued.
+ //
+
+ CTEAssert (Connection->DisconnectWaitRequest == NULL);
+
+
+ Connection->State = CONNECTION_STATE_INACTIVE;
+
+ //
+ // BUGBUG: Make NbiInitializeConnection() to take care of all this.
+ //
+
+ RtlZeroMemory (&Connection->ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
+ Connection->TickCount = 1;
+ Connection->HopCount = 1;
+ Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
+
+ Connection->ConnectionInfo.TransmittedTsdus = 0;
+ Connection->ConnectionInfo.TransmissionErrors = 0;
+ Connection->ConnectionInfo.ReceivedTsdus = 0;
+ Connection->ConnectionInfo.ReceiveErrors = 0;
+
+ //
+ // See if we need to do a disassociate now.
+ //
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->DisassociatePending != NULL)) {
+
+ //
+ // A disassociate pended, now we complete it.
+ //
+
+ DisassociatePending = Connection->DisassociatePending;
+ Connection->DisassociatePending = NULL;
+
+ //
+ // Set this so nobody else tries to disassociate.
+ //
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ if (DisassociatePending != (PVOID)-1) {
+ REQUEST_STATUS(DisassociatePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (DisassociatePending);
+ NbiFreeRequest (Device, DisassociatePending);
+ }
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+
+ //
+ // If a close was pending, complete that.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ if ((Connection->ReferenceCount == 0) &&
+ (Connection->ClosePending)) {
+
+ ClosePending = Connection->ClosePending;
+ Connection->ClosePending = NULL;
+
+ //
+ // If we are associated with an address, we need
+ // to simulate a disassociate at this point.
+ //
+
+ if ((Connection->AddressFile != NULL) &&
+ (Connection->AddressFile != (PVOID)-1)) {
+
+ AddressFile = Connection->AddressFile;
+ Connection->AddressFile = (PVOID)-1;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Take this connection out of the address file's list.
+ //
+
+ Address = AddressFile->Address;
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (Connection->AddressFileLinked) {
+ Connection->AddressFileLinked = FALSE;
+ RemoveEntryList (&Connection->AddressFileLinkage);
+ }
+
+ //
+ // We are done.
+ //
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ Connection->AddressFile = NULL;
+
+ //
+ // Clean up the reference counts and complete any
+ // disassociate requests that pended.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
+
+ } else {
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ //
+ // Even if the ref count is zero and we just cleaned up everything,
+ // we can not destroy the connection bcoz some other thread might still be
+ // in HandleConnectionZero routine. This could happen when 2 threads call into
+ // HandleConnectionZero, one thread runs thru completion, close comes along
+ // and the other thread is still in HandleConnectionZero routine.
+ //
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ if (ExInterlockedAddUlong ( &Connection->ThreadsInHandleConnectionZero, (ULONG)-1, &Device->Lock.Lock) == 1) {
+ NbiDestroyConnection(Connection);
+ }
+
+ REQUEST_STATUS(ClosePending) = STATUS_SUCCESS;
+ NbiCompleteRequest (ClosePending);
+ NbiFreeRequest (Device, ClosePending);
+
+ } else {
+
+ if ( Connection->ReferenceCount == 0 ) {
+ Connection->CanBeDestroyed = TRUE;
+ }
+
+ CTEAssert( Connection->ThreadsInHandleConnectionZero );
+ Connection->ThreadsInHandleConnectionZero--;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+} /* NbiHandleConnectionZero */
+
diff --git a/private/ntos/tdi/isnp/nb/datagram.c b/private/ntos/tdi/isnp/nb/datagram.c
new file mode 100644
index 000000000..e81579d1b
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/datagram.c
@@ -0,0 +1,1089 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ datagram.c
+
+Abstract:
+
+ This module contains the code to handle datagram reception
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles datagram indications.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+ Broadcast - TRUE if the frame was a broadcast datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PADDRESS Address;
+ NDIS_STATUS NdisStatus;
+ PUCHAR NetbiosName;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+ PDEVICE Device = NbiDevice;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ ULONG DataOffset;
+ UINT BytesTransferred;
+ PNDIS_PACKET Packet;
+ CTELockHandle LockHandle;
+
+
+ //
+ // See if there is an address that might want this.
+ //
+
+ if (Broadcast) {
+ NetbiosName = (PVOID)-1;
+ } else {
+ NetbiosName = (PUCHAR)Connectionless->Datagram.DestinationName;
+ if (Device->AddressCounts[NetbiosName[0]] == 0) {
+ return;
+ }
+ }
+
+ DataOffset = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+#if defined(_PNP_POWER)
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->CurMaxReceiveBufferSize)) {
+#else
+ if ((PacketSize < DataOffset) ||
+ (PacketSize > DataOffset + Device->Bind.LineInfo.MaximumPacketSize)) {
+#endif _PNP_POWER
+
+ NB_DEBUG (DATAGRAM, ("Datagram length %d discarded\n", PacketSize));
+ return;
+ }
+
+ Address = NbiFindAddress (Device, NetbiosName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // We need to cache the remote name if the packet came across the router.
+ // This allows this machine to get back to the RAS client which might
+ // have sent this datagram. We currently dont allow broadcasts to go out
+ // on the dial-in line.
+ // Dont cache some of the widely used group names, that would be too much
+ // to store in cache.
+ //
+
+#if 0
+ if ( Connectionless->IpxHeader.TransportControl &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x0 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x01 ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) &&
+ !( (Address->NetbiosAddress.NetbiosName[15] == 0x1E ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+#endif
+ if ( Connectionless->IpxHeader.TransportControl &&
+ ( (Address->NetbiosAddress.NetbiosName[15] == 0x1c ) &&
+ (Address->NetbiosAddress.NetbiosNameType & TDI_ADDRESS_NETBIOS_TYPE_GROUP)) ) {
+
+ PNETBIOS_CACHE CacheName;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ if ( FindInNetbiosCacheTable ( Device->NameCache,
+ Connectionless->Datagram.SourceName,
+ &CacheName ) != STATUS_SUCCESS ) {
+
+ CacheName = NbiAllocateMemory (sizeof(NETBIOS_CACHE), MEMORY_CACHE, "Cache Entry");
+ if (CacheName ) {
+ RtlCopyMemory (CacheName->NetbiosName, Connectionless->Datagram.SourceName, 16);
+ CacheName->Unique = TRUE;
+ CacheName->ReferenceCount = 1;
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->NetworksAllocated = 1;
+ CacheName->NetworksUsed = 1;
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+ NB_DEBUG2 (CACHE, ("Alloc new cache from Datagram %lx for <%.16s>\n",
+ CacheName, CacheName->NetbiosName));
+
+ CacheName->TimeStamp = Device->CacheTimeStamp;
+
+ InsertInNetbiosCacheTable(
+ Device->NameCache,
+ CacheName);
+
+ }
+ } else if ( CacheName->Unique ) {
+ //
+ // We already have an entry for this remote. We should update
+ // the address. This is so that if the ras client dials-out
+ // then dials-in again and gets a new address, we dont end up
+ // caching the old address.
+ //
+ if ( !RtlEqualMemory( &CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12) ) {
+
+ RtlCopyMemory (&CacheName->FirstResponse, Connectionless->IpxHeader.SourceNetwork, 12);
+ CacheName->Networks[0].Network = *(UNALIGNED ULONG *)(Connectionless->IpxHeader.SourceNetwork);
+ CacheName->Networks[0].LocalTarget = *RemoteAddress;
+
+ }
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ //
+ // We need to allocate a packet and buffer for the transfer.
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+
+
+ s = NbiPopReceiveBuffer (Device);
+ if (s == NULL) {
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ ReceiveBuffer = CONTAINING_RECORD (s, NB_RECEIVE_BUFFER, PoolLinkage);
+
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = ReceiveBuffer;
+
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // The indication to the TDI clients will happen at receive
+ // complete time.
+ //
+
+ NdisChainBufferAtFront (Packet, ReceiveBuffer->NdisBuffer);
+ ReceiveBuffer->Address = Address;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATAGRAM;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ TdiCopyLookaheadData(
+ &ReceiveBuffer->RemoteName,
+ Connectionless->Datagram.SourceName,
+ 16,
+ (MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA) ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + DataOffset,
+ PacketSize - DataOffset,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == PacketSize - DataOffset);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessDatagram */
+
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine indicates a datagram to clients on the specified
+ address. It is called from NbiReceiveComplete.
+
+Arguments:
+
+ Address - The address the datagram was sent to.
+
+ RemoteName - The source netbios address of the datagram.
+
+ Data - The data.
+
+ DataLength - The length of the data.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p, q;
+ PIRP Irp;
+ ULONG IndicateBytesCopied;
+ PREQUEST Request;
+ TA_NETBIOS_ADDRESS SourceName;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_CONNECTION_INFORMATION DatagramInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * DatagramAddress;
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // Update our statistics.
+ //
+
+ ++Device->Statistics.DatagramsReceived;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesReceived,
+ DataLength);
+
+ //
+ // Call the client's ReceiveDatagram indication handler. He may
+ // want to accept the datagram that way.
+ //
+
+ TdiBuildNetbiosAddress (RemoteName, FALSE, &SourceName);
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ //
+ // do we have a datagram receive request outstanding? If so, we will
+ // satisfy it first. We run through the receive datagram queue
+ // until we find a datagram with no remote address or with
+ // this sender's address as its remote address.
+ //
+
+ for (q = AddressFile->ReceiveDatagramQueue.Flink;
+ q != &AddressFile->ReceiveDatagramQueue;
+ q = q->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (q);
+ DatagramInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReceiveDatagramInformation;
+
+ if (DatagramInformation &&
+ (DatagramInformation->RemoteAddress) &&
+ (DatagramAddress = NbiParseTdiAddress(DatagramInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ RemoteName,
+ DatagramAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+ break;
+ }
+
+ if (q != &AddressFile->ReceiveDatagramQueue) {
+
+ RemoveEntryList (q);
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // Do this deref now, we hold another one so it
+ // will stick around.
+ //
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ IndicateBytesCopied = 0;
+
+ //
+ // Fall past the else to copy the data.
+ //
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No receive datagram requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE_DATAGRAM]) {
+
+ IndicateBytesCopied = 0;
+
+ if ((*AddressFile->ReceiveDatagramHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_RECEIVE_DATAGRAM],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0,
+ NULL,
+ TDI_RECEIVE_COPY_LOOKAHEAD,
+ DataLength, // indicated
+ DataLength, // available
+ &IndicateBytesCopied,
+ Data,
+ &Irp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ Request = NbiAllocateRequest (Device, Irp);
+
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+ }
+
+ } else {
+
+ //
+ // The client has nothing posted and no handler,
+ // go on to the next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+ continue;
+
+ }
+
+ }
+
+ //
+ // We have a request; copy the actual user data.
+ //
+ if ( REQUEST_NDIS_BUFFER (Request) ) {
+
+ REQUEST_STATUS(Request) =
+ TdiCopyBufferToMdl (
+ Data,
+ IndicateBytesCopied,
+ DataLength - IndicateBytesCopied,
+ REQUEST_NDIS_BUFFER (Request),
+ 0,
+ &REQUEST_INFORMATION (Request));
+
+ } else {
+ //
+ // No buffer specified in the request
+ //
+ REQUEST_INFORMATION (Request) = 0;
+ //
+ // If there was any data to be copied, return error o/w success
+ //
+ REQUEST_STATUS(Request) = ( (DataLength - IndicateBytesCopied) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS );
+ }
+
+ //
+ // Copy the addressing information.
+ //
+
+ RemoteInformation = ((PTDI_REQUEST_KERNEL_RECEIVEDG)
+ REQUEST_PARAMETERS(Request))->ReturnDatagramInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+} /* NbiIndicateDatagram */
+
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram on an address.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the datagram send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PADDRESS_FILE AddressFile;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName;
+ PTDI_REQUEST_KERNEL_SENDDG Parameters;
+ PSINGLE_LIST_ENTRY s;
+ PNETBIOS_CACHE CacheName;
+ CTELockHandle LockHandle;
+ NTSTATUS Status;
+
+ //
+ // Make sure that the address is valid.
+ //
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status == STATUS_SUCCESS) {
+
+ Parameters = (PTDI_REQUEST_KERNEL_SENDDG)REQUEST_PARAMETERS(Request);
+ RemoteName = NbiParseTdiAddress((PTRANSPORT_ADDRESS)(Parameters->SendDatagramInformation->RemoteAddress), TRUE);
+
+
+ //
+ // Check that datagram size is less than the maximum allowable
+ // by the adapters. In the worst case this would be
+ // 576 - 64 = 512.
+ //
+
+#if defined(_PNP_POWER)
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumSendSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumSendSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#else
+ if ( ( Parameters->SendLength + sizeof(NB_DATAGRAM) ) > Device->Bind.LineInfo.MaximumPacketSize ) {
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ NB_DEBUG(DATAGRAM, ("Datagram too large %d, Max allowed %d\n", Parameters->SendLength + sizeof(NB_DATAGRAM), Device->Bind.LineInfo.MaximumPacketSize ));
+ return STATUS_INVALID_PARAMETER;
+ }
+#endif _PNP_POWER
+
+ if (RemoteName != NULL) {
+
+ //
+ // Get a packet to use in this send.
+ //
+
+ s = NbiPopSendPacket (Device, FALSE);
+
+ if (s != NULL) {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Check on the cache status of this name.
+ //
+
+ Reserved->u.SR_DG.DatagramRequest = Request;
+ Reserved->u.SR_DG.AddressFile = AddressFile;
+ Reserved->u.SR_DG.RemoteName = RemoteName;
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength;
+
+ ++Device->Statistics.DatagramsSent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DatagramBytesSent,
+ Parameters->SendLength);
+
+ if (Device->Internet) {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ (RemoteName == (PVOID)-1) ? NULL : (PUCHAR)RemoteName->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this datagram
+ // request and processing will be resumed when
+ // we get a response.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Queueing up datagram %lx on %lx\n",
+ Request, AddressFile));
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ InsertTailList(
+ &Device->WaitingDatagrams,
+ &Reserved->WaitLinkage);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (CONNECTION, ("Found datagram cached %lx on %lx\n",
+ Request, AddressFile));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ Reserved->u.SR_DG.Cache = CacheName;
+ Reserved->u.SR_DG.CurrentNetwork = 0;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ //
+ // Only this failure gets passed back up to
+ // the caller, to avoid confusing the browser.
+ //
+
+ if (Status != STATUS_DEVICE_DOES_NOT_EXIST) {
+
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = 0;
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+
+
+
+ }
+
+ } else {
+
+ //
+ // We are not in internet mode, so we do not
+ // need to do the name discovery.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Sending datagram direct %lx on %lx\n",
+ Request, AddressFile));
+
+ Reserved->u.SR_DG.Cache = NULL;
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_SEND_DGRAM);
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ if ( REQUEST_NDIS_BUFFER(Request) ) {
+ NdisChainBufferAtBack (Packet, REQUEST_NDIS_BUFFER(Request));
+ }
+ NbiTransmitDatagram(
+ Reserved);
+
+ Status = STATUS_PENDING;
+
+ }
+
+ } else {
+
+ //
+ // Could not allocate a packet for the datagram.
+ //
+
+ NB_DEBUG (DATAGRAM, ("Couldn't get packet to send DG %lx\n", Request));
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // There is no netbios remote address specified.
+ //
+
+ NB_DEBUG (DATAGRAM, ("No netbios address in DG %lx\n", Request));
+ Status = STATUS_BAD_NETWORK_PATH;
+
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ } else {
+
+ NB_DEBUG (DATAGRAM, ("Invalid address file for DG %lx\n", Request));
+
+ }
+
+ return Status;
+
+} /* NbiTdiSendDatagram */
+
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a datagram to the next net in the
+ cache entry for the remote name.
+
+Arguments:
+
+ Reserved - The reserved section of the packet that has
+ been allocated for this send. Reserved->u.SR_DG.Cache
+ will be NULL if Internet mode is off, otherwise it
+ will contain the cache entry to use when sending
+ this datagram.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_PACKET Packet;
+ PNETBIOS_CACHE CacheName;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DATAGRAM;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+ if (CacheName == NULL) {
+
+#if defined(_PNP_POWER)
+ //
+ // IPX will send this on all the Nics.
+ //
+ TempLocalTarget.NicHandle.NicId = 0;
+#else
+ TempLocalTarget.NicId = 1;
+#endif _PNP_POWER
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+
+ } else {
+
+ if (CacheName->Unique) {
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+ } else {
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+ }
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+ }
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), HeaderLength);
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiTransmitDatagram */
+
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiReceiveDatagram request for the transport
+ provider. Receive datagrams just get queued up to an address, and are
+ completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
+ the address.
+
+Arguments:
+
+ Request - Describes this request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ CTELockHandle LockHandle;
+ CTELockHandle CancelLH;
+
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (Status != STATUS_SUCCESS) {
+ return Status;
+ }
+
+ Address = AddressFile->Address;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_INVALID_HANDLE;
+ }
+
+
+ if (Request->Cancel) {
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ return STATUS_CANCELLED;
+ }
+
+ InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
+
+ IoSetCancelRoutine (Request, NbiCancelReceiveDatagram);
+
+ NB_DEBUG2 (DATAGRAM, ("RDG posted on %lx\n", AddressFile));
+
+ NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_RCV_DGRAM);
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ return STATUS_PENDING;
+
+} /* NbiTdiReceiveDatagram */
+
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive
+ datagram. The datagram is found on the address file's receive
+ datagram queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PREQUEST Request = (PREQUEST)Irp;
+ BOOLEAN Found;
+ NB_DEFINE_LOCK_HANDLE(LockHandle)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+ Address = AddressFile->Address;
+
+ Found = FALSE;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = AddressFile->ReceiveDatagramQueue.Flink;
+ p != &AddressFile->ReceiveDatagramQueue;
+ p = p->Flink) {
+
+ if (LIST_ENTRY_TO_REQUEST(p) == Request) {
+
+ RemoveEntryList (p);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NB_DEBUG (DATAGRAM, ("Cancelled datagram on %lx\n", AddressFile));
+
+ REQUEST_INFORMATION(Request) = 0;
+ REQUEST_STATUS(Request) = STATUS_CANCELLED;
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest((PDEVICE)DeviceObject, Request);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
+
+ }
+
+} /* NbiCancelReceiveDatagram */
+
diff --git a/private/ntos/tdi/isnp/nb/device.c b/private/ntos/tdi/isnp/nb/device.c
new file mode 100644
index 000000000..d1a9af781
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/device.c
@@ -0,0 +1,461 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ device.c
+
+Abstract:
+
+ This module contains code which implements the DEVICE object.
+ Routines are provided to reference, and dereference transport device
+ context objects.
+
+ The transport device context object is a structure which contains a
+ system-defined DEVICE_OBJECT followed by information which is maintained
+ by the transport provider, called the context.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiCreateDevice)
+#endif
+
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine increments the reference count on a device context.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ CTEAssert (Device->ReferenceCount > 0); // not perfect, but...
+
+ (VOID)InterlockedIncrement (&Device->ReferenceCount);
+
+} /* NbiRefDevice */
+
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dereferences a device context by decrementing the
+ reference count contained in the structure. Currently, we don't
+ do anything special when the reference count drops to zero, but
+ we could dynamically unload stuff then.
+
+Arguments:
+
+ Device - Pointer to a transport device context object.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ LONG result;
+
+ result = InterlockedDecrement (&Device->ReferenceCount);
+
+ CTEAssert (result >= 0);
+
+ if (result == 0) {
+ NbiDestroyDevice (Device);
+ }
+
+} /* NbiDerefDevice */
+
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a device context structure.
+
+Arguments:
+
+
+ DriverObject - pointer to the IO subsystem supplied driver object.
+
+ Device - Pointer to a pointer to a transport device context object.
+
+ DeviceName - pointer to the name of the device this device object points to.
+
+Return Value:
+
+ STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE Device;
+ ULONG DeviceSize;
+ UINT i;
+
+
+ //
+ // Create the device object for the sample transport, allowing
+ // room at the end for the device name to be stored (for use
+ // in logging errors) and the RIP fields.
+ //
+
+ DeviceSize = sizeof(DEVICE) - sizeof(DEVICE_OBJECT) +
+ DeviceName->Length + sizeof(UNICODE_NULL);
+
+ status = IoCreateDevice(
+ DriverObject,
+ DeviceSize,
+ DeviceName,
+ FILE_DEVICE_TRANSPORT,
+ 0,
+ FALSE,
+ &deviceObject);
+
+ if (!NT_SUCCESS(status)) {
+ NB_DEBUG(DEVICE, ("Create device %ws failed %lx\n", DeviceName->Buffer, status));
+ return status;
+ }
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ Device = (PDEVICE)deviceObject;
+
+ NB_DEBUG2 (DEVICE, ("Create device %ws succeeded %lx\n", DeviceName->Buffer, Device));
+
+ //
+ // Initialize our part of the device context.
+ //
+
+ RtlZeroMemory(
+ ((PUCHAR)Device) + sizeof(DEVICE_OBJECT),
+ sizeof(DEVICE) - sizeof(DEVICE_OBJECT));
+
+ //
+ // Copy over the device name.
+ //
+
+ Device->DeviceNameLength = DeviceName->Length + sizeof(WCHAR);
+ Device->DeviceName = (PWCHAR)(Device+1);
+ RtlCopyMemory(
+ Device->DeviceName,
+ DeviceName->Buffer,
+ DeviceName->Length);
+ Device->DeviceName[DeviceName->Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ //
+ // Initialize the reference count.
+ //
+
+ Device->ReferenceCount = 1;
+#if DBG
+ Device->RefTypes[DREF_CREATE] = 1;
+#endif
+
+#if DBG
+ RtlCopyMemory(Device->Signature1, "NDC1", 4);
+ RtlCopyMemory(Device->Signature2, "NDC2", 4);
+#endif
+
+ //
+ // BETABUGBUG: Clean this up a bit.
+ //
+
+ Device->Information.Version = 0x0100;
+ Device->Information.MaxSendSize = 65535;
+ Device->Information.MaxConnectionUserData = 0;
+ Device->Information.MaxDatagramSize = 500;
+ Device->Information.ServiceFlags =
+ TDI_SERVICE_CONNECTION_MODE | TDI_SERVICE_ERROR_FREE_DELIVERY |
+ TDI_SERVICE_MULTICAST_SUPPORTED | TDI_SERVICE_BROADCAST_SUPPORTED |
+ TDI_SERVICE_DELAYED_ACCEPTANCE | TDI_SERVICE_CONNECTIONLESS_MODE |
+ TDI_SERVICE_MESSAGE_MODE;
+ Device->Information.MinimumLookaheadData = 128;
+ Device->Information.MaximumLookaheadData = 1500;
+ Device->Information.NumberOfResources = 0;
+ KeQuerySystemTime (&Device->Information.StartTime);
+
+ Device->Statistics.Version = 0x0100;
+ Device->Statistics.MaximumSendWindow = 4;
+ Device->Statistics.AverageSendWindow = 4;
+
+ //
+ // Set this so we won't ignore the broadcast name.
+ //
+
+ Device->AddressCounts['*'] = 1;
+
+ //
+ // Initialize the resource that guards address ACLs.
+ //
+
+ ExInitializeResource (&Device->AddressResource);
+
+ //
+ // initialize the various fields in the device context
+ //
+
+ CTEInitLock (&Device->Interlock.Lock);
+ CTEInitLock (&Device->Lock.Lock);
+
+ CTEInitTimer (&Device->FindNameTimer);
+
+ Device->ControlChannelIdentifier = 1;
+
+ InitializeListHead (&Device->GlobalSendPacketList);
+ InitializeListHead (&Device->GlobalReceivePacketList);
+ InitializeListHead (&Device->GlobalReceiveBufferList);
+
+ InitializeListHead (&Device->AddressDatabase);
+#if defined(_PNP_POWER)
+ InitializeListHead (&Device->AdapterAddressDatabase);
+#endif _PNP_POWER
+
+ InitializeListHead (&Device->WaitingFindNames);
+
+ InitializeListHead (&Device->WaitingConnects);
+ InitializeListHead (&Device->WaitingDatagrams);
+
+ InitializeListHead (&Device->WaitingAdapterStatus);
+ InitializeListHead (&Device->ActiveAdapterStatus);
+
+ InitializeListHead (&Device->WaitingNetbiosFindName);
+
+ InitializeListHead (&Device->ReceiveDatagrams);
+ InitializeListHead (&Device->ConnectIndicationInProgress);
+
+ InitializeListHead (&Device->ListenQueue);
+
+ InitializeListHead (&Device->ReceiveCompletionQueue);
+
+ InitializeListHead (&Device->WaitPacketConnections);
+ InitializeListHead (&Device->PacketizeConnections);
+ InitializeListHead (&Device->DataAckConnections);
+
+ Device->MemoryUsage = 0;
+
+ InitializeListHead (&Device->SendPoolList);
+ InitializeListHead (&Device->ReceivePoolList);
+ InitializeListHead (&Device->ReceiveBufferPoolList);
+
+ ExInitializeSListHead( &Device->SendPacketList );
+ ExInitializeSListHead( &Device->ReceivePacketList );
+ Device->ReceiveBufferList.Next = NULL;
+
+ for (i = 0; i < CONNECTION_HASH_COUNT; i++) {
+ Device->ConnectionHash[i].Connections = NULL;
+ Device->ConnectionHash[i].ConnectionCount = 0;
+ Device->ConnectionHash[i].NextConnectionId = 1;
+ }
+
+ KeQuerySystemTime (&Device->NbiStartTime);
+
+ Device->State = DEVICE_STATE_CLOSED;
+
+ Device->Type = NB_DEVICE_SIGNATURE;
+ Device->Size - sizeof (DEVICE);
+
+
+ *DevicePtr = Device;
+ return STATUS_SUCCESS;
+
+} /* NbiCreateDevice */
+
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys a device context structure.
+
+Arguments:
+
+ Device - Pointer to a pointer to a transport device context object.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLIST_ENTRY p;
+ PNB_SEND_POOL SendPool;
+ PNB_SEND_PACKET SendPacket;
+ UINT SendPoolSize;
+ PNB_RECEIVE_POOL ReceivePool;
+ PNB_RECEIVE_PACKET ReceivePacket;
+ UINT ReceivePoolSize;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ ULONG HeaderLength;
+ UINT i;
+
+ NB_DEBUG2 (DEVICE, ("Destroy device %lx\n", Device));
+
+ //
+ // Take all the connectionless packets out of its pools.
+ //
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->SendPoolList)) {
+
+ p = RemoveHeadList (&Device->SendPoolList);
+ SendPool = CONTAINING_RECORD (p, NB_SEND_POOL, Linkage);
+
+ for (i = 0; i < SendPool->PacketCount; i++) {
+
+ SendPacket = &SendPool->Packets[i];
+ NbiDeinitializeSendPacket (Device, SendPacket, HeaderLength);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", SendPool));
+
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(SendPool->PoolHandle);
+#endif
+
+ NbiFreeMemory (SendPool, SendPoolSize, MEMORY_PACKET, "SendPool");
+ }
+
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceivePoolList)) {
+
+ p = RemoveHeadList (&Device->ReceivePoolList);
+ ReceivePool = CONTAINING_RECORD (p, NB_RECEIVE_POOL, Linkage);
+
+ for (i = 0; i < ReceivePool->PacketCount; i++) {
+
+ ReceivePacket = &ReceivePool->Packets[i];
+ NbiDeinitializeReceivePacket (Device, ReceivePacket);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free packet pool %lx\n", ReceivePool));
+#if !defined(NB_OWN_PACKETS)
+ NdisFreePacketPool(ReceivePool->PoolHandle);
+#endif
+ NbiFreeMemory (ReceivePool, ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ }
+
+#if defined(_PNP_POWER)
+ NbiDestroyReceiveBufferPools( Device );
+
+ //
+ // Destroy adapter address list.
+ //
+ while(!IsListEmpty( &Device->AdapterAddressDatabase ) ){
+ PADAPTER_ADDRESS AdapterAddress;
+ AdapterAddress = CONTAINING_RECORD( Device->AdapterAddressDatabase.Flink, ADAPTER_ADDRESS, Linkage );
+ NbiDestroyAdapterAddress( AdapterAddress, NULL );
+ }
+#else
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (Device->Bind.LineInfo.MaximumPacketSize * Device->InitPackets);
+
+ while (!IsListEmpty (&Device->ReceiveBufferPoolList)) {
+
+ p = RemoveHeadList (&Device->ReceiveBufferPoolList);
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ }
+#endif _PNP_POWER
+
+ NB_DEBUG (DEVICE, ("Final memory use is %d\n", Device->MemoryUsage));
+
+#if DBG
+ for (i = 0; i < MEMORY_MAX; i++) {
+ if (NbiMemoryTag[i].BytesAllocated != 0) {
+ NB_DEBUG (DEVICE, ("Tag %d: %d bytes left\n", i, NbiMemoryTag[i].BytesAllocated));
+ }
+ }
+#endif
+
+ //
+ // If we are being unloaded then someone is waiting for this
+ // event to finish the cleanup, since we may be at DISPATCH_LEVEL;
+ // otherwise it is during load and we can just kill ourselves here.
+ //
+
+ if (Device->UnloadWaiting) {
+
+ KeSetEvent(
+ &Device->UnloadEvent,
+ 0L,
+ FALSE);
+
+ } else {
+
+ CTEAssert (KeGetCurrentIrql() < DISPATCH_LEVEL);
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+ }
+
+} /* NbiDestroyDevice */
+
diff --git a/private/ntos/tdi/isnp/nb/dirs b/private/ntos/tdi/isnp/nb/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/dirs
@@ -0,0 +1,22 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS=up mp
diff --git a/private/ntos/tdi/isnp/nb/driver.c b/private/ntos/tdi/isnp/nb/driver.c
new file mode 100644
index 000000000..c4df8cbe6
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/driver.c
@@ -0,0 +1,1794 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ driver.c
+
+Abstract:
+
+ This module contains the DriverEntry and other initialization
+ code for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+PDEVICE NbiDevice = NULL;
+DEFINE_LOCK_STRUCTURE(NbiGlobalPoolInterlock);
+
+#ifdef RSRC_TIMEOUT_DBG
+
+ULONG NbiGlobalDebugResTimeout = 1;
+LARGE_INTEGER NbiGlobalMaxResTimeout;
+ // the packet is allocated from ndis pool.
+NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+UCHAR NbiGlobalDeathPacketHeader[100];
+
+VOID
+NbiInitDeathPacket()
+{
+
+ NDIS_HANDLE PoolHandle; // poolhandle for sendpacket below when
+ NTSTATUS Status;
+
+ //
+ // if we are using ndis packets, first create packet pool for 1 packet descriptor
+ //
+ NdisAllocatePacketPool( &Status, &PoolHandle, 1, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+ } else {
+
+ if (NbiInitializeSendPacket(
+ NbiDevice,
+ PoolHandle,
+ &NbiGlobalDeathPacket,
+ NbiGlobalDeathPacketHeader,
+ NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) != STATUS_SUCCESS) {
+
+ DbgPrint("Could not allocatee death packet %lx\n", Status);
+ NbiGlobalDebugResTimeout = 0;
+
+ //
+ // Also free up the pool which we allocated above.
+ //
+ NdisFreePacketPool(PoolHandle);
+ }
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+#if DBG
+
+ULONG NbiDebug = 0xffffffff;
+ULONG NbiDebug2 = 0x00000000;
+ULONG NbiMemoryDebug = 0x0002482c;
+
+UCHAR NbiTempDebugBuffer[150];
+UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+PUCHAR NbiDebugMemoryLoc = NbiDebugMemory[0];
+PUCHAR NbiDebugMemoryEnd = NbiDebugMemory[NB_MEMORY_LOG_SIZE];
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+)
+
+{
+ INT ArgLen;
+ va_list ArgumentPointer;
+
+ va_start(ArgumentPointer, FormatString);
+
+ //
+ // To avoid any overflows, copy this in a temp buffer first.
+ RtlZeroMemory (NbiTempDebugBuffer, 150);
+ ArgLen = vsprintf(NbiTempDebugBuffer,FormatString, ArgumentPointer);
+ va_end(ArgumentPointer);
+
+ if ( ArgLen > 64 ) {
+ CTEAssert( FALSE );
+ } else {
+ RtlZeroMemory (NbiDebugMemoryLoc, 64);
+ RtlCopyMemory( NbiDebugMemoryLoc, NbiTempDebugBuffer, ArgLen );
+
+ NbiDebugMemoryLoc += 64;
+ if (NbiDebugMemoryLoc >= NbiDebugMemoryEnd) {
+ NbiDebugMemoryLoc = NbiDebugMemory[0];
+ }
+ }
+
+} /* NbiDebugMemoryLog */
+
+
+DEFINE_LOCK_STRUCTURE(NbiMemoryInterlock);
+MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+DEFINE_LOCK_STRUCTURE(NbiGlobalInterlock);
+
+
+#ifdef RASAUTODIAL
+VOID
+NbiAcdBind();
+
+VOID
+NbiAcdUnbind();
+#endif
+
+#ifdef NB_PACKET_LOG
+
+ULONG NbiPacketLogDebug = NB_PACKET_LOG_RCV_OTHER | NB_PACKET_LOG_SEND_OTHER;
+USHORT NbiPacketLogSocket = 0;
+DEFINE_LOCK_STRUCTURE(NbiPacketLogLock);
+NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+PNB_PACKET_LOG_ENTRY NbiPacketLogLoc = NbiPacketLog;
+PNB_PACKET_LOG_ENTRY NbiPacketLogEnd = &NbiPacketLog[NB_PACKET_LOG_LENGTH];
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ )
+
+{
+
+ CTELockHandle LockHandle;
+ PNB_PACKET_LOG_ENTRY PacketLog;
+ LARGE_INTEGER TickCount;
+ ULONG DataLength;
+
+ CTEGetLock (&NbiPacketLogLock, &LockHandle);
+
+ PacketLog = NbiPacketLogLoc;
+
+ ++NbiPacketLogLoc;
+ if (NbiPacketLogLoc >= NbiPacketLogEnd) {
+ NbiPacketLogLoc = NbiPacketLog;
+ }
+ *(UNALIGNED ULONG *)NbiPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
+
+ CTEFreeLock (&NbiPacketLogLock, LockHandle);
+
+ RtlZeroMemory (PacketLog, sizeof(NB_PACKET_LOG_ENTRY));
+
+ PacketLog->SendReceive = Send ? '>' : '<';
+
+ KeQueryTickCount(&TickCount);
+ _itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
+
+ RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
+ RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
+ PacketLog->Length[0] = Length / 256;
+ PacketLog->Length[1] = Length % 256;
+
+ if (Length < sizeof(IPX_HEADER)) {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, Length);
+ } else {
+ RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, sizeof(IPX_HEADER));
+ }
+
+ DataLength = Length - sizeof(IPX_HEADER);
+ if (DataLength < 14) {
+ RtlCopyMemory(PacketLog->Data, Data, DataLength);
+ } else {
+ RtlCopyMemory(PacketLog->Data, Data, 14);
+ }
+
+} /* NbiLogPacket */
+
+#endif // NB_PACKET_LOG
+
+
+//
+// Forward declaration of various routines used in this module.
+//
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ );
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiDispatchInternal (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,DriverEntry)
+#endif
+
+//
+// This prevents us from having a bss section.
+//
+
+ULONG _setjmpexused = 0;
+
+
+//
+// These two are used in various places in the driver.
+//
+
+#if defined(_PNP_POWER)
+IPX_LOCAL_TARGET BroadcastTarget = { {0}, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
+#endif _PNP_POWER
+
+UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+UCHAR NetbiosBroadcastName[16] = { '*', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ULONG NbiFailLoad = FALSE;
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs initialization of the Netbios ISN module.
+ It creates the device objects for the transport
+ provider and performs other driver initialization.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+ RegistryPath - The name of Netbios's node in the registry.
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("Netbios/IPX Transport");
+ PDEVICE Device;
+ PIPX_HEADER IpxHeader;
+ CTELockHandle LockHandle;
+
+ PCONFIG Config = NULL;
+
+#if 0
+ DbgPrint ("NBI: FailLoad at %lx\n", &NbiFailLoad);
+ DbgBreakPoint();
+
+ if (NbiFailLoad) {
+ return STATUS_UNSUCCESSFUL;
+ }
+#endif
+
+ //
+ // Initialize the Common Transport Environment.
+ //
+
+ if (CTEInitialize() == 0) {
+ NB_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_TRANSPORT_REGISTER_FAILED,
+ 101,
+ STATUS_UNSUCCESSFUL,
+ NULL,
+ 0,
+ NULL);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+#if DBG
+ CTEInitLock (&NbiGlobalInterlock);
+ CTEInitLock (&NbiMemoryInterlock);
+ {
+ UINT i;
+ for (i = 0; i < MEMORY_MAX; i++) {
+ NbiMemoryTag[i].Tag = i;
+ NbiMemoryTag[i].BytesAllocated = 0;
+ }
+ }
+#endif
+#ifdef NB_PACKET_LOG
+ CTEInitLock (&NbiPacketLogLock);
+#endif
+
+#if defined(NB_OWN_PACKETS)
+ CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
+#endif
+
+ NB_DEBUG2 (DEVICE, ("ISN Netbios loaded\n"));
+
+ //
+ // This allocates the CONFIG structure and returns
+ // it in Config.
+ //
+
+ status = NbiGetConfiguration(DriverObject, RegistryPath, &Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n");
+ return status;
+ }
+
+
+ //
+ // Initialize the driver object with this driver's entry points.
+ //
+
+ DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
+ DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbiDispatchInternal;
+ DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
+
+ DriverObject->DriverUnload = NbiUnload;
+
+
+ //
+ // Create the device object which exports our name.
+ //
+
+ status = NbiCreateDevice (DriverObject, &Config->DeviceName, &Device);
+
+ if (!NT_SUCCESS (status)) {
+
+ NbiWriteGeneralErrorLog(
+ (PVOID)DriverObject,
+ EVENT_IPX_CREATE_DEVICE,
+ 801,
+ status,
+ NULL,
+ 0,
+ NULL);
+
+ NbiFreeConfiguration(Config);
+ return status;
+ }
+
+ NbiDevice = Device;
+
+ //
+ // Initialize the global pool interlock
+ //
+ CTEInitLock (&NbiGlobalPoolInterlock);
+
+
+ //
+ // Save the relevant configuration parameters.
+ //
+
+ Device->AckDelayTime = (Config->Parameters[CONFIG_ACK_DELAY_TIME] / SHORT_TIMER_DELTA) + 1;
+ Device->AckWindow = Config->Parameters[CONFIG_ACK_WINDOW];
+ Device->AckWindowThreshold = Config->Parameters[CONFIG_ACK_WINDOW_THRESHOLD];
+ Device->EnablePiggyBackAck = Config->Parameters[CONFIG_ENABLE_PIGGYBACK_ACK];
+ Device->Extensions = Config->Parameters[CONFIG_EXTENSIONS];
+ Device->RcvWindowMax = Config->Parameters[CONFIG_RCV_WINDOW_MAX];
+ Device->BroadcastCount = Config->Parameters[CONFIG_BROADCAST_COUNT];
+ Device->BroadcastTimeout = Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500;
+ Device->ConnectionCount = Config->Parameters[CONFIG_CONNECTION_COUNT];
+ Device->ConnectionTimeout = Config->Parameters[CONFIG_CONNECTION_TIMEOUT] * 500;
+ Device->InitPackets = Config->Parameters[CONFIG_INIT_PACKETS];
+ Device->MaxPackets = Config->Parameters[CONFIG_MAX_PACKETS];
+ Device->InitialRetransmissionTime = Config->Parameters[CONFIG_INIT_RETRANSMIT_TIME];
+ Device->Internet = Config->Parameters[CONFIG_INTERNET];
+ Device->KeepAliveCount = Config->Parameters[CONFIG_KEEP_ALIVE_COUNT];
+ Device->KeepAliveTimeout = Config->Parameters[CONFIG_KEEP_ALIVE_TIMEOUT];
+ Device->RetransmitMax = Config->Parameters[CONFIG_RETRANSMIT_MAX];
+ Device->RouterMtu = Config->Parameters[CONFIG_ROUTER_MTU];
+
+ Device->FindNameTimeout =
+ ((Config->Parameters[CONFIG_BROADCAST_TIMEOUT] * 500) + (FIND_NAME_GRANULARITY/2)) /
+ FIND_NAME_GRANULARITY;
+
+ Device->MaxReceiveBuffers = 20; // BUGBUG: Make it configurable?
+
+#if defined(_PNP_POWER)
+ //
+ // Make Tdi ready for pnp notifications before binding
+ // to IPX
+ //
+ TdiInitialize();
+
+ // Initialize the timer system. This should be done before
+ // binding to ipx because we should have timers intialized
+ // before ipx calls our pnp indications.
+
+ NbiInitializeTimers (Device);
+#endif _PNP_POWER
+
+ //
+ // Now bind to IPX via the internal interface.
+ //
+
+ status = NbiBind (Device, Config);
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ NbiInitDeathPacket();
+ // NbiGlobalMaxResTimeout.QuadPart = 50; // 1*1000*10000;
+ NbiGlobalMaxResTimeout.QuadPart = 20*60*1000;
+ NbiGlobalMaxResTimeout.QuadPart *= 10000;
+#endif // RSRC_TIMEOUT_DBG
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Create Hash Table to store netbios cache entries
+ // For server create a big table, for workstation a small one
+ //
+
+ if ( MmIsThisAnNtAsSystem() ) {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_LARGE );
+ } else {
+ status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_SMALL );
+ }
+
+ if (!NT_SUCCESS (status)) {
+
+ //
+ // If it failed it logged an error.
+ //
+
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+ NbiFreeConfiguration(Config);
+ NbiDereferenceDevice (Device, DREF_LOADED);
+ return status;
+ }
+
+ //
+ // Allocate our initial connectionless packet pool.
+ //
+
+ NbiAllocateSendPool (Device);
+
+ //
+ // Allocate our initial receive packet pool.
+ //
+
+ NbiAllocateReceivePool (Device);
+
+ //
+ // Allocate our initial receive buffer pool.
+ //
+ //
+#if !defined(_PNP_POWER)
+ NbiAllocateReceiveBufferPool (Device);
+#endif !_PNP_POWER
+
+#if defined(_PNP_POWER)
+ if ( DEVICE_STATE_CLOSED == Device->State ) {
+ Device->State = DEVICE_STATE_LOADED;
+ }
+#endif _PNP_POWER
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+#if !defined(_PNP_POWER)
+ //
+ // Start the timer system.
+ //
+
+ NbiInitializeTimers (Device);
+#endif !_PNP_POWER
+
+
+ //
+ // Fill in the default connnectionless header.
+ //
+
+ IpxHeader = &Device->ConnectionlessHeader;
+ IpxHeader->CheckSum = 0xffff;
+ IpxHeader->PacketLength[0] = 0;
+ IpxHeader->PacketLength[1] = 0;
+ IpxHeader->TransportControl = 0;
+ IpxHeader->PacketType = 0;
+ *(UNALIGNED ULONG *)(IpxHeader->DestinationNetwork) = 0;
+ RtlCopyMemory(IpxHeader->DestinationNode, BroadcastAddress, 6);
+ IpxHeader->DestinationSocket = NB_SOCKET;
+ IpxHeader->SourceSocket = NB_SOCKET;
+#if !defined(_PNP_POWER)
+ RtlCopyMemory(IpxHeader->SourceNetwork, Device->Bind.Network, 4);
+ RtlCopyMemory(IpxHeader->SourceNode, Device->Bind.Node, 6);
+
+ Device->State = DEVICE_STATE_OPEN;
+#endif !_PNP_POWER
+
+
+ NbiFreeConfiguration(Config);
+
+#ifdef RASAUTODIAL
+ //
+ // Get the automatic connection
+ // driver entry points.
+ //
+ NbiAcdBind();
+#endif
+
+ return STATUS_SUCCESS;
+
+} /* DriverEntry */
+
+VOID
+NbiUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unloads the sample transport driver.
+ It unbinds from any NDIS drivers that are open and frees all resources
+ associated with the transport. The I/O system will not call us until
+ nobody above has Netbios open.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ None. When the function returns, the driver is unloaded.
+
+--*/
+
+{
+ PNETBIOS_CACHE CacheName;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+
+ UNREFERENCED_PARAMETER (DriverObject);
+
+
+#ifdef RASAUTODIAL
+ //
+ // Unbind from the
+ // automatic connection driver.
+ //
+ NbiAcdUnbind();
+#endif
+
+ Device->State = DEVICE_STATE_STOPPING;
+
+ //
+ // Free the cache of netbios names.
+ //
+
+ DestroyNetbiosCacheTable( Device->NameCache );
+
+ //
+ // Cancel the long timer.
+ //
+
+ if (CTEStopTimer (&Device->LongTimer)) {
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+ //
+ // Unbind from the IPX driver.
+ //
+
+ NbiUnbind (Device);
+
+ //
+ // This event will get set when the reference count
+ // drops to 0.
+ //
+
+ KeInitializeEvent(
+ &Device->UnloadEvent,
+ NotificationEvent,
+ FALSE);
+ Device->UnloadWaiting = TRUE;
+
+ //
+ // Remove the reference for us being loaded.
+ //
+
+ NbiDereferenceDevice (Device, DREF_LOADED);
+
+ //
+ // Wait for our count to drop to zero.
+ //
+
+ KeWaitForSingleObject(
+ &Device->UnloadEvent,
+ Executive,
+ KernelMode,
+ TRUE,
+ (PLARGE_INTEGER)NULL
+ );
+
+ //
+ // Do the cleanup that has to happen at IRQL 0.
+ //
+
+ ExDeleteResource (&Device->AddressResource);
+ IoDeleteDevice ((PDEVICE_OBJECT)Device);
+
+} /* NbiUnload */
+
+
+VOID
+NbiFreeResources (
+ IN PVOID Adapter
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by Netbios to clean up the data structures associated
+ with a given Device. When this routine exits, the Device
+ should be deleted as it no longer has any assocaited resources.
+
+Arguments:
+
+ Device - Pointer to the Device we wish to clean up.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if 0
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PTP_PACKET packet;
+ PNDIS_PACKET ndisPacket;
+ PBUFFER_TAG BufferTag;
+#endif
+
+
+#if 0
+ //
+ // Clean up packet pool.
+ //
+
+ while ( Device->PacketPool.Next != NULL ) {
+ s = PopEntryList( &Device->PacketPool );
+ packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
+
+ NbiDeallocateSendPacket (Device, packet);
+ }
+
+ //
+ // Clean up receive packet pool
+ //
+
+ while ( Device->ReceivePacketPool.Next != NULL) {
+ s = PopEntryList (&Device->ReceivePacketPool);
+
+ //
+ // HACK: This works because Linkage is the first field in
+ // ProtocolReserved for a receive packet.
+ //
+
+ ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
+
+ NbiDeallocateReceivePacket (Device, ndisPacket);
+ }
+
+
+ //
+ // Clean up receive buffer pool.
+ //
+
+ while ( Device->ReceiveBufferPool.Next != NULL ) {
+ s = PopEntryList( &Device->ReceiveBufferPool );
+ BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
+
+ NbiDeallocateReceiveBuffer (Device, BufferTag);
+ }
+
+#endif
+
+} /* NbiFreeResources */
+
+
+NTSTATUS
+NbiDispatchOpenClose(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main dispatch routine for the IPXNB device driver.
+ It accepts an I/O Request Packet, performs the request, and then
+ returns with the appropriate status.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ CTELockHandle LockHandle;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ NTSTATUS Status;
+ PFILE_FULL_EA_INFORMATION openType;
+ BOOLEAN found;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST Request;
+ UINT i;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+#if !defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+#endif !_PNP_POWER
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+ //
+ // Case on the function that is being performed by the requestor. If the
+ // operation is a valid one for this device, then make it look like it was
+ // successfully completed, where possible.
+ //
+
+
+ switch (REQUEST_MAJOR_FUNCTION(Request)) {
+
+ //
+ // The Create function opens a transport object (either address or
+ // connection). Access checking is performed on the specified
+ // address to ensure security of transport-layer addresses.
+ //
+
+ case IRP_MJ_CREATE:
+
+#if defined(_PNP_POWER)
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ openType = OPEN_REQUEST_EA_INFORMATION(Request);
+
+ if (openType != NULL) {
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiTransportAddress[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenAddress (Device, Request);
+ break;
+ }
+
+ //
+ // Connection?
+ //
+
+ found = TRUE;
+
+ for (i=0;i<openType->EaNameLength;i++) {
+ if (openType->EaName[i] == TdiConnectionContext[i]) {
+ continue;
+ } else {
+ found = FALSE;
+ break;
+ }
+ }
+
+ if (found) {
+ Status = NbiOpenConnection (Device, Request);
+ break;
+ }
+
+ } else {
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier);
+ ++Device->ControlChannelIdentifier;
+ if (Device->ControlChannelIdentifier == 0) {
+ Device->ControlChannelIdentifier = 1;
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONTROL_CHANNEL_FILE;
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case IRP_MJ_CLOSE:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // The Close function closes a transport endpoint, terminates
+ // all outstanding transport activity on the endpoint, and unbinds
+ // the endpoint from its transport address, if any. If this
+ // is the last transport endpoint bound to the address, then
+ // the address is removed from the provider.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // This creates a reference to AddressFile.
+ //
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ Status = STATUS_INVALID_HANDLE;
+ } else {
+ Status = NbiCloseAddressFile (Device, Request);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // We don't call VerifyConnection because the I/O
+ // system should only give us one close and the file
+ // object should be valid. This helps avoid a window
+ // where two threads call HandleConnectionZero at the
+ // same time.
+ //
+
+ Status = NbiCloseConnection (Device, Request);
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ //
+ // See if it is one of the upper driver's control channels.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ case IRP_MJ_CLEANUP:
+
+#if defined(_PNP_POWER)
+ if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ break;
+ }
+#endif _PNP_POWER
+
+ //
+ // Handle the two stage IRP for a file close operation. When the first
+ // stage hits, run down all activity on the object of interest. This
+ // do everything to it but remove the creation hold. Then, when the
+ // CLOSE irp hits, actually close the object.
+ //
+
+ switch ((ULONG)REQUEST_OPEN_TYPE(Request)) {
+
+ case TDI_TRANSPORT_ADDRESS_FILE:
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile(AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NbiStopAddressFile (AddressFile, AddressFile->Address);
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONNECTION_FILE:
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection(Connection);
+
+ if (!NT_SUCCESS (Status)) {
+
+ Status = STATUS_INVALID_HANDLE;
+
+ } else {
+
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_INVALID_CONNECTION
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ NB_END_SYNC (&SyncContext);
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+ Status = STATUS_SUCCESS;
+ }
+
+ break;
+
+ case TDI_CONTROL_CHANNEL_FILE:
+
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_HANDLE;
+
+ }
+
+ break;
+
+ default:
+
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ } /* major function switch */
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchOpenClose */
+
+
+NTSTATUS
+NbiDispatchDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ //
+ // Branch to the appropriate request handler. Preliminary checking of
+ // the size of the request block is performed here so that it is known
+ // in the handlers that the minimum input parameters are readable. It
+ // is *not* determined here whether variable length input fields are
+ // passed correctly; this is a check which must be made within each routine.
+ //
+
+ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+
+ default:
+
+ //
+ // Convert the user call to the proper internal device call.
+ //
+
+ Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // If TdiMapUserRequest returns SUCCESS then the IRP
+ // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
+ // IRP, so we dispatch it as usual. The IRP will
+ // be completed by this call.
+ //
+
+ Status = NbiDispatchInternal (DeviceObject, Irp);
+
+ } else {
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+
+ }
+
+ break;
+ }
+
+ return Status;
+
+} /* NbiDeviceControl */
+
+
+NB_TDI_DISPATCH_ROUTINE NbiDispatchInternalTable[] = {
+ NbiTdiAssociateAddress,
+ NbiTdiDisassociateAddress,
+ NbiTdiConnect,
+ NbiTdiListen,
+ NbiTdiAccept,
+ NbiTdiDisconnect,
+ NbiTdiSend,
+ NbiTdiReceive,
+ NbiTdiSendDatagram,
+ NbiTdiReceiveDatagram,
+ NbiTdiSetEventHandler,
+ NbiTdiQueryInformation,
+ NbiTdiSetInformation,
+ NbiTdiAction
+ };
+
+
+NTSTATUS
+NbiDispatchInternal(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dispatches TDI request types to different handlers based
+ on the minor IOCTL function code in the IRP's current stack location.
+ In addition to cracking the minor function code, this routine also
+ reaches into the IRP and passes the packetized parameters stored there
+ as parameters to the various TDI request handlers so that they are
+ not IRP-dependent.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PDEVICE Device = (PDEVICE)DeviceObject;
+ PREQUEST Request;
+ UCHAR MinorFunction;
+
+ if (Device->State != DEVICE_STATE_OPEN) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+
+ //
+ // Allocate a request to track this IRP.
+ //
+
+ Request = NbiAllocateRequest (Device, Irp);
+ IF_NOT_ALLOCATED(Request) {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // Make sure status information is consistent every time.
+ //
+
+ MARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = STATUS_PENDING;
+ REQUEST_INFORMATION(Request) = 0;
+
+
+ //
+ // Branch to the appropriate request handler.
+ //
+
+ MinorFunction = REQUEST_MINOR_FUNCTION(Request) - 1;
+
+ if (MinorFunction <= (TDI_ACTION-1)) {
+
+ Status = (*NbiDispatchInternalTable[MinorFunction]) (
+ Device,
+ Request);
+
+ } else {
+
+ NB_DEBUG (DRIVER, ("Unsupported minor code %d\n", MinorFunction+1));
+ if ((MinorFunction+1) == TDI_DISCONNECT) {
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+
+ if (Status != STATUS_PENDING) {
+ UNMARK_REQUEST_PENDING(Request);
+ REQUEST_STATUS(Request) = Status;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+ }
+
+ //
+ // Return the immediate status code to the caller.
+ //
+
+ return Status;
+
+} /* NbiDispatchInternal */
+
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, making sure it is within
+ the limit allowed by the device.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+ PDEVICE Device = NbiDevice;
+
+ if (ChargeDevice) {
+ if ((Device->MemoryLimit != 0) &&
+ (((LONG)(Device->MemoryUsage + BytesNeeded) >
+ Device->MemoryLimit))) {
+
+ NbiPrint1 ("Nbi: Could not allocate %d: limit\n", BytesNeeded);
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ return NULL;
+ }
+ }
+
+#if ISN_NT
+ Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' IBN');
+#else
+ Memory = CTEAllocMem (BytesNeeded);
+#endif
+
+ if (Memory == NULL) {
+
+ NbiPrint1("Nbi: Could not allocate %d: no pool\n", BytesNeeded);
+
+ if (ChargeDevice) {
+ NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
+ }
+
+ return NULL;
+ }
+
+ if (ChargeDevice) {
+ Device->MemoryUsage += BytesNeeded;
+ }
+
+ return Memory;
+
+} /* NbipAllocateMemory */
+
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ ChargeDevice - TRUE if the device should be charged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+#if ISN_NT
+ ExFreePool (Memory);
+#else
+ CTEFreeMem (Memory);
+#endif
+
+ if (ChargeDevice) {
+ Device->MemoryUsage -= BytesAllocated;
+ }
+
+} /* NbipFreeMemory */
+
+#if DBG
+
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory, charging it to the device.
+ If it cannot allocate memory it uses the Tag and Descriptor
+ to log an error.
+
+Arguments:
+
+ BytesNeeded - The number of bytes to allocated.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOID Memory;
+
+ UNREFERENCED_PARAMETER(Description);
+
+ Memory = NbipAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+ if (Memory) {
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ BytesNeeded,
+ &NbiMemoryInterlock);
+ }
+
+ return Memory;
+
+} /* NbipAllocateTaggedMemory */
+
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees memory allocated with NbipAllocateTaggedMemory.
+
+Arguments:
+
+ Memory - The memory allocated.
+
+ BytesAllocated - The number of bytes to freed.
+
+ Tag - A unique ID used in the error log.
+
+ Description - A text description of the allocation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Description);
+
+ ExInterlockedAddUlong(
+ &NbiMemoryTag[Tag].BytesAllocated,
+ (ULONG)(-(LONG)BytesAllocated),
+ &NbiMemoryInterlock);
+
+ NbipFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
+
+} /* NbipFreeTaggedMemory */
+
+#endif
+
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ an out of resources condition.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ BytesNeeded - If applicable, the number of bytes that could not
+ be allocated.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ PUCHAR StringLoc;
+ ULONG TempUniqueError;
+ static WCHAR UniqueErrorBuffer[4] = L"000";
+ INT i;
+
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ Device->DeviceNameLength +
+ sizeof(UniqueErrorBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the error value into a buffer.
+ //
+
+ TempUniqueError = UniqueErrorValue;
+ for (i=1; i>=0; i--) {
+ UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
+ TempUniqueError /= 10;
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = sizeof(ULONG);
+ errorLogEntry->NumberOfStrings = 2;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+ errorLogEntry->DumpData[0] = BytesNeeded;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+
+ StringLoc += Device->DeviceNameLength;
+ RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteResourceErrorLog */
+
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a general problem as indicated by the parameters. It handles
+ event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
+ TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
+ events have messages with one or two strings in them.
+
+Arguments:
+
+ Device - Pointer to the device context, or this may be
+ a driver object instead.
+
+ ErrorCode - The transport event code.
+
+ UniqueErrorValue - Used as the UniqueErrorValue in the error log
+ packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ SecondString - If not NULL, the string to use as the %3
+ value in the error log packet.
+
+ DumpDataCount - The number of ULONGs of dump data.
+
+ DumpData - Dump data for the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG SecondStringSize;
+ PUCHAR StringLoc;
+ static WCHAR DriverName[8] = L"NwlnkNb";
+
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
+ (DumpDataCount * sizeof(ULONG));
+
+ if (Device->Type == IO_TYPE_DEVICE) {
+ EntrySize += (UCHAR)Device->DeviceNameLength;
+ } else {
+ EntrySize += sizeof(DriverName);
+ }
+
+ if (SecondString) {
+ SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize += (UCHAR)SecondStringSize;
+ }
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
+ errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
+ errorLogEntry->StringOffset =
+ sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG));
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = UniqueErrorValue;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ if (DumpDataCount) {
+ RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+ }
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ if (Device->Type == IO_TYPE_DEVICE) {
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+ } else {
+ RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
+ StringLoc += sizeof(DriverName);
+ }
+ if (SecondString) {
+ RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
+ }
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteGeneralErrorLog */
+
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and writes an error log entry indicating
+ a problem querying or setting an OID on an adapter. It handles
+ event codes SET_OID_FAILED and QUERY_OID_FAILED.
+
+Arguments:
+
+ Device - Pointer to the device context.
+
+ ErrorCode - Used as the ErrorCode in the error log packet.
+
+ FinalStatus - Used as the FinalStatus in the error log packet.
+
+ AdapterString - The name of the adapter we were bound to.
+
+ OidValue - The OID which could not be set or queried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_ERROR_LOG_PACKET errorLogEntry;
+ UCHAR EntrySize;
+ ULONG AdapterStringSize;
+ PUCHAR StringLoc;
+ static WCHAR OidBuffer[9] = L"00000000";
+ INT i;
+ UINT CurrentDigit;
+
+ AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
+ sizeof(ULONG) +
+ Device->DeviceNameLength +
+ AdapterStringSize +
+ sizeof(OidBuffer);
+
+ errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+ (PDEVICE_OBJECT)Device,
+ EntrySize
+ );
+
+ //
+ // Convert the OID into a buffer.
+ //
+
+ for (i=7; i>=0; i--) {
+ CurrentDigit = OidValue & 0xf;
+ OidValue >>= 4;
+ if (CurrentDigit >= 0xa) {
+ OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
+ } else {
+ OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
+ }
+ }
+
+ if (errorLogEntry != NULL) {
+
+ errorLogEntry->MajorFunctionCode = (UCHAR)-1;
+ errorLogEntry->RetryCount = (UCHAR)-1;
+ errorLogEntry->DumpDataSize = 0;
+ errorLogEntry->NumberOfStrings = 3;
+ errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
+ errorLogEntry->EventCategory = 0;
+ errorLogEntry->ErrorCode = ErrorCode;
+ errorLogEntry->UniqueErrorValue = 0;
+ errorLogEntry->FinalStatus = FinalStatus;
+ errorLogEntry->SequenceNumber = (ULONG)-1;
+ errorLogEntry->IoControlCode = 0;
+
+ StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
+ RtlCopyMemory (StringLoc, Device->DeviceName, Device->DeviceNameLength);
+ StringLoc += Device->DeviceNameLength;
+
+ RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
+ StringLoc += sizeof(OidBuffer);
+
+ RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
+
+ IoWriteErrorLogEntry(errorLogEntry);
+
+ }
+
+} /* NbiWriteOidErrorLog */
+
diff --git a/private/ntos/tdi/isnp/nb/event.c b/private/ntos/tdi/isnp/nb/event.c
new file mode 100644
index 000000000..f6cff7105
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/event.c
@@ -0,0 +1,117 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ event.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiSetEventHandler
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+PVOID TdiDefaultHandlers[6] = {
+ TdiDefaultConnectHandler,
+ TdiDefaultDisconnectHandler,
+ TdiDefaultErrorHandler,
+ TdiDefaultReceiveHandler,
+ TdiDefaultRcvDatagramHandler,
+ TdiDefaultRcvExpeditedHandler
+ };
+
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetEventHandler request for the
+ transport provider. The caller (request dispatcher) verifies
+ that this routine will not be executed on behalf of a user-mode
+ client, as this request enables direct callouts at DISPATCH_LEVEL.
+
+Arguments:
+
+ Device - The netbios device object.
+
+ Request - Pointer to the request.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ CTELockHandle LockHandle;
+ PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+ PADDRESS_FILE AddressFile;
+ UINT EventType;
+
+ UNREFERENCED_PARAMETER (Device);
+
+ //
+ // Get the Address this is associated with; if there is none, get out.
+ //
+
+ AddressFile = REQUEST_OPEN_CONTEXT(Request);
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ NB_GET_LOCK (&AddressFile->Address->Lock, &LockHandle);
+
+ Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)REQUEST_PARAMETERS(Request);
+ EventType = (UINT)(Parameters->EventType);
+
+ if (Parameters->EventType > TDI_EVENT_RECEIVE_EXPEDITED) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } else {
+
+ if (Parameters->EventHandler == NULL) {
+ AddressFile->RegisteredHandler[EventType] = FALSE;
+ AddressFile->Handlers[EventType] = TdiDefaultHandlers[EventType];
+ AddressFile->HandlerContexts[EventType] = NULL;
+ } else {
+ AddressFile->Handlers[EventType] = Parameters->EventHandler;
+ AddressFile->HandlerContexts[EventType] = Parameters->EventContext;
+ AddressFile->RegisteredHandler[EventType] = TRUE;
+ }
+
+ }
+
+ NB_FREE_LOCK (&AddressFile->Address->Lock, LockHandle);
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ return Status;
+
+} /* NbiTdiSetEventHandler */
+
diff --git a/private/ntos/tdi/isnp/nb/frame.c b/private/ntos/tdi/isnp/nb/frame.c
new file mode 100644
index 000000000..bbc14fd56
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/frame.c
@@ -0,0 +1,1095 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ frame.c
+
+Abstract:
+
+ This module contains code which creates and sends various
+ types of frames.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ ReqFrame - If specified, the request frame for which this
+ response is being sent. The reqframe contains the
+ destination ipx address and the netbios name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(ReqFrame)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ LocalTarget = &BroadcastTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#else
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a name frame on the
+ specified address. It handles add name, name in use, and
+ delete name frames.
+
+Arguments:
+
+ Address - The address on which the frame is sent. This will
+ be NULL if we are responding to a request to the
+ broadcast address.
+
+ NameTypeFlag - The name type flag to use.
+
+ DataStreamType - The type of the command.
+
+ LocalTarget - If specified, the local target to use for the
+ send (if not, it will be broadcast).
+
+ DestAddress - If specified, the destination IPX address to
+ use for the send (if not, it will be broadcast on net 0).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LOCAL_TARGET TempLocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->u.SR_NF.Address = Address; // may be NULL
+ Reserved->Type = SEND_TYPE_NAME_FRAME;
+
+ //
+ // Frame that are not sent to a specific address are
+ // sent to all valid NIC IDs.
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ Reserved->u.SR_NF.CurrentNicId = 1;
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ } else {
+ Reserved->u.SR_NF.CurrentNicId = 0;
+ }
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ if (ARGUMENT_PRESENT(DestAddress)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)DestAddress, 12);
+ }
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ if (ARGUMENT_PRESENT(LocalTarget)) {
+ Header->IpxHeader.PacketType = 0x04;
+ } else {
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+ }
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = DataStreamType;
+ Header->NameFrame.NameTypeFlag = NameTypeFlag;
+
+ //
+ // DataStreamType2 is the same as DataStreamType except for
+ // name in use frames where it is set to the add name type.
+ //
+
+ Header->NameFrame.DataStreamType2 = (UCHAR)
+ ((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address ? Address->NetbiosAddress.NetbiosName : NetbiosBroadcastName,
+ 16);
+
+ if (Address) {
+ NbiReferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiReferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ if (!ARGUMENT_PRESENT(LocalTarget)) {
+ TempLocalTarget.NicId = 1; // BUGBUG: What if 1 isn't valid?
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+ }
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
+ sizeof(NB_NAME_FRAME));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendNameFrame */
+#endif _PNP_POWER
+
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ sizeof(NB_SESSION_INIT));
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Device->Extensions) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = 0xffff;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = sizeof(NB_SESSION_INIT);
+ Header->Session.ReceiveSequence = 0;
+ if (Device->Extensions) {
+ Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitialize */
+
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session initialize ack
+ frame for the specified connection. If extra data was
+ specified in the session initialize frame it is echoed
+ back to the remote.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ ExtraData - Any extra data (after the SESSION_INIT buffer)
+ in the frame.
+
+ ExtraDataLength - THe length of the extra data.
+
+ LockHandle - If specified, indicates the connection lock
+ is held and should be released. This is for cases
+ where the ExtraData is in memory which may be freed
+ once the connection lock is released.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ ULONG SessionInitBufferLength;
+ PNB_SESSION_INIT SessionInitMemory;
+ PNDIS_BUFFER SessionInitBuffer;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+
+ //
+ // Allocate a buffer for the extra portion of the
+ // session initialize.
+ //
+
+ SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
+ SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ if (!SessionInitMemory) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+ return;
+ }
+
+ //
+ // Save the extra data, now we can free the lock.
+ //
+
+ if (ExtraDataLength != 0) {
+ RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
+ }
+ if (ARGUMENT_PRESENT(LockHandle)) {
+ NB_FREE_LOCK (&Connection->Lock, *LockHandle);
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &SessionInitBuffer,
+ Device->NdisBufferPoolHandle,
+ SessionInitMemory,
+ SessionInitBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_INIT;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ if (Connection->NewNetbios) {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
+ } else {
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
+ }
+ CTEAssert (Connection->CurrentSend.SendSequence == 0);
+ CTEAssert (Connection->ReceiveSequence == 1);
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = (USHORT)SessionInitBufferLength;
+ Header->Session.ReceiveSequence = 1;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
+ RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: Should we ref the connection? It doesn't
+ // really matter which we do.
+ //
+
+ NbiReferenceDevice (Device, DREF_SESSION_INIT);
+
+ NdisChainBufferAtBack (Packet, SessionInitBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION) + SessionInitBufferLength,
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionInitAck */
+
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a data ack frame.
+
+ THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+ AckType - Indicates if this is a query to the remote,
+ a response to a received probe, or a request to resend.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, try for the connection
+ // packet. If that's not available, that's OK since data
+ // acks are connectionless anyway.
+ //
+
+ if (s == NULL) {
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ } else {
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ switch (AckType) {
+ case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
+ case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
+ case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
+ }
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ NbiReferenceConnectionSync(Connection, CREF_FRAME);
+
+ //
+ // Set this so we will accept a probe from a remote without
+ // the send ack bit on. However if we receive such a request
+ // we turn this flag off until we get something else from the
+ // remote.
+ //
+
+ Connection->IgnoreNextDosProbe = FALSE;
+
+ Connection->ReceivesWithoutAck = 0;
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+} /* NbiSendDataAck */
+
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame for the specified connection.
+
+Arguments:
+
+ Connection - The connection on which the frame is sent.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
+ Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. We don't advance the
+ // send pointer, since it is the last frame of the session
+ // and we want it to stay the same in the case of resends.
+ //
+
+ Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceConnection (Connection, CREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEnd */
+
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and sends a session end
+ frame. Generally it is sent on a connection but we
+ are not tied to that, to allow us to respond to
+ session ends from unknown remotes.
+
+Arguments:
+
+ RemoteAddress - The remote IPX address.
+
+ LocalTarget - The local target of the remote.
+
+ SessionEnd - The received session end frame.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTION UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ //
+ // If we can't allocate a frame, that is OK, since
+ // it is connectionless anyway.
+ //
+
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
+ Reserved->u.SR_CO.Connection = NULL;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Session.ConnectionControlFlag = 0x00;
+ Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
+ Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
+ Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
+ Header->Session.SendSequence = SessionEnd->ReceiveSequence;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+ if (SessionEnd->BytesReceived != 0) { // BUGBUG: Will this detect new netbios?
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
+ Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
+ } else {
+ Header->Session.ReceiveSequence = SessionEnd->SendSequence;
+ Header->Session.BytesReceived = 0;
+ }
+
+ NbiReferenceDevice (Device, DREF_FRAME);
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiSendSessionEndAck */
+
diff --git a/private/ntos/tdi/isnp/nb/isnnb.h b/private/ntos/tdi/isnp/nb/isnnb.h
new file mode 100644
index 000000000..2d142e346
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/isnnb.h
@@ -0,0 +1,787 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ isnnb.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 2-September-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#define NB_MAXIMUM_MAC 40
+
+#define NB_SOCKET 0x5504
+
+#if defined(_PNP_POWER)
+#define NB_NETBIOS_NAME_SIZE 16
+
+#define LOCK_ACQUIRED TRUE
+#define LOCK_NOT_ACQUIRED FALSE
+#endif _PNP_POWER
+
+//
+// Defined granularity of find name timeouts in milliseconds --
+// we make this the same as the spec'ed RIP gap to avoid
+// flooding routers.
+//
+
+#define FIND_NAME_GRANULARITY 55
+
+
+//
+// Defines the number of milliseconds between expirations of the
+// short and long timers.
+//
+
+#define MILLISECONDS 10000 // number of NT time units in one
+
+#define SHORT_TIMER_DELTA 100
+#define LONG_TIMER_DELTA 2000
+
+
+//
+// Convert a ushort netware order <-> machine order
+//
+
+#define REORDER_USHORT(_Ushort) ((((_Ushort) & 0xff00) >> 8) | (((_Ushort) & 0x00ff) << 8))
+
+//
+// Convert a ulong netware order <-> machine order
+//
+
+#define REORDER_ULONG(_Ulong) \
+ ((((_Ulong) & 0xff000000) >> 24) | \
+ (((_Ulong) & 0x00ff0000) >> 8) | \
+ (((_Ulong) & 0x0000ff00) << 8) | \
+ (((_Ulong) & 0x000000ff) << 24))
+
+
+
+#include <packon.h>
+
+//
+// Definition of the IPX header.
+//
+
+typedef struct _IPX_HEADER {
+ USHORT CheckSum;
+ UCHAR PacketLength[2];
+ UCHAR TransportControl;
+ UCHAR PacketType;
+ UCHAR DestinationNetwork[4];
+ UCHAR DestinationNode[6];
+ USHORT DestinationSocket;
+ UCHAR SourceNetwork[4];
+ UCHAR SourceNode[6];
+ USHORT SourceSocket;
+} IPX_HEADER, *PIPX_HEADER;
+
+
+//
+// Definition of the Netbios header for name frames.
+//
+
+typedef struct _NB_NAME_FRAME {
+ union {
+ struct {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ };
+ UCHAR RoutingInfo[32];
+ };
+ UCHAR NameTypeFlag;
+ UCHAR DataStreamType2;
+ UCHAR Name[16];
+} NB_NAME_FRAME, *PNB_NAME_FRAME;
+
+//
+// Definition of the Netbios header for directed datagrams.
+//
+
+typedef struct _NB_DATAGRAM {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+} NB_DATAGRAM, *PNB_DATAGRAM;
+
+//
+// Definition of the Netbios header for a status query.
+//
+
+typedef struct _NB_STATUS_QUERY {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ UCHAR Padding[14];
+} NB_STATUS_QUERY, *PNB_STATUS_QUERY;
+
+//
+// Definition of the Netbios header for a status response
+// (this does not include the status buffer itself).
+//
+
+typedef struct _NB_STATUS_RESPONSE {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+} NB_STATUS_RESPONSE, *PNB_STATUS_RESPONSE;
+
+
+//
+// Definition of the general Netbios connectionless header.
+//
+
+typedef struct _NB_CONNECTIONLESS {
+ IPX_HEADER IpxHeader;
+ union {
+ NB_NAME_FRAME NameFrame;
+ NB_DATAGRAM Datagram;
+ NB_STATUS_QUERY StatusQuery;
+ NB_STATUS_RESPONSE StatusResponse;
+ };
+} NB_CONNECTIONLESS, *PNB_CONNECTIONLESS;
+
+
+//
+// Definition of the Netbios session frame.
+//
+
+typedef struct _NB_SESSION {
+ UCHAR ConnectionControlFlag;
+ UCHAR DataStreamType;
+ USHORT SourceConnectionId;
+ USHORT DestConnectionId;
+ USHORT SendSequence;
+ USHORT TotalDataLength;
+ USHORT Offset;
+ USHORT DataLength;
+ USHORT ReceiveSequence;
+ union {
+ USHORT BytesReceived;
+ USHORT ReceiveSequenceMax;
+ };
+} NB_SESSION, *PNB_SESSION;
+
+
+//
+// Definition of the extra fields in a Netbios
+// session frame for session init and session init
+// ack.
+//
+
+typedef struct _NB_SESSION_INIT {
+ UCHAR SourceName[16];
+ UCHAR DestinationName[16];
+ USHORT MaximumDataSize;
+ USHORT MaximumPacketTime;
+ USHORT StartTripTime;
+} NB_SESSION_INIT, *PNB_SESSION_INIT;
+
+
+//
+// Definition of the general Netbios connection-oriented header.
+//
+
+typedef struct _NB_CONNECTION {
+ IPX_HEADER IpxHeader;
+ NB_SESSION Session;
+} NB_CONNECTION, *PNB_CONNECTION;
+
+
+//
+// Definition of a Netbios packet.
+//
+
+typedef union _NB_FRAME {
+ NB_CONNECTIONLESS Connectionless;
+ NB_CONNECTION Connection;
+} NB_FRAME, *PNB_FRAME;
+
+#include <packoff.h>
+
+
+//
+// Definitions for the DataStreamType field, with the
+// format used shown in the comment afterward.
+//
+
+#define NB_CMD_FIND_NAME 0x01 // NAME_FRAME
+#define NB_CMD_NAME_RECOGNIZED 0x02 // NAME_FRAME
+#define NB_CMD_ADD_NAME 0x03 // NAME_FRAME
+#define NB_CMD_NAME_IN_USE 0x04 // NAME_FRAME
+#define NB_CMD_DELETE_NAME 0x05 // NAME_FRAME
+#define NB_CMD_SESSION_DATA 0x06 // SESSION
+#define NB_CMD_SESSION_END 0x07 // SESSION
+#define NB_CMD_SESSION_END_ACK 0x08 // SESSION
+#define NB_CMD_STATUS_QUERY 0x09 // STATUS_QUERY
+#define NB_CMD_STATUS_RESPONSE 0x0a // STATUS_RESPONSE
+#define NB_CMD_DATAGRAM 0x0b // DATAGRAM
+#define NB_CMD_BROADCAST_DATAGRAM 0x0c // BROADCAST_DATAGRAM
+
+#ifdef RSRC_TIMEOUT_DBG
+#define NB_CMD_DEATH_PACKET 0x99 //
+#endif // RSRC_TIMEOUT_DBG
+
+//
+// Bit values in the NameTypeFlag of NB_NAME_FRAME frames.
+//
+
+#define NB_NAME_UNIQUE 0x00
+#define NB_NAME_GROUP 0x80
+#define NB_NAME_USED 0x40
+#define NB_NAME_REGISTERED 0x04
+#define NB_NAME_DUPLICATED 0x02
+#define NB_NAME_DEREGISTERED 0x01
+
+//
+// Bit values in the ConnectionControlFlag.
+//
+
+#define NB_CONTROL_SYSTEM 0x80
+#define NB_CONTROL_SEND_ACK 0x40
+#define NB_CONTROL_ATTENTION 0x20
+#define NB_CONTROL_EOM 0x10
+#define NB_CONTROL_RESEND 0x08
+#define NB_CONTROL_NEW_NB 0x01
+
+
+
+#define NB_DEVICE_SIGNATURE 0x1401
+#if defined(_PNP_POWER)
+#define NB_ADAPTER_ADDRESS_SIGNATURE 0x1403
+#endif _PNP_POWER
+#define NB_ADDRESS_SIGNATURE 0x1404
+#define NB_ADDRESSFILE_SIGNATURE 0x1405
+#define NB_CONNECTION_SIGNATURE 0x1406
+
+
+//
+// Useful in various places.
+//
+#if defined(_PNP_POWER)
+extern IPX_LOCAL_TARGET BroadcastTarget;
+#endif _PNP_POWER
+extern UCHAR BroadcastAddress[6];
+extern UCHAR NetbiosBroadcastName[16];
+
+
+//
+// Contains the default handler for each of the TDI event types
+// that are supported.
+//
+
+extern PVOID TdiDefaultHandlers[6];
+
+
+//
+// Define a structure that can track lock acquire/release.
+//
+
+typedef struct _NB_LOCK {
+ CTELock Lock;
+#if DBG
+ ULONG LockAcquired;
+ UCHAR LastAcquireFile[8];
+ ULONG LastAcquireLine;
+ UCHAR LastReleaseFile[8];
+ ULONG LastReleaseLine;
+#endif
+} NB_LOCK, *PNB_LOCK;
+
+
+
+#if DBG
+
+extern ULONG NbiDebug;
+extern ULONG NbiDebug2;
+extern ULONG NbiMemoryDebug;
+
+#define NB_MEMORY_LOG_SIZE 128
+extern UCHAR NbiDebugMemory[NB_MEMORY_LOG_SIZE][64];
+extern PUCHAR NbiDebugMemoryLoc;
+extern PUCHAR NbiDebugMemoryEnd;
+
+VOID
+NbiDebugMemoryLog(
+ IN PUCHAR FormatString,
+ ...
+);
+
+#define NB_DEBUG(_Flag, _Print) { \
+ if (NbiDebug & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#define NB_DEBUG2(_Flag, _Print) { \
+ if (NbiDebug2 & (NB_DEBUG_ ## _Flag)) { \
+ DbgPrint ("NBI: "); \
+ DbgPrint _Print; \
+ } \
+ if (NbiMemoryDebug & (NB_DEBUG_ ## _Flag)) { \
+ NbiDebugMemoryLog _Print; \
+ } \
+}
+
+#else
+
+#define NB_DEBUG(_Flag, _Print)
+#define NB_DEBUG2(_Flag, _Print)
+
+#endif
+
+
+//
+// These definitions are for abstracting IRPs from the
+// transport for portability.
+//
+
+#if ISN_NT
+
+typedef IRP REQUEST, *PREQUEST;
+typedef struct _REQUEST_LIST_HEAD {
+ PREQUEST Head; // list is empty if this is NULL
+ PREQUEST Tail; // undefined if the list is empty.
+} REQUEST_LIST_HEAD, *PREQUEST_LIST_HEAD;
+
+
+//
+// PREQUEST
+// NbiAllocateRequest(
+// IN PDEVICE Device,
+// IN PIRP Irp
+// );
+//
+// Allocates a request for the system-specific request structure.
+//
+
+#define NbiAllocateRequest(_Device,_Irp) \
+ (_Irp)
+
+
+//
+// BOOLEAN
+// IF_NOT_ALLOCATED(
+// IN PREQUEST Request
+// );
+//
+// Checks if a request was not successfully allocated.
+//
+
+#define IF_NOT_ALLOCATED(_Request) \
+ if (0)
+
+
+//
+// VOID
+// NbiFreeRequest(
+// IN PDEVICE Device,
+// IN PREQUEST Request
+// );
+//
+// Frees a previously allocated request.
+//
+
+#define NbiFreeRequest(_Device,_Request) \
+ ;
+
+
+//
+// VOID
+// MARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will pend.
+//
+
+#define MARK_REQUEST_PENDING(_Request) \
+ IoMarkIrpPending(_Request)
+
+
+//
+// VOID
+// UNMARK_REQUEST_PENDING(
+// IN PREQUEST Request
+// );
+//
+// Marks that a request will not pend.
+//
+
+#define UNMARK_REQUEST_PENDING(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->Control) &= ~SL_PENDING_RETURNED)
+
+
+//
+// UCHAR
+// REQUEST_MAJOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the major function code of a request.
+//
+
+#define REQUEST_MAJOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MajorFunction)
+
+
+//
+// UCHAR
+// REQUEST_MINOR_FUNCTION
+// IN PREQUEST Request
+// );
+//
+// Returns the minor function code of a request.
+//
+
+#define REQUEST_MINOR_FUNCTION(_Request) \
+ ((IoGetCurrentIrpStackLocation(_Request))->MinorFunction)
+
+
+//
+// PNDIS_BUFFER
+// REQUEST_NDIS_BUFFER
+// IN PREQUEST Request
+// );
+//
+// Returns the NDIS buffer chain associated with a request.
+//
+
+#define REQUEST_NDIS_BUFFER(_Request) \
+ ((PNDIS_BUFFER)((_Request)->MdlAddress))
+
+
+//
+// PVOID
+// REQUEST_OPEN_CONTEXT(
+// IN PREQUEST Request
+// );
+//
+// Gets the context associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_CONTEXT(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext)
+
+
+//
+// PVOID
+// REQUEST_OPEN_TYPE(
+// IN PREQUEST Request
+// );
+//
+// Gets the type associated with an opened address/connection/control channel.
+//
+
+#define REQUEST_OPEN_TYPE(_Request) \
+ (((IoGetCurrentIrpStackLocation(_Request))->FileObject)->FsContext2)
+
+
+//
+// PFILE_FULL_EA_INFORMATION
+// OPEN_REQUEST_EA_INFORMATION(
+// IN PREQUEST Request
+// );
+//
+// Returns the EA information associated with an open/close request.
+//
+
+#define OPEN_REQUEST_EA_INFORMATION(_Request) \
+ ((PFILE_FULL_EA_INFORMATION)((_Request)->AssociatedIrp.SystemBuffer))
+
+
+//
+// PTDI_REQUEST_KERNEL
+// REQUEST_PARAMETERS(
+// IN PREQUEST Request
+// );
+//
+// Obtains a pointer to the parameters of a request.
+//
+
+#define REQUEST_PARAMETERS(_Request) \
+ (&((IoGetCurrentIrpStackLocation(_Request))->Parameters))
+
+
+//
+// PLIST_ENTRY
+// REQUEST_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Returns a pointer to a linkage field in the request.
+//
+
+#define REQUEST_LINKAGE(_Request) \
+ (&((_Request)->Tail.Overlay.ListEntry))
+
+
+//
+// PREQUEST
+// REQUEST_SINGLE_LINKAGE(
+// IN PREQUEST Request
+// );
+//
+// Used to access a single list linkage field in the request.
+//
+
+#define REQUEST_SINGLE_LINKAGE(_Request) \
+ (*((PREQUEST *)&((_Request)->Tail.Overlay.ListEntry.Flink)))
+
+
+//
+// ULONG
+// REQUEST_REFCOUNT(
+// IN PREQUEST Request
+// );
+//
+// Used to access a field in the request which can be used for
+// the reference count, as long as it is on a REQUEST_LIST.
+//
+
+#define REQUEST_REFCOUNT(_Request) \
+ (*((PULONG)&((_Request)->Tail.Overlay.ListEntry.Blink)))
+
+
+//
+// VOID
+// REQUEST_LIST_INSERT_TAIL(
+// IN PREQUEST_LIST_HEAD Head,
+// IN PREQUEST Entry
+// );
+//
+// Inserts a request into a single list linkage queue.
+//
+
+#define REQUEST_LIST_INSERT_TAIL(_Head,_Entry) { \
+ if ((_Head)->Head == NULL) { \
+ (_Head)->Head = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } else { \
+ REQUEST_SINGLE_LINKAGE((_Head)->Tail) = (_Entry); \
+ (_Head)->Tail = (_Entry); \
+ } \
+}
+
+
+//
+// PREQUEST
+// LIST_ENTRY_TO_REQUEST(
+// IN PLIST_ENTRY ListEntry
+// );
+//
+// Returns a request given a linkage field in it.
+//
+
+#define LIST_ENTRY_TO_REQUEST(_ListEntry) \
+ ((PREQUEST)(CONTAINING_RECORD(_ListEntry, REQUEST, Tail.Overlay.ListEntry)))
+
+
+//
+// NTSTATUS
+// REQUEST_STATUS(
+// IN PREQUEST Request
+// );
+//
+// Used to access the status field of a request.
+//
+
+#define REQUEST_STATUS(_Request) \
+ (_Request)->IoStatus.Status
+
+
+//
+// ULONG
+// REQUEST_INFORMATION(
+// IN PREQUEST Request)
+// );
+//
+// Used to access the information field of a request.
+//
+
+#define REQUEST_INFORMATION(_Request) \
+ (_Request)->IoStatus.Information
+
+
+//
+// VOID
+// NbiCompleteRequest(
+// IN PREQUEST Request
+// );
+//
+// Completes a request whose status and information fields have
+// been filled in.
+//
+
+#define NbiCompleteRequest(_Request) \
+ IoCompleteRequest (_Request, IO_NETWORK_INCREMENT)
+
+#else
+
+//
+// These routines must be defined for portability to a VxD.
+//
+
+#endif
+
+//
+// some utility macros.
+
+// Minimum of two
+//
+#define NB_MIN( _a , _b ) ( ( (_a) < (_b) ) ? (_a) : (_b) )
+
+//
+// Swap the _s1 and _s2 of Type _T
+//
+
+#define NB_SWAP(_s1, _s2, _T) { \
+ _T _temp; \
+ _temp = (_s1); \
+ (_s1) = (_s2); \
+ (_s2) = _temp; \
+}
+
+#define NB_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+//
+// Define our own spinlock routines.
+//
+
+#if DBG
+
+#define NB_GET_LOCK(_Lock, _LockHandle) { \
+ CTEGetLock(&(_Lock)->Lock, _LockHandle); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK(_Lock, _LockHandle) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ CTEFreeLock(&(_Lock)->Lock, _LockHandle); \
+}
+
+#define NB_GET_LOCK_DPC(_Lock) { \
+ ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock); \
+ (_Lock)->LockAcquired = TRUE; \
+ strncpy((_Lock)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastAcquireLine = __LINE__; \
+}
+
+#define NB_FREE_LOCK_DPC(_Lock) { \
+ (_Lock)->LockAcquired = FALSE; \
+ strncpy((_Lock)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \
+ (_Lock)->LastReleaseLine = __LINE__; \
+ ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock); \
+}
+
+#else
+
+#define NB_GET_LOCK(_Lock, _LockHandle) CTEGetLock(&(_Lock)->Lock, _LockHandle)
+#define NB_FREE_LOCK(_Lock, _LockHandle) CTEFreeLock(&(_Lock)->Lock, _LockHandle)
+#define NB_GET_LOCK_DPC(_Lock) ExAcquireSpinLockAtDpcLevel(&(_Lock)->Lock)
+#define NB_FREE_LOCK_DPC(_Lock) ExReleaseSpinLockFromDpcLevel(&(_Lock)->Lock)
+
+#endif
+
+
+#define NB_GET_CANCEL_LOCK( _LockHandle ) IoAcquireCancelSpinLock( _LockHandle )
+
+#define NB_FREE_CANCEL_LOCK( _LockHandle ) IoReleaseCancelSpinLock( _LockHandle )
+
+
+//
+// Routines to optimize for a uni-processor environment.
+//
+
+
+#define NB_INCREMENT(_Long, _Lock) InterlockedIncrement(_Long)
+#define NB_DECREMENT(_Long, _Lock) InterlockedDecrement(_Long)
+
+#define NB_ADD_ULONG(_Pulong, _Ulong, _Lock) ExInterlockedAddUlong(_Pulong, _Ulong, &(_Lock)->Lock)
+
+#define NB_DEFINE_SYNC_CONTEXT(_SyncContext)
+#define NB_BEGIN_SYNC(_SyncContext)
+#define NB_END_SYNC(_SyncContext)
+
+#define NB_DEFINE_LOCK_HANDLE(_LockHandle) CTELockHandle _LockHandle;
+
+//
+// BUGBUG: Make these be NB_XXX_LOCK_DPC calls -- then the definitions
+// of the NB_SYNC_XXX_LOCK calls can be changed to not need _LockHandle
+// and many of the functions won't need that as a parameter.
+//
+
+#define NB_SYNC_GET_LOCK(_Lock, _LockHandle) NB_GET_LOCK(_Lock, _LockHandle)
+#define NB_SYNC_FREE_LOCK(_Lock, _LockHandle) NB_FREE_LOCK(_Lock, _LockHandle)
+
+#define NB_REMOVE_HEAD_LIST(_Queue, _Lock) ExInterlockedRemoveHeadList(_Queue, &(_Lock)->Lock)
+#define NB_LIST_WAS_EMPTY(_Queue, _OldHead) ((_OldHead) == NULL)
+#define NB_INSERT_HEAD_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertHeadList(_Queue, _Entry, &(_Lock)->Lock)
+#define NB_INSERT_TAIL_LIST(_Queue, _Entry, _Lock) ExInterlockedInsertTailList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_POP_ENTRY_LIST(_Queue, _Lock) ExInterlockedPopEntryList(_Queue, &(_Lock)->Lock)
+#define NB_PUSH_ENTRY_LIST(_Queue, _Entry, _Lock) ExInterlockedPushEntryList(_Queue, _Entry, &(_Lock)->Lock)
+
+#define NB_LOCK_HANDLE_PARAM(_LockHandle) , IN CTELockHandle _LockHandle
+#define NB_LOCK_HANDLE_ARG(_LockHandle) , (_LockHandle)
+
+#define NB_SYNC_SWAP_IRQL( _s1, _s2 ) NB_SWAP( _s1, _s2, CTELockHandle )
+
+
+//
+// This macro adds a ULONG to a LARGE_INTEGER (should be
+// called with a spinlock held).
+//
+
+#define ADD_TO_LARGE_INTEGER(_LargeInteger,_Ulong) \
+ ExInterlockedAddLargeStatistic((_LargeInteger),(ULONG)(_Ulong))
+
+#define NB_DEBUG_DEVICE 0x00000001
+#define NB_DEBUG_ADDRESS 0x00000004
+#define NB_DEBUG_SEND 0x00000008
+#define NB_DEBUG_RECEIVE 0x00000020
+#define NB_DEBUG_CONFIG 0x00000040
+#define NB_DEBUG_PACKET 0x00000080
+#define NB_DEBUG_BIND 0x00000200
+#define NB_DEBUG_ADDRESS_FRAME 0x00000400
+#define NB_DEBUG_CONNECTION 0x00000800
+#define NB_DEBUG_QUERY 0x00001000
+#define NB_DEBUG_DRIVER 0x00002000
+#define NB_DEBUG_CACHE 0x00004000
+#define NB_DEBUG_DATAGRAM 0x00008000
+#define NB_DEBUG_TIMER 0x00010000
+#define NB_DEBUG_SEND_WINDOW 0x00020000
+
+
+
+//
+// NB_GET_NBHDR_BUFF - gets the nb header in the packet. It is always the
+// second buffer.
+//
+#define NB_GET_NBHDR_BUFF(Packet) (NDIS_BUFFER_LINKAGE((Packet)->Private.Head))
+
+
diff --git a/private/ntos/tdi/isnp/nb/mp/makefile b/private/ntos/tdi/isnp/nb/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/mp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/mp/sources b/private/ntos/tdi/isnp/nb/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/mp/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+NT_UP=0
+
+TARGETPATH=\nt\public\sdk\lib
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/nb/nbcount/makefile b/private/ntos/tdi/isnp/nb/nbcount/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/nbcount/nbcount.c b/private/ntos/tdi/isnp/nb/nbcount/nbcount.c
new file mode 100644
index 000000000..74a656f16
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/nbcount.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+* (c) Copyright 1990, 1993 Micro Computer Systems, Inc. All rights reserved.
+*****************************************************************************
+*
+* Title: IPX/SPX Compatible Source Routing Daemon for Windows NT
+*
+* Module: ipx/route/ipxroute.c
+*
+* Version: 1.00.00
+*
+* Date: 04-08-93
+*
+* Author: Brian Walker
+*
+*****************************************************************************
+*
+* Change Log:
+*
+* Date DevSFC Comment
+* -------- ------ -------------------------------------------------------
+*****************************************************************************
+*
+* Functional Description:
+*
+*
+****************************************************************************/
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <ntstapi.h>
+#include <sys/stropts.h>
+#include <windows.h>
+#include "errno.h"
+#include "tdi.h"
+#include "isnkrnl.h"
+
+
+typedef struct _NB_ACTION_GET_COUNTS {
+ USHORT MaximumNicId; // returns maximum NIC ID
+ USHORT NicIdCounts[32]; // session counts for first 32 NIC IDs
+} NB_ACTION_GET_COUNTS, *PNB_ACTION_GET_COUNTS;
+
+HANDLE isnnbfd;
+wchar_t isnnbname[] = L"\\Device\\NwlnkNb";
+char pgmname[] = "NBCOUNT";
+
+/** **/
+
+#define INVALID_HANDLE (HANDLE)(-1)
+
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen);
+
+/*page*************************************************************
+ m a i n
+
+ This is the main routine that gets executed when a NET START
+ happens.
+
+ Arguments - None
+
+ Returns - Nothing
+********************************************************************/
+void _CRTAPI1 main(int argc, char **argv)
+{
+ UNICODE_STRING FileString;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ NTSTATUS Status;
+ NB_ACTION_GET_COUNTS GetCounts;
+ int rc;
+ int i;
+
+ /** Open the nwlnknb driver **/
+
+ RtlInitUnicodeString (&FileString, isnnbname);
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(
+ &isnnbfd,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+ isnnbfd = INVALID_HANDLE;
+ printf("Could not open transport\n");
+ }
+
+ if (isnnbfd == INVALID_HANDLE) {
+ exit(1);
+ }
+
+ rc = do_isnnbioctl(isnnbfd, (I_MIPX | 351), (char *)&GetCounts, sizeof(NB_ACTION_GET_COUNTS));
+ if (rc == 0) {
+
+ printf("NB NIC count: %d\n", GetCounts.MaximumNicId);
+ for (i = 1; i <= GetCounts.MaximumNicId; i++) {
+ printf("NIC %d: %d sessions\n", i, GetCounts.NicIdCounts[i]);
+ }
+ }
+}
+
+
+/*page***************************************************************
+ d o _ i s n i p x i o c t l
+
+ Do the equivalent of a stream ioctl to isnnb
+
+ Arguments - fd = Handle to put on
+ cmd = Command to send
+ datap = Ptr to ctrl buffer
+ dlen = Ptr to len of data buffer
+
+ Returns - 0 = OK
+ else = Error
+********************************************************************/
+int do_isnnbioctl(HANDLE fd, int cmd, char *datap, int dlen)
+{
+ NTSTATUS Status;
+ UCHAR buffer[300];
+ PNWLINK_ACTION action;
+ IO_STATUS_BLOCK IoStatusBlock;
+ int rc;
+
+ /** Fill out the structure **/
+
+ action = (PNWLINK_ACTION)buffer;
+
+ action->Header.TransportId = ISN_ACTION_TRANSPORT_ID;
+ action->OptionType = NWLINK_OPTION_CONTROL;
+ action->BufferLength = sizeof(ULONG) + dlen;
+ action->Option = cmd;
+ RtlMoveMemory(action->Data, datap, dlen);
+
+ /** Issue the ioctl **/
+
+ Status = NtDeviceIoControlFile(
+ fd,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ IOCTL_TDI_ACTION,
+ NULL,
+ 0,
+ action,
+ FIELD_OFFSET(NWLINK_ACTION,Data) + dlen);
+
+ if (Status != STATUS_SUCCESS) {
+ if (Status == STATUS_INVALID_PARAMETER) {
+ rc = ERANGE;
+ } else {
+ rc = EINVAL;
+ }
+ } else {
+ if (dlen > 0) {
+ RtlMoveMemory (datap, action->Data, dlen);
+ }
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
diff --git a/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc b/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc
new file mode 100644
index 000000000..ada219b24
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/nbcount.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NWLink Netbios Session Count Application"
+#define VER_INTERNALNAME_STR "nbcount.exe"
+#define VER_ORIGINALFILENAME_STR "nbcount.exe"
+
+#include "common.ver"
diff --git a/private/ntos/tdi/isnp/nb/nbcount/sources b/private/ntos/tdi/isnp/nb/nbcount/sources
new file mode 100644
index 000000000..f9dfe3561
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbcount/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1993 Micro Computer Systems, Inc.
+
+!ENDIF
+
+MAJORCOMP=nwlink
+MINORCOMP=nbcount
+
+TARGETNAME=nbcount
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=UMAPPL_NOLIB
+
+USE_CRTDLL=1
+
+C_DEFINES=$(C_DEFINES)
+
+!IF 0
+INCLUDES=..\h;..\..\..\..\..\inc;..\..\..\..\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\h;$(BASEDIR)\private\inc;$(BASEDIR)\private\ntos\inc;$(BASEDIR)\private\ntos\streams\inc
+!ENDIF
+
+SOURCES= nbcount.c nbcount.rc
+
+UMTYPE=console
+UMAPPL=$(TARGETNAME)
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+
diff --git a/private/ntos/tdi/isnp/nb/nbiprocs.h b/private/ntos/tdi/isnp/nb/nbiprocs.h
new file mode 100644
index 000000000..dff399019
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbiprocs.h
@@ -0,0 +1,1530 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbiprocs.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// MACROS.
+//
+//
+// Debugging aids
+//
+
+//
+// VOID
+// PANIC(
+// IN PSZ Message
+// );
+//
+
+#if DBG
+#define PANIC(Msg) \
+ CTEPrint ((Msg))
+#else
+#define PANIC(Msg)
+#endif
+
+
+//
+// These are define to allow CTEPrints that disappear when
+// DBG is 0.
+//
+
+#if DBG
+#define NbiPrint0(fmt) DbgPrint(fmt)
+#define NbiPrint1(fmt,v0) DbgPrint(fmt,v0)
+#define NbiPrint2(fmt,v0,v1) DbgPrint(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2) DbgPrint(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3) DbgPrint(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4) DbgPrint(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5) DbgPrint(fmt,v0,v1,v2,v3,v4,v5)
+#else
+#define NbiPrint0(fmt)
+#define NbiPrint1(fmt,v0)
+#define NbiPrint2(fmt,v0,v1)
+#define NbiPrint3(fmt,v0,v1,v2)
+#define NbiPrint4(fmt,v0,v1,v2,v3)
+#define NbiPrint5(fmt,v0,v1,v2,v3,v4)
+#define NbiPrint6(fmt,v0,v1,v2,v3,v4,v5)
+#endif
+
+
+//
+// Routines to log packets to a buffer.
+//
+
+#if DBG
+#define NB_PACKET_LOG 1
+#endif
+
+#ifdef NB_PACKET_LOG
+
+//
+// The size of this is 64 bytes for easy display.
+//
+
+typedef struct _NB_PACKET_LOG_ENTRY {
+ UCHAR SendReceive;
+ UCHAR TimeStamp[5]; // low 5 digits of tick count.
+ UCHAR DestMac[6];
+ UCHAR SrcMac[6];
+ UCHAR Length[2];
+ IPX_HEADER NbiHeader;
+ UCHAR Data[14];
+} NB_PACKET_LOG_ENTRY, *PNB_PACKET_LOG_ENTRY;
+
+#define NB_PACKET_LOG_LENGTH 128
+extern ULONG NbiPacketLogDebug;
+extern USHORT NbiPacketLogSocket;
+EXTERNAL_LOCK(NbiPacketLogLock);
+extern NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogLoc;
+extern PNB_PACKET_LOG_ENTRY NbiPacketLogEnd;
+
+//
+// Bit fields in NbiPacketLogDebug
+//
+
+#define NB_PACKET_LOG_RCV_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_RCV_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_RCV_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_RCV_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_RCV_SOCKET 0x0010 // All packets to NbiPacketLogSocket
+#define NB_PACKET_LOG_RCV_ALL 0x0020 // All packets (even non-NB)
+
+#define NB_PACKET_LOG_SEND_RIP 0x0001 // All RIP packets
+#define NB_PACKET_LOG_SEND_SPX 0x0002 // All SPX packets
+#define NB_PACKET_LOG_SEND_NB 0x0004 // All Netbios packets
+#define NB_PACKET_LOG_SEND_OTHER 0x0008 // All TDI client packets
+#define NB_PACKET_LOG_SEND_SOCKET 0x0010 // All packets from NbiPacketLogSocket
+
+VOID
+NbiLogPacket(
+ IN BOOLEAN Send,
+ IN PUCHAR DestMac,
+ IN PUCHAR SrcMac,
+ IN USHORT Length,
+ IN PVOID NbiHeader,
+ IN PVOID Data
+ );
+
+#define PACKET_LOG(_Bit) (NbiPacketLogDebug & (_Bit))
+
+#else // NB_PACKET_LOG
+
+#define NbiLogPacket(_MacHeader,_Length,_NbiHeader,_Data)
+#define PACKET_LOG(_Bit) 0
+
+#endif // NB_PACKET_LOG
+
+
+#if DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefDevice (_Device)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Device)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefDevice (_Device)
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddress (_Address)
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressLock (_Address)
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Address)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFile (_AddressFile)
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefAddressFileLock (_AddressFile)
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefAddressFile (_AddressFile)
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_AddressFile)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+
+#define NbiReferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnection (_Connection)
+
+#define NbiReferenceConnectionLock(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionLock (_Connection)
+
+#define NbiReferenceConnectionSync(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ 1, \
+ &NbiGlobalInterlock); \
+ NbiRefConnectionSync (_Connection)
+
+#define NbiDereferenceConnection(_Connection, _Type) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_Type], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock); \
+ NbiDerefConnection (_Connection)
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType) \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_NewType], \
+ 1, \
+ &NbiGlobalInterlock); \
+ (VOID)ExInterlockedAddUlong ( \
+ &(_Connection)->RefTypes[_OldType], \
+ (ULONG)-1, \
+ &NbiGlobalInterlock);
+
+#else // DBG
+
+#define NbiReferenceDevice(_Device, _Type) \
+ InterlockedIncrement(&(_Device)->ReferenceCount)
+
+#define NbiDereferenceDevice(_Device, _Type) \
+ NbiDerefDevice (_Device)
+
+
+
+#define NbiReferenceAddress(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiReferenceAddressLock(_Address, _Type) \
+ InterlockedIncrement( &(_Address)->ReferenceCount )
+
+#define NbiDereferenceAddress(_Address, _Type) \
+ NbiDerefAddress (_Address)
+
+
+#define NbiReferenceAddressFile(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiReferenceAddressFileLock(_AddressFile, _Type) \
+ InterlockedIncrement( &(_AddressFile)->ReferenceCount )
+
+#define NbiDereferenceAddressFile(_AddressFile, _Type) \
+ if ( !InterlockedDecrement(&(_AddressFile)->ReferenceCount )) { \
+ NbiDestroyAddressFile (_AddressFile); \
+ }
+
+#define NbiTransferReferenceAddressFile(_AddressFile, _OldType, _NewType)
+
+
+#define NbiReferenceConnection(_Connection, _Type) { \
+ (VOID)ExInterlockedAddUlong( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ &(_Connection)->DeviceLock->Lock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionLock(_Connection, _Type) { \
+ ++(_Connection)->ReferenceCount; \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiReferenceConnectionSync(_Connection, _Type) { \
+ (VOID)NB_ADD_ULONG( \
+ &(_Connection)->ReferenceCount, \
+ 1, \
+ (_Connection)->DeviceLock); \
+ (_Connection)->CanBeDestroyed = FALSE; \
+}
+
+#define NbiDereferenceConnection(_Connection, _Type) { \
+ CTELockHandle _LockHandle; \
+ NB_GET_LOCK( (_Connection)->DeviceLock, &_LockHandle ); \
+ if ( !(--(_Connection)->ReferenceCount) ) { \
+ (_Connection)->ThreadsInHandleConnectionZero++; \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ NbiHandleConnectionZero (_Connection); \
+ } else { \
+ NB_FREE_LOCK( (_Connection)->DeviceLock, _LockHandle ); \
+ } \
+}
+
+
+#define NbiTransferReferenceConnection(_Connection, _OldType, _NewType)
+
+#endif // DBG
+
+
+
+#if DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateTaggedMemory(_BytesNeeded,_Tag,_Description)
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeTaggedMemory(_Memory,_BytesAllocated,_Tag,_Description)
+
+#else // DBG
+
+#define NbiAllocateMemory(_BytesNeeded,_Tag,_Description) \
+ NbipAllocateMemory(_BytesNeeded,_Tag,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+#define NbiFreeMemory(_Memory,_BytesAllocated,_Tag,_Description) \
+ NbipFreeMemory(_Memory,_BytesAllocated,(BOOLEAN)((_Tag) != MEMORY_CONFIG))
+
+
+#endif // DBG
+
+
+//
+// Definition of the callback routine where an NdisTransferData
+// call is not needed.
+//
+
+typedef VOID
+(*NB_CALLBACK_NO_TRANSFER) (
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+
+//
+// This routine compares two node addresses.
+//
+
+#define NB_NODE_EQUAL(_A,_B) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == *(UNALIGNED ULONG *)((PUCHAR)(_B))) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == *(UNALIGNED USHORT *)(((PUCHAR)(_B))+4)))
+
+//
+// This routine checks if an address is the broadcast address.
+//
+
+#define NB_NODE_BROADCAST(_A) \
+ ((*(UNALIGNED ULONG *)((PUCHAR)(_A)) == 0xffffffff) && \
+ (*(UNALIGNED USHORT *)(((PUCHAR)(_A))+4) == 0xffff))
+
+
+//
+// Definition of the routine to handler a particular minor
+// code for an IOCTL_MJ_INTERNAL_DEVICE_CONTROL IRP.
+//
+
+typedef NTSTATUS
+(*NB_TDI_DISPATCH_ROUTINE) (
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+
+//
+// Routines in action.c
+//
+
+NTSTATUS
+NbiTdiAction(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in address.c
+//
+
+TDI_ADDRESS_NETBIOS UNALIGNED *
+NbiParseTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN BOOLEAN BroadcastAddressOk
+ );
+
+BOOLEAN
+NbiValidateTdiAddress(
+ IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
+ IN ULONG TransportAddressLength
+ );
+
+NTSTATUS
+NbiOpenAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStartRegistration(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRegistrationTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiProcessFindName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+PADDRESS
+NbiCreateAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+
+NTSTATUS
+NbiVerifyAddressFile (
+#if defined(_PNP_POWER)
+ IN PADDRESS_FILE AddressFile,
+ IN BOOLEAN ConflictIsOk
+#else
+ IN PADDRESS_FILE AddressFile
+#endif _PNP_POWER
+ );
+
+VOID
+NbiDestroyAddress(
+ IN PVOID Parameter
+ );
+
+#if DBG
+
+VOID
+NbiRefAddress(
+ IN PADDRESS Address
+ );
+
+VOID
+NbiRefAddressLock(
+ IN PADDRESS Address
+ );
+
+#endif
+
+VOID
+NbiDerefAddress(
+ IN PADDRESS Address
+ );
+
+PADDRESS_FILE
+NbiCreateAddressFile(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiDestroyAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if DBG
+
+VOID
+NbiRefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+VOID
+NbiRefAddressFileLock(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#endif
+
+VOID
+NbiDerefAddressFile(
+ IN PADDRESS_FILE AddressFile
+ );
+
+#if !defined(_PNP_POWER)
+PADDRESS
+NbiLookupAddress(
+ IN PDEVICE Device,
+ IN TDI_ADDRESS_NETBIOS UNALIGNED * NetbiosAddress
+ );
+#endif !_PNP_POWER
+
+PADDRESS
+NbiFindAddress(
+ IN PDEVICE Device,
+ IN PUCHAR NetbiosName
+ );
+
+NTSTATUS
+NbiStopAddressFile(
+ IN PADDRESS_FILE AddressFile,
+ IN PADDRESS Address
+ );
+
+NTSTATUS
+NbiCloseAddressFile(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+#if defined(_PNP_POWER)
+PADAPTER_ADDRESS
+NbiCreateAdapterAddress(
+ IN PCHAR AdapterMacAddress
+ );
+
+NTSTATUS
+NbiDestroyAdapterAddress(
+ IN PADAPTER_ADDRESS AdapterAddress OPTIONAL,
+ IN PCHAR AdapterMacAddress OPTIONAL
+ );
+
+PADAPTER_ADDRESS
+NbiFindAdapterAddress(
+ IN PCHAR NetbiosName,
+ IN BOOLEAN LockHeld
+ );
+#endif _PNP_POWER
+
+
+//
+// Routines in bind.c
+//
+
+NTSTATUS
+NbiBind(
+ IN PDEVICE Device,
+ IN PCONFIG Config
+ );
+
+VOID
+NbiUnbind(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiStatus(
+ IN USHORT NicId,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferLength
+ );
+
+VOID
+NbiLineUp(
+ IN USHORT NicId,
+ IN PIPX_LINE_INFO LineInfo,
+ IN NDIS_MEDIUM DeviceType,
+ IN PVOID ConfigurationData
+ );
+
+VOID
+NbiLineDown(
+ IN USHORT NicId
+ );
+
+
+//
+// Routines in cache.c
+//
+
+NTSTATUS
+CacheFindName(
+ IN PDEVICE Device,
+ IN FIND_NAME_TYPE Type,
+ IN PUCHAR RemoteName OPTIONAL,
+ OUT PNETBIOS_CACHE * CacheName
+);
+
+VOID
+FindNameTimeout(
+ CTEEvent * Event,
+ PVOID Context
+ );
+
+VOID
+CacheHandlePending(
+ IN PDEVICE Device,
+ IN PUCHAR RemoteName,
+ IN NETBIOS_NAME_RESULT Result,
+ IN PNETBIOS_CACHE CacheName OPTIONAL
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessNameRecognized(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+PNETBIOS_CACHE
+CacheUpdateNameCache(
+ IN PNETBIOS_CACHE NameCache,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN TDI_ADDRESS_IPX UNALIGNED * SourceAddress,
+ IN BOOLEAN ModifyQueue
+ );
+
+VOID
+CacheUpdateFromAddName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN NB_CONNECTIONLESS UNALIGNED * Connectionless,
+ IN BOOLEAN LocalFrame
+ );
+
+VOID
+NbiProcessDeleteName(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+InsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+ReinsertInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE OldEntry,
+ IN PNETBIOS_CACHE NewEntry
+ );
+
+VOID
+RemoveFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PNETBIOS_CACHE CacheEntry
+ );
+
+VOID
+FlushOldFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN USHORT AgeLimit
+ );
+
+VOID
+FlushFailedNetbiosCacheEntries(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+VOID
+RemoveInvalidRoutesFromNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN NIC_HANDLE UNALIGNED *InvalidNicHandle
+ );
+
+NTSTATUS
+FindInNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable,
+ IN PUCHAR NameToBeFound,
+ OUT PNETBIOS_CACHE *CacheEntry
+ );
+
+NTSTATUS
+CreateNetbiosCacheTable(
+ IN OUT PNETBIOS_CACHE_TABLE *NewTable,
+ IN USHORT MaxHashIndex
+ );
+
+VOID
+DestroyNetbiosCacheTable(
+ IN PNETBIOS_CACHE_TABLE CacheTable
+ );
+
+//
+// Routines in connect.c
+//
+
+VOID
+NbiFindRouteComplete(
+ IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
+ IN BOOLEAN FoundRoute
+ );
+
+NTSTATUS
+NbiOpenConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiStopConnection(
+ IN PCONNECTION Connection,
+ IN NTSTATUS DisconnectStatus
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiCloseConnection(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAssociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiDisassociateAddress(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiListen(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiAccept(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiConnectFindName(
+ IN PDEVICE Device,
+ IN PREQUEST Request,
+ IN PCONNECTION Connection,
+ IN CTELockHandle CancelLH,
+ IN CTELockHandle ConnectionLH,
+ IN CTELockHandle DeviceLH,
+ IN PBOOLEAN pbLockFreed
+ );
+
+NTSTATUS
+NbiTdiDisconnect(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+BOOLEAN
+NbiAssignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDeassignConnectionId(
+ IN PDEVICE Device,
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiConnectionTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiCancelListen(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectFindName(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelConnectWaitResponse(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+NbiCancelDisconnectWait(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+PCONNECTION
+NbiLookupConnectionByContext(
+ IN PADDRESS_FILE AddressFile,
+ IN CONNECTION_CONTEXT ConnectionContext
+ );
+
+PCONNECTION
+NbiCreateConnection(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiVerifyConnection (
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDestroyConnection(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+VOID
+NbiRefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionLock(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiRefConnectionSync(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiDerefConnectionSync(
+ IN PCONNECTION Connection
+ );
+#endif
+
+VOID
+NbiHandleConnectionZero(
+ IN PCONNECTION Connection
+ );
+
+
+//
+// Routines in datagram.c
+//
+
+VOID
+NbiProcessDatagram(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize,
+ IN BOOLEAN Broadcast
+ );
+
+VOID
+NbiIndicateDatagram(
+ IN PADDRESS Address,
+ IN PUCHAR RemoteName,
+ IN PUCHAR Data,
+ IN ULONG DataLength
+ );
+
+NTSTATUS
+NbiTdiSendDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiTransmitDatagram(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+NTSTATUS
+NbiTdiReceiveDatagram(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceiveDatagram(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in device.c
+//
+
+VOID
+NbiRefDevice(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiDerefDevice(
+ IN PDEVICE Device
+ );
+
+NTSTATUS
+NbiCreateDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING DeviceName,
+ IN OUT PDEVICE *DevicePtr
+ );
+
+VOID
+NbiDestroyDevice(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in driver.c
+//
+
+PVOID
+NbipAllocateMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN BOOLEAN ChargeDevice
+ );
+
+VOID
+NbipFreeMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN BOOLEAN ChargeDevice
+ );
+
+#if DBG
+
+PVOID
+NbipAllocateTaggedMemory(
+ IN ULONG BytesNeeded,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+VOID
+NbipFreeTaggedMemory(
+ IN PVOID Memory,
+ IN ULONG BytesAllocated,
+ IN ULONG Tag,
+ IN PUCHAR Description
+ );
+
+#endif
+
+VOID
+NbiWriteResourceErrorLog(
+ IN PDEVICE Device,
+ IN ULONG BytesNeeded,
+ IN ULONG UniqueErrorValue
+ );
+
+VOID
+NbiWriteGeneralErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN ULONG UniqueErrorValue,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR SecondString,
+ IN ULONG DumpDataCount,
+ IN ULONG DumpData[]
+ );
+
+VOID
+NbiWriteOidErrorLog(
+ IN PDEVICE Device,
+ IN NTSTATUS ErrorCode,
+ IN NTSTATUS FinalStatus,
+ IN PWSTR AdapterString,
+ IN ULONG OidValue
+ );
+
+
+//
+// Routines in event.c
+//
+
+NTSTATUS
+NbiTdiSetEventHandler(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+
+//
+// Routines in frame.c
+//
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+#if defined(_PNP_POWER)
+ IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
+#else
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress OPTIONAL
+#endif _PNP_POWER
+ );
+
+VOID
+NbiSendSessionInitialize(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionInitAck(
+ IN PCONNECTION Connection,
+ IN PUCHAR ExtraData,
+ IN ULONG ExtraDataLength,
+ IN CTELockHandle * LockHandle OPTIONAL
+ );
+
+VOID
+NbiSendDataAck(
+ IN PCONNECTION Connection,
+ IN NB_ACK_TYPE AckType
+ IN NB_LOCK_HANDLE_PARAM (LockHandle)
+ );
+
+VOID
+NbiSendSessionEnd(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiSendSessionEndAck(
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
+ IN PIPX_LOCAL_TARGET LocalTarget,
+ IN NB_SESSION UNALIGNED * SessionEnd
+ );
+
+
+//
+// Routines in packet.c
+//
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ );
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ );
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ );
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ );
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ );
+
+#if defined(_PNP_POWER)
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ );
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ );
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ );
+#else
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ );
+#endif _PNP_POWER
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ );
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ );
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ );
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ );
+
+
+//
+// Routines in query.c
+//
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ );
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ );
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ );
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ );
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in receive.c
+//
+
+
+VOID
+NbiReceive(
+ 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
+NbiReceiveComplete(
+ IN USHORT NicId
+ );
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ );
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+//
+// Routines in send.c
+//
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ );
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ );
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ );
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ );
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ );
+
+
+//
+// Routines in session.c
+//
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ );
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ );
+
+
+//
+// Routines in timer.c
+//
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ );
+
+#else
+
+#define NbiStopRetransmit(_Connection) \
+ (_Connection)->Retransmit = 0;
+
+#define NbiStopWatchdog(_Connection) \
+ (_Connection)->Watchdog = 0;
+
+#endif
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ );
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ );
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ );
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ );
+
diff --git a/private/ntos/tdi/isnp/nb/nbitypes.h b/private/ntos/tdi/isnp/nb/nbitypes.h
new file mode 100644
index 000000000..604df5fb5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nbitypes.h
@@ -0,0 +1,1511 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ nbitypes.h
+
+Abstract:
+
+ This module contains definitions specific to the
+ Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 16-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+//
+// For find name requests, defines the current status (SR_FN.Status).
+//
+
+typedef enum {
+ FNStatusNoResponse, // no response has been received
+ FNStatusResponseUnique, // response received, is a unique name
+ FNStatusResponseGroup // response received, is a group name
+};
+
+//
+// Defines the results we can get from sending a series of find
+// names to locate a netbios name.
+//
+
+typedef enum _NETBIOS_NAME_RESULT {
+ NetbiosNameFound, // name was located
+ NetbiosNameNotFoundNormal, // name not found, no response received
+ NetbiosNameNotFoundWanDown // name not found, all lines were down
+} NETBIOS_NAME_RESULT, *PNETBIOS_NAME_RESULT;
+
+
+//
+// Definition of the protocol reserved field of a send packet.
+//
+
+typedef struct _NB_SEND_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN SendInProgress; // used in an NdisSend
+ UCHAR Type; // what to do on completion
+ BOOLEAN OwnedByConnection; // if this is a connection's one packet
+#if defined(_PNP_POWER)
+ PVOID Reserved[SEND_RESERVED_COMMON_SIZE]; // used by ipx for even-padding and local target etc.
+#else
+ PVOID Reserved[2]; // used by ipx for even-padding
+#endif _PNP_POWER
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+ LIST_ENTRY WaitLinkage; // when waiting on other queues
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+ union {
+ struct {
+ UCHAR NetbiosName[16]; // name being searched for
+ UCHAR StatusAndSentOnUpLine; // low nibble: look at FNStatusXXX enum
+ // high nibble: TRUE if while sending, found lan or up wan line
+ UCHAR RetryCount; // number of times sent
+ USHORT SendTime; // based on Device->FindNameTime
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // current nic id it is being sent on
+ USHORT MaximumNicId; // highest one it will be sent on
+#endif !_PNP_POWER
+ struct _NETBIOS_CACHE * NewCache; // new cache entry for group names
+ } SR_FN;
+ struct {
+ struct _ADDRESS * Address; // that owns this packet, if one does
+ PREQUEST Request; // send datagram request
+ struct _ADDRESS_FILE * AddressFile; // that this send is on
+#if !defined(_PNP_POWER)
+ USHORT CurrentNicId; // non-zero for frames that go to all
+#endif !_PNP_POWER
+ UCHAR NameTypeFlag; // save these two values for frames
+ UCHAR DataStreamType; // that need to be sent to all nic id's
+ } SR_NF;
+ struct {
+ PREQUEST DatagramRequest; // holds the passed-in request
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteName; // will be -1 for broadcast
+ struct _ADDRESS_FILE * AddressFile; // that the datagram was sent on
+ struct _NETBIOS_CACHE * Cache; // how to route to the netbios address
+ ULONG CurrentNetwork; // within the cache entry
+ } SR_DG;
+ struct {
+ struct _CONNECTION * Connection; // that this frame was sent on.
+ PREQUEST Request; // that this frame was sent for.
+ ULONG PacketLength; // total packet length.
+ BOOLEAN NoNdisBuffer; // none allocate for send
+ } SR_CO;
+ struct {
+ ULONG ActualBufferLength; // real length of allocated buffer.
+ } SR_AS;
+ } u;
+ PUCHAR Header; // points to the MAC/IPX/NB header
+ PNDIS_BUFFER HeaderBuffer; // the NDIS_BUFFER describing Header
+} NB_SEND_RESERVED, *PNB_SEND_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define SEND_TYPE_NAME_FRAME 1
+#define SEND_TYPE_SESSION_INIT 2
+#define SEND_TYPE_FIND_NAME 3
+#define SEND_TYPE_DATAGRAM 4
+#define SEND_TYPE_SESSION_NO_DATA 5
+#define SEND_TYPE_SESSION_DATA 6
+#define SEND_TYPE_STATUS_QUERY 7
+#define SEND_TYPE_STATUS_RESPONSE 8
+
+#ifdef RSRC_TIMEOUT_DBG
+#define SEND_TYPE_DEATH_PACKET 9
+#endif //RSRC_TIMEOUT_DBG
+
+//
+// Macros to access StatusAndSentOnUpLine.
+//
+
+#define NB_GET_SR_FN_STATUS(_Reserved) \
+ ((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f)
+
+#define NB_SET_SR_FN_STATUS(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) | (_Value));
+
+#define NB_GET_SR_FN_SENT_ON_UP_LINE(_Reserved) \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0xf0) != 0)
+
+#define NB_SET_SR_FN_SENT_ON_UP_LINE(_Reserved,_Value) \
+ (_Reserved)->u.SR_FN.StatusAndSentOnUpLine = \
+ (((_Reserved)->u.SR_FN.StatusAndSentOnUpLine & 0x0f) | ((_Value) << 4));
+
+
+//
+// Definition of the protocol reserved field of a receive packet.
+//
+
+typedef struct _NB_RECEIVE_RESERVED {
+ UCHAR Identifier; // 0 for NB packets
+ BOOLEAN TransferInProgress; // used in an NdisTransferData
+ UCHAR Type; // what to do on completion
+#if defined(_PNP_POWER)
+ PVOID Pool; // send pool it was allocated from
+#else
+
+#ifdef IPX_TRACK_POOL
+ PVOID Pool; // send pool it was allocated from
+#endif
+
+#endif _PNP_POWER
+ union {
+ struct {
+ struct _CONNECTION * Connection; // that the transfer is for
+ BOOLEAN EndOfMessage; // this was the last part of a message
+ BOOLEAN CompleteReceive; // receive should be completed
+ BOOLEAN NoNdisBuffer; // user's mdl chain was used
+ BOOLEAN PartialReceive; // (new nb) don't ack this packet
+ } RR_CO;
+ struct {
+ struct _NB_RECEIVE_BUFFER * ReceiveBuffer; // datagram receive buffer
+ } RR_DG;
+ struct {
+ PREQUEST Request; // for this request
+ } RR_AS;
+ } u;
+ LIST_ENTRY GlobalLinkage; // all packets are on this
+ SINGLE_LIST_ENTRY PoolLinkage; // when on free queue
+} NB_RECEIVE_RESERVED, *PNB_RECEIVE_RESERVED;
+
+//
+// Values for Type.
+//
+
+#define RECEIVE_TYPE_DATAGRAM 1
+#define RECEIVE_TYPE_DATA 2
+#define RECEIVE_TYPE_ADAPTER_STATUS 3
+
+
+
+typedef struct _NB_RECEIVE_BUFFER {
+ LIST_ENTRY GlobalLinkage; // all buffers are on this
+#if defined(_PNP_POWER)
+ PVOID Pool; // receive buffer pool was allocated from
+#else
+#ifdef NB_TRACK_POOL
+ PVOID Pool; // receive buffer pool was allocated from
+#endif
+#endif _PNP_POWER
+ struct _ADDRESS * Address; // that the datagram is for
+ SINGLE_LIST_ENTRY PoolLinkage; // when in free pool
+ LIST_ENTRY WaitLinkage; // when in ReceiveDatagrams queue
+ PNDIS_BUFFER NdisBuffer; // describes the data
+ UCHAR RemoteName[16]; // datagram was received from
+ ULONG DataLength; // length for current one, not allocated
+ PUCHAR Data; // points to data to hold packet
+} NB_RECEIVE_BUFFER, *PNB_RECEIVE_BUFFER;
+
+
+//
+// Types to abstract NDIS packets. This is to allow us to
+// switch from using our own memory for packets to using
+// authentically allocated NDIS packets.
+//
+
+//#define NB_OWN_PACKETS 1
+
+#ifdef NB_OWN_PACKETS
+
+#define NDIS_PACKET_SIZE 48
+// #define NDIS_PACKET_SIZE FIELD_OFFSET(NDIS_PACKET,ProtocolReserved[0])
+
+typedef struct _NB_SEND_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_SEND_RESERVED)];
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ UCHAR Data[NDIS_PACKET_SIZE+sizeof(NB_RECEIVE_RESERVED)];
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_SEND_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((PNDIS_PACKET)((_Packet)->Data))
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_SendPacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiAllocateReceivePacket(_Device,_PoolHandle, _ReceivePacket,_Status) { \
+ NdisReinitializePacket((PNDIS_PACKET)((_ReceivePacket)->Data)); \
+ *(_Status) = STATUS_SUCCESS; \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet)
+
+#define NbiFreeReceivePacket(_Device,_Packet)
+
+
+#else // NB_OWN_PACKETS
+
+typedef struct _NB_SEND_PACKET {
+ PNDIS_PACKET Packet;
+} NB_SEND_PACKET, *PNB_SEND_PACKET;
+
+typedef struct _NB_RECEIVE_PACKET {
+ PNDIS_PACKET Packet;
+} NB_RECEIVE_PACKET, *PNB_RECEIVE_PACKET;
+
+typedef struct _NB_PACKET_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_SEND_PACKET Packets[1];
+ // after the packets the header buffers are allocated also.
+} NB_SEND_POOL, *PNB_SEND_POOL;
+
+typedef struct _NB_RECEIVE_POOL {
+ LIST_ENTRY Linkage;
+ UINT PacketCount;
+ UINT PacketFree;
+ NDIS_HANDLE PoolHandle;
+ NB_RECEIVE_PACKET Packets[1];
+} NB_RECEIVE_POOL, *PNB_RECEIVE_POOL;
+
+#define PACKET(_Packet) ((_Packet)->Packet)
+
+#define NbiAllocateSendPacket(_Device,_PoolHandle, _SendPacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_SendPacket)->Packet, _PoolHandle); \
+}
+
+#define NbiAllocateReceivePacket(_Device, _PoolHandle, _ReceivePacket,_Status) { \
+ NdisAllocatePacket(_Status, &(_ReceivePacket)->Packet, _PoolHandle); \
+}
+
+#define NbiFreeSendPacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#define NbiFreeReceivePacket(_Device,_Packet) { \
+ NdisFreePacket(PACKET(_Packet)); \
+}
+
+#endif // NB_OWN_PACKETS
+
+#define SEND_RESERVED(_Packet) ((PNB_SEND_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+#define RECEIVE_RESERVED(_Packet) ((PNB_RECEIVE_RESERVED)((PACKET(_Packet))->ProtocolReserved))
+
+
+
+typedef struct _NB_RECEIVE_BUFFER_POOL {
+ LIST_ENTRY Linkage;
+ UINT BufferCount;
+ UINT BufferFree;
+#if defined(_PNP_POWER)
+ UINT BufferDataSize; // allocation size of each buffer data
+#endif _PNP_POWER
+ NB_RECEIVE_BUFFER Buffers[1];
+ // after the packets the data buffers are allocated also.
+} NB_RECEIVE_BUFFER_POOL, *PNB_RECEIVE_BUFFER_POOL;
+
+
+//
+// Tags for memory allocation.
+//
+
+#define MEMORY_CONFIG 0
+#define MEMORY_ADAPTER 1
+#define MEMORY_ADDRESS 2
+#define MEMORY_PACKET 3
+#define MEMORY_CACHE 4
+#define MEMORY_CONNECTION 5
+#define MEMORY_STATUS 6
+#define MEMORY_QUERY 7
+#if defined(_PNP_POWER)
+#define MEMORY_WORK_ITEM 8
+#define MEMORY_ADAPTER_ADDRESS 9
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+#define MEMORY_MAX 10
+#else
+#define MEMORY_MAX 8
+#endif _PNP_POWER
+
+#if DBG
+
+//
+// Holds the allocations for a specific memory type.
+//
+
+typedef struct _MEMORY_TAG {
+ ULONG Tag;
+ ULONG BytesAllocated;
+} MEMORY_TAG, *PMEMORY_TAG;
+
+EXTERNAL_LOCK(NbiMemoryInterlock);
+extern MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
+
+#endif
+
+
+
+//
+// This structure holds a single remote network which a
+// Netbios name exists on.
+//
+
+typedef struct _NETBIOS_NETWORK {
+ ULONG Network;
+ IPX_LOCAL_TARGET LocalTarget;
+} NETBIOS_NETWORK, *PNETBIOS_NETWORK;
+
+//
+// This defines a netbios cache entry for a given name.
+//
+
+typedef struct _NETBIOS_CACHE {
+ UCHAR NetbiosName[16];
+ BOOLEAN Unique;
+ BOOLEAN FailedOnDownWan; // if NetworksUsed == 0, was it due to down wan lines?
+ USHORT TimeStamp; // in seconds - CacheTimeStamp when inserted
+ ULONG ReferenceCount;
+ LIST_ENTRY Linkage;
+ TDI_ADDRESS_IPX FirstResponse;
+ USHORT NetworksAllocated;
+ USHORT NetworksUsed;
+ NETBIOS_NETWORK Networks[1]; // may be more than one of these
+} NETBIOS_CACHE, *PNETBIOS_CACHE;
+
+typedef struct _NETBIOS_CACHE_TABLE {
+ USHORT MaxHashIndex;
+ USHORT CurrentEntries;
+ LIST_ENTRY Bucket[1];
+} NETBIOS_CACHE_TABLE, *PNETBIOS_CACHE_TABLE;
+
+#define NB_NETBIOS_CACHE_TABLE_LARGE 26 // for server
+#define NB_NETBIOS_CACHE_TABLE_SMALL 8 // for workstation
+#define NB_MAX_AVG_CACHE_ENTRIES_PER_BUCKET 8
+
+//
+// This defines the different kind of requests that can be made
+// to CacheFindName().
+//
+
+typedef enum _FIND_NAME_TYPE {
+ FindNameConnect,
+ FindNameNetbiosFindName,
+ FindNameOther
+} FIND_NAME_TYPE, *PFIND_NAME_TYPE;
+
+
+//
+// The number of hash entries in the non-inactive connection
+// database.
+//
+
+#define CONNECTION_HASH_COUNT 8
+
+//
+// Mask and shift to retrieve the hash number from a connection
+// ID.
+//
+
+#define CONNECTION_HASH_MASK 0xe000
+#define CONNECTION_HASH_SHIFT 13
+
+//
+// The maximum connection ID we can assign, not counting the
+// shifted-over hash id (which occupies the top 3 bits of the
+// real id we use on the wire). We can use all the bits except
+// the top one, to prevent an ID of 0xffff being used.
+//
+
+#define CONNECTION_MAXIMUM_ID (USHORT)(~CONNECTION_HASH_MASK & ~1)
+
+//
+// A single connection hash bucket.
+//
+
+typedef struct _CONNECTION_HASH {
+ struct _CONNECTION * Connections;
+ USHORT ConnectionCount;
+ USHORT NextConnectionId;
+} CONNECTION_HASH, *PCONNECTION_HASH;
+
+
+//
+// These are queued in the ConnectIndicationInProgress
+// queue to track indications to TDI clients.
+//
+
+typedef struct _CONNECT_INDICATION {
+ LIST_ENTRY Linkage;
+ UCHAR NetbiosName[16];
+ TDI_ADDRESS_IPX RemoteAddress;
+ USHORT ConnectionId;
+} CONNECT_INDICATION, *PCONNECT_INDICATION;
+
+//
+// This structure defines the per-device structure for NB
+// (one of these is allocated globally).
+//
+
+#define DREF_CREATE 0
+#define DREF_LOADED 1
+#define DREF_ADAPTER 2
+#define DREF_ADDRESS 3
+#define DREF_CONNECTION 4
+#define DREF_FN_TIMER 5
+#define DREF_FIND_NAME 6
+#define DREF_SESSION_INIT 7
+#define DREF_NAME_FRAME 8
+#define DREF_FRAME 9
+#define DREF_SHORT_TIMER 10
+#define DREF_LONG_TIMER 11
+#define DREF_STATUS_QUERY 12
+#define DREF_STATUS_RESPONSE 13
+#define DREF_STATUS_FRAME 14
+#define DREF_NB_FIND_NAME 15
+
+#define DREF_TOTAL 16
+
+typedef struct _DEVICE {
+
+ DEVICE_OBJECT DeviceObject; // the I/O system's device object.
+
+#if DBG
+ ULONG RefTypes[DREF_TOTAL];
+#endif
+
+ CSHORT Type; // type of this structure
+ USHORT Size; // size of this structure
+
+#if DBG
+ UCHAR Signature1[4]; // contains "IDC1"
+#endif
+
+ NB_LOCK Interlock; // GLOBAL lock for reference count.
+ // (used in ExInterlockedXxx calls)
+ NB_LOCK Lock;
+ LONG ReferenceCount; // activity count/this provider.
+
+ //
+ // These are kept around for error logging, and stored right
+ // after this structure.
+ //
+
+ PWCHAR DeviceName;
+#if defined(_PNP_POWER)
+ USHORT DeviceNameLength;
+#else
+ ULONG DeviceNameLength;
+#endif _PNP_POWER
+
+ LIST_ENTRY GlobalSendPacketList;
+ LIST_ENTRY GlobalReceivePacketList;
+ LIST_ENTRY GlobalReceiveBufferList;
+
+ //
+ // All send packet pools are chained on this list.
+ //
+
+ LIST_ENTRY SendPoolList;
+ LIST_ENTRY ReceivePoolList;
+ LIST_ENTRY ReceiveBufferPoolList;
+
+ SLIST_HEADER SendPacketList;
+ SLIST_HEADER ReceivePacketList;
+ SINGLE_LIST_ENTRY ReceiveBufferList;
+
+ //
+ // Receive requests waiting to be completed.
+ //
+
+ LIST_ENTRY ReceiveCompletionQueue;
+
+ //
+ // Connections waiting for send packets.
+ //
+
+ LIST_ENTRY WaitPacketConnections;
+
+ //
+ // Connections waiting to packetize.
+ //
+
+ LIST_ENTRY PacketizeConnections;
+
+ //
+ // Connections waiting to send a data ack.
+ //
+
+ LIST_ENTRY DataAckConnections;
+
+ //
+ // The list changed while we were processing it.
+ //
+
+ BOOLEAN DataAckQueueChanged;
+
+ //
+ // Information to manage the Netbios name cache.
+ //
+
+ LIST_ENTRY WaitingConnects; // connect requests waiting for a name
+ LIST_ENTRY WaitingDatagrams; // datagram requests waiting for a name
+ LIST_ENTRY WaitingAdapterStatus; // adapter status requests waiting for a name
+ LIST_ENTRY WaitingNetbiosFindName; // netbios find name requests waiting for a name
+
+ //
+ // Holds adapter status request which have a name and
+ // are waiting for a response. The long timeout aborts
+ // these after a couple of expirations (BUGBUG: currently we
+ // do not do resends).
+ //
+
+ LIST_ENTRY ActiveAdapterStatus;
+
+ //
+ // Receive datagrams waiting to be indicated.
+ //
+
+ LIST_ENTRY ReceiveDatagrams;
+
+ //
+ // In-progress connect indications (used to make
+ // sure we don't indicate the same packet twice).
+ //
+
+ LIST_ENTRY ConnectIndicationInProgress;
+
+ //
+ // Listens that have been posted to connections.
+ //
+
+ LIST_ENTRY ListenQueue;
+
+ UCHAR State;
+
+ //
+ // The following fields control the timer system.
+ // The short timer is used for retransmission and
+ // delayed acks, and the long timer is used for
+ // watchdog timeouts.
+ //
+ BOOLEAN ShortListActive; // ShortList is not empty.
+ BOOLEAN DataAckActive; // DataAckConnections is not empty.
+ BOOLEAN TimersInitialized; // has the timer system been initialized.
+ BOOLEAN ProcessingShortTimer; // TRUE if we are in ScanShortTimer.
+#if defined(_PNP_POWER)
+ BOOLEAN LongTimerRunning; // True if the long timer is running.
+#endif _PNP_POWER
+ LARGE_INTEGER ShortTimerStart; // tick count when the short timer was set.
+ CTETimer ShortTimer; // controls the short timer.
+ ULONG ShortAbsoluteTime; // up-count timer ticks, short timer.
+ CTETimer LongTimer; // kernel DPC object, long timer.
+ ULONG LongAbsoluteTime; // up-count timer ticks, long timer.
+ NB_LOCK TimerLock; // lock for following timer queues
+ LIST_ENTRY ShortList; // list of waiting connections
+ LIST_ENTRY LongList; // list of waiting connections
+
+
+ //
+ // Hash table of non-inactive connections.
+ //
+
+ CONNECTION_HASH ConnectionHash[CONNECTION_HASH_COUNT];
+
+ //
+ // Control the queue of waiting find names.
+ //
+
+ USHORT FindNameTime; // incremented each time the timer runs
+ BOOLEAN FindNameTimerActive; // TRUE if the timer is queued
+ CTETimer FindNameTimer; // runs every FIND_NAME_GRANULARITY
+ ULONG FindNameTimeout; // the retry count in timer ticks
+
+ ULONG FindNamePacketCount; // Count of packets on the queue
+ LIST_ENTRY WaitingFindNames; // FIND_NAME frames waiting to go out
+
+ //
+ // The cache of NETBIOS_CACHE entries.
+ //
+
+ PNETBIOS_CACHE_TABLE NameCache;
+
+ //
+ // The current time stamp, incremented every second.
+ //
+
+ USHORT CacheTimeStamp;
+
+ //
+ // Maximum valid NIC ID we can use.
+ //
+
+ USHORT MaximumNicId;
+
+
+ //
+ // Handle for our binding to the IPX driver.
+ //
+
+ HANDLE BindHandle;
+
+ //
+ // Holds the output from binding to IPX.
+ //
+ union {
+ IPX_INTERNAL_BIND_OUTPUT Bind;
+ IPX_INTERNAL_BIND_INPUT BindInput;
+ };
+
+ //
+ // Holds our reserved netbios name, which is 10 bytes
+ // of zeros followed by our node address.
+ //
+#if !defined(_PNP_POWER)
+ UCHAR ReservedNetbiosName[16];
+#endif !_PNP_POWER
+
+ //
+ // This holds the total memory allocated for the above structures.
+ //
+
+ LONG MemoryUsage;
+ LONG MemoryLimit;
+
+ //
+ // How many packets have been allocated.
+ //
+
+ ULONG AllocatedSendPackets;
+ ULONG AllocatedReceivePackets;
+ ULONG AllocatedReceiveBuffers;
+
+#if defined(_PNP_POWER)
+ //
+ // This is the size of each buffer in the receive buffer pool.
+ // We reallocate buffer pool when the LineInfo.MaxPacketSize changes(increases)
+ // from IPX because of a new adapter. The LineInfo.MaxPacketSize could
+ // also change(decrease) when a adapter disappears but our buffer pool size
+ // will stay at this value.
+ //
+ ULONG CurMaxReceiveBufferSize;
+#endif _PNP_POWER
+
+ //
+ // Other configuration parameters.
+ //
+
+ ULONG AckDelayTime; // converted to short timeouts, rounded up
+ ULONG AckWindow;
+ ULONG AckWindowThreshold;
+ ULONG EnablePiggyBackAck;
+ ULONG Extensions;
+ ULONG RcvWindowMax;
+ ULONG BroadcastCount;
+ ULONG BroadcastTimeout;
+ ULONG ConnectionCount;
+ ULONG ConnectionTimeout;
+ ULONG InitPackets;
+ ULONG MaxPackets;
+ ULONG InitialRetransmissionTime;
+ ULONG Internet;
+ ULONG KeepAliveCount;
+ ULONG KeepAliveTimeout;
+ ULONG RetransmitMax;
+ ULONG RouterMtu;
+
+ ULONG MaxReceiveBuffers;
+
+
+ //
+ // Where we tell upper drivers to put their headers.
+ //
+
+ ULONG IncludedHeaderOffset;
+
+ //
+ // The following field is a head of a list of ADDRESS objects that
+ // are defined for this transport provider. To edit the list, you must
+ // hold the spinlock of the device context object.
+ //
+
+ LIST_ENTRY AddressDatabase; // list of defined transport addresses.
+#if defined(_PNP_POWER)
+ LIST_ENTRY AdapterAddressDatabase; // list of netbios names made from adapter addresses.
+#endif _PNP_POWER
+
+ ULONG AddressCount; // number of addresses in the database.
+
+ NDIS_HANDLE NdisBufferPoolHandle;
+
+#if DBG
+ UCHAR Signature2[4]; // contains "IDC2"
+#endif
+
+ //
+ // This structure holds a pre-built IPX header which is used
+ // to quickly fill in common fields of outgoing connectionless
+ // frames.
+ //
+
+ IPX_HEADER ConnectionlessHeader;
+
+ //
+ // This event is used when unloading to signal that
+ // the reference count is now 0.
+ //
+
+ KEVENT UnloadEvent;
+ BOOLEAN UnloadWaiting;
+
+#if defined(_PNP_POWER)
+ HANDLE TdiRegistrationHandle;
+#endif _PNP_POWER
+
+ //
+ // Counters for most of the statistics that NB maintains;
+ // some of these are kept elsewhere. Including the structure
+ // itself wastes a little space but ensures that the alignment
+ // inside the structure is correct.
+ //
+
+ TDI_PROVIDER_STATISTICS Statistics;
+
+ //
+ // These are "temporary" versions of the other counters.
+ // During normal operations we update these, then during
+ // the short timer expiration we update the real ones.
+ //
+
+ ULONG TempFrameBytesSent;
+ ULONG TempFramesSent;
+ ULONG TempFrameBytesReceived;
+ ULONG TempFramesReceived;
+
+
+ //
+ // This contains the next unique indentified to use as
+ // the FsContext in the file object associated with an
+ // open of the control channel.
+ //
+
+ USHORT ControlChannelIdentifier;
+
+ //
+ // Counters for "active" time.
+ //
+
+ LARGE_INTEGER NbiStartTime;
+
+ //
+ // This array is used to quickly dismiss connectionless frames
+ // that are not destined for us. The count is the number
+ // of addresses with that first letter that are registered
+ // on this device.
+ //
+
+ UCHAR AddressCounts[256];
+
+ //
+ // This resource guards access to the ShareAccess
+ // and SecurityDescriptor fields in addresses.
+ //
+
+ ERESOURCE AddressResource;
+
+ //
+ // The following structure contains statistics counters for use
+ // by TdiQueryInformation and TdiSetInformation. They should not
+ // be used for maintenance of internal data structures.
+ //
+
+ TDI_PROVIDER_INFO Information; // information about this provider.
+
+} DEVICE, * PDEVICE;
+
+
+extern PDEVICE NbiDevice;
+EXTERNAL_LOCK(NbiGlobalPoolInterlock);
+
+//
+// This is used only for CHK build. For
+// tracking the refcount problem on connection, this
+// is moved here for now.
+//
+
+EXTERNAL_LOCK(NbiGlobalInterlock);
+
+
+//
+// device state definitions
+//
+#if defined(_PNP_POWER)
+#define DEVICE_STATE_CLOSED 0x00 // Initial state
+#define DEVICE_STATE_LOADED 0x01 // Loaded and bound to IPX but no adapters
+#define DEVICE_STATE_OPEN 0x02 // Fully operational
+#define DEVICE_STATE_STOPPING 0x03 // Unload has been initiated, The I/O system
+ // will not call us until nobody above has Netbios open.
+#else
+#define DEVICE_STATE_CLOSED 0x00
+#define DEVICE_STATE_OPEN 0x01
+#define DEVICE_STATE_STOPPING 0x02
+#endif _PNP_POWER
+
+
+#define NB_TDI_RESOURCES 9
+
+
+//
+// This structure is pointed to by the FsContext field in the FILE_OBJECT
+// for this Address. This structure is the base for all activities on
+// the open file object within the transport provider. All active connections
+// on the address point to this structure, although no queues exist here to do
+// work from. This structure also maintains a reference to an ADDRESS
+// structure, which describes the address that it is bound to.
+//
+
+#define AFREF_CREATE 0
+#define AFREF_RCV_DGRAM 1
+#define AFREF_SEND_DGRAM 2
+#define AFREF_VERIFY 3
+#define AFREF_INDICATION 4
+#define AFREF_TIMEOUT 5
+#define AFREF_CONNECTION 6
+
+#define AFREF_TOTAL 8
+
+typedef struct _ADDRESS_FILE {
+
+#if DBG
+ ULONG RefTypes[AFREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ CSHORT Size;
+
+ LIST_ENTRY Linkage; // next address file on this address.
+ // also used for linkage in the
+ // look-aside list
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ //
+ // the current state of the address file structure; this is either open or
+ // closing
+ //
+
+ UCHAR State;
+
+ PNB_LOCK AddressLock;
+
+ //
+ // The following fields are kept for housekeeping purposes.
+ //
+
+ PREQUEST OpenRequest; // the request used for open
+ struct _ADDRESS *Address; // address to which we are bound.
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+ struct _DEVICE *Device; // device to which we are attached.
+
+ LIST_ENTRY ConnectionDatabase; // associated with this address.
+
+ LIST_ENTRY ReceiveDatagramQueue; // posted by the client.
+
+ //
+ // This holds the request used to close this address file,
+ // for pended completion.
+ //
+
+ PREQUEST CloseRequest;
+
+ //
+ // Handler for kernel event actions. First we have a set of booleans that
+ // indicate whether or not this address has an event handler of the given
+ // type registered.
+ //
+
+ BOOLEAN RegisteredHandler[6];
+
+ //
+ // This is a list of handlers for a given event. They can be
+ // accessed using the explicit names for type-checking, or the
+ // array (indexed by the event type) for speed.
+ //
+
+ union {
+ struct {
+ PTDI_IND_CONNECT ConnectionHandler;
+ PTDI_IND_DISCONNECT DisconnectHandler;
+ PTDI_IND_ERROR ErrorHandler;
+ PTDI_IND_RECEIVE ReceiveHandler;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+ PTDI_IND_RECEIVE_EXPEDITED ExpeditedDataHandler;
+ };
+ PVOID Handlers[6];
+ };
+
+ PVOID HandlerContexts[6];
+
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+#define ADDRESSFILE_STATE_OPENING 0x00 // not yet open for business
+#define ADDRESSFILE_STATE_OPEN 0x01 // open for business
+#define ADDRESSFILE_STATE_CLOSING 0x02 // closing
+
+
+//
+// This structure defines a NETBIOS name as a character array for use when
+// passing preformatted NETBIOS names between internal routines. It is
+// not a part of the external interface to the transport provider.
+//
+
+typedef struct _NBI_NETBIOS_ADDRESS {
+ UCHAR NetbiosName[16];
+ USHORT NetbiosNameType;
+ BOOLEAN Broadcast;
+} NBI_NETBIOS_ADDRESS, *PNBI_NETBIOS_ADDRESS;
+
+//
+// This structure defines an ADDRESS, or active transport address,
+// maintained by the transport provider. It contains all the visible
+// components of the address (such as the TSAP and network name components),
+// and it also contains other maintenance parts, such as a reference count,
+// ACL, and so on. All outstanding connection-oriented and connectionless
+// data transfer requests are queued here.
+//
+
+#define AREF_ADDRESS_FILE 0
+#define AREF_LOOKUP 1
+#define AREF_RECEIVE 2
+#define AREF_NAME_FRAME 3
+#define AREF_TIMER 4
+#define AREF_FIND 5
+
+#define AREF_TOTAL 8
+
+
+typedef struct _ADDRESS {
+
+#if DBG
+ ULONG RefTypes[AREF_TOTAL];
+#endif
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ ULONG ReferenceCount; // number of references to this object.
+
+ NB_LOCK Lock;
+
+ //
+ // The following fields comprise the actual address itself.
+ //
+
+ PREQUEST Request; // pointer to address creation request.
+
+ UCHAR NameTypeFlag; // NB_NAME_UNIQUE or NB_NAME_GROUP
+
+ NBI_NETBIOS_ADDRESS NetbiosAddress; // our netbios name.
+
+ //
+ // The following fields are used to maintain state about this address.
+ //
+
+ ULONG Flags; // attributes of the address.
+ ULONG State; // current state of the address.
+ struct _DEVICE *Device; // device context to which we are attached.
+ PNB_LOCK DeviceLock;
+
+ //
+ // The following queues is used to hold send datagrams for this
+ // address. Receive datagrams are queued to the address file. Requests are
+ // processed in a first-in, first-out manner, so that the very next request
+ // to be serviced is always at the head of its respective queue. These
+ // queues are managed by the EXECUTIVE interlocked list management routines.
+ // The actual objects which get queued to this structure are request control
+ // blocks (RCBs).
+ //
+
+ LIST_ENTRY AddressFileDatabase; // list of defined address file objects
+
+ UCHAR SendPacketHeader[NB_MAXIMUM_MAC + sizeof(IPX_HEADER)];
+
+ //
+ // This timer is used for registering the name.
+ //
+
+ CTETimer RegistrationTimer;
+
+ //
+ // Number of times an add name frame has been sent.
+ //
+
+ ULONG RegistrationCount;
+
+#ifdef ISN_NT
+
+ //
+ // These two can be a union because they are not used
+ // concurrently.
+ //
+
+ union {
+
+ //
+ // This structure is used for checking share access.
+ //
+
+ SHARE_ACCESS ShareAccess;
+
+ //
+ // Used for delaying NbiDestroyAddress to a thread so
+ // we can access the security descriptor.
+ //
+
+ WORK_QUEUE_ITEM DestroyAddressQueueItem;
+
+ } u;
+
+ //
+ // This structure is used to hold ACLs on the address.
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+#endif
+
+} ADDRESS, *PADDRESS;
+
+//
+// Values for Flags
+//
+
+#define ADDRESS_FLAGS_DUPLICATE_NAME 0x00000002
+#if defined(_PNP_POWER)
+#define ADDRESS_FLAGS_CONFLICT 0x00000010
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+//
+// this booleans are passed to nbiverifyaddressfile calls.
+//
+#define CONFLICT_IS_OK TRUE
+#define CONFLICT_IS_NOT_OK FALSE
+#endif _PNP_POWER
+
+//
+// Values for State
+//
+
+#define ADDRESS_STATE_REGISTERING 1
+#define ADDRESS_STATE_OPEN 2
+#define ADDRESS_STATE_STOPPING 3
+
+#if defined(_PNP_POWER)
+//
+// This holds the adapters names i.e netbios names which are
+// created from adater node address to support adapter status
+// queries using adapter node addresses.
+//
+typedef struct _ADAPTER_ADDRESS {
+
+ USHORT Size;
+ CSHORT Type;
+
+ LIST_ENTRY Linkage; // next address/this device object.
+ NIC_HANDLE NicHandle; // NicHandle corresponding to this address.
+ UCHAR NetbiosName[16];
+} ADAPTER_ADDRESS, *PADAPTER_ADDRESS;
+#endif _PNP_POWER
+
+//
+// This defines the types of probe packets we can send.
+//
+
+typedef enum _NB_ACK_TYPE {
+ NbiAckQuery,
+ NbiAckResponse,
+ NbiAckResend
+} NB_ACK_TYPE, *PNB_ACK_TYPE;
+
+
+//
+// This defines the a packetizing location in a
+// send.
+//
+
+typedef struct _SEND_POINTER {
+ ULONG MessageOffset; // up count, bytes sent this message.
+ PREQUEST Request; // current send request in chain.
+ PNDIS_BUFFER Buffer; // current buffer in send chain.
+ ULONG BufferOffset; // current byte offset in current buffer.
+ USHORT SendSequence;
+} SEND_POINTER, *PSEND_POINTER;
+
+//
+// This defines the current location in a receive.
+//
+
+typedef struct _RECEIVE_POINTER {
+ ULONG MessageOffset; // up count, bytes received this message.
+ ULONG Offset; // up count, bytes received this request.
+ PNDIS_BUFFER Buffer; // current buffer in receive request.
+ ULONG BufferOffset; // current byte offset in current buffer.
+} RECEIVE_POINTER, *PRECEIVE_POINTER;
+
+
+//
+// This structure defines a connection, which controls a
+// session with a remote.
+//
+
+#define CREF_VERIFY 0
+#define CREF_LISTEN 1
+#define CREF_CONNECT 2
+#define CREF_WAIT_CACHE 3
+#define CREF_TIMER 4
+#define CREF_INDICATE 5
+#define CREF_ACTIVE 6
+#define CREF_FRAME 7
+#define CREF_BY_CONTEXT 8
+#define CREF_W_ACCEPT 9
+#define CREF_SEND 10
+#define CREF_RECEIVE 11
+#define CREF_PACKETIZE 12
+#define CREF_DISASSOC 13
+#define CREF_W_PACKET 14
+#define CREF_CANCEL 15
+#define CREF_NDIS_SEND 16
+#define CREF_SHORT_D_ACK 17
+#define CREF_LONG_D_ACK 18
+#define CREF_FIND_ROUTE 19
+#define CREF_ACCEPT 20
+
+#define CREF_TOTAL 24
+
+typedef struct _CONNECTION {
+
+#if DBG
+ ULONG RefTypes[CREF_TOTAL];
+#endif
+
+ CSHORT Type;
+ USHORT Size;
+
+ NB_LOCK Lock;
+ PNB_LOCK DeviceLock;
+
+ ULONG ReferenceCount; // number of references to this object.
+
+ CONNECTION_CONTEXT Context; // client-specified value.
+
+ ULONG State;
+ ULONG SubState;
+ ULONG ReceiveState; // SubState tracks sends when active.
+ ULONG NewNetbios; // 1 if we negotiated this.
+
+ REQUEST_LIST_HEAD SendQueue;
+ REQUEST_LIST_HEAD ReceiveQueue;
+
+ USHORT ReceiveSequence;
+
+ USHORT LocalRcvSequenceMax; // we advertise to him (will be near SendSequence)
+ USHORT RemoteRcvSequenceMax; // he advertises to us (will be near ReceiveSequence)
+ USHORT SendWindowSequenceLimit; // when this send window ends (may send past it however)
+
+ //
+ // RemoteRcvSequenceMax is the largest frame number that he expects to
+ // receive, while SendWindowSequenceLimit is one more than the max
+ // we can send. I.e. if he is advertising a window of 4 and we think
+ // the window should be 2, and the current send sequence is 7,
+ // RemoteRcvSequenceMax is 10 and SendWindowSequenceLimit is 9.
+ //
+
+ USHORT ReceiveWindowSize; // when it is open, how big to make it
+ USHORT SendWindowSize; // what we'll send, may be less than what he advertises
+ USHORT MaxSendWindowSize; // maximum we allow it to grow to
+
+ USHORT IncreaseWindowFailures; // how many windows after increase have had retransmits
+ BOOLEAN RetransmitThisWindow; // we had to retransmit in this send window
+ BOOLEAN SendWindowIncrease; // send window was just increased.
+ BOOLEAN ResponseTimeout; // we hit timeout in SEND_W or REMOTE_W
+
+ BOOLEAN SendBufferInUse; // current send's already queued on packet
+
+ ULONG Retries;
+
+ //
+ // Tracks the current send.
+ //
+
+ SEND_POINTER CurrentSend;
+
+ //
+ // Tracks the unacked point in the send.
+ //
+
+ SEND_POINTER UnAckedSend;
+
+ PREQUEST FirstMessageRequest; // first one in the message.
+ PREQUEST LastMessageRequest; // last one in the message.
+
+ ULONG CurrentMessageLength; // total length of current message.
+
+ //
+ // Tracks the current receive.
+ //
+
+ RECEIVE_POINTER CurrentReceive; // where to receive next data
+ RECEIVE_POINTER PreviousReceive; // stores it while transfer in progress
+
+ PREQUEST ReceiveRequest; // current one; not in ReceiveQueue
+ ULONG ReceiveLength; // length of ReceiveRequest
+
+ ULONG ReceiveUnaccepted; // by client...only indicate when == 0
+
+ ULONG CurrentIndicateOffset; // if previous frame was partially accepted.
+
+ IPX_LINE_INFO LineInfo; // for the adapter this connect is on.
+ ULONG MaximumPacketSize; // as negotiated during session init/ack
+
+ //
+ // Links us in the non-inactive connection hash bucket.
+ //
+
+ struct _CONNECTION * NextConnection;
+
+ //
+ // These are used to determine when to piggyback and when not to.
+ //
+
+ BOOLEAN NoPiggybackHeuristic; // we have reason to assume it would be bad.
+ BOOLEAN PiggybackAckTimeout; // we got a timeout last time we tried.
+ ULONG ReceivesWithoutAck; // used to do an auto ack.
+
+ //
+ // The following field is used as linkage in the device's
+ // PacketizeConnections queue.
+ //
+
+ LIST_ENTRY PacketizeLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // WaitPacketConnections queue.
+ //
+
+ LIST_ENTRY WaitPacketLinkage;
+
+ //
+ // The following field is used as linkage in the device's
+ // DataAckConnections queue.
+ //
+
+ LIST_ENTRY DataAckLinkage;
+
+ //
+ // TRUE if we are on these queues.
+ //
+
+ BOOLEAN OnPacketizeQueue;
+ BOOLEAN OnWaitPacketQueue;
+ BOOLEAN OnDataAckQueue;
+
+ //
+ // TRUE if we have a piggyback ack pending.
+ //
+
+ BOOLEAN DataAckPending;
+
+ //
+ // TRUE if the current receive does not allow piggyback acks.
+ //
+
+ BOOLEAN CurrentReceiveNoPiggyback;
+
+ //
+ // Number of short timer expirations with the data ack queued.
+ //
+
+ ULONG DataAckTimeouts;
+
+ //
+ // Used to queue sends so that no two are outstanding at once.
+ //
+
+ ULONG NdisSendsInProgress;
+ LIST_ENTRY NdisSendQueue;
+
+ //
+ // This pointer is valid when NdisSendsInProgress is non-zero;
+ // it holds a pointer to a location on the stack of the thread
+ // which is inside NbiAssignSequenceAndSend. If this location
+ // is set to TRUE, it means the connection was stopped by another
+ // thread and a reference was added to keep the connection around.
+ //
+
+ PBOOLEAN NdisSendReference;
+
+ //
+ // These are used for timeouts.
+ //
+
+ ULONG BaseRetransmitTimeout; // config # of short timeouts we wait.
+ ULONG CurrentRetransmitTimeout; // possibly backed-off number
+ ULONG WatchdogTimeout; // how many long timeouts we wait.
+ ULONG Retransmit; // timer; based on Device->ShortAbsoluteTime
+ ULONG Watchdog; // timer; based on Device->LongAbsoluteTime
+ USHORT TickCount; // 18.21/second, # for 576-byte packet.
+ USHORT HopCount; // As returned by ipx on find route.
+ BOOLEAN OnShortList; // are we inserted in the list
+ BOOLEAN OnLongList; // are we inserted in the list
+ LIST_ENTRY ShortList; // queues us on Device->ShortList
+ LIST_ENTRY LongList; // queues us on Device->LongList
+
+ //
+ // These are valid when we have a connection established;
+ //
+
+ USHORT LocalConnectionId;
+ USHORT RemoteConnectionId;
+
+ PREQUEST DisassociatePending; // guarded by device lock.
+ PREQUEST ClosePending;
+
+ PREQUEST ConnectRequest;
+ PREQUEST ListenRequest;
+ PREQUEST AcceptRequest;
+ PREQUEST DisconnectRequest;
+ PREQUEST DisconnectWaitRequest;
+
+ ULONG CanBeDestroyed; // FALSE if reference is non-zero
+ ULONG ThreadsInHandleConnectionZero; // # of threads in HandleConnectionZero
+
+ //
+ // These are used to hold extra data that was sent on a session
+ // init, for use in sending the ack. Generally will be NULL and 0.
+ //
+
+ PUCHAR SessionInitAckData;
+ ULONG SessionInitAckDataLength;
+
+ IPX_LOCAL_TARGET LocalTarget; // for the remote when active.
+ IPX_HEADER RemoteHeader;
+
+ CTETimer Timer;
+
+ PADDRESS_FILE AddressFile; // guarded by device lock if associated.
+ LIST_ENTRY AddressFileLinkage; // guarded by device lock
+ ULONG AddressFileLinked; // TRUE if queued using AddressFileLinkage
+
+ PDEVICE Device;
+#ifdef ISN_NT
+ PFILE_OBJECT FileObject; // easy backlink to file object.
+#endif
+
+ CHAR RemoteName[16]; // for an active connection.
+
+ IPX_FIND_ROUTE_REQUEST FindRouteRequest; // use this to verify route.
+
+ TDI_CONNECTION_INFO ConnectionInfo; // can be queried from above.
+
+ BOOLEAN FindRouteInProgress; // we have a request pending.
+
+ BOOLEAN SendPacketInUse; // put this here to align packet/header.
+ BOOLEAN IgnoreNextDosProbe;
+
+ NTSTATUS Status; // status code for connection rundown.
+
+#ifdef RSRC_TIMEOUT_DBG
+ LARGE_INTEGER FirstMessageRequestTime;
+#endif //RSRC_TIMEOUT_DBG
+
+ NDIS_HANDLE SendPacketPoolHandle; // poolhandle for sendpacket below when
+ // the packet is allocated from ndis pool.
+
+ NB_SEND_PACKET SendPacket; // try to use this first for sends
+
+ ULONG Flags; // miscellaneous connection flags
+
+ UCHAR SendPacketHeader[1]; // connection is extended to include this
+
+ //
+ // NOTE: This is variable length structure!
+ // Do not add fields below this comment.
+ //
+} CONNECTION, *PCONNECTION;
+
+
+#define CONNECTION_STATE_INACTIVE 1
+#define CONNECTION_STATE_CONNECTING 2
+#define CONNECTION_STATE_LISTENING 3
+#define CONNECTION_STATE_ACTIVE 4
+#define CONNECTION_STATE_DISCONNECT 5
+#define CONNECTION_STATE_CLOSING 6
+
+
+#define CONNECTION_SUBSTATE_L_WAITING 1 // queued by a listen
+#define CONNECTION_SUBSTATE_L_W_ACCEPT 2 // waiting for user to accept
+#define CONNECTION_SUBSTATE_L_W_ROUTE 3 // waiting for rip response
+
+#define CONNECTION_SUBSTATE_C_FIND_NAME 1 // waiting for cache response
+#define CONNECTION_SUBSTATE_C_W_ACK 2 // waiting for session init ack
+#define CONNECTION_SUBSTATE_C_W_ROUTE 3 // waiting for rip response
+#define CONNECTION_SUBSTATE_C_DISCONN 4 // disconnect was issued
+
+#define CONNECTION_SUBSTATE_A_IDLE 1 // no sends in progress
+#define CONNECTION_SUBSTATE_A_PACKETIZE 2 // packetizing a send
+#define CONNECTION_SUBSTATE_A_W_ACK 3 // waiting for an ack
+#define CONNECTION_SUBSTATE_A_W_PACKET 4 // waiting for a packet
+#define CONNECTION_SUBSTATE_A_W_EOR 5 // waiting for eor to start packetizing
+#define CONNECTION_SUBSTATE_A_W_PROBE 6 // waiting for a keep-alive response
+#define CONNECTION_SUBSTATE_A_REMOTE_W 7 // remote shut down our window
+
+#define CONNECTION_RECEIVE_IDLE 1 // no receives queued
+#define CONNECTION_RECEIVE_ACTIVE 2 // receive is queued
+#define CONNECTION_RECEIVE_W_RCV 3 // waiting for receive to be posted
+#define CONNECTION_RECEIVE_INDICATE 4 // indication in progress
+#define CONNECTION_RECEIVE_TRANSFER 5 // transfer is in progress
+#define CONNECTION_RECEIVE_PENDING 6 // last request is queued for completion
+
+#define CONNECTION_SUBSTATE_D_W_ACK 1
+#define CONNECTION_SUBSTATE_D_GOT_ACK 2
+
+//
+// Bit values for Flags field in
+// the CONNECTION structure.
+//
+#define CONNECTION_FLAGS_AUTOCONNECTING 0x00000001 // RAS autodial in progress
+#define CONNECTION_FLAGS_AUTOCONNECTED 0x00000002 // RAS autodial connected
+
+#ifdef RSRC_TIMEOUT_DBG
+extern ULONG NbiGlobalDebugResTimeout;
+extern LARGE_INTEGER NbiGlobalMaxResTimeout;
+extern NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
+#endif //RSRC_TIMEOUT_DBG
diff --git a/private/ntos/tdi/isnp/nb/nwlnknb.ini b/private/ntos/tdi/isnp/nb/nwlnknb.ini
new file mode 100644
index 000000000..e2df88f54
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nwlnknb.ini
@@ -0,0 +1,43 @@
+\Registry\Machine\System\CurrentControlSet\Services\NwlnkNb
+ Type = REG_DWORD 0x00000001
+ Start = REG_DWORD 0x00000003
+ ErrorControl = REG_DWORD 0x00000001
+ ImagePath = REG_EXPAND_SZ \SystemRoot\System32\drivers\nwlnknb.sys
+ DisplayName = NWLINK2 IPX Netbios Protocol
+ Group = TDI
+ DependOnService = REG_MULTI_SZ "NwlnkIpx"
+ DependOnGroup = REG_MULTI_SZ "NDIS"
+ Linkage
+ Bind = REG_MULTI_SZ "\Device\NwlnkIpx"
+ Export = REG_MULTI_SZ "\Device\NwlnkNb"
+ Route = REG_MULTI_SZ ""NwlnkIpx""
+ Disabled
+ Bind = REG_MULTI_SZ
+ Export = REG_MULTI_SZ
+ Route = REG_MULTI_SZ
+ Parameters
+ AckDelayTime = REG_DWORD 0x000000fa
+ AckWindow = REG_DWORD 0x00000002
+ AckWindowThreshold = REG_DWORD 0x000001f4
+ EnablePiggyBackAck = REG_DWORD 0x00000001
+ Extensions = REG_DWORD 0x00000001
+ RcvWindowMax = REG_DWORD 0x00000004
+ BroadcastCount = REG_DWORD 0x00000003
+ BroadcastTimeout = REG_DWORD 0x00000001
+ ConnectionCount = REG_DWORD 0x00000005
+ ConnectionTimeout = REG_DWORD 0x00000002
+ InitPackets= REG_DWORD 0x00000005
+ MaxPackets = REG_DWORD 0x0000001e
+ InitialRetransmissionTime = REG_DWORD 0x000001f4
+ Internet = REG_DWORD 0x00000001
+ KeepAliveCount = REG_DWORD 0x00000008
+ KeepAliveTimeout = REG_DWORD 0x0000003c
+ RetransmitMax = REG_DWORD 0x00000008
+ Performance
+ Library = Perfctrs.dll
+ Open = OpenNbfPerformanceData
+ Collect = CollectNbfPerformanceData
+ Close = CloseNbfPerformanceData
+\Registry\Machine\System\CurrentControlSet\Services\EventLog\System\NwlnkNb
+ EventMessageFile = REG_EXPAND_SZ %SystemRoot%\System32\netevent.dll
+ TypesSupported = REG_DWORD 0x00000007
diff --git a/private/ntos/tdi/isnp/nb/nwlnknb.rc b/private/ntos/tdi/isnp/nb/nwlnknb.rc
new file mode 100644
index 000000000..1b0163cf3
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/nwlnknb.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR "NWLINK2 IPX Netbios Protocol Driver"
+#define VER_INTERNALNAME_STR "nwlnknb.sys"
+#define VER_ORIGINALFILENAME_STR "nwlnknb.sys"
+
+#include "common.ver"
+
diff --git a/private/ntos/tdi/isnp/nb/packet.c b/private/ntos/tdi/isnp/nb/packet.c
new file mode 100644
index 000000000..7e22534a8
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/packet.c
@@ -0,0 +1,1482 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ packet.c
+
+Abstract:
+
+ This module contains code that implements the SEND_PACKET and
+ RECEIVE_PACKET objects, which describe NDIS packets used
+ by the transport.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Local Function Protos
+//
+#if defined(_PNP_POWER)
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ );
+#endif _PNP_POWER
+
+
+NTSTATUS
+NbiInitializeSendPacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_SEND_PACKET Packet,
+ IN PUCHAR Header,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a send packet by chaining the
+ buffer for the header on it.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+ Header - Points to storage for the header.
+
+ HeaderLength - The length of the header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ NTSTATUS Status;
+ PNDIS_BUFFER NdisBuffer;
+ PNDIS_BUFFER NdisNbBuffer;
+ PNB_SEND_RESERVED Reserved;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ NbiAllocateSendPacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+// DbgPrint("NbiInitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+
+ //
+ // allocate the mac header.
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ Header,
+ MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NdisChainBufferAtFront (PACKET(Packet), NdisBuffer);
+
+// DbgPrint("NbiInitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+ //
+ // Allocate the nb header
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisNbBuffer,
+ Device->NdisBufferPoolHandle,
+ Header + MacHeaderNeeded,
+ HeaderLength - MacHeaderNeeded);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+ NbiFreeSendPacket (Device, Packet);
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // DbgPrint("NbiInitializeSendPacket: IPX header address is (%x)\n", NdisNbBuffer);
+ NdisChainBufferAtBack (PACKET(Packet), NdisNbBuffer);
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->SendInProgress = FALSE;
+ Reserved->OwnedByConnection = FALSE;
+ Reserved->Header = Header;
+ Reserved->HeaderBuffer = NdisBuffer;
+
+ Reserved->Reserved[0] = NULL;
+ Reserved->Reserved[1] = NULL;
+
+ InsertHeadList(
+ &Device->GlobalSendPacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeSendPacket */
+
+
+NTSTATUS
+NbiInitializeReceivePacket(
+ IN PDEVICE Device,
+ IN NDIS_HANDLE PoolHandle OPTIONAL,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ PoolHandle - Ndis packet pool handle if !NB_OWN_PACKETS
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+ PNB_RECEIVE_RESERVED Reserved;
+
+ NbiAllocateReceivePacket (Device, PoolHandle, Packet, &Status);
+
+ if (Status != STATUS_SUCCESS) {
+ // ERROR LOG
+ return Status;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+ Reserved->Identifier = IDENTIFIER_NB;
+ Reserved->TransferInProgress = FALSE;
+
+ InsertHeadList(
+ &Device->GlobalReceivePacketList,
+ &Reserved->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceivePacket */
+
+
+NTSTATUS
+NbiInitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer,
+ IN PUCHAR DataBuffer,
+ IN ULONG DataBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive buffer by allocating
+ an NDIS_BUFFER to describe the data buffer.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD,
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer to initialize.
+
+ DataBuffer - The data buffer.
+
+ DataBufferLength - The length of the data buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER NdisBuffer;
+
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Device->NdisBufferPoolHandle,
+ DataBuffer,
+ DataBufferLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ // ERROR LOG
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ReceiveBuffer->NdisBuffer = NdisBuffer;
+ ReceiveBuffer->Data = DataBuffer;
+ ReceiveBuffer->DataLength = 0;
+
+ InsertHeadList(
+ &Device->GlobalReceiveBufferList,
+ &ReceiveBuffer->GlobalLinkage);
+
+ return STATUS_SUCCESS;
+
+} /* NbiInitializeReceiveBuffer */
+
+
+
+VOID
+NbiDeinitializeSendPacket(
+ IN PDEVICE Device,
+ IN PNB_SEND_PACKET Packet,
+ IN ULONG HeaderLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a send packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to deinitialize.
+
+ HeaderLength - The length of the first buffer on the packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNDIS_BUFFER NdisBuffer;
+ PNB_SEND_RESERVED Reserved;
+ CTELockHandle LockHandle;
+ ULONG MacHeaderNeeded = NbiDevice->Bind.MacHeaderNeeded;
+
+ CTEAssert(HeaderLength > MacHeaderNeeded);
+ Reserved = SEND_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // Free the mac header
+ //
+ // DbgPrint("NbiDeinitializeSendPacket: PACKET is (%x)\n", PACKET(Packet));
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ CTEAssert (NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: MAC header address is (%x)\n", NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // Free the nb header
+ //
+ NdisUnchainBufferAtFront (PACKET(Packet), &NdisBuffer);
+ // DbgPrint("NbiDeinitializeSendPacket: IPX header address is (%x)\n", NdisBuffer);
+ CTEAssert (NdisBuffer);
+
+ NdisAdjustBufferLength (NdisBuffer, HeaderLength - MacHeaderNeeded);
+ NdisFreeBuffer (NdisBuffer);
+
+ //
+ // free the packet
+ //
+ NbiFreeSendPacket (Device, Packet);
+
+} /* NbiDeinitializeSendPacket */
+
+
+VOID
+NbiDeinitializeReceivePacket(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a receive packet.
+
+Arguments:
+
+ Device - The device.
+
+ Packet - The packet to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PNB_RECEIVE_RESERVED Reserved;
+ CTELockHandle LockHandle;
+
+ Reserved = RECEIVE_RESERVED(Packet);
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&Reserved->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiFreeReceivePacket (Device, Packet);
+
+} /* NbiDeinitializeReceivePacket */
+
+
+
+VOID
+NbiDeinitializeReceiveBuffer(
+ IN PDEVICE Device,
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deinitializes a receive buffer.
+
+Arguments:
+
+ Device - The device.
+
+ ReceiveBuffer - The receive buffer.
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE SHOULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+#else
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ RemoveEntryList (&ReceiveBuffer->GlobalLinkage);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+
+ NdisFreeBuffer (ReceiveBuffer->NdisBuffer);
+
+} /* NbiDeinitializeReceiveBuffer */
+
+
+
+VOID
+NbiAllocateSendPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 10 packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_SEND_POOL SendPool;
+ UINT SendPoolSize;
+ UINT PacketNum;
+ PNB_SEND_PACKET Packet;
+ PNB_SEND_RESERVED Reserved;
+ PUCHAR Header;
+ ULONG HeaderLength;
+ NTSTATUS Status;
+
+ HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTIONLESS);
+ SendPoolSize = FIELD_OFFSET (NB_SEND_POOL, Packets[0]) +
+ (sizeof(NB_SEND_PACKET) * Device->InitPackets) +
+ (HeaderLength * Device->InitPackets);
+
+ SendPool = (PNB_SEND_POOL)NbiAllocateMemory (SendPoolSize, MEMORY_PACKET, "SendPool");
+ if (SendPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate send pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (SendPool, SendPoolSize);
+
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &SendPool->PoolHandle, Device->InitPackets, sizeof(NB_SEND_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( SendPool, SendPoolSize, MEMORY_PACKET, "Send Pool Freed");
+ return;
+ }
+#endif
+
+ NB_DEBUG2 (PACKET, ("Initializing send pool %lx, %d packets, header %d\n",
+ SendPool, Device->InitPackets, HeaderLength));
+
+ Header = (PUCHAR)(&SendPool->Packets[Device->InitPackets]);
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+
+ if (NbiInitializeSendPacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ SendPool->PoolHandle,
+#endif
+ Packet,
+ Header,
+ HeaderLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = SEND_RESERVED(Packet);
+ Reserved->u.SR_NF.Address = NULL;
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = SendPool;
+#endif
+
+ Header += HeaderLength;
+
+ }
+
+ SendPool->PacketCount = PacketNum;
+ SendPool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < SendPool->PacketCount; PacketNum++) {
+
+ Packet = &SendPool->Packets[PacketNum];
+ Reserved = SEND_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ }
+
+ InsertTailList (&Device->SendPoolList, &SendPool->Linkage);
+
+ Device->AllocatedSendPackets += SendPool->PacketCount;
+
+} /* NbiAllocateSendPool */
+
+
+VOID
+NbiAllocateReceivePool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds 5 receive packets to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_POOL ReceivePool;
+ UINT ReceivePoolSize;
+ UINT PacketNum;
+ PNB_RECEIVE_PACKET Packet;
+ PNB_RECEIVE_RESERVED Reserved;
+ NTSTATUS Status;
+
+ ReceivePoolSize = FIELD_OFFSET (NB_RECEIVE_POOL, Packets[0]) +
+ (sizeof(NB_RECEIVE_PACKET) * Device->InitPackets);
+
+ ReceivePool = (PNB_RECEIVE_POOL)NbiAllocateMemory (ReceivePoolSize, MEMORY_PACKET, "ReceivePool");
+ if (ReceivePool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceivePool, ReceivePoolSize);
+
+#if !defined(NB_OWN_PACKETS)
+ //
+ // Now allocate the ndis packet pool
+ //
+ NdisAllocatePacketPool( &Status, &ReceivePool->PoolHandle, Device->InitPackets, sizeof(NB_RECEIVE_RESERVED));
+ if (!NT_SUCCESS(Status)){
+ NB_DEBUG (PACKET, ("Could not allocate Ndis Packet Pool memory\n"));
+ NbiFreeMemory( ReceivePool, ReceivePoolSize, MEMORY_PACKET, "Receive Pool Freed");
+ return;
+ }
+#endif NB_OWN_PACKETS
+
+ NB_DEBUG2 (PACKET, ("Initializing receive pool %lx, %d packets\n",
+ ReceivePool, Device->InitPackets));
+
+ for (PacketNum = 0; PacketNum < Device->InitPackets; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+
+ if (NbiInitializeReceivePacket (
+ Device,
+#ifdef NB_OWN_PACKETS
+ NULL,
+#else
+ ReceivePool->PoolHandle,
+#endif
+ Packet) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize packet %lx\n", Packet));
+ break;
+ }
+
+ Reserved = RECEIVE_RESERVED(Packet);
+#ifdef NB_TRACK_POOL
+ Reserved->Pool = ReceivePool;
+#endif
+
+ }
+
+ ReceivePool->PacketCount = PacketNum;
+ ReceivePool->PacketFree = PacketNum;
+
+ for (PacketNum = 0; PacketNum < ReceivePool->PacketCount; PacketNum++) {
+
+ Packet = &ReceivePool->Packets[PacketNum];
+ Reserved = RECEIVE_RESERVED(Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+// PushEntryList (&Device->ReceivePacketList, &Reserved->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceivePoolList, &ReceivePool->Linkage);
+
+ Device->AllocatedReceivePackets += ReceivePool->PacketCount;
+
+} /* NbiAllocateReceivePool */
+
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device,
+ IN UINT DataLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+ DataLength - Max length of the data in each buffer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PUCHAR Data;
+
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+ ReceiveBufferPool->BufferDataSize = DataLength;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+ Device->CurMaxReceiveBufferSize = DataLength;
+
+} /* NbiAllocateReceiveBufferPool */
+#else
+
+VOID
+NbiAllocateReceiveBufferPool(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds receive buffers to the pool for this device.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE DEVICE LOCK HELD AND
+ RETURNS WITH IT HELD.
+
+Arguments:
+
+ Device - The device.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize;
+ UINT BufferNum;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ UINT DataLength;
+ PUCHAR Data;
+
+ DataLength = Device->Bind.LineInfo.MaximumPacketSize;
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (DataLength * Device->InitPackets);
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)NbiAllocateMemory (ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+ if (ReceiveBufferPool == NULL) {
+ NB_DEBUG (PACKET, ("Could not allocate receive buffer pool memory\n"));
+ return;
+ }
+
+ RtlZeroMemory (ReceiveBufferPool, ReceiveBufferPoolSize);
+
+ NB_DEBUG2 (PACKET, ("Initializing receive buffer pool %lx, %d buffers, data %d\n",
+ ReceiveBufferPool, Device->InitPackets, DataLength));
+
+ Data = (PUCHAR)(&ReceiveBufferPool->Buffers[Device->InitPackets]);
+
+ for (BufferNum = 0; BufferNum < Device->InitPackets; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+
+ if (NbiInitializeReceiveBuffer (Device, ReceiveBuffer, Data, DataLength) != STATUS_SUCCESS) {
+ NB_DEBUG (PACKET, ("Could not initialize buffer %lx\n", ReceiveBuffer));
+ break;
+ }
+
+#ifdef NB_TRACK_POOL
+ ReceiveBuffer->Pool = ReceiveBufferPool;
+#endif
+
+ Data += DataLength;
+
+ }
+
+ ReceiveBufferPool->BufferCount = BufferNum;
+ ReceiveBufferPool->BufferFree = BufferNum;
+
+ for (BufferNum = 0; BufferNum < ReceiveBufferPool->BufferCount; BufferNum++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[BufferNum];
+ PushEntryList (&Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage);
+
+ }
+
+ InsertTailList (&Device->ReceiveBufferPoolList, &ReceiveBufferPool->Linkage);
+
+ Device->AllocatedReceiveBuffers += ReceiveBufferPool->BufferCount;
+
+} /* NbiAllocateReceiveBufferPool */
+#endif _PNP_POWER
+
+#if defined(_PNP_POWER)
+
+VOID
+NbiReAllocateReceiveBufferPool(
+ IN PWORK_QUEUE_ITEM WorkItem
+ )
+
+/*++
+
+Routine Description:
+
+ This routines destroys all the existing Buffer Pools and creates
+ new one using the larger packet size given to us by IPX because
+ a new card was inserted with a larger packet size.
+
+Arguments:
+
+ WorkItem - The work item that was allocated for this.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK ( &Device->Lock, &LockHandle );
+
+ if ( Device->Bind.LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("Reallocating new pools due to new maxpacketsize\n");
+#endif
+ NbiDestroyReceiveBufferPools( Device );
+ NbiAllocateReceiveBufferPool( Device, Device->Bind.LineInfo.MaximumPacketSize );
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+
+ NbiFreeMemory( WorkItem, sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buff Work Item freed");
+}
+
+#if !defined(DBG)
+__inline
+#endif
+VOID
+NbiFreeReceiveBufferPool (
+ IN PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+{
+ PDEVICE Device = NbiDevice;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ UINT ReceiveBufferPoolSize,i;
+
+ CTEAssert( ReceiveBufferPool->BufferDataSize );
+
+ ReceiveBufferPoolSize = FIELD_OFFSET (NB_RECEIVE_BUFFER_POOL, Buffers[0]) +
+ (sizeof(NB_RECEIVE_BUFFER) * Device->InitPackets) +
+ (ReceiveBufferPool->BufferDataSize * Device->InitPackets);
+
+ //
+ // Check if we can free this pool
+ //
+ CTEAssert(ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree );
+
+ for (i = 0; i < ReceiveBufferPool->BufferCount; i++) {
+
+ ReceiveBuffer = &ReceiveBufferPool->Buffers[i];
+ NbiDeinitializeReceiveBuffer (Device, ReceiveBuffer);
+
+ }
+
+ RemoveEntryList( &ReceiveBufferPool->Linkage );
+
+ NB_DEBUG2 (PACKET, ("Free buffer pool %lx\n", ReceiveBufferPool));
+
+ NbiFreeMemory (ReceiveBufferPool, ReceiveBufferPoolSize, MEMORY_PACKET, "ReceiveBufferPool");
+
+}
+
+
+VOID
+NbiDestroyReceiveBufferPools(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routines walks the ReceiveBufferPoolList and destroys the
+ pool which does not have any buffer in use.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+ THIS ROUTINE COULD BE CALLED WITH THE DEVICE LOCK HELD. If this
+ routine is also called from the DestroyDevice routine, it is not
+ necessary to call this with the lock.
+
+--*/
+{
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY Unused;
+
+
+ //
+ // Clean up this list before we call NbiFreeReceiveBufferPool bcoz that will
+ // simply destroy all the buffer which might be queue here on this list.
+ // At the end of this routine we must start with a fresh ReceiveBufferList.
+ //
+ do {
+ Unused = PopEntryList( &Device->ReceiveBufferList );
+ } while( Unused );
+
+ //
+ // Now destroy each individual ReceiveBufferPool.
+ //
+ for ( p = Device->ReceiveBufferPoolList.Flink;
+ p != &Device->ReceiveBufferPoolList;
+ ) {
+
+
+ ReceiveBufferPool = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER_POOL, Linkage);
+ p = p->Flink;
+
+ //
+ // This will destroy and unlink this Pool if none of its buffer is
+ // in use currently.
+ //
+
+ if ( ReceiveBufferPool->BufferCount == ReceiveBufferPool->BufferFree ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ } else {
+ //
+ // When the device is stopping we must succeed in freeing the pool.
+ CTEAssert( Device->State != DEVICE_STATE_STOPPING );
+ }
+
+ }
+
+}
+
+
+VOID
+NbiPushReceiveBuffer (
+ IN PNB_RECEIVE_BUFFER ReceiveBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the receive buffer back to the free list.
+ It checks the size of this buffer. If it is smaller than the
+ the CurMaxReceiveBufferSize, then it does not return this back
+ to the free list, instead it destroys it and possibly also
+ destroys the pool associated with it. O/w it simply returns this
+ to the free list.
+
+Arguments:
+
+ ReceiveBuffer - Pointer to the buffer to be returned to the free list.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+#if defined(DBG)
+ ULONG BufLen = 0;
+#endif
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+#if defined(DBG)
+ NdisQueryBuffer( ReceiveBuffer->NdisBuffer, NULL, &BufLen );
+ CTEAssert( BufLen == ReceiveBufferPool->BufferDataSize );
+#endif
+
+ //
+ // This is an old buffer which was in use when we changed
+ // the CurMaxReceiveBufferSize due to new adapter. We must not
+ // return this buffer back to free list. Infact, if the pool
+ // associated with this buffer does not have any other buffers
+ // in use, we should free the pool also.
+ CTEAssert( ReceiveBufferPool->BufferFree < ReceiveBufferPool->BufferCount );
+ ReceiveBufferPool->BufferFree++;
+
+ if ( ReceiveBufferPool->BufferDataSize < Device->CurMaxReceiveBufferSize ) {
+
+#if DBG
+ DbgPrint("ReceiveBuffer %lx, not returned to pool %lx( Free %d)\n", ReceiveBuffer, ReceiveBufferPool, ReceiveBufferPool->BufferFree);
+#endif
+
+
+ if ( ReceiveBufferPool->BufferFree == ReceiveBufferPool->BufferCount ) {
+ NbiFreeReceiveBufferPool( ReceiveBufferPool );
+ }
+ } else {
+
+ PushEntryList( &Device->ReceiveBufferList, &ReceiveBuffer->PoolLinkage );
+
+
+ }
+
+ NB_FREE_LOCK( &Device->Lock, LockHandle );
+}
+#endif _PNP_POWER
+
+
+PSINGLE_LIST_ENTRY
+NbiPopSendPacket(
+ IN PDEVICE Device,
+ IN BOOLEAN LockAcquired
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+ LockAcquired - TRUE if Device->Lock is acquired.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (!LockAcquired) {
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+ }
+
+ if (Device->AllocatedSendPackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateSendPool (Device);
+
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ return s;
+ } else {
+
+ if (!LockAcquired) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ return NULL;
+ }
+
+} /* NbiPopSendPacket */
+
+
+VOID
+NbiPushSendPacket(
+ IN PNB_SEND_RESERVED Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a packet back to the device context's pool.
+ If there are connections waiting for packets, it removes
+ one from the list and inserts it on the packetize queue.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ &Reserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // BUGBUG: Make this a function. Optimize for
+ // UP by not doing two checks?
+ //
+
+ if (!IsListEmpty (&Device->WaitPacketConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = RemoveHeadList (&Device->WaitPacketConnections);
+
+ //
+ // Take a connection off the WaitPacketQueue and put it
+ // on the PacketizeQueue. We don't worry about if the
+ // connection has stopped, that will get checked when
+ // the PacketizeQueue is run down.
+ //
+ // Since this is in send completion, we may not get
+ // a receive complete. We guard against this by calling
+ // NbiReceiveComplete from the long timer timeout.
+ //
+
+ if (p != &Device->WaitPacketConnections) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, WaitPacketLinkage);
+
+ CTEAssert (Connection->OnWaitPacketQueue);
+ Connection->OnWaitPacketQueue = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPushSendPacket */
+
+
+VOID
+NbiCheckForWaitPacket(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks if a connection is on the wait packet
+ queue and if so takes it off and queues it to be packetized.
+ It is meant to be called when the connection's packet has
+ been freed.
+
+Arguments:
+
+ Connection - The connection to check.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle1);
+
+ if (Connection->OnWaitPacketQueue) {
+
+ Connection->OnWaitPacketQueue = FALSE;
+ RemoveEntryList (&Connection->WaitPacketLinkage);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NbiTransferReferenceConnection (Connection, CREF_W_PACKET, CREF_PACKETIZE);
+
+ InsertTailList(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage);
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NbiDereferenceConnection (Connection, CREF_W_PACKET);
+
+ return;
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle1);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiCheckForWaitPacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceivePacket(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a packet from the device context's pool.
+ If there are no packets in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the packet to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated packet.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No packets in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceivePackets < Device->MaxPackets) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceivePool (Device);
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ s = ExInterlockedPopEntrySList(
+ &Device->ReceivePacketList,
+ &NbiGlobalPoolInterlock);
+
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+
+} /* NbiPopReceivePacket */
+
+
+PSINGLE_LIST_ENTRY
+NbiPopReceiveBuffer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a receive buffer from the device context's pool.
+ If there are no buffers in the pool, it allocates one up to
+ the configured limit.
+
+Arguments:
+
+ Device - Pointer to our device to charge the buffer to.
+
+Return Value:
+
+ The pointer to the Linkage field in the allocated receive buffer.
+
+--*/
+
+{
+#if defined(_PNP_POWER)
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PNB_RECEIVE_BUFFER_POOL ReceiveBufferPool;
+ CTELockHandle LockHandle;
+
+ NB_GET_LOCK( &Device->Lock, &LockHandle );
+
+ s = PopEntryList( &Device->ReceiveBufferList );
+
+
+ if ( !s ) {
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+
+ NbiAllocateReceiveBufferPool (Device, Device->CurMaxReceiveBufferSize );
+ s = PopEntryList(&Device->ReceiveBufferList);
+ }
+ }
+
+ if ( s ) {
+
+
+ //
+ // Decrement the BufferFree count on the corresponding ReceiveBufferPool.
+ // so that we know that
+ ReceiveBuffer = CONTAINING_RECORD( s, NB_RECEIVE_BUFFER, PoolLinkage );
+
+
+ ReceiveBufferPool = (PNB_RECEIVE_BUFFER_POOL)ReceiveBuffer->Pool;
+
+ CTEAssert( ReceiveBufferPool->BufferFree && ( ReceiveBufferPool->BufferFree <= ReceiveBufferPool->BufferCount ) );
+ CTEAssert( ReceiveBufferPool->BufferDataSize == Device->CurMaxReceiveBufferSize );
+
+ ReceiveBufferPool->BufferFree--;
+
+ }
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+#else
+ PSINGLE_LIST_ENTRY s;
+ CTELockHandle LockHandle;
+
+ s = ExInterlockedPopEntryList(
+ &Device->ReceiveBufferList,
+ &Device->Lock.Lock);
+
+ if (s != NULL) {
+ return s;
+ }
+
+ //
+ // No buffer in the pool, see if we can allocate more.
+ //
+
+ if (Device->AllocatedReceiveBuffers < Device->MaxReceiveBuffers) {
+
+ //
+ // Allocate a pool and try again.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ NbiAllocateReceiveBufferPool (Device);
+ s = PopEntryList(&Device->ReceiveBufferList);
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ return s;
+
+ } else {
+
+ return NULL;
+
+ }
+#endif _PNP_POWER
+} /* NbiPopReceiveBuffer */
+
diff --git a/private/ntos/tdi/isnp/nb/precomp.h b/private/ntos/tdi/isnp/nb/precomp.h
new file mode 100644
index 000000000..a024f2d3d
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/precomp.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Precompilation header file.
+
+Author:
+
+ Adam Barr (adamba) 08-Sep-1993
+
+Revision History:
+
+--*/
+
+#define ISN_NT 1
+
+//
+// These are needed for CTE
+//
+
+#if DBG
+#define DEBUG 1
+#endif
+
+#define NT 1
+
+#include <ntos.h>
+#include <tdikrnl.h>
+#include <ndis.h>
+#include <cxport.h>
+#include <bind.h>
+#include "isnnb.h"
+#include "config.h"
+#include "nbitypes.h"
+#include "nbiprocs.h"
+#include "zwapi.h"
diff --git a/private/ntos/tdi/isnp/nb/query.c b/private/ntos/tdi/isnp/nb/query.c
new file mode 100644
index 000000000..6ee33adf3
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/query.c
@@ -0,0 +1,1817 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ query.c
+
+Abstract:
+
+ This module contains code which performs the following TDI services:
+
+ o TdiQueryInformation
+ o TdiSetInformation
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Remove the warning -- this is defined in windef also.
+//
+
+#ifdef FAR
+#undef FAR
+#endif
+
+#include <windef.h>
+#include <nb30.h>
+
+
+//
+// Useful macro to obtain the total length of a buffer chain.
+// BUGBUG: Make this use NDIS macros.
+//
+
+#define NbiGetBufferChainLength(Buffer, Length) { \
+ PNDIS_BUFFER _Buffer = (Buffer); \
+ *(Length) = 0; \
+ while (_Buffer) { \
+ *(Length) += MmGetMdlByteCount(_Buffer); \
+ _Buffer = _Buffer->Next; \
+ } \
+}
+
+
+NTSTATUS
+NbiTdiQueryInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiQueryInformation request for the transport
+ provider.
+
+Arguments:
+
+ Request - the request for the operation.
+
+Return Value:
+
+ The status of operation.
+
+--*/
+
+{
+ NTSTATUS Status;
+ PTDI_REQUEST_KERNEL_QUERY_INFORMATION Query;
+ PADDRESS_FILE AddressFile;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ union {
+ struct {
+ ULONG ActivityCount;
+ TA_NETBIOS_ADDRESS NbiAddress;
+ } AddressInfo;
+ TA_NETBIOS_ADDRESS BroadcastAddress;
+ TDI_ADDRESS_IPX IpxAddress;
+ TDI_DATAGRAM_INFO DatagramInfo;
+ struct {
+ FIND_NAME_HEADER Header;
+ FIND_NAME_BUFFER Buffer;
+ } FindNameInfo;
+ } TempBuffer;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ PADAPTER_STATUS AdapterStatus;
+ BOOLEAN RemoteAdapterStatus;
+ TDI_ADDRESS_NETBIOS UNALIGNED * RemoteAddress;
+ ULONG TargetBufferLength;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ ULONG ElementSize, TransportAddressSize;
+ PTRANSPORT_ADDRESS TransportAddress;
+ TA_ADDRESS UNALIGNED * CurAddress;
+ PNETBIOS_CACHE CacheName;
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+ NTSTATUS QueryStatus;
+ CTELockHandle LockHandle;
+ PLIST_ENTRY p;
+ BOOLEAN UsedConnection;
+ UINT i;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ Query = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Request);
+
+ switch (Query->QueryType) {
+
+ case TDI_QUERY_ADDRESS_INFO:
+
+ //
+ // The caller wants the exact address value.
+ //
+
+ if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+
+ AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
+
+#if defined(_PNP_POWER)
+ Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
+#else
+ Status = NbiVerifyAddressFile (AddressFile);
+#endif _PNP_POWER
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = FALSE;
+
+ } else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) {
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ UsedConnection = TRUE;
+
+ AddressFile = Connection->AddressFile;
+
+ } else {
+
+ Status = STATUS_INVALID_ADDRESS;
+ break;
+
+ }
+
+ Address = AddressFile->Address;
+
+ NB_DEBUG2 (QUERY, ("Query address info on %lx\n", AddressFile));
+
+ TempBuffer.AddressInfo.ActivityCount = 0;
+
+ NB_GET_LOCK (&Address->Lock, &LockHandle);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ if (CONTAINING_RECORD (p, ADDRESS_FILE, Linkage)->State == ADDRESSFILE_STATE_OPEN) {
+ ++TempBuffer.AddressInfo.ActivityCount;
+ }
+ }
+
+ NB_FREE_LOCK (&Address->Lock, LockHandle);
+
+ TdiBuildNetbiosAddress(
+ AddressFile->Address->NetbiosAddress.NetbiosName,
+ (BOOLEAN)(AddressFile->Address->NetbiosAddress.NetbiosNameType == TDI_ADDRESS_NETBIOS_TYPE_GROUP),
+ &TempBuffer.AddressInfo.NbiAddress);
+
+ Status = TdiCopyBufferToMdl(
+ &TempBuffer.AddressInfo,
+ 0,
+ sizeof(ULONG) + sizeof(TA_NETBIOS_ADDRESS),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ if (UsedConnection) {
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ } else {
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
+
+ }
+
+ break;
+
+ case TDI_QUERY_CONNECTION_INFO:
+
+ //
+ // Connection info is queried on a connection,
+ // verify this.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ Status = NbiVerifyConnection (Connection);
+
+ if (!NT_SUCCESS (Status)) {
+ return Status;
+ }
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Status = STATUS_INVALID_CONNECTION;
+
+ } else {
+
+ //
+ // Assume 50 ms of delay for every hop after the
+ // first. The delay is returned as a negative number.
+ //
+
+ if (Connection->HopCount > 1) {
+ Connection->ConnectionInfo.Delay.HighPart = (ULONG)-1;
+ Connection->ConnectionInfo.Delay.LowPart =
+ -((Connection->HopCount-1) * 50 * MILLISECONDS);
+ } else {
+ Connection->ConnectionInfo.Delay.HighPart = 0;
+ Connection->ConnectionInfo.Delay.LowPart = 0;
+ }
+
+ //
+ // We have tick count; to convert to bytes/second we do:
+ //
+ // packet 576 bytes 18.21 ticks
+ // ---------------- * --------- * -----------
+ // tick_count ticks packet seconds
+ //
+ // to get 10489/tick_count = bytes/second. We
+ // double this because routers tend to
+ // overestimate it.
+ //
+ // Since tick_count has such a low granularity,
+ // a tick count of 1 gives us a throughput of
+ // only 84 kbps, which is much too low. In
+ // that case we return twice the link speed
+ // which is in 100 bps units; that corresponds
+ // to about 1/6 of our bandwidth in bytes/sec.
+ //
+
+ if (Connection->TickCount <= Connection->HopCount) {
+
+ Connection->ConnectionInfo.Throughput.QuadPart =
+ UInt32x32To64 (Connection->LineInfo.LinkSpeed, 2);
+
+ } else {
+
+ Connection->ConnectionInfo.Throughput.HighPart = 0;
+ Connection->ConnectionInfo.Throughput.LowPart =
+ 20978 / (Connection->TickCount - Connection->HopCount);
+
+ }
+
+ Connection->ConnectionInfo.Unreliable = FALSE;
+
+ Status = TdiCopyBufferToMdl (
+ &Connection->ConnectionInfo,
+ 0,
+ sizeof(TDI_CONNECTION_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_VERIFY);
+
+ break;
+
+ case TDI_QUERY_PROVIDER_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query provider info\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Information,
+ 0,
+ sizeof (TDI_PROVIDER_INFO),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_BROADCAST_ADDRESS:
+
+ //
+ // for this provider, the broadcast address is a zero byte name,
+ // contained in a Transport address structure.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query broadcast address\n"));
+
+ TempBuffer.BroadcastAddress.TAAddressCount = 1;
+ TempBuffer.BroadcastAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
+ TempBuffer.BroadcastAddress.Address[0].AddressLength = 0;
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.BroadcastAddress,
+ 0L,
+ sizeof (TempBuffer.BroadcastAddress.TAAddressCount) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressType) +
+ sizeof (TempBuffer.BroadcastAddress.Address[0].AddressLength),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ break;
+
+ case TDI_QUERY_ADAPTER_STATUS:
+
+ //
+ // Determine if this is a local or remote query.
+ //
+
+ RemoteAdapterStatus = FALSE;
+
+ if (Query->RequestConnectionInformation != NULL) {
+
+ RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE);
+
+ if (RemoteAddress == NULL) {
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+#if defined(_PNP_POWER)
+ if ( !NbiFindAdapterAddress(
+ RemoteAddress->NetbiosName,
+ LOCK_NOT_ACQUIRED ) ) {
+
+ RemoteAdapterStatus = TRUE;
+ }
+#else
+ if (!RtlEqualMemory(
+ RemoteAddress->NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+
+ RemoteAdapterStatus = TRUE;
+
+ }
+#endif _PNP_POWER
+
+ }
+
+ if (RemoteAdapterStatus) {
+
+ //
+ // See if we have this name cached.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameOther,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this status
+ // request and processing will be resumed when
+ // we get a response.
+ //
+ // The status field in the request will hold
+ // the cache entry for the remote. The information
+ // field will hold the remote netbios name while
+ // it is in the WaitingAdapterStatus queue, and
+ // will hold a timeout value while we it is in
+ // the ActiveAdapterStatus queue.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up adapter status %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ InsertTailList(
+ &Device->WaitingAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found adapter status cached %lx\n", Request));
+
+ //
+ // We reference the cache name entry so it won't
+ // go away while we are using it.
+ //
+
+ REQUEST_STATUS(Request) = (NTSTATUS)CacheName;
+ ++CacheName->ReferenceCount;
+
+ NbiReferenceDevice (Device, DREF_STATUS_QUERY);
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ InsertTailList(
+ &Device->ActiveAdapterStatus,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ NbiSendStatusQuery (Request);
+
+ Status = STATUS_PENDING;
+
+ } else {
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // Local adapter status.
+ //
+
+ NbiGetBufferChainLength (REQUEST_NDIS_BUFFER(Request), &TargetBufferLength);
+
+ Status = NbiStoreAdapterStatus(
+ TargetBufferLength,
+ 1, // NIC ID, was 0, changed to 1 for Bug #18026
+ // because for NicId = 0, Ipx returns virtual
+ // address. Netbios uses that to register the
+ // name (00...01) and fails.
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+
+ //
+ // This should succeed since we know the length
+ // will fit.
+ //
+
+ (VOID)TdiCopyBufferToMdl(
+ AdapterStatus,
+ 0,
+ ValidStatusLength,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+
+ }
+
+ }
+
+ break;
+
+ case TDI_QUERY_FIND_NAME:
+
+ //
+ // Check that there is a valid Netbios remote address.
+ //
+
+ if ((Query->RequestConnectionInformation == NULL) ||
+ ((RemoteAddress = NbiParseTdiAddress(Query->RequestConnectionInformation->RemoteAddress, FALSE)) == NULL)) {
+
+ return STATUS_BAD_NETWORK_PATH;
+ }
+
+ //
+ // We assume the entire request buffer is in the first
+ // piece of the MDL chain (BUGBUG: Can we do this?).
+ // Make sure there is room for at least the header.
+ //
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER)) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+
+ //
+ // See if we have this name cached. We specify that this is
+ // a netbios name query, so this will only succeed if this is a
+ // unique name -- for a group name it will queue up a find
+ // name query and when we get the response we will fill in
+ // the request's buffer based on it.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Status = CacheFindName(
+ Device,
+ FindNameNetbiosFindName,
+ RemoteAddress->NetbiosName,
+ &CacheName);
+
+ if (Status == STATUS_PENDING) {
+
+ //
+ // A request for routes to this name has been
+ // sent out on the net, we queue up this find
+ // name request and processing will be resumed when
+ // we get a response.
+ //
+ // The information field will hold the remote
+ // netbios name while it is in the WaitingNetbiosFindName
+ // queue. The status will hold the current status --
+ // initially failure, then success, then overflow
+ // if the buffer is too small.
+ //
+
+ NB_DEBUG2 (QUERY, ("Queueing up find name %lx\n", Request));
+
+ NbiReferenceDevice (Device, DREF_NB_FIND_NAME);
+
+ FindNameHeader->node_count = 0;
+ FindNameHeader->reserved = 0;
+ FindNameHeader->unique_group = 0;
+
+ REQUEST_INFORMATION (Request) = (ULONG)RemoteAddress;
+
+ //
+ // Assume it fails, we update the status to
+ // SUCCESS or BUFFER_OVERFLOW if needed.
+ //
+
+ REQUEST_STATUS (Request) = STATUS_IO_TIMEOUT;
+
+ InsertTailList(
+ &Device->WaitingNetbiosFindName,
+ REQUEST_LINKAGE (Request));
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ NB_DEBUG2 (QUERY, ("Found find name cached %lx\n", Request));
+
+ //
+ // We don't need to reference the cache entry since
+ // we only use it here with the lock still held.
+ //
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query. Since we
+ // use TempBuffer.IpxAddress for this query, we have
+ // to immediately copy it to its correct place in
+ // TempBuffer.FindNameInfo.Buffer.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicHandle.NicId ));
+
+ goto QueryFindNameFailed;
+ }
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ CacheName->Networks[0].LocalTarget.NicId,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ RtlMoveMemory (TempBuffer.FindNameInfo.Buffer.destination_addr, TempBuffer.IpxAddress.NodeAddress, 6);
+ TempBuffer.FindNameInfo.Buffer.access_control = 0x10; // standard token-ring values
+ TempBuffer.FindNameInfo.Buffer.frame_control = 0x40;
+ RtlCopyMemory (TempBuffer.FindNameInfo.Buffer.source_addr, CacheName->FirstResponse.NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, CacheName->FirstResponse.NodeAddress, 6);
+
+ QueryStatus = (*Device->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ &CacheName->Networks[0].LocalTarget.NicHandle,
+#else
+ CacheName->Networks[0].LocalTarget.NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(TempBuffer.FindNameInfo.Buffer.routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ TempBuffer.FindNameInfo.Buffer.routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ TempBuffer.FindNameInfo.Buffer.length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ TempBuffer.FindNameInfo.Header.node_count = 1;
+ TempBuffer.FindNameInfo.Header.reserved = 0;
+ TempBuffer.FindNameInfo.Header.unique_group = 0; // unique
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ Status = TdiCopyBufferToMdl (
+ (PVOID)&TempBuffer.FindNameInfo,
+ 0,
+ sizeof(FIND_NAME_HEADER) + 33,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+ } else {
+
+#if defined(_PNP_POWER)
+QueryFindNameFailed:
+#endif _PNP_POWER
+
+ if (Status != STATUS_INSUFFICIENT_RESOURCES) {
+ Status = STATUS_IO_TIMEOUT;
+ }
+
+ REQUEST_INFORMATION (Request) = 0;
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+
+ break;
+
+ case TDI_QUERY_PROVIDER_STATISTICS:
+
+ //
+ // BETABUGBUG: Keep track of more of these.
+ //
+
+ NB_DEBUG2 (QUERY, ("Query provider statistics\n"));
+
+ Status = TdiCopyBufferToMdl (
+ &Device->Statistics,
+ 0,
+ FIELD_OFFSET (TDI_PROVIDER_STATISTICS, ResourceStats[0]),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATAGRAM_INFO:
+
+ NB_DEBUG2 (QUERY, ("Query datagram info\n"));
+
+ TempBuffer.DatagramInfo.MaximumDatagramBytes = 0;
+ TempBuffer.DatagramInfo.MaximumDatagramCount = 0;
+
+ Status = TdiCopyBufferToMdl (
+ &TempBuffer.DatagramInfo,
+ 0,
+ sizeof(TempBuffer.DatagramInfo),
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+ break;
+
+ case TDI_QUERY_DATA_LINK_ADDRESS:
+ case TDI_QUERY_NETWORK_ADDRESS:{
+#if defined(_PNP_POWER)
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS
+ ? IPX_QUERY_DATA_LINK_ADDRESS
+ : IPX_QUERY_NETWORK_ADDRESS ),
+ NULL,
+ Request,
+ 0,
+ NULL);
+#else
+ ULONG TransportAddressAllocSize;
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ ElementSize = (2 * sizeof(USHORT)) + 6;
+ } else {
+ ElementSize = (2 * sizeof(USHORT)) + sizeof(TDI_ADDRESS_IPX);
+ }
+
+// TransportAddress = CTEAllocMem(sizeof(int) + (ElementSize * Device->MaximumNicId));
+ TransportAddressAllocSize = sizeof(int) + ( ElementSize * Device->MaximumNicId);
+ TransportAddress = NbiAllocateMemory( TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ if (TransportAddress == NULL) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ TransportAddress->TAAddressCount = 0;
+ TransportAddressSize = sizeof(int);
+ CurAddress = (TA_ADDRESS UNALIGNED *)TransportAddress->Address;
+
+ for (i = 1; i <= Device->MaximumNicId; i++) {
+
+ Status = (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ (USHORT)i,
+ &TempBuffer.IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ if (Status != STATUS_SUCCESS) {
+ continue;
+ }
+
+ if (Query->QueryType == TDI_QUERY_DATA_LINK_ADDRESS) {
+ CurAddress->AddressLength = 6;
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_UNSPEC;
+ RtlCopyMemory (CurAddress->Address, TempBuffer.IpxAddress.NodeAddress, 6);
+ } else {
+ CurAddress->AddressLength = sizeof(TDI_ADDRESS_IPX);
+ CurAddress->AddressType = TDI_ADDRESS_TYPE_IPX;
+ RtlCopyMemory (CurAddress->Address, &TempBuffer.IpxAddress, sizeof(TDI_ADDRESS_IPX));
+ }
+ ++TransportAddress->TAAddressCount;
+ TransportAddressSize += ElementSize;
+ CurAddress = (TA_ADDRESS UNALIGNED *)(((PUCHAR)CurAddress) + ElementSize);
+
+ }
+
+ Status = TdiCopyBufferToMdl (
+ TransportAddress,
+ 0,
+ TransportAddressSize,
+ REQUEST_NDIS_BUFFER(Request),
+ 0,
+ &REQUEST_INFORMATION(Request));
+
+// CTEFreeMem (TransportAddress);
+ NbiFreeMemory( TransportAddress, TransportAddressAllocSize, MEMORY_QUERY, "Temp Query Allocation");
+
+ }
+#endif _PNP_POWER
+ break;
+ }
+ default:
+
+ NB_DEBUG (QUERY, ("Invalid query type %d\n", Query->QueryType));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ return Status;
+
+} /* NbiTdiQueryInformation */
+
+
+NTSTATUS
+NbiStoreAdapterStatus(
+ IN ULONG MaximumLength,
+ IN USHORT NicId,
+ OUT PVOID * StatusBuffer,
+ OUT ULONG * StatusBufferLength,
+ OUT ULONG * ValidBufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an ADAPTER_STATUS buffer and
+ fills it in. The buffer will be allocated at most
+ MaximumLength size. The caller is responsible for
+ freeing the buffer.
+
+Arguments:
+
+ MaximumLength - The maximum length to allocate.
+
+ NicId - The NIC ID the query was received on, or 0 for
+ a local query.
+
+ StatusBuffer - Returns the allocated buffer.
+
+ StatusBufferLength - Returns the length of the buffer.
+
+ ValidBufferLength - Returns the length of the buffer which
+ contains valid adapter status data.
+
+Return Value:
+
+ STATUS_SUCCESS - The buffer was written successfully.
+ STATUS_BUFFER_OVERFLOW - The buffer was written but not all
+ data could fit in MaximumLength bytes.
+ STATUS_INSUFFICIENT_RESOURCES - The buffer could not be allocated.
+
+--*/
+
+{
+
+ PADAPTER_STATUS AdapterStatus;
+ PNAME_BUFFER NameBuffer;
+ ADAPTER_STATUS TempAdapterStatus;
+#if !defined(_PNP_POWER)
+ TDI_ADDRESS_IPX IpxAddress;
+#endif !_PNP_POWER
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ UCHAR NameCount;
+ ULONG LengthNeeded;
+ ULONG BytesWritten;
+ NTSTATUS Status;
+ PLIST_ENTRY p;
+ CTELockHandle LockHandle;
+
+
+ //
+ // First fill in the basic adapter status structure, to make
+ // it easier to copy over if the target buffer is really short.
+ //
+
+ RtlZeroMemory ((PVOID)&TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+#if defined(_PNP_POWER)
+ RtlCopyMemory (TempAdapterStatus.adapter_address, Device->Bind.Node, 6);
+#else
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &IpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+
+ RtlCopyMemory (TempAdapterStatus.adapter_address, IpxAddress.NodeAddress, 6);
+#endif _PNP_POWER
+
+
+ //
+ // Some of the fields mean different things for Novell Netbios,
+ // as described in the comments.
+ //
+
+ TempAdapterStatus.rev_major = 0; // Jumpers
+ TempAdapterStatus.reserved0 = 0; // SelfTest
+ TempAdapterStatus.adapter_type = 0; // MajorVersion
+ TempAdapterStatus.rev_minor = 0; // MinorVersion
+
+ TempAdapterStatus.duration = 0; // ReportingPeriod
+ TempAdapterStatus.frmr_recv = 0; // ReceiveCRCErrors
+ TempAdapterStatus.frmr_xmit = 0; // ReceiveAlignErrors
+
+ TempAdapterStatus.iframe_recv_err = 0; // XmitCollisions
+ TempAdapterStatus.xmit_aborts = 0; // XmitAbort
+
+ TempAdapterStatus.xmit_success = Device->Statistics.DataFramesSent; // SuccessfulXmits
+ TempAdapterStatus.recv_success = Device->Statistics.DataFramesReceived; // SuccessfulReceive
+
+ TempAdapterStatus.iframe_xmit_err = (WORD)Device->Statistics.DataFramesResent; // XmitRetries
+ TempAdapterStatus.recv_buff_unavail = (WORD)Device->Statistics.DataFramesRejected; // ExhaustedResource
+
+ // t1_timeouts, ti_timeouts, and reserved1 are unused.
+
+ TempAdapterStatus.free_ncbs = 0xffff; // FreeBlocks
+ TempAdapterStatus.max_cfg_ncbs = 0xffff; // ConfiguredNCB
+ TempAdapterStatus.max_ncbs = 0xffff; // MaxNCB
+
+ // xmit_bug_unavail and max_dgram_size are unused.
+
+ TempAdapterStatus.pending_sess = (WORD)Device->Statistics.OpenConnections; // CurrentSessions
+ TempAdapterStatus.max_cfg_sess = 0xffff; // MaxSessionConfigured
+ TempAdapterStatus.max_sess = 0xffff; // MaxSessionPossible
+ TempAdapterStatus.max_sess_pkt_size =
+ Device->Bind.LineInfo.MaximumSendSize - sizeof(NB_CONNECTION); // MaxSessionPacketSize
+
+ TempAdapterStatus.name_count = 0;
+
+
+ //
+ // Do a quick estimate of how many names we need room for.
+ // This includes stopping addresses and the broadcast
+ // address, for the moment. BUGBUG: Fix this?
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ LengthNeeded = sizeof(ADAPTER_STATUS) + (Device->AddressCount * sizeof(NAME_BUFFER));
+
+ if (LengthNeeded > MaximumLength) {
+ LengthNeeded = MaximumLength;
+ }
+
+ AdapterStatus = NbiAllocateMemory(LengthNeeded, MEMORY_STATUS, "Adapter Status");
+ if (AdapterStatus == NULL) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *StatusBuffer = AdapterStatus;
+ *StatusBufferLength = LengthNeeded;
+
+ if (LengthNeeded < sizeof(ADAPTER_STATUS)) {
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, LengthNeeded);
+ *ValidBufferLength = LengthNeeded;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ RtlCopyMemory (AdapterStatus, &TempAdapterStatus, sizeof(ADAPTER_STATUS));
+
+ BytesWritten = sizeof(ADAPTER_STATUS);
+ NameBuffer = (PNAME_BUFFER)(AdapterStatus+1);
+ NameCount = 0;
+
+ //
+ // Scan through the device's address database, filling in
+ // the NAME_BUFFERs.
+ //
+
+ Status = STATUS_SUCCESS;
+
+ for (p = Device->AddressDatabase.Flink;
+ p != &Device->AddressDatabase;
+ p = p->Flink) {
+
+ Address = CONTAINING_RECORD (p, ADDRESS, Linkage);
+
+ //
+ // Ignore addresses that are shutting down.
+ //
+
+#if defined(_PNP_POWER)
+ if ((Address->State != ADDRESS_STATE_OPEN) ||
+ (Address->Flags & ADDRESS_FLAGS_CONFLICT)) {
+ continue;
+ }
+#else
+ if ((Address->State != ADDRESS_STATE_OPEN) != 0) {
+ continue;
+ }
+#endif _PNP_POWER
+
+ //
+ // Ignore the broadcast address.
+ //
+
+ if (Address->NetbiosAddress.Broadcast) {
+ continue;
+ }
+
+ //
+ // Ignore our reserved address.
+ //
+#if defined(_PNP_POWER)
+ if ( NbiFindAdapterAddress(
+ Address->NetbiosAddress.NetbiosName,
+ LOCK_ACQUIRED
+ )) {
+ continue;
+ }
+#else
+ if (RtlEqualMemory(
+ Address->NetbiosAddress.NetbiosName,
+ Device->ReservedNetbiosName,
+ 16)) {
+ continue;
+ }
+
+#endif _PNP_POWER
+ //
+ // Make sure we still have room.
+ //
+
+ if (BytesWritten + sizeof(NAME_BUFFER) > LengthNeeded) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ break;
+ }
+
+ RtlCopyMemory(
+ NameBuffer->name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ ++NameCount;
+ NameBuffer->name_num = NameCount;
+
+ NameBuffer->name_flags = REGISTERED;
+ if (Address->NameTypeFlag == NB_NAME_GROUP) {
+ NameBuffer->name_flags |= GROUP_NAME;
+ }
+
+ //
+ // BUGBUG: name_flags should be done more accurately.
+ //
+
+ BytesWritten += sizeof(NAME_BUFFER);
+ ++NameBuffer;
+
+ }
+
+ AdapterStatus->name_count = (WORD)NameCount;
+ *ValidBufferLength = BytesWritten;
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return Status;
+
+} /* NbiStoreAdapterStatus */
+
+
+VOID
+NbiUpdateNetbiosFindName(
+ IN PREQUEST Request,
+#if defined(_PNP_POWER)
+ IN PNIC_HANDLE NicHandle,
+#else
+ IN USHORT NicId,
+#endif _PNP_POWER
+ IN TDI_ADDRESS_IPX UNALIGNED * RemoteIpxAddress,
+ IN BOOLEAN Unique
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the find name request with the
+ new information received. It updates the status in
+ the request if needed.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+ NicId - The NIC ID the response was received on.
+
+ RemoteIpxAddress - The IPX address of the remote.
+
+ Unique - TRUE if the name is unique.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ FIND_NAME_BUFFER UNALIGNED * FindNameBuffer;
+ UINT FindNameBufferLength;
+ TDI_ADDRESS_IPX LocalIpxAddress;
+ IPX_SOURCE_ROUTING_INFO SourceRoutingInfo;
+ NTSTATUS QueryStatus;
+ UINT i;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // Scan through the names saved so far and see if this one
+ // is there.
+ //
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)(FindNameHeader+1);
+
+ for (i = 0; i < FindNameHeader->node_count; i++) {
+
+ if (RtlEqualMemory(
+ FindNameBuffer->source_addr,
+ RemoteIpxAddress->NodeAddress,
+ 6)) {
+
+ //
+ // This remote already responded, ignore it.
+ //
+
+ return;
+
+ }
+
+ FindNameBuffer = (FIND_NAME_BUFFER UNALIGNED *)
+ (((PUCHAR)FindNameBuffer) + 33);
+
+ }
+
+ //
+ // Make sure there is room for this new node. 33 is
+ // sizeof(FIND_NAME_BUFFER) without padding.
+ //
+
+ if (FindNameBufferLength < sizeof(FIND_NAME_HEADER) + ((FindNameHeader->node_count+1) * 33)) {
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+ return;
+ }
+
+ //
+ // Query the local address, which we will return as
+ // the destination address of this query.
+ //
+
+#if defined(_PNP_POWER)
+ if( (*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicHandle,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Ignore this response if the query fails. maybe the NicHandle
+ // is bad or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_IPX_ADDRESS,
+ NicHandle->NicId ));
+ return;
+ }
+#else
+ (VOID)(*NbiDevice->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_IPX_ADDRESS,
+ NicId,
+ &LocalIpxAddress,
+ sizeof(TDI_ADDRESS_IPX),
+ NULL);
+#endif _PNP_POWER
+
+ FindNameBuffer->access_control = 0x10; // standard token-ring values
+ FindNameBuffer->frame_control = 0x40;
+ RtlMoveMemory (FindNameBuffer->destination_addr, LocalIpxAddress.NodeAddress, 6);
+ RtlCopyMemory (FindNameBuffer->source_addr, RemoteIpxAddress->NodeAddress, 6);
+
+ //
+ // Query source routing information about this remote, if any.
+ //
+
+ SourceRoutingInfo.Identifier = IDENTIFIER_NB;
+ RtlCopyMemory (SourceRoutingInfo.RemoteAddress, RemoteIpxAddress->NodeAddress, 6);
+
+ QueryStatus = (*NbiDevice->Bind.QueryHandler)(
+ IPX_QUERY_SOURCE_ROUTING,
+#if defined(_PNP_POWER)
+ NicHandle,
+#else
+ NicId,
+#endif _PNP_POWER
+ &SourceRoutingInfo,
+ sizeof(IPX_SOURCE_ROUTING_INFO),
+ NULL);
+
+ RtlZeroMemory(FindNameBuffer->routing_info, 18);
+ if (QueryStatus != STATUS_SUCCESS) {
+ SourceRoutingInfo.SourceRoutingLength = 0;
+ } else if (SourceRoutingInfo.SourceRoutingLength > 0) {
+ RtlMoveMemory(
+ FindNameBuffer->routing_info,
+ SourceRoutingInfo.SourceRouting,
+ SourceRoutingInfo.SourceRoutingLength);
+ }
+
+ FindNameBuffer->length = (UCHAR)(14 + SourceRoutingInfo.SourceRoutingLength);
+
+ ++FindNameHeader->node_count;
+ if (!Unique) {
+ FindNameHeader->unique_group = 1; // group
+ }
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+} /* NbiUpdateNetbiosFindName */
+
+
+VOID
+NbiSetNetbiosFindNameInformation(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the REQUEST_INFORMATION field to the right
+ value based on the number of responses recorded in the netbios
+ find name request's buffer.
+
+Arguments:
+
+ Request - The netbios find name request.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FIND_NAME_HEADER UNALIGNED * FindNameHeader;
+ UINT FindNameBufferLength;
+
+
+ NdisQueryBuffer(REQUEST_NDIS_BUFFER(Request), (PVOID *)&FindNameHeader, &FindNameBufferLength);
+
+ //
+ // 33 is sizeof(FIND_NAME_BUFFER) without the padding.
+ //
+
+ REQUEST_INFORMATION(Request) = sizeof(FIND_NAME_HEADER) + (FindNameHeader->node_count * 33);
+
+} /* NbiSetNetbiosFindNameInformation */
+
+
+NTSTATUS
+NbiTdiSetInformation(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiSetInformation request for the transport
+ provider.
+
+Arguments:
+
+ Device - the device.
+
+ Request - the request for the operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER (Device);
+ UNREFERENCED_PARAMETER (Request);
+
+ return STATUS_NOT_IMPLEMENTED;
+
+} /* NbiTdiSetInformation */
+
+
+VOID
+NbiProcessStatusQuery(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ IPX_LINE_INFO LineInfo;
+ ULONG ResponseSize;
+ NTSTATUS Status;
+ PNDIS_BUFFER AdapterStatusBuffer;
+ PADAPTER_STATUS AdapterStatus;
+ ULONG AdapterStatusLength;
+ ULONG ValidStatusLength;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)PacketBuffer;
+
+
+ //
+ // The old stack does not include the 14 bytes of padding in
+ // the 802.3 or IPX length of the packet.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + 2)) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+#if defined(_PNP_POWER)
+ if( (*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ &RemoteAddress->NicHandle,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL) != STATUS_SUCCESS ) {
+ //
+ // Bad NicHandle or it just got removed.
+ //
+ NB_DEBUG( QUERY, ("Ipx Query %d failed for Nic %x\n",IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicHandle.NicId ));
+
+ return;
+ }
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+#else
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ //
+ // Get the maximum size we can send.
+ //
+
+ (VOID)(*Device->Bind.QueryHandler)( // BUGBUG: Check return code
+ IPX_QUERY_LINE_INFO,
+ RemoteAddress->NicId,
+ &LineInfo,
+ sizeof(IPX_LINE_INFO),
+ NULL);
+#endif _PNP_POWER
+
+ ResponseSize = LineInfo.MaximumSendSize - sizeof(IPX_HEADER) - sizeof(NB_STATUS_RESPONSE);
+
+ //
+ // Get the local adapter status (this allocates a buffer).
+ //
+
+ Status = NbiStoreAdapterStatus(
+ ResponseSize,
+#if defined(_PNP_POWER)
+ RemoteAddress->NicHandle.NicId,
+#else
+ RemoteAddress->NicId,
+#endif _PNP_POWER
+ &AdapterStatus,
+ &AdapterStatusLength,
+ &ValidStatusLength);
+
+ if (Status == STATUS_INSUFFICIENT_RESOURCES) {
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ //
+ // Allocate an NDIS buffer to map the extra buffer.
+ //
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &AdapterStatusBuffer,
+ Device->NdisBufferPoolHandle,
+ AdapterStatus,
+ ValidStatusLength);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ NbiFreeMemory (AdapterStatus, AdapterStatusLength, MEMORY_STATUS, "Adapter Status");
+ ExInterlockedPushEntrySList(
+ &Device->SendPacketList,
+ s,
+ &NbiGlobalPoolInterlock);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Reply to AdapterStatus from %lx %2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ *(UNALIGNED ULONG *)Connectionless->IpxHeader.SourceNetwork,
+ Connectionless->IpxHeader.SourceNode[0],
+ Connectionless->IpxHeader.SourceNode[1],
+ Connectionless->IpxHeader.SourceNode[2],
+ Connectionless->IpxHeader.SourceNode[3],
+ Connectionless->IpxHeader.SourceNode[4],
+ Connectionless->IpxHeader.SourceNode[5]));
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_RESPONSE;
+ Reserved->u.SR_AS.ActualBufferLength = AdapterStatusLength;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, Connectionless->IpxHeader.SourceNetwork, 12);
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_RESPONSE)+ValidStatusLength) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_RESPONSE;
+
+ NbiReferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ NdisChainBufferAtBack (Packet, AdapterStatusBuffer);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ RemoteAddress,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + ValidStatusLength,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiSendStatusQuery(
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends NB_CMD_STATUS_QUERY frames.
+
+Arguments:
+
+ Request - Holds the request describing the remote adapter
+ status query. REQUEST_STATUS(Request) points
+ to the netbios cache entry for the remote name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_ENTRY s;
+ PNB_SEND_RESERVED Reserved;
+ PNDIS_PACKET Packet;
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ NDIS_STATUS NdisStatus;
+ PNETBIOS_CACHE CacheName;
+ PIPX_LOCAL_TARGET LocalTarget;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Allocate a packet from the pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+ if (s == NULL) {
+ return;
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_STATUS_QUERY;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(Request);
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ RtlCopyMemory (Header->IpxHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
+
+ LocalTarget = &CacheName->Networks[0].LocalTarget;
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_STATUS_QUERY)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->StatusResponse.ConnectionControlFlag = 0x00;
+ Header->StatusResponse.DataStreamType = NB_CMD_STATUS_QUERY;
+
+ NbiReferenceDevice (Device, DREF_STATUS_FRAME);
+
+
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY),
+ sizeof(IPX_HEADER) + sizeof(NB_STATUS_QUERY))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+} /* NbiProcessStatusQuery */
+
+
+VOID
+NbiProcessStatusResponse(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_STATUS_RESPONSE frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ CTELockHandle LockHandle;
+ PREQUEST AdapterStatusRequest;
+ PNETBIOS_CACHE CacheName;
+ PLIST_ENTRY p;
+ PSINGLE_LIST_ENTRY s;
+ PNDIS_BUFFER TargetBuffer;
+ ULONG TargetBufferLength, BytesToTransfer;
+ ULONG BytesTransferred;
+ NDIS_STATUS NdisStatus;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ BOOLEAN Found;
+ PNAME_BUFFER NameBuffer;
+ UINT i,NameCount = 0;
+ NB_CONNECTIONLESS UNALIGNED * Connectionless =
+ (NB_CONNECTIONLESS UNALIGNED *)LookaheadBuffer;
+
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE))) {
+ return;
+ }
+
+ //
+ // Find out how many names are there.
+ //
+ NameBuffer = (PNAME_BUFFER)(LookaheadBuffer + sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS));
+ if ( LookaheadBufferSize > sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS) ) {
+ NameCount = (LookaheadBufferSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE) + sizeof(ADAPTER_STATUS)) ) /
+ sizeof(NAME_BUFFER);
+ }
+ //
+ // Find a request queued to this remote. If there are
+ // multiple requests outstanding for the same name we
+ // should get multiple responses, so we only need to
+ // find one.
+ //
+
+ NB_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Found = FALSE;
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if ( CacheName->Unique ) {
+ if (RtlEqualMemory(
+ &CacheName->FirstResponse,
+ Connectionless->IpxHeader.SourceNetwork,
+ 12)) {
+ Found = TRUE;
+ break;
+ }
+ } else if ( RtlEqualMemory( CacheName->NetbiosName,NetbiosBroadcastName,16)){
+ //
+ // It's a broadcast name. Any response is fine.
+ //
+ Found = TRUE;
+ break;
+ } else {
+ //
+ // It's group name. Make sure that this remote
+ // has this group name registered with him.
+ //
+ for (i =0;i<NameCount;i++) {
+ if ( (RtlEqualMemory(
+ CacheName->NetbiosName,
+ NameBuffer[i].name,
+ 16)) &&
+
+ (NameBuffer[i].name_flags & GROUP_NAME) ) {
+
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ }
+
+ if (!Found) {
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NB_DEBUG2 (QUERY, ("Got response to AdapterStatus %lx\n", AdapterStatusRequest));
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ NB_FREE_LOCK (&Device->Lock, LockHandle);
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ REQUEST_INFORMATION (AdapterStatusRequest) = 0;
+ REQUEST_STATUS (AdapterStatusRequest) = STATUS_INSUFFICIENT_RESOURCES;
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->Type = RECEIVE_TYPE_ADAPTER_STATUS;
+ ReceiveReserved->u.RR_AS.Request = AdapterStatusRequest;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_SUCCESS;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // Now that we have a packet and a buffer, set up the transfer.
+ // We will complete the request when the transfer completes.
+ //
+
+ TargetBuffer = REQUEST_NDIS_BUFFER (AdapterStatusRequest);
+
+ NdisChainBufferAtFront (Packet, TargetBuffer);
+
+ NbiGetBufferChainLength (TargetBuffer, &TargetBufferLength);
+ BytesToTransfer = PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE));
+ if (TargetBufferLength < BytesToTransfer) {
+ BytesToTransfer = TargetBufferLength;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_BUFFER_OVERFLOW;
+ }
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + (sizeof(IPX_HEADER) + sizeof(NB_STATUS_RESPONSE)),
+ BytesToTransfer,
+ Packet,
+ &BytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (BytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete(
+ Packet,
+ NdisStatus,
+ BytesTransferred);
+
+ }
+
+} /* NbiProcessStatusResponse */
+
diff --git a/private/ntos/tdi/isnp/nb/receive.c b/private/ntos/tdi/isnp/nb/receive.c
new file mode 100644
index 000000000..54ce78944
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/receive.c
@@ -0,0 +1,1303 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ receive.c
+
+Abstract:
+
+ This module contains the code to handle receive indication
+ and posted receives for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// This routine is a no-op to put in the NbiCallbacks table so
+// we can avoid checking for runt session frames (this is because
+// of how the if is structure below).
+//
+
+VOID
+NbiProcessSessionRunt(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+{
+ return;
+}
+
+NB_CALLBACK_NO_TRANSFER NbiCallbacksNoTransfer[] = {
+ NbiProcessFindName,
+ NbiProcessNameRecognized,
+ NbiProcessAddName,
+ NbiProcessAddName, // processes name in use frames also
+ NbiProcessDeleteName,
+ NbiProcessSessionRunt, // in case get a short session packet
+ NbiProcessSessionEnd,
+ NbiProcessSessionEndAck,
+ NbiProcessStatusQuery
+ };
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiProcessDeathPacket(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+
+ DbgPrint("******Received death packet - connid %x\n",Sess->DestConnectionId);
+
+ if ( !NbiGlobalDebugResTimeout ) {
+ return;
+ }
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ DbgPrint("********No Connection found with %x id\n",Sess->DestConnectionId);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ DbgPrint("******Received death packet on conn %lx from <%.16s>\n",Connection,Connection->RemoteName);
+ DbgBreakPoint();
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ }
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiReceive(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive indications from IPX.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_FRAME NbFrame = (PNB_FRAME)LookaheadBuffer;
+ UCHAR DataStreamType;
+
+ //
+ // We know that this is a frame with a valid IPX header
+ // because IPX would not give it to use otherwise. However,
+ // it does not check the source socket.
+ //
+
+ if (NbFrame->Connectionless.IpxHeader.SourceSocket != NB_SOCKET) {
+ return;
+ }
+
+ ++NbiDevice->Statistics.PacketsReceived;
+
+ // First assume that the DataStreamType is at the normal place i.e 2nd byte
+ //
+
+ // Now see if this is a name frame.
+ //
+ if ( PacketSize == sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME) ) {
+ // In the internet mode, the DataStreamType2 becomes DataStreamType
+ if (NbFrame->Connectionless.IpxHeader.PacketType == 0x14 ) {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType2;
+ } else {
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ }
+
+ // Is this a name frame?
+ // NB_CMD_FIND_NAME = 1 .... NB_CMD_DELETE_NAME = 5
+ //
+ if ((DataStreamType >= NB_CMD_FIND_NAME) && (DataStreamType <= NB_CMD_DELETE_NAME)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+ return;
+ }
+
+ }
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_DEATH_PACKET)) {
+
+ NbiProcessDeathPacket(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ if ((PacketSize >= sizeof(NB_CONNECTION)) &&
+ (NbFrame->Connection.Session.DataStreamType == NB_CMD_SESSION_DATA)) {
+
+ NbiProcessSessionData(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else {
+
+ DataStreamType = NbFrame->Connectionless.NameFrame.DataStreamType;
+ // Handle NB_CMD_SESSION_END = 7 ... NB_CMD_STATUS_QUERY = 9
+ //
+ if ((DataStreamType >= NB_CMD_SESSION_END ) && (DataStreamType <= NB_CMD_STATUS_QUERY)) {
+ if (LookaheadBufferSize == PacketSize) {
+ (*NbiCallbacksNoTransfer[DataStreamType-1])(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+ }
+
+ } else if (DataStreamType == NB_CMD_STATUS_RESPONSE) {
+
+ NbiProcessStatusResponse(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize);
+
+ } else if ((DataStreamType == NB_CMD_DATAGRAM) ||
+ (DataStreamType == NB_CMD_BROADCAST_DATAGRAM)) {
+
+ NbiProcessDatagram(
+ MacBindingHandle,
+ MacReceiveContext,
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize,
+ LookaheadBufferOffset,
+ PacketSize,
+ (BOOLEAN)(DataStreamType == NB_CMD_BROADCAST_DATAGRAM));
+
+ }
+
+ }
+
+} /* NbiReceive */
+
+
+VOID
+NbiReceiveComplete(
+ IN USHORT NicId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles receive complete indications from IPX.
+
+Arguments:
+
+ NicId - The NIC ID on which a receive was previously indicated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY p;
+ PADDRESS Address;
+ PREQUEST Request;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PDEVICE Device = NbiDevice;
+ LIST_ENTRY LocalList;
+ PCONNECTION Connection;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ //
+ // Complete any pending receive requests.
+ //
+
+
+ if (!IsListEmpty (&Device->ReceiveCompletionQueue)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveCompletionQueue, p)) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+
+ //
+ // BUGBUG: Cache the connection somewhere easier
+ // to retrieve?
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveCompletionQueue,
+ &Device->Lock);
+
+ }
+
+ }
+
+
+ //
+ // Indicate any datagrams to clients.
+ //
+
+ if (!IsListEmpty (&Device->ReceiveDatagrams)) {
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ while (!NB_LIST_WAS_EMPTY(&Device->ReceiveDatagrams, p)) {
+
+ ReceiveBuffer = CONTAINING_RECORD (p, NB_RECEIVE_BUFFER, WaitLinkage);
+ Address = ReceiveBuffer->Address;
+
+ NbiIndicateDatagram(
+ Address,
+ ReceiveBuffer->RemoteName,
+ ReceiveBuffer->Data,
+ ReceiveBuffer->DataLength);
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ p = NB_REMOVE_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &Device->Lock);
+
+ }
+ }
+
+
+ //
+ // Start packetizing connections.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ //
+ // Check again because it may just have become
+ // empty, and the code below depends on it being
+ // non-empty.
+ //
+
+ if (!IsListEmpty (&Device->PacketizeConnections)) {
+
+ //
+ // We copy the list locally, in case someone gets
+ // put back on it. We have to hack the end so
+ // it points to LocalList instead of PacketizeConnections.
+ //
+
+ LocalList = Device->PacketizeConnections;
+ LocalList.Flink->Blink = &LocalList;
+ LocalList.Blink->Flink = &LocalList;
+
+ InitializeListHead (&Device->PacketizeConnections);
+
+ //
+ // Set all these connections to not be on the list, so
+ // NbiStopConnection won't try to take them off.
+ //
+
+ for (p = LocalList.Flink; p != &LocalList; p = p->Flink) {
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ CTEAssert (Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = FALSE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ while (TRUE) {
+
+ p = RemoveHeadList (&LocalList);
+ if (p == &LocalList) {
+ break;
+ }
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, PacketizeLinkage);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_PACKETIZE);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ }
+ }
+
+} /* NbiReceiveComplete */
+
+
+VOID
+NbiTransferDataComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a transfer data complete indication from
+ IPX, indicating that a previously issued NdisTransferData
+ call has completed.
+
+Arguments:
+
+ Packet - The packet associated with the transfer.
+
+ Status - The status of the transfer.
+
+ BytesTransferred - The number of bytes transferred.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNB_RECEIVE_BUFFER ReceiveBuffer;
+ PADDRESS Address;
+ PCONNECTION Connection;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PREQUEST AdapterStatusRequest;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ ReceiveReserved = (PNB_RECEIVE_RESERVED)(Packet->ProtocolReserved);
+
+ switch (ReceiveReserved->Type) {
+
+ case RECEIVE_TYPE_DATA:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ Connection = ReceiveReserved->u.RR_CO.Connection;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive = Connection->PreviousReceive;
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ //
+ // BUGBUG: Send a resend ack?
+ //
+
+ } else {
+
+ //
+ // This aborts the current receive and
+ // releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ } else {
+
+
+ Connection->CurrentReceive.Offset += BytesTransferred;
+ Connection->CurrentReceive.MessageOffset += BytesTransferred;
+
+ if (ReceiveReserved->u.RR_CO.CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (ReceiveReserved->u.RR_CO.EndOfMessage) {
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (ReceiveReserved->u.RR_CO.PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesTransferred;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ ReceiveReserved->u.RR_CO.EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!ReceiveReserved->u.RR_CO.PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ }
+
+ //
+ // Free the NDIS buffer chain if we allocated one.
+ //
+
+ if (!ReceiveReserved->u.RR_CO.NoNdisBuffer) {
+
+ NdisQueryPacket (Packet, NULL, NULL, &CurBuffer, NULL);
+
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ break;
+
+ case RECEIVE_TYPE_DATAGRAM:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ ReceiveBuffer = ReceiveReserved->u.RR_DG.ReceiveBuffer;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ ReceiveReserved->u.RR_DG.ReceiveBuffer = NULL;
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // If it succeeded then queue it for indication,
+ // otherwise free the receive buffer also.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ ReceiveBuffer->DataLength = BytesTransferred;
+ NB_INSERT_HEAD_LIST(
+ &Device->ReceiveDatagrams,
+ &ReceiveBuffer->WaitLinkage,
+ &Device->Lock);
+
+ } else {
+
+ Address = ReceiveBuffer->Address;
+
+#if defined(_PNP_POWER)
+ NbiPushReceiveBuffer ( ReceiveBuffer );
+#else
+ NB_PUSH_ENTRY_LIST(
+ &Device->ReceiveBufferList,
+ &ReceiveBuffer->PoolLinkage,
+ &Device->Lock);
+#endif _PNP_POWER
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ }
+
+ break;
+
+ case RECEIVE_TYPE_ADAPTER_STATUS:
+
+ CTEAssert (ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = FALSE;
+
+ AdapterStatusRequest = ReceiveReserved->u.RR_AS.Request;
+
+ //
+ // Free the packet used for the transfer.
+ //
+
+ NdisReinitializePacket (Packet);
+ ExInterlockedPushEntrySList(
+ &Device->ReceivePacketList,
+ &ReceiveReserved->PoolLinkage,
+ &NbiGlobalPoolInterlock);
+
+ //
+ // Complete the request.
+ //
+
+ if (Status == STATUS_SUCCESS) {
+
+ //
+ // REQUEST_STATUS() is already to set to SUCCESS or
+ // BUFFER_OVERFLOW based on whether the buffer was
+ // big enough.
+ //
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = BytesTransferred;
+
+ } else {
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_UNEXPECTED_NETWORK_ERROR;
+
+ }
+
+ NbiCompleteRequest (AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ break;
+
+ }
+
+} /* NbiTransferDataComplete */
+
+
+VOID
+NbiAcknowledgeReceive(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a receive needs to be acked to
+ the remote. It either sends a data ack or queues up a piggyback
+ ack request.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+
+ if (Connection->NewNetbios) {
+
+ //
+ // CurrentReceiveNoPiggyback is based on the bits he
+ // set in his frame, NoPiggybackHeuristic is based on
+ // guesses about the traffic pattern, it is set to
+ // TRUE if we think we should not piggyback.
+ //
+
+ if ((!Device->EnablePiggyBackAck) ||
+ (Connection->CurrentReceiveNoPiggyback) ||
+ (Connection->PiggybackAckTimeout) ||
+ (Connection->NoPiggybackHeuristic)) {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (!Connection->DataAckPending) {
+
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+ //
+ // Some stacks can have multiple messages
+ // outstanding, so we may already have an
+ // ack queued.
+ //
+
+ Connection->DataAckTimeouts = 0;
+ Connection->DataAckPending = TRUE;
+
+ ++Device->Statistics.PiggybackAckQueued;
+
+ if (!Connection->OnDataAckQueue) {
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle1);
+
+ if (!Connection->OnDataAckQueue) {
+ Connection->OnDataAckQueue = TRUE;
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ }
+
+ if (!Device->DataAckActive) {
+ NbiStartShortTimer (Device);
+ Device->DataAckActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle1);
+ }
+
+ //
+ // Clear this, since a message ack resets the count.
+ //
+
+ Connection->ReceivesWithoutAck = 0;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+}
+
+
+VOID
+NbiCompleteReceive(
+ IN PCONNECTION Connection,
+ IN BOOLEAN EndOfMessage,
+ IN CTELockHandle CancelLH
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have filled up a receive request
+ and need to complete it.
+
+ NOTE: THIS FUNCTION IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+ THIS ROUTINE ALSO HOLDS CANCEL SPIN LOCK WHEN IT IS CALLED
+ AND RELEASES IT WHEN IT RETURNS.
+Arguments:
+
+ Connection - Pointer to the connection.
+
+ EndOfMessage - BOOLEAN set to true if the message end was received.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // Complete the current receive request. If the connection
+ // has shut down then we complete it right here, otherwise
+ // we queue it for completion in the receive complete
+ // handler.
+ //
+
+ Request = Connection->ReceiveRequest;
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveRequest = NULL; // StopConnection won't do this
+
+ REQUEST_STATUS(Request) = Connection->Status;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("Completing receive %lx (%d), status %lx\n",
+ Request, REQUEST_INFORMATION(Request), REQUEST_STATUS(Request)));
+
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (NbiDevice, Request);
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+
+ NbiDereferenceConnection (Connection, CREF_RECEIVE);
+
+ } else {
+
+ REQUEST_INFORMATION (Request) = Connection->CurrentReceive.Offset;
+
+ if (EndOfMessage) {
+
+ REQUEST_STATUS(Request) = STATUS_SUCCESS;
+
+ } else {
+
+ REQUEST_STATUS(Request) = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // If we indicated to the client, adjust this down by the
+ // amount of data taken, when it hits zero we can reindicate.
+ //
+
+ if (Connection->ReceiveUnaccepted) {
+ NB_DEBUG2 (RECEIVE, ("Moving Unaccepted %d down by %d\n",
+ Connection->ReceiveUnaccepted, Connection->CurrentReceive.Offset));
+ if (Connection->CurrentReceive.Offset >= Connection->ReceiveUnaccepted) {
+ Connection->ReceiveUnaccepted = 0;
+ } else {
+ Connection->ReceiveUnaccepted -= Connection->CurrentReceive.Offset;
+ }
+ }
+
+ //
+ // BUGBUG: Check whether to activate another receive?
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_PENDING;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (EndOfMessage) {
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ if (Connection->CurrentIndicateOffset != 0) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ EndOfMessage ? NbiAckResponse : NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // This will complete the request inside ReceiveComplete,
+ // dereference the connection, and set the state to IDLE.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->ReceiveCompletionQueue,
+ REQUEST_LINKAGE (Request),
+ &Device->Lock);
+
+ }
+
+} /* NbiCompleteReceive */
+
+
+NTSTATUS
+NbiTdiReceive(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a receive on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the receive.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+
+ PCONNECTION Connection;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+ IoSetCancelRoutine (Request, NbiCancelReceive);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ //
+ // Insert this in our queue, then see if we need
+ // to wake up the remote.
+ //
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->ReceiveQueue, Request);
+
+ if (Connection->ReceiveState != CONNECTION_RECEIVE_W_RCV) {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx idle\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx awakened\n", Request, Connection));
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax = (USHORT)
+ (Connection->ReceiveSequence + Connection->ReceiveWindowSize - 1);
+
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (RECEIVE, ("Receive connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Receive connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiReceive */
+
+
+VOID
+NbiCancelReceive(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a receive.
+ The request is found on the connection's receive queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+
+ //
+ // Just stop the connection, that will tear down any
+ // receives.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // receives without stopping the connection??
+ //
+ // BUGBUG: This routine is the same as NbiCancelSend,
+ // so if we don't make it more specific, merge the two.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelReceive */
+
diff --git a/private/ntos/tdi/isnp/nb/send.c b/private/ntos/tdi/isnp/nb/send.c
new file mode 100644
index 000000000..a4443c73c
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/send.c
@@ -0,0 +1,2886 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This module contains the send routines for the Netbios
+ module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 22-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+VOID
+NbiSendComplete(
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+)
+
+/*++
+
+Routine Description:
+
+ This routine handles a send completion call from IPX.
+
+Arguments:
+
+ Packet - The packet which has been completed.
+
+ Status - The status of the send.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+
+{
+ PDEVICE Device = NbiDevice;
+ PADDRESS Address;
+ PADDRESS_FILE AddressFile;
+ PCONNECTION Connection;
+ PREQUEST DatagramRequest;
+ PREQUEST SendRequest, TmpRequest;
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+ PNETBIOS_CACHE CacheName;
+ PNDIS_BUFFER SecondBuffer;
+ PVOID SecondBufferMemory;
+ UINT SecondBufferLength;
+ ULONG oldvalue;
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ CTELockHandle CancelLH;
+#if defined(_PNP_POWER)
+ CTELockHandle LockHandle;
+#endif _PNP_POWER
+
+ //
+ // We jump back here if we re-call send from inside this
+ // function and it doesn't pend (to avoid stack overflow).
+ //
+
+FunctionStart:;
+
+ ++Device->Statistics.PacketsSent;
+
+ switch (Reserved->Type) {
+
+ case SEND_TYPE_SESSION_DATA:
+
+ //
+ // This was a send on a session. This references the
+ // IRP.
+ //
+
+ NB_DEBUG2 (SEND, ("Complete NDIS packet %lx\n", Reserved));
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+ SendRequest = Reserved->u.SR_CO.Request;
+
+ if (!Reserved->u.SR_CO.NoNdisBuffer) {
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ }
+
+ //
+ // If NoNdisBuffer is TRUE, then we could set
+ // Connection->SendBufferInUse to FALSE here. The
+ // problem is that a new send might be in progress
+ // by the time this completes and it may have
+ // used the user buffer, then if we need to
+ // retransmit that packet we would use the buffer
+ // twice. We instead rely on the fact that whenever
+ // we make a new send active we set SendBufferInUse
+ // to FALSE. The net effect is that the user's buffer
+ // can be used the first time a send is packetize
+ // but not on resends.
+ //
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+#if DBG
+ if (REQUEST_REFCOUNT(SendRequest) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, SendRequest);
+ DbgBreakPoint();
+ }
+#endif
+
+#if defined(__PNP)
+ NB_GET_LOCK( &Connection->Lock, &LockHandle );
+ oldvalue = REQUEST_REFCOUNT(SendRequest)--;
+ if ( DEVICE_NETWORK_PATH_NOT_FOUND == Status ) {
+ Connection->LocalTarget = Reserved->LocalTarget;
+ }
+ NB_FREE_LOCK( &Connection->Lock, LockHandle );
+#else
+ oldvalue = NB_ADD_ULONG(
+ &REQUEST_REFCOUNT (SendRequest),
+ (ULONG)-1,
+ &Connection->Lock);
+#endif __PNP
+
+ if (oldvalue == 1) {
+
+ //
+ // If the refcount on this request is now zero then
+ // we already got the ack for it, which means
+ // that the ack-processing code has unlinked the
+ // request from Connection->SendQueue. So we
+ // can just run the queue of connections here
+ // and complete them.
+ //
+ // We dereference the connection for all but one
+ // of the requests, we hang on to that until a bit
+ // later so everything stays around.
+ //
+
+ while (TRUE) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
+ NB_DEBUG2 (SEND, ("Completing request %lx from send complete\n", SendRequest));
+ REQUEST_STATUS (SendRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (SendRequest);
+ NbiFreeRequest (Device, SendRequest);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ SendRequest = TmpRequest;
+
+ if (SendRequest == NULL) {
+ break;
+ }
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ }
+
+ if (Reserved->OwnedByConnection) {
+
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (oldvalue == 1) {
+ NbiDereferenceConnection (Connection, CREF_SEND);
+ }
+
+ break;
+
+ case SEND_TYPE_NAME_FRAME:
+
+ //
+ // The frame is an add name/delete name; put it back in
+ // the pool and deref the address.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+
+ Address = Reserved->u.SR_NF.Address;
+
+#if !defined(_PNP_POWER)
+ if ((Reserved->u.SR_NF.CurrentNicId) &&
+ (Reserved->u.SR_NF.CurrentNicId < Device->MaximumNicId)) {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ IPX_LOCAL_TARGET TempLocalTarget;
+
+ //
+ // This is a name frame being sent to every address, so
+ // resent it to the next NIC ID. We hold the address
+ // reference through this send.
+ //
+
+ CTEAssert (Address != NULL);
+
+ ++Reserved->u.SR_NF.CurrentNicId;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+ Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
+
+ Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
+ Header->NameFrame.ConnectionControlFlag = 0x00;
+ Header->NameFrame.DataStreamType = Reserved->u.SR_NF.DataStreamType;
+ Header->NameFrame.NameTypeFlag = Reserved->u.SR_NF.NameTypeFlag;
+
+ //
+ // This is not a name in use frame so DataStreamType2
+ // is the same as DataStreamType.
+ //
+
+ Header->NameFrame.DataStreamType2 = Reserved->u.SR_NF.DataStreamType;
+
+ RtlCopyMemory(
+ Header->NameFrame.Name,
+ Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ //
+ // Now send the frame (because it is all in the first segment,
+ // IPX will adjust the length of the buffer correctly).
+ //
+
+ TempLocalTarget.NicId = Reserved->u.SR_NF.CurrentNicId;
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME));
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ &TempLocalTarget,
+ Packet,
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
+ sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
+
+ goto FunctionStart;
+
+ }
+
+ return;
+
+ }
+#endif !_PNP_POWER
+
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ if (Address) {
+ NbiDereferenceAddress (Address, AREF_NAME_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_NAME_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_SESSION_INIT:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+ CTEAssert (SecondBufferLength == sizeof(NB_SESSION_INIT));
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_SESSION_INIT);
+
+ break;
+
+ case SEND_TYPE_SESSION_NO_DATA:
+
+ //
+ // This is a frame which was sent on a connection but
+ // has no data (ack, session end, session end ack).
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ Connection = Reserved->u.SR_CO.Connection;
+
+ if (Reserved->OwnedByConnection) {
+
+ CTEAssert (Connection != NULL);
+ Connection->SendPacketInUse = FALSE;
+
+ if (Connection->OnWaitPacketQueue) {
+
+ //
+ // This will put the connection on the packetize
+ // queue if appropriate.
+ //
+
+ NbiCheckForWaitPacket (Connection);
+
+ }
+
+ } else {
+
+ NbiPushSendPacket(Reserved);
+
+ }
+
+ if (Connection != NULL) {
+ NbiDereferenceConnection (Connection, CREF_FRAME);
+ } else {
+ NbiDereferenceDevice (Device, DREF_FRAME);
+ }
+
+ break;
+
+ case SEND_TYPE_FIND_NAME:
+
+ //
+ // The frame is a find name; just set SendInProgress to
+ // FALSE and FindNameTimeout will clean it up.
+ //
+#if defined(_PNP_POWER)
+ NB_GET_LOCK( &Device->Lock, &LockHandle);
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ //
+ // We keep track of when it finds a net that isn't
+ // a down wan line so that we can tell when datagram
+ // sends should fail (otherwise we succeed them, so
+ // the browser won't think this is a down wan line).
+ //
+ if ( STATUS_SUCCESS == Status ) {
+ NB_SET_SR_FN_SENT_ON_UP_LINE (Reserved, TRUE);
+ } else {
+ NB_DEBUG( CACHE, ("Send complete of find name with failure %lx\n",Status ));
+ }
+ NB_FREE_LOCK(&Device->Lock, LockHandle);
+#else
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+#endif _PNP_POWER
+ break;
+
+ case SEND_TYPE_DATAGRAM:
+
+ //
+ // If there are any more networks to send this on then
+ // do so, otherwise put it back in the pool and complete
+ // the request.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ if ((Reserved->u.SR_DG.Cache == NULL) ||
+ (++Reserved->u.SR_DG.CurrentNetwork >=
+ Reserved->u.SR_DG.Cache->NetworksUsed)) {
+
+ AddressFile = Reserved->u.SR_DG.AddressFile;
+ DatagramRequest = Reserved->u.SR_DG.DatagramRequest;
+
+ NB_DEBUG2 (DATAGRAM, ("Completing datagram %lx on %lx\n", DatagramRequest, AddressFile));
+
+ //
+ // Remove any user buffers chained on this packet.
+ //
+
+ NdisReinitializePacket (Packet);
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisChainBufferAtFront (Packet, Reserved->HeaderBuffer);
+
+ //
+ // Complete the request.
+ //
+
+ REQUEST_STATUS(DatagramRequest) = Status;
+
+ NbiCompleteRequest(DatagramRequest);
+ NbiFreeRequest (Device, DatagramRequest);
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+ NbiPushSendPacket (Reserved);
+
+ //
+ // Since we are no longer referencing the cache
+ // name, see if we should delete it (this will
+ // happen if the cache entry was aged out while
+ // the datagram was being processed).
+ //
+
+ if (CacheName != NULL) {
+
+ oldvalue = NB_ADD_ULONG(
+ &CacheName->ReferenceCount,
+ (ULONG)-1,
+ &Device->Lock);
+
+ if (oldvalue == 1) {
+
+ NB_DEBUG2 (CACHE, ("Free aged cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Free old cache");
+
+ }
+ }
+
+ NbiDereferenceAddressFile (AddressFile, AFREF_SEND_DGRAM);
+
+ } else {
+
+ NB_CONNECTIONLESS UNALIGNED * Header;
+ PIPX_LOCAL_TARGET LocalTarget;
+ ULONG HeaderLength;
+ ULONG PacketLength;
+
+ // send the datagram on the next net.
+ CTEAssert (!Reserved->u.SR_DG.Cache->Unique);
+ Reserved->SendInProgress = TRUE;
+
+ CacheName = Reserved->u.SR_DG.Cache;
+
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address, so we modify
+ // that for the current netbios cache entry if needed.
+ //
+
+ Header = (NB_CONNECTIONLESS UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
+
+
+ *(UNALIGNED ULONG *)Header->IpxHeader.DestinationNetwork = CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].Network;
+ RtlCopyMemory (&Header->IpxHeader.DestinationNode, BroadcastAddress, 6);
+
+ LocalTarget = &CacheName->Networks[Reserved->u.SR_DG.CurrentNetwork].LocalTarget;
+
+
+ HeaderLength = sizeof(IPX_HEADER) + sizeof(NB_DATAGRAM);
+
+ PacketLength = HeaderLength + REQUEST_INFORMATION(Reserved->u.SR_DG.DatagramRequest);
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+ Header->IpxHeader.PacketType = 0x04;
+
+
+ //
+ // Now fill in the Netbios header.
+ //
+
+ Header->Datagram.ConnectionControlFlag = 0x00;
+ RtlCopyMemory(
+ Header->Datagram.SourceName,
+ Reserved->u.SR_DG.AddressFile->Address->NetbiosAddress.NetbiosName,
+ 16);
+
+ if (Reserved->u.SR_DG.RemoteName != (PVOID)-1) {
+
+ //
+ // This is a directed, as opposed to broadcast, datagram.
+ //
+
+ Header->Datagram.DataStreamType = NB_CMD_DATAGRAM;
+ RtlCopyMemory(
+ Header->Datagram.DestinationName,
+ Reserved->u.SR_DG.RemoteName->NetbiosName,
+ 16);
+
+ } else {
+
+ Header->Datagram.DataStreamType = NB_CMD_BROADCAST_DATAGRAM;
+ RtlZeroMemory(
+ Header->Datagram.DestinationName,
+ 16);
+
+ }
+
+
+ //
+ // Now send the frame (IPX will adjust the length of the
+ // first buffer and the whole frame correctly).
+ //
+
+ if ((Status =
+ (*Device->Bind.SendHandler)(
+ LocalTarget,
+ Packet,
+ PacketLength,
+ HeaderLength)) != STATUS_PENDING) {
+
+ goto FunctionStart;
+ }
+
+ }
+
+ break;
+
+ case SEND_TYPE_STATUS_QUERY:
+
+ //
+ // This is an adapter status query, which is a simple
+ // packet.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_FRAME);
+
+ break;
+
+ case SEND_TYPE_STATUS_RESPONSE:
+
+ //
+ // This is an adapter status response, we have to free the
+ // second buffer.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+
+ NdisUnchainBufferAtBack (Packet, &SecondBuffer);
+ NdisQueryBuffer (SecondBuffer, &SecondBufferMemory, &SecondBufferLength);
+
+ NdisFreeBuffer(SecondBuffer);
+ NbiFreeMemory (SecondBufferMemory, Reserved->u.SR_AS.ActualBufferLength, MEMORY_STATUS, "Adapter Status");
+
+ NbiPushSendPacket (Reserved);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_RESPONSE);
+
+ break;
+
+#ifdef RSRC_TIMEOUT_DBG
+ case SEND_TYPE_DEATH_PACKET:
+
+ //
+ // This is a session initialize or session init ack; free
+ // the second buffer, put the packet back in the pool and
+ // deref the device.
+ //
+
+ CTEAssert (Reserved->SendInProgress);
+ Reserved->SendInProgress = FALSE;
+ DbgPrint("********Death packet send completed status %lx\n",Status);
+ DbgBreakPoint();
+ break;
+#endif //RSRC_TIMEOUT_DBG
+
+ default:
+
+ CTEAssert (FALSE);
+ break;
+
+ }
+
+} /* NbiSendComplete */
+
+#if 0
+ULONG NbiLoudSendQueue = 1;
+#endif
+
+VOID
+NbiAssignSequenceAndSend(
+ IN PCONNECTION Connection,
+ IN PNDIS_PACKET Packet
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that receive sequence numbers on
+ packets are numbered correctly. It is called in place of the lower-level
+ send handler; after assigning the receive sequence number it locks out
+ other sends until the NdisSend call has returned (not necessarily completed),
+ insuring that the packets with increasing receive sequence numbers
+ are queue in the right order by the MAC.
+
+ NOTE: THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD, AND
+ RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection the send is on.
+
+ Packet - The packet to send.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS NdisStatus;
+ PNB_SEND_RESERVED Reserved;
+ PLIST_ENTRY p;
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ BOOLEAN NdisSendReference;
+ ULONG result;
+
+
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ CTEAssert (Connection->State == CONNECTION_STATE_ACTIVE);
+
+ //
+ // If there is a send in progress, then queue this packet
+ // and return.
+ //
+
+ if (Connection->NdisSendsInProgress > 0) {
+
+ NB_DEBUG2 (SEND, ("Queueing send packet %lx on %lx\n", Reserved, Connection));
+ InsertTailList (&Connection->NdisSendQueue, &Reserved->WaitLinkage);
+ ++Connection->NdisSendsInProgress;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // No send in progress. Set the flag to true, and fill in the
+ // receive sequence fields in the packet.
+ //
+
+ Connection->NdisSendsInProgress = 1;
+ NdisSendReference = FALSE;
+ Connection->NdisSendReference = &NdisSendReference;
+
+ while (TRUE) {
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ if (Connection->NewNetbios) {
+ Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
+ } else {
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+ }
+
+ //
+ // Since we are acking as much as we know, we can clear
+ // this flag. The connection will eventually get removed
+ // from the queue by the long timeout.
+ //
+
+ Connection->DataAckPending = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ NdisStatus = (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ Reserved->u.SR_CO.PacketLength,
+ sizeof(NB_CONNECTION));
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+ //
+ // Take the ref count down, which may allow others
+ // to come through.
+ //
+
+ result = NB_ADD_ULONG(
+ &Connection->NdisSendsInProgress,
+ (ULONG)-1,
+ &Connection->Lock);
+
+ //
+ // We have now sent a packet, see if any queued up while we
+ // were doing it. If the count was zero after removing ours,
+ // then anything else queued is being processed, so we can
+ // exit. If the connection was stopped while we were sending,
+ // a special reference was added which we remove (NbiStopConnection
+ // sets NdisSendReference to TRUE, using the pointer saved
+ // in Connection->NdisSendReference).
+ //
+
+ if (result == 1) {
+ if (NdisSendReference) {
+ NB_DEBUG2 (SEND, ("Remove CREF_NDIS_SEND from %lx\n", Connection));
+ NbiDereferenceConnection (Connection, CREF_NDIS_SEND);
+ }
+ return;
+ }
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ p = RemoveHeadList(&Connection->NdisSendQueue);
+
+ //
+ // If the refcount was not zero, then nobody else should
+ // have taken packets off since they would have been
+ // blocked by us. So, the queue should not be empty.
+ //
+
+ ASSERT (p != &Connection->NdisSendQueue);
+
+ Reserved = CONTAINING_RECORD (p, NB_SEND_RESERVED, WaitLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ } // while loop
+
+ //
+ // We should never reach here.
+ //
+
+ CTEAssert (FALSE);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+} /* NbiAssignSequenceAndSend */
+
+
+NTSTATUS
+NbiTdiSend(
+ IN PDEVICE Device,
+ IN PREQUEST Request
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+Arguments:
+
+ Device - The netbios device.
+
+ Request - The request describing the send.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ //
+ // First make sure the connection is valid.
+ //
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->Type == NB_CONNECTION_SIGNATURE) {
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_BEGIN_SYNC (&SyncContext);
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // Make sure the connection is in a good state.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ //
+ // If the connection is idle then send it now, otherwise
+ // queue it.
+ //
+
+
+ if (!Request->Cancel) {
+
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+
+ //
+ // For old netbios, don't allow sends greater than 64K-1.
+ //
+
+ if ((Connection->NewNetbios) ||
+ (Parameters->SendLength <= 0xffff)) {
+
+ IoSetCancelRoutine (Request, NbiCancelSend);
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle );
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_INFORMATION (Request) = Parameters->SendLength; // assume it succeeds.
+
+ REQUEST_REFCOUNT (Request) = 1; // refcount starts at 1.
+ NbiReferenceConnectionSync (Connection, CREF_SEND);
+
+ //
+ // NOTE: The connection send queue is managed such
+ // that the current send being packetized is not on
+ // the queue. For multiple-request messages, the
+ // first one is not on the queue, but its linkage
+ // field points to the next request in the message
+ // (which will be on the head of the queue).
+ //
+
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a final send.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx idle\n", Request, Connection));
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have been collecting partial sends waiting
+ // for a final one, which we have now received,
+ // so start packetizing.
+ //
+ // We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx got eor\n", Request, Connection));
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ //
+ // This frees the connection lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ //
+ // The state is PACKETIZE, W_ACK, or W_PACKET.
+ //
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx busy\n", Request, Connection));
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // This is a partial send. We queue them up without
+ // packetizing until we get a final (this is because
+ // we have to put a correct Connection->CurrentMessageLength
+ // in the frames.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE) {
+
+ //
+ // Start collecting partial sends. NOTE: Partial sends
+ // are always inserted in the send queue
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Connection->FirstMessageRequestTime.QuadPart;
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ } else if (Connection->SubState == CONNECTION_SUBSTATE_A_W_EOR) {
+
+ //
+ // We have got another partial send to add to our
+ // list. We chain it on the back of the send queue,
+ // in addition if this is the second request in the
+ // message, we have to link the first request (which
+ // is not on the queue) to this one.
+ //
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength += Parameters->SendLength;
+
+ if (Connection->SendQueue.Head == NULL) {
+ REQUEST_SINGLE_LINKAGE(Connection->FirstMessageRequest) = Request;
+ }
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ } else {
+
+ REQUEST_SINGLE_LINKAGE(Request) = NULL;
+ REQUEST_LIST_INSERT_TAIL(&Connection->SendQueue, Request);
+
+#ifdef RSRC_TIMEOUT_DBG
+ {
+ LARGE_INTEGER Time;
+ KeQuerySystemTime(&Time);
+ (((LARGE_INTEGER UNALIGNED *)&(IoGetCurrentIrpStackLocation(Request))->Parameters.Others.Argument3))->QuadPart =
+ Time.QuadPart;
+ }
+#endif //RSRC_TIMEOUT_DBG
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NB_END_SYNC (&SyncContext);
+ return STATUS_PENDING;
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, too long for connection %lx (%d)\n", Request, Connection, Parameters->SendLength));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ } else {
+
+ NB_DEBUG2 (SEND, ("Send %lx, connection %lx cancelled\n", Request, Connection));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_CANCELLED;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx state is %d\n", Connection, Connection->State));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_END_SYNC (&SyncContext);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+ } else {
+
+ NB_DEBUG (SEND, ("Send connection %lx has bad signature\n", Connection));
+ return STATUS_INVALID_CONNECTION;
+
+ }
+
+} /* NbiTdiSend */
+
+
+VOID
+NbiPacketizeSend(
+ IN PCONNECTION Connection
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a send on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ PNB_SEND_RESERVED Reserved;
+ PDEVICE Device = NbiDevice;
+ NB_CONNECTION UNALIGNED * Header;
+ ULONG PacketLength;
+ ULONG PacketSize;
+ ULONG DesiredLength;
+ ULONG ActualLength;
+ NTSTATUS Status;
+ PSINGLE_LIST_ENTRY s;
+ USHORT ThisSendSequence;
+ USHORT ThisOffset;
+ BOOLEAN ExitAfterSend;
+ UCHAR ConnectionControlFlag;
+ CTELockHandle DeviceLockHandle;
+
+ //
+ // We jump back here if we are talking new Netbios and it
+ // is OK to packetize another send.
+ //
+
+SendAnotherPacket:
+
+ //
+ // If we decide to packetize another send after this, we
+ // change ExitAfterSend to FALSE and SubState to PACKETIZE.
+ // Right now we don't change SubState in case it is W_PACKET.
+ //
+
+ ExitAfterSend = TRUE;
+
+ CTEAssert (Connection->CurrentSend.Request != NULL);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // Check that we have send window, both that advertised
+ // by the remote and our own locally-decided window which
+ // may be smaller.
+ //
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence-1) == Connection->RemoteRcvSequenceMax) ||
+ (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize)) {
+
+ //
+ // Keep track of whether we are waiting because of his window
+ // or because of our local window. If it is because of our local
+ // window then we may want to adjust it after this window
+ // is acked.
+ //
+
+ if ((USHORT)(Connection->CurrentSend.SendSequence-1) != Connection->RemoteRcvSequenceMax) {
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+ NB_DEBUG2 (SEND, ("Connection %lx local shut down at %lx, %lx\n", Connection, Connection->CurrentSend.SendSequence, Connection->UnAckedSend.SendSequence));
+ } else {
+ Connection->SubState = CONNECTION_SUBSTATE_A_REMOTE_W;
+ NB_DEBUG2 (SEND, ("Connection %lx remote shut down at %lx\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ //
+ // Start the timer so we will keep bugging him about
+ // this. BUGBUG: What if he doesn't get a receive down
+ // quickly -- but this is better than losing his ack
+ // and then dying. We won't really back off our timer
+ // because we will keep getting acks, and resetting it.
+ //
+
+ NbiStartRetransmit (Connection);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+ }
+
+ Request = Connection->CurrentSend.Request;
+
+ //
+ // If we are in this routine then we know that
+ // we are coming out of IDLE, W_ACK, or W_PACKET
+ // and we still have the lock held. We also know
+ // that there is a send request in progress. If
+ // an ack for none or part of the last packet was
+ // received, then our send pointers have been
+ // adjusted to reflect that.
+ //
+
+ //
+ // First get a packet for the current send.
+ //
+
+ if (!Connection->SendPacketInUse) {
+
+ Connection->SendPacketInUse = TRUE;
+ Packet = PACKET(&Connection->SendPacket);
+ Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+
+ } else {
+
+ s = ExInterlockedPopEntrySList(
+ &Device->SendPacketList,
+ &NbiGlobalPoolInterlock);
+
+ if (s == NULL) {
+
+ //
+ // This function tries to allocate another packet pool.
+ //
+
+ s = NbiPopSendPacket(Device, FALSE);
+
+ if (s == NULL) {
+
+ //
+ // It is possible to come in here and already be in
+ // W_PACKET state -- this is because we may packetize
+ // when in that state, and rather than always be
+ // checking that we weren't in W_PACKET, we go
+ // ahead and check again here.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PACKET) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PACKET;
+
+ NB_GET_LOCK (&Device->Lock, &DeviceLockHandle);
+ if (!Connection->OnWaitPacketQueue) {
+
+ NbiReferenceConnectionLock (Connection, CREF_W_PACKET);
+
+ Connection->OnWaitPacketQueue = TRUE;
+
+ InsertTailList(
+ &Device->WaitPacketConnections,
+ &Connection->WaitPacketLinkage
+ );
+
+// NB_INSERT_TAIL_LIST(
+// &Device->WaitPacketConnections,
+// &Connection->WaitPacketLinkage,
+// &Device->Lock);
+
+ }
+ NB_FREE_LOCK (&Device->Lock, DeviceLockHandle);
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+ }
+
+ Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ }
+
+ //
+ // Set this now, we will change it later if needed.
+ //
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_ACK;
+
+
+ //
+ // Save these since they go in this next packet.
+ //
+
+ ThisSendSequence = Connection->CurrentSend.SendSequence;
+ ThisOffset = (USHORT)Connection->CurrentSend.MessageOffset;
+
+
+ //
+ // Now see if we need to copy the buffer chain.
+ //
+
+ PacketSize = Connection->MaximumPacketSize;
+
+ if (Connection->CurrentSend.MessageOffset + PacketSize >= Connection->CurrentMessageLength) {
+
+ PacketSize = Connection->CurrentMessageLength - Connection->CurrentSend.MessageOffset;
+
+ if ((Connection->CurrentSend.MessageOffset == 0) &&
+ (!Connection->SendBufferInUse)) {
+
+ //
+ // If the entire send remaining fits in one packet,
+ // and this is also the first packet in the send,
+ // then the entire send fits in one packet and
+ // we don't need to build a duplicate buffer chain.
+ //
+
+ BufferChain = Connection->CurrentSend.Buffer;
+ Reserved->u.SR_CO.NoNdisBuffer = TRUE;
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->CurrentSend.MessageOffset = Connection->CurrentMessageLength;
+ Connection->CurrentSend.Request = NULL;
+ ++Connection->CurrentSend.SendSequence;
+ Connection->SendBufferInUse = TRUE;
+ if (Connection->NewNetbios) {
+ if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+ } else {
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ }
+
+ if (BufferChain != NULL) {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), user buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ NdisChainBufferAtBack (Packet, BufferChain);
+ } else {
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+ }
+
+ goto GotBufferChain;
+
+ }
+
+ }
+
+ //
+ // We need to build a partial buffer chain. In the case
+ // where the current request is a partial one, we may
+ // build this from the ndis buffer chains of several
+ // requests.
+ //
+
+ if (PacketSize > 0) {
+
+ DesiredLength = PacketSize;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), allocate buffer\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ while (TRUE) {
+
+ Status = NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentSend.Buffer,
+ Connection->CurrentSend.BufferOffset,
+ DesiredLength,
+ &BufferChain,
+ &Connection->CurrentSend.Buffer,
+ &Connection->CurrentSend.BufferOffset,
+ &ActualLength);
+
+ if (Status != STATUS_SUCCESS) {
+
+ PNDIS_BUFFER CurBuffer, TmpBuffer;
+
+ NB_DEBUG2 (SEND, ("Allocate buffer chain failed for packet %lx\n", Reserved));
+
+ //
+ // We could not allocate resources for this send.
+ // We'll put the connection on the packetize
+ // queue and hope we get more resources later.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ //
+ // Connection->CurrentSend can stay where it is.
+ //
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Free any buffers we have allocated on previous calls
+ // to BuildBufferChain inside this same while(TRUE) loop,
+ // then free the packet.
+ //
+
+ CurBuffer = NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer));
+ while (CurBuffer) {
+ TmpBuffer = NDIS_BUFFER_LINKAGE (CurBuffer);
+ NdisFreeBuffer (CurBuffer);
+ CurBuffer = TmpBuffer;
+ }
+
+ NDIS_BUFFER_LINKAGE (NDIS_BUFFER_LINKAGE(Reserved->HeaderBuffer)) = NULL;
+ NdisRecalculatePacketCounts (Packet);
+
+ if (Reserved->OwnedByConnection) {
+ Connection->SendPacketInUse = FALSE;
+ } else {
+ NbiPushSendPacket(Reserved);
+ }
+
+ return;
+
+ }
+
+ NdisChainBufferAtBack (Packet, BufferChain);
+ Connection->CurrentSend.MessageOffset += ActualLength;
+
+ DesiredLength -= ActualLength;
+
+ if (DesiredLength == 0) {
+
+ //
+ // We have gotten enough data for our packet.
+ //
+
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ Connection->CurrentSend.Request = NULL;
+ }
+ break;
+ }
+
+ //
+ // We ran out of buffer chain on this send, which means
+ // that we must have another one behind it (since we
+ // don't start packetizing partial sends until all of
+ // them are queued).
+ //
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+ if (Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+
+ }
+
+ } else {
+
+ //
+ // This is a zero-length send (in general we will go
+ // through the code before the if that uses the user's
+ // buffer, but not on a resend).
+ //
+
+ Connection->CurrentSend.Buffer = NULL;
+ Connection->CurrentSend.BufferOffset = 0;
+ CTEAssert (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength);
+ Connection->CurrentSend.Request = NULL;
+
+ NB_DEBUG2 (SEND, ("Send packet %lx on %lx (%d/%d), no alloc buf\n",
+ Reserved, Connection,
+ Connection->CurrentSend.SendSequence,
+ Connection->CurrentSend.MessageOffset));
+
+ }
+
+ Reserved->u.SR_CO.NoNdisBuffer = FALSE;
+
+ if (Connection->NewNetbios) {
+
+ ++Connection->CurrentSend.SendSequence;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+
+ if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else if ((ThisSendSequence == Connection->RemoteRcvSequenceMax) ||
+ ((((PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request))->SendFlags) &
+ TDI_SEND_NO_RESPONSE_EXPECTED)) { // BUGBUG: optimize this check
+
+ ConnectionControlFlag = NB_CONTROL_EOM | NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_EOM;
+ }
+ Connection->PiggybackAckTimeout = FALSE;
+
+ } else if (((USHORT)(Connection->CurrentSend.SendSequence - Connection->UnAckedSend.SendSequence)) >= Connection->SendWindowSize) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else if (ThisSendSequence == Connection->RemoteRcvSequenceMax) {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+
+ } else {
+
+ ConnectionControlFlag = 0;
+ ExitAfterSend = FALSE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ }
+
+ } else {
+
+ ConnectionControlFlag = NB_CONTROL_SEND_ACK;
+ if (Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) {
+ ++Connection->CurrentSend.SendSequence;
+ }
+ }
+
+GotBufferChain:
+
+ //
+ // We have a packet and a buffer chain, there are
+ // no other resources required for a send so we can
+ // fill in the header and go.
+ //
+
+ CTEAssert (Reserved->SendInProgress == FALSE);
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_SESSION_DATA;
+ Reserved->u.SR_CO.Connection = Connection;
+ Reserved->u.SR_CO.Request = Connection->FirstMessageRequest;
+
+ PacketLength = PacketSize + sizeof(NB_CONNECTION);
+ Reserved->u.SR_CO.PacketLength = PacketLength;
+
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (UCHAR)(PacketLength / 256);
+ Header->IpxHeader.PacketLength[1] = (UCHAR)(PacketLength % 256);
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header. BUGBUG: Put this in
+ // a contiguous buffer in the connection.
+ //
+
+ Header->Session.ConnectionControlFlag = ConnectionControlFlag;
+ Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = ThisSendSequence;
+ Header->Session.TotalDataLength = (USHORT)Connection->CurrentMessageLength;
+ Header->Session.Offset = ThisOffset;
+ Header->Session.DataLength = (USHORT)PacketSize;
+
+#if 0
+ //
+ // These are set by NbiAssignSequenceAndSend.
+ //
+
+ Header->Session.ReceiveSequence = Connection->ReceiveSequence;
+ Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
+#endif
+
+ //
+ // Reference the request to account for this send.
+ //
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ ++REQUEST_REFCOUNT (Request);
+
+ ++Device->TempFramesSent;
+ Device->TempFrameBytesSent += PacketSize;
+
+ //
+ // Start the timer.
+ //
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // This frees the lock. IPX will adjust the length of
+ // the first buffer correctly.
+ //
+
+ NbiAssignSequenceAndSend(
+ Connection,
+ Packet
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ if (!ExitAfterSend) {
+
+ //
+ // BUGBUG: Did we need to reference the connection until we
+ // get the lock back??
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ //
+ // Jump back to the beginning of the function to
+ // repacketize.
+
+ goto SendAnotherPacket;
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+} /* NbiPacketizeSend */
+
+
+VOID
+NbiAdjustSendWindow(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adjusts a connection's send window if needed. It is
+ assumed that we just got an ack for a full send window.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Connection->RetransmitThisWindow) {
+
+ //
+ // Move it down. Check if this keeps happening.
+ //
+
+ if (Connection->SendWindowSize > 2) {
+ --Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lower window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased the window.
+ //
+
+ ++Connection->IncreaseWindowFailures;
+ NB_DEBUG2 (SEND_WINDOW, ("%d consecutive increase failues on %lx (%lx)\n", Connection->IncreaseWindowFailures, Connection, Connection->CurrentSend.SendSequence));
+
+ if (Connection->IncreaseWindowFailures >= 2) {
+
+ if (Connection->MaxSendWindowSize > 2) {
+
+ //
+ // Lock ourselves at a smaller window.
+ //
+
+ Connection->MaxSendWindowSize = Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Lock send window at %d on %lx (%lx)\n", Connection->MaxSendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ }
+
+ Connection->IncreaseWindowFailures = 0;
+ }
+
+ Connection->SendWindowIncrease = FALSE;
+ }
+
+ } else {
+
+ //
+ // Increase it if allowed, and make a note
+ // in case this increase causes problems in
+ // the next window.
+ //
+
+ if (Connection->SendWindowSize < Connection->MaxSendWindowSize) {
+
+ ++Connection->SendWindowSize;
+ NB_DEBUG2 (SEND_WINDOW, ("Raise window to %d on %lx (%lx)\n", Connection->SendWindowSize, Connection, Connection->CurrentSend.SendSequence));
+ Connection->SendWindowIncrease = TRUE;
+
+ } else {
+
+ if (Connection->SendWindowIncrease) {
+
+ //
+ // We just increased it and nothing failed,
+ // which is good.
+ //
+
+ Connection->SendWindowIncrease = FALSE;
+ Connection->IncreaseWindowFailures = 0;
+ NB_DEBUG2 (SEND_WINDOW, ("Raised window OK on %lx (%lx)\n", Connection, Connection->CurrentSend.SendSequence));
+ }
+ }
+ }
+
+
+ //
+ // This controls when we'll check this again.
+ //
+
+ Connection->SendWindowSequenceLimit += Connection->SendWindowSize;
+
+} /* NbiAdjustSendWindow */
+
+
+VOID
+NbiReframeConnection(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence,
+ IN USHORT BytesReceived,
+ IN BOOLEAN Resend
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when we have gotten an ack
+ for some data. It completes any sends that have
+ been acked, and if needed modifies the current send
+ pointer and queues the connection for repacketizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ ReceiveSequence - The receive sequence from the remote.
+
+ BytesReceived - The number of bytes received in this message.
+
+ Resend - If it is OK to resend based on this packet.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ PREQUEST RequestToComplete;
+ PDEVICE Device = NbiDevice;
+ CTELockHandle CancelLH;
+
+
+ //
+ // BUGBUG: We should change to stop the timer
+ // only if we go idle, since otherwise we still
+ // want it running, or will restart it when we
+ // packetize.
+ //
+
+ //
+ // See how much is acked here.
+ //
+
+ if ((Connection->CurrentSend.MessageOffset == Connection->CurrentMessageLength) &&
+ (ReceiveSequence == (USHORT)(Connection->CurrentSend.SendSequence)) &&
+ (Connection->FirstMessageRequest != NULL)) {
+
+ // Special check for 0 length send which was not accepted by the remote.
+ // In this case it will pass the above 3 conditions yet, nothing
+ // is acked. BUG#10395
+ if (!Connection->CurrentSend.MessageOffset && Connection->CurrentSend.SendSequence == Connection->UnAckedSend.SendSequence ) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+ }
+
+ //
+ // This acks the entire message.
+ //
+
+ NB_DEBUG2 (SEND, ("Got ack for entire message on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ Connection->CurrentSend.MessageOffset = 0; // BUGBUG: Needed?
+ Connection->UnAckedSend.MessageOffset = 0;
+
+ //
+ // We don't adjust the send window since we likely stopped
+ // packetizing before we hit it.
+ //
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ if (Connection->NewNetbios) {
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Request = Connection->FirstMessageRequest;
+
+ //
+ // We dequeue these requests from the connection's
+ // send queue.
+ //
+
+ if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
+
+ REQUEST_SINGLE_LINKAGE (Request) = NULL;
+
+ } else {
+
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
+ REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
+
+ }
+
+#if DBG
+ if (REQUEST_REFCOUNT(Request) > 100) {
+ DbgPrint ("Request %lx (%lx) has high refcount\n",
+ Connection, Request);
+ DbgBreakPoint();
+ }
+#endif
+ if (--REQUEST_REFCOUNT(Request) == 0) {
+
+ RequestToComplete = Request;
+
+ } else {
+
+ //
+ // There are still sends pending, this will get
+ // completed when the last send completes. Since
+ // we have already unlinked the request from the
+ // connection's send queue we can do this without
+ // any locks.
+ //
+
+ RequestToComplete = NULL;
+
+ }
+
+ //
+ // Now see if there is a send to activate.
+ //
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ //
+ // Now complete any requests we need to.
+ //
+
+ while (RequestToComplete != NULL) {
+
+ TmpRequest = REQUEST_SINGLE_LINKAGE (RequestToComplete);
+ REQUEST_STATUS (RequestToComplete) = STATUS_SUCCESS;
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ NbiCompleteRequest (RequestToComplete);
+ NbiFreeRequest (Device, RequestToComplete);
+ ++Connection->ConnectionInfo.TransmittedTsdus;
+ RequestToComplete = TmpRequest;
+
+ NbiDereferenceConnection (Connection, CREF_SEND);
+
+ }
+
+ } else if ((ReceiveSequence == Connection->CurrentSend.SendSequence) &&
+ (Connection->NewNetbios || (BytesReceived == Connection->CurrentSend.MessageOffset)) &&
+ (Connection->CurrentSend.Request != NULL)) {
+
+ //
+ // This acks whatever we sent last time, and we are
+ // not done packetizing this send, so we can repacketize.
+ // BUGBUG: With SendSequence changing as it does now,
+ // don't need the CurrentSend.Request check???
+ //
+
+ NB_DEBUG2 (SEND, ("Got full ack on %lx (%d)\n", Connection, Connection->CurrentSend.SendSequence));
+
+ NbiStopRetransmit (Connection);
+
+ if (Connection->NewNetbios) {
+
+ //
+ // If we are waiting for a window, and this does not open it
+ // anymore, then we don't reset our timers/retries.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) {
+
+ if (Connection->RemoteRcvSequenceMax != BytesReceived) {
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ if (((SHORT)(Connection->CurrentSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ } else {
+
+ //
+ // Advance this, we won't get meaningful results until we
+ // send a full window in one message.
+ //
+
+ Connection->SendWindowSequenceLimit = Connection->CurrentSend.SendSequence + Connection->SendWindowSize;
+ }
+
+ }
+
+ } else {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ Connection->RetransmitThisWindow = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ //
+ // We may be on if this ack is duplicated.
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if( Connection->FirstMessageRequest ) {
+
+ //
+ // This acked part of the current send. If the
+ // remote is requesting a resend then we advance
+ // the current send location by the amount
+ // acked and resend from there. If he does
+ // not want a resend, just ignore this.
+ //
+ // We repacketize immediately because we have
+ // backed up the pointer, and this would
+ // cause us to ignore an ack for the amount
+ // sent. Since we don't release the lock
+ // until we have packetized, the current
+ // pointer will be advanced past there.
+ //
+ // BUGBUG: If he is acking more than we sent, we
+ // ignore this -- the remote is confused and there
+ // is nothing much we can do.
+ //
+
+ if (Resend) {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RetransmitThisWindow = TRUE;
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+ }
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else if (!Connection->NewNetbios &&
+ ((ReceiveSequence == Connection->UnAckedSend.SendSequence) &&
+ (BytesReceived <= Connection->CurrentSend.MessageOffset))) {
+
+ ULONG BytesAcked =
+ BytesReceived - Connection->UnAckedSend.MessageOffset;
+
+ //
+ // Old netbios.
+ //
+
+ NbiStopRetransmit (Connection);
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ BytesAcked);
+
+ ++Connection->ConnectionInfo.TransmissionErrors;
+ ++Device->Statistics.DataFramesResent;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesResent,
+ Connection->CurrentSend.MessageOffset - Connection->UnAckedSend.MessageOffset);
+
+ //
+ // Packetize from that point on.
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+
+ //
+ // If anything was acked, reset the retry count
+ //
+ if ( BytesAcked ) {
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+ }
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE) {
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ if (Connection->NewNetbios &&
+ (((Connection->UnAckedSend.SendSequence < Connection->CurrentSend.SendSequence) &&
+ (ReceiveSequence >= Connection->UnAckedSend.SendSequence) &&
+ (ReceiveSequence < Connection->CurrentSend.SendSequence)) ||
+ ((Connection->UnAckedSend.SendSequence > Connection->CurrentSend.SendSequence) &&
+ ((ReceiveSequence >= Connection->UnAckedSend.SendSequence) ||
+ (ReceiveSequence < Connection->CurrentSend.SendSequence))))) {
+
+ BOOLEAN SomethingAcked = (BOOLEAN)
+ (ReceiveSequence != Connection->UnAckedSend.SendSequence);
+
+ //
+ // New netbios and the receive sequence is valid. We advance
+ // the back of our send window, but we don't repacketize.
+ //
+
+ //
+ // Advance our unacked pointer by the amount
+ // acked in this response.
+ //
+
+ NbiAdvanceUnAckedBySequence(
+ Connection,
+ ReceiveSequence);
+
+ Connection->RemoteRcvSequenceMax = BytesReceived; // really RcvSeqMac
+
+ //
+ // If anything was acked, then reset the retry count.
+ //
+
+ if (SomethingAcked) {
+
+ //
+ // See if we need to adjust our send window.
+ //
+
+ if (((SHORT)(Connection->UnAckedSend.SendSequence - Connection->SendWindowSequenceLimit)) >= 0) {
+
+ NbiAdjustSendWindow (Connection);
+
+ }
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
+
+
+ //
+ // Now packetize. This will set the state to
+ // something meaningful and release the lock.
+ //
+
+ if ((Connection->CurrentSend.Request != NULL) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_A_PACKETIZE)) {
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert(!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ }
+ }
+ }
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+} /* NbiReframeConnection */
+
+
+VOID
+NbiRestartConnection(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when have gotten an ack for
+ a full message, or received a response to a watchdog
+ probe, and need to check if the connection should
+ start packetizing.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request, TmpRequest;
+ ULONG TempCount;
+ PTDI_REQUEST_KERNEL_SEND Parameters;
+ PDEVICE Device = NbiDevice;
+
+ //
+ // See if there is a send to activate.
+ //
+
+ if (Connection->SendQueue.Head != NULL) {
+
+ //
+ // Take the first send off the queue and make
+ // it current.
+ //
+
+ Request = Connection->SendQueue.Head;
+ Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Request);
+
+ //
+ // BUGBUG: Cache the information about being EOM
+ // in a more easily accessible location?
+ //
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ //
+ // This is a one-request message.
+ //
+
+ Connection->CurrentSend.Request = Request;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->LastMessageRequest = Request;
+ Connection->CurrentMessageLength = Parameters->SendLength;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ } else {
+
+ //
+ // This is a multiple-request message. We scan
+ // to see if we have the end of message received
+ // yet.
+ //
+
+ TempCount = Parameters->SendLength;
+ TmpRequest = Request;
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ while (Request != NULL) {
+
+ TempCount += Parameters->SendLength;
+
+ Parameters = (PTDI_REQUEST_KERNEL_SEND)REQUEST_PARAMETERS(Request);
+ if ((Parameters->SendFlags & TDI_SEND_PARTIAL) == 0) {
+
+ Connection->CurrentSend.Request = TmpRequest;
+ Connection->CurrentSend.MessageOffset = 0;
+ Connection->CurrentSend.Buffer = REQUEST_NDIS_BUFFER (TmpRequest);
+ Connection->CurrentSend.BufferOffset = 0;
+ Connection->SendBufferInUse = FALSE;
+
+ Connection->UnAckedSend = Connection->CurrentSend;
+
+ Connection->FirstMessageRequest = TmpRequest;
+ Connection->LastMessageRequest = Request;
+#ifdef RSRC_TIMEOUT_DBG
+ KeQuerySystemTime(&Connection->FirstMessageRequestTime);
+#endif //RSRC_TIMEOUT_DBG
+
+ Connection->CurrentMessageLength = TempCount;
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_PACKETIZE;
+
+ NbiReferenceConnectionSync (Connection, CREF_PACKETIZE);
+
+ CTEAssert (!Connection->OnPacketizeQueue);
+ Connection->OnPacketizeQueue = TRUE;
+
+ NB_INSERT_TAIL_LIST(
+ &Device->PacketizeConnections,
+ &Connection->PacketizeLinkage,
+ &Device->Lock);
+
+ break;
+
+ }
+
+ Request = REQUEST_SINGLE_LINKAGE(Request);
+
+ }
+
+ if (Request == NULL) {
+
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_EOR;
+
+ }
+
+ }
+
+ } else {
+
+ Connection->FirstMessageRequest = NULL;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+
+ NbiStartWatchdog (Connection);
+
+ }
+
+} /* NbiRestartConnection */
+
+
+VOID
+NbiAdvanceUnAckedByBytes(
+ IN PCONNECTION Connection,
+ IN ULONG BytesAcked
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer by the specified number of bytes. It
+ assumes that there are enough send requests to
+ handle the number specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+ BytesAcked - The number of bytes acked.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ ULONG CurSendBufferLength;
+ ULONG BytesLeft = BytesAcked;
+ ULONG TempBytes;
+
+ while (BytesLeft > 0) {
+
+ NdisQueryBuffer (Connection->UnAckedSend.Buffer, NULL, &CurSendBufferLength);
+
+ //
+ // See if bytes acked ends within the current buffer.
+ //
+
+ if (Connection->UnAckedSend.BufferOffset + BytesLeft <
+ CurSendBufferLength) {
+
+ Connection->UnAckedSend.BufferOffset += BytesLeft;
+ Connection->UnAckedSend.MessageOffset += BytesLeft;
+ break;
+
+ } else {
+
+ TempBytes = CurSendBufferLength - Connection->UnAckedSend.BufferOffset;
+ BytesLeft -= TempBytes;
+ Connection->UnAckedSend.MessageOffset += TempBytes;
+
+ //
+ // No, so advance the buffer.
+ //
+
+ Connection->UnAckedSend.BufferOffset = 0;
+ Connection->UnAckedSend.Buffer =
+ NDIS_BUFFER_LINKAGE (Connection->UnAckedSend.Buffer);
+
+ //
+ // Is there a next buffer in this request?
+ //
+
+ if (Connection->UnAckedSend.Buffer == NULL) {
+
+ //
+ // No, so advance the request unless we are done.
+ //
+
+ if (BytesLeft == 0) {
+ return;
+ }
+
+ Connection->UnAckedSend.Request =
+ REQUEST_SINGLE_LINKAGE(Connection->UnAckedSend.Request);
+
+ if (Connection->UnAckedSend.Request == NULL) {
+ KeBugCheck (NDIS_INTERNAL_ERROR);
+ }
+
+ Connection->UnAckedSend.Buffer =
+ REQUEST_NDIS_BUFFER (Connection->UnAckedSend.Request);
+
+ }
+ }
+ }
+
+} /* NbiAdvanceUnAckedByBytes */
+
+
+VOID
+NbiAdvanceUnAckedBySequence(
+ IN PCONNECTION Connection,
+ IN USHORT ReceiveSequence
+ )
+
+/*++
+
+Routine Description:
+
+ This routine advances the Connection->UnAckedSend
+ send pointer so that the next packet to send will be
+ the correct one for ReceiveSequence. UnAckedSend
+ must point to a known valid combination. It
+ assumes that there are enough send requests to
+ handle the sequence specified.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT HELD.
+
+Arguments:
+
+ Connection - The connection.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ USHORT PacketsAcked;
+
+ //
+ // BUGBUG: Fix this to account for partial sends, where
+ // we might not have used the max. for all packets.
+ //
+
+ PacketsAcked = ReceiveSequence - Connection->UnAckedSend.SendSequence;
+
+ NbiAdvanceUnAckedByBytes(
+ Connection,
+ PacketsAcked * Connection->MaximumPacketSize);
+
+ Connection->UnAckedSend.SendSequence += PacketsAcked;
+
+} /* NbiAdvanceUnAckedBySequence */
+
+
+VOID
+NbiCancelSend(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel a send
+ The request is found on the connection's send queue.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PCONNECTION Connection;
+ PREQUEST Request = (PREQUEST)Irp;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_SYNC_CONTEXT (SyncContext)
+
+
+ CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (REQUEST_MINOR_FUNCTION(Request) == TDI_SEND));
+
+ CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
+
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ //
+ // Just stop the connection, that will tear down any
+ // sends.
+ //
+ // BUGBUG: Do we care about cancelling non-active
+ // sends without stopping the connection??
+ //
+
+ NbiReferenceConnectionSync (Connection, CREF_CANCEL);
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+
+ NB_BEGIN_SYNC (&SyncContext);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // This frees the lock, cancels any sends, etc.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_CANCELLED
+ NB_LOCK_HANDLE_ARG (LockHandle));
+
+ NbiDereferenceConnection (Connection, CREF_CANCEL);
+
+ NB_END_SYNC (&SyncContext);
+
+} /* NbiCancelSend */
+
+
+NTSTATUS
+NbiBuildBufferChainFromBufferChain (
+ IN NDIS_HANDLE BufferPoolHandle,
+ IN PNDIS_BUFFER CurrentSourceBuffer,
+ IN ULONG CurrentByteOffset,
+ IN ULONG DesiredLength,
+ OUT PNDIS_BUFFER *DestinationBuffer,
+ OUT PNDIS_BUFFER *NewSourceBuffer,
+ OUT ULONG *NewByteOffset,
+ OUT ULONG *ActualLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to build an NDIS_BUFFER chain from a source
+ NDIS_BUFFER chain and offset into it. We assume we don't know the
+ length of the source Mdl chain, and we must allocate the NDIS_BUFFERs
+ for the destination chain, which we do from the NDIS buffer pool.
+
+ If the system runs out of memory while we are building the destination
+ NDIS_BUFFER chain, we completely clean up the built chain and return with
+ NewCurrentMdl and NewByteOffset set to the current values of CurrentMdl
+ and ByteOffset.
+
+Environment:
+
+Arguments:
+
+ BufferPoolHandle - The buffer pool to allocate buffers from.
+
+ CurrentSourceBuffer - Points to the start of the NDIS_BUFFER chain
+ from which to draw the packet.
+
+ CurrentByteOffset - Offset within this NDIS_BUFFER to start the packet at.
+
+ DesiredLength - The number of bytes to insert into the packet.
+
+ DestinationBuffer - returned pointer to the NDIS_BUFFER chain describing
+ the packet.
+
+ NewSourceBuffer - returned pointer to the NDIS_BUFFER that would
+ be used for the next byte of packet. NULL if the source NDIS_BUFFER
+ chain was exhausted.
+
+ NewByteOffset - returned offset into the NewSourceBuffer for the next byte
+ of packet. NULL if the source NDIS_BUFFER chain was exhausted.
+
+ ActualLength - The actual length of the data copied.
+
+Return Value:
+
+ STATUS_SUCCESS if the build of the returned NDIS_BUFFER chain succeeded
+ and was the correct length.
+
+ STATUS_INSUFFICIENT_RESOURCES if we ran out of NDIS_BUFFERs while
+ building the destination chain.
+
+--*/
+{
+ ULONG AvailableBytes;
+ ULONG CurrentByteCount;
+ ULONG BytesCopied;
+ PNDIS_BUFFER OldNdisBuffer;
+ PNDIS_BUFFER NewNdisBuffer;
+ NDIS_STATUS NdisStatus;
+
+
+ OldNdisBuffer = CurrentSourceBuffer;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ AvailableBytes = CurrentByteCount - CurrentByteOffset;
+ if (AvailableBytes > DesiredLength) {
+ AvailableBytes = DesiredLength;
+ }
+
+ //
+ // Build the first NDIS_BUFFER, which could conceivably be the only one...
+ //
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &NewNdisBuffer,
+ BufferPoolHandle,
+ OldNdisBuffer,
+ CurrentByteOffset,
+ AvailableBytes);
+
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ *DestinationBuffer = NewNdisBuffer;
+ BytesCopied = AvailableBytes;
+
+ //
+ // Was the first NDIS_BUFFER enough data.
+ //
+
+ if (BytesCopied == DesiredLength) {
+ if (CurrentByteOffset + AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = CurrentSourceBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = CurrentSourceBuffer;
+ *NewByteOffset = CurrentByteOffset + AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ if (CurrentSourceBuffer->Next == NULL) {
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+ }
+
+ //
+ // Need more data, so follow the in Mdl chain to create a packet.
+ //
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ while (OldNdisBuffer != NULL) {
+
+ AvailableBytes = DesiredLength - BytesCopied;
+ if (AvailableBytes > CurrentByteCount) {
+ AvailableBytes = CurrentByteCount;
+ }
+
+ NdisCopyBuffer(
+ &NdisStatus,
+ &(NDIS_BUFFER_LINKAGE(NewNdisBuffer)),
+ BufferPoolHandle,
+ OldNdisBuffer,
+ 0,
+ AvailableBytes);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ //
+ // ran out of resources. put back what we've used in this call and
+ // return the error.
+ //
+
+ while (*DestinationBuffer != NULL) {
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(*DestinationBuffer);
+ NdisFreeBuffer (*DestinationBuffer);
+ *DestinationBuffer = NewNdisBuffer;
+ }
+
+ *NewByteOffset = CurrentByteOffset;
+ *NewSourceBuffer = CurrentSourceBuffer;
+
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NewNdisBuffer = NDIS_BUFFER_LINKAGE(NewNdisBuffer);
+
+ BytesCopied += AvailableBytes;
+
+ if (BytesCopied == DesiredLength) {
+ if (AvailableBytes == CurrentByteCount) {
+ *NewSourceBuffer = OldNdisBuffer->Next;
+ *NewByteOffset = 0;
+ } else {
+ *NewSourceBuffer = OldNdisBuffer;
+ *NewByteOffset = AvailableBytes;
+ }
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+ }
+
+ OldNdisBuffer = OldNdisBuffer->Next;
+ NdisQueryBuffer (OldNdisBuffer, NULL, &CurrentByteCount);
+
+ }
+
+ //
+ // We ran out of source buffer chain.
+ //
+
+ *NewSourceBuffer = NULL;
+ *NewByteOffset = 0;
+ *ActualLength = BytesCopied;
+ return STATUS_SUCCESS;
+
+} /* NbiBuildBufferChainFromBufferChain */
+
diff --git a/private/ntos/tdi/isnp/nb/session.c b/private/ntos/tdi/isnp/nb/session.c
new file mode 100644
index 000000000..fe998feb2
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/session.c
@@ -0,0 +1,2450 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ session.c
+
+Abstract:
+
+ This module contains the code to handle session frames
+ for the Netbios module of the ISN transport.
+
+Author:
+
+ Adam Barr (adamba) 28-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#ifdef RASAUTODIAL
+#include <acd.h>
+#include <acdapi.h>
+#endif // RASAUTODIAL
+#pragma hdrstop
+
+#ifdef RASAUTODIAL
+extern BOOLEAN fAcdLoadedG;
+extern ACD_DRIVER AcdDriverG;
+
+VOID
+NbiNoteNewConnection(
+ PCONNECTION pConnection
+ );
+#endif
+
+#ifdef RSRC_TIMEOUT_DBG
+VOID
+NbiSendDeathPacket(
+ IN PCONNECTION Connection,
+ IN CTELockHandle LockHandle
+ )
+{
+ PNDIS_PACKET Packet = PACKET(&NbiGlobalDeathPacket);
+ PNB_SEND_RESERVED Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
+ NB_CONNECTION UNALIGNED * Header;
+ PDEVICE Device = NbiDevice;
+ NDIS_STATUS NdisStatus;
+
+ if ( Reserved->SendInProgress ) {
+ DbgPrint("***Could not send death packet - in use\n");
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+ return;
+ }
+
+ Reserved->SendInProgress = TRUE;
+ Reserved->Type = SEND_TYPE_DEATH_PACKET;
+
+ //
+ // Fill in the IPX header -- the default header has the broadcast
+ // address on net 0 as the destination IPX address.
+ //
+
+ Header = (NB_CONNECTION UNALIGNED *)
+ (&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
+ RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
+
+ Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
+ Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
+
+ Header->IpxHeader.PacketType = 0x04;
+
+ //
+ // Now fill in the Netbios header.
+ //
+ Header->Session.ConnectionControlFlag = 0;
+ Header->Session.DataStreamType = NB_CMD_DEATH_PACKET;
+ Header->Session.SourceConnectionId = Connection->LocalConnectionId;
+ Header->Session.DestConnectionId = Connection->RemoteConnectionId;
+ Header->Session.SendSequence = 0;
+ Header->Session.TotalDataLength = 0;
+ Header->Session.Offset = 0;
+ Header->Session.DataLength = 0;
+
+
+ NB_FREE_LOCK(&Connection->Lock, LockHandle);
+
+ DbgPrint("*****Death packet is being sent for connection %lx, to <%.16s>\n",Connection, Connection->RemoteName);
+ //
+ // Now send the frame, IPX will adjust the length of the
+ // first buffer correctly.
+ //
+
+ NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
+ if ((NdisStatus =
+ (*Device->Bind.SendHandler)(
+ &Connection->LocalTarget,
+ Packet,
+ sizeof(NB_CONNECTION),
+ sizeof(NB_CONNECTION))) != STATUS_PENDING) {
+
+ NbiSendComplete(
+ Packet,
+ NdisStatus);
+
+ }
+
+}
+#endif //RSRC_TIMEOUT_DBG
+
+
+VOID
+NbiProcessSessionData(
+ IN NDIS_HANDLE MacBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR LookaheadBuffer,
+ IN UINT LookaheadBufferSize,
+ IN UINT LookaheadBufferOffset,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_DATA frames.
+
+Arguments:
+
+ MacBindingHandle - A handle to use when calling NdisTransferData.
+
+ MacReceiveContext - A context to use when calling NdisTransferData.
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The lookahead buffer, starting at the IPX
+ header.
+
+ LookaheadBufferSize - The length of the lookahead data.
+
+ LookaheadBufferOffset - The offset to add when calling
+ NdisTransferData.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)LookaheadBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PREQUEST Request;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ ULONG ReceiveFlags;
+ ULONG IndicateBytesTransferred;
+ ULONG DataAvailable, DataIndicated;
+ ULONG DestBytes, BytesToTransfer;
+ PUCHAR DataHeader;
+ BOOLEAN Last, CompleteReceive, EndOfMessage, PartialReceive, CopyLookahead;
+ NTSTATUS Status;
+ NDIS_STATUS NdisStatus;
+ ULONG NdisBytesTransferred;
+ PIRP ReceiveIrp;
+ PSINGLE_LIST_ENTRY s;
+ PNB_RECEIVE_RESERVED ReceiveReserved;
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER BufferChain;
+ ULONG BufferChainLength;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ CTELockHandle CancelLH;
+
+ if (Sess->DestConnectionId != 0xffff) {
+
+ //
+ // This is an active connection, find it using
+ // our session id.
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+#ifdef RSRC_TIMEOUT_DBG
+ if ( Connection->FirstMessageRequest && NbiGlobalDebugResTimeout ) {
+ LARGE_INTEGER CurrentTime, ElapsedTime;
+ KeQuerySystemTime(&CurrentTime);
+ ElapsedTime.QuadPart = CurrentTime.QuadPart - Connection->FirstMessageRequestTime.QuadPart;
+// DbgPrint("*****Elapsed %lx.%lx time\n",ElapsedTime.HighPart,ElapsedTime.LowPart);
+ if ( ElapsedTime.QuadPart > NbiGlobalMaxResTimeout.QuadPart ) {
+
+ DbgPrint("*****Connection %lx is not copleting irp %lx for %lx.%lx time\n",Connection, Connection->FirstMessageRequest,
+ ElapsedTime.HighPart,ElapsedTime.LowPart);
+ DbgPrint("************irp arrived at %lx.%lx current time %lx.%lx\n",
+ Connection->FirstMessageRequestTime.HighPart,Connection->FirstMessageRequestTime.LowPart,
+ CurrentTime.HighPart, CurrentTime.LowPart);
+
+ NbiSendDeathPacket( Connection, LockHandle );
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+ }
+ }
+#endif //RSRC_TIMEOUT_DBG
+
+ //
+ // The connection is up, see if this is data should
+ // be received.
+ //
+
+ if (Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) {
+
+ //
+ // This is an ack. This call releases
+ // the lock. BUGBUG: Does this need to
+ // be a function?
+ //
+
+ NbiProcessDataAck(
+ Connection,
+ Sess,
+ RemoteAddress
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // See if there is any piggyback ack here.
+ //
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. Even the old netbios sometimes piggyback
+ // acks (and doesn't send the explicit ack).
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if ((Connection->NewNetbios) &&
+ (Connection->CurrentSend.SendSequence != Connection->UnAckedSend.SendSequence)) {
+
+ //
+ // For the new netbios, even if we are not waiting
+ // for an ack he may have acked something with this
+ // send and we should check, since it may allow
+ // us to open our send window.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State != CONNECTION_STATE_ACTIVE) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ }
+
+ //
+ // This is data on the connection. First make sure
+ // it is the data we expect next.
+ //
+
+ if (Connection->NewNetbios) {
+
+ if (Sess->SendSequence != Connection->ReceiveSequence) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp data on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving a packet we have already seen, just
+ // send a normal ack, otherwise force a resend. This test
+ // we do is equivalent to
+ // Sess->SendSequence < Connection->ReceiveSequence
+ // but rearranged so it works when the numbers wrap.
+ //
+
+ if ((SHORT)(Sess->SendSequence - Connection->ReceiveSequence) < 0) {
+
+ //
+ // Since this is a resend, check if the local
+ // target has changed.
+ //
+#if defined(_PNP_POWER)
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, sizeof(IPX_LOCAL_TARGET))) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx, (%d,%d)\n", Connection,
+ Connection->LocalTarget.NicHandle.NicId, RemoteAddress->NicHandle.NicId);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#else
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+#endif _PNP_POWER
+ AckType = NbiAckResponse;
+
+ } else {
+
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // Old netbios.
+ //
+
+ if ((Sess->SendSequence != Connection->ReceiveSequence) ||
+ (Sess->Offset != Connection->CurrentReceive.MessageOffset)) {
+
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ PacketSize - sizeof(NB_CONNECTION));
+
+ if ((Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) ||
+ (Connection->ReceiveState == CONNECTION_RECEIVE_ACTIVE)) {
+
+ NB_ACK_TYPE AckType;
+
+ NB_DEBUG2 (RECEIVE, ("Got unexp on %lx, %x(%d) expect %x(%d)\n",
+ Connection, Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+
+ //
+ // If we are receiving the last packet again, just
+ // send a normal ack, otherwise force a resend.
+ //
+
+ if (((Sess->SendSequence == Connection->ReceiveSequence) &&
+ ((ULONG)(Sess->Offset + Sess->DataLength) == Connection->CurrentReceive.MessageOffset)) ||
+ (Sess->SendSequence == (USHORT)(Connection->ReceiveSequence-1))) {
+ AckType = NbiAckResponse;
+ } else {
+ AckType = NbiAckResend;
+ }
+
+ //
+ // This frees the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ AckType
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_DEBUG (RECEIVE, ("Got unexp on %lx RcvState %d, %x(%d) exp %x(%d)\n",
+ Connection, Connection->ReceiveState,
+ Sess->SendSequence, Sess->Offset,
+ Connection->ReceiveSequence, Connection->CurrentReceive.MessageOffset));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+
+ IndicateBytesTransferred = 0;
+ DataAvailable = PacketSize - sizeof(NB_CONNECTION);
+ DataIndicated = LookaheadBufferSize - sizeof(NB_CONNECTION);
+ DataHeader = LookaheadBuffer + sizeof(NB_CONNECTION);
+
+ ++Device->TempFramesReceived;
+ Device->TempFrameBytesReceived += DataAvailable;
+
+ if (Connection->CurrentIndicateOffset) {
+ CTEAssert (DataAvailable >= Connection->CurrentIndicateOffset);
+ DataAvailable -= Connection->CurrentIndicateOffset;
+ if (DataIndicated >= Connection->CurrentIndicateOffset) {
+ DataIndicated -= Connection->CurrentIndicateOffset;
+ } else {
+ DataIndicated = 0;
+ }
+ DataHeader += Connection->CurrentIndicateOffset;
+ }
+
+ CopyLookahead = (BOOLEAN)(MacOptions & NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA);
+
+ if (Connection->NewNetbios) {
+ Last = (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_EOM) != 0);
+ } else {
+ Last = (BOOLEAN)(Sess->Offset + Sess->DataLength == Sess->TotalDataLength);
+ }
+
+ Connection->CurrentReceiveNoPiggyback =
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) != 0);
+
+ if (Connection->ReceiveState == CONNECTION_RECEIVE_IDLE) {
+
+ //
+ // We don't have a receive posted, so see if we can
+ // get one from the queue or our client.
+ //
+
+ if (Connection->ReceiveQueue.Head != NULL) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Request = Connection->ReceiveQueue.Head;
+ Connection->ReceiveQueue.Head = REQUEST_SINGLE_LINKAGE(Request);
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NB_DEBUG2 (RECEIVE, ("Activated receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ if ((Connection->ReceiveUnaccepted == 0) &&
+ (Connection->AddressFile->RegisteredHandler[TDI_EVENT_RECEIVE])) {
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_INDICATE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ ReceiveFlags = TDI_RECEIVE_AT_DISPATCH_LEVEL;
+ if (Last) {
+ ReceiveFlags |= TDI_RECEIVE_ENTIRE_MESSAGE;
+ }
+ if (CopyLookahead) {
+ ReceiveFlags |= TDI_RECEIVE_COPY_LOOKAHEAD;
+ }
+
+ Status = (*Connection->AddressFile->ReceiveHandler)(
+ Connection->AddressFile->HandlerContexts[TDI_EVENT_RECEIVE],
+ Connection->Context,
+ ReceiveFlags,
+ DataIndicated,
+ DataAvailable,
+ &IndicateBytesTransferred,
+ DataHeader,
+ &ReceiveIrp);
+
+ if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // We got an IRP, activate it.
+ //
+
+ Request = NbiAllocateRequest (Device, ReceiveIrp);
+
+ IF_NOT_ALLOCATED(Request) {
+
+ ReceiveIrp->IoStatus.Information = 0;
+ ReceiveIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ IoCompleteRequest (ReceiveIrp, IO_NETWORK_INCREMENT);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ CTEAssert (REQUEST_OPEN_CONTEXT(Request) == Connection);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ PTDI_REQUEST_KERNEL_RECEIVE ReceiveParameters;
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+ Connection->ReceiveUnaccepted = DataAvailable - IndicateBytesTransferred;
+
+ Connection->ReceiveRequest = Request;
+ ReceiveParameters = (PTDI_REQUEST_KERNEL_RECEIVE)
+ (REQUEST_PARAMETERS(Request));
+ Connection->ReceiveLength = ReceiveParameters->ReceiveLength;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE) {
+ Connection->NoPiggybackHeuristic = TRUE;
+ } else {
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ ((ReceiveParameters->ReceiveFlags & TDI_RECEIVE_NO_RESPONSE_EXP) != 0);
+ }
+
+ Connection->CurrentReceive.Offset = 0;
+ Connection->CurrentReceive.Buffer = REQUEST_NDIS_BUFFER (Request);
+ Connection->CurrentReceive.BufferOffset = 0;
+
+ NbiReferenceConnectionSync (Connection, CREF_RECEIVE);
+
+ NB_DEBUG2 (RECEIVE, ("Indicate got receive %lx on %lx (%d)\n", Request, Connection, Connection->ReceiveSequence));
+
+ //
+ // Fall through the if and process the data.
+ //
+
+ } else {
+
+ //
+ // The connection has been stopped.
+ //
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ } else if (Status == STATUS_SUCCESS) {
+
+ //
+ // He accepted some or all of the data.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Indicate took receive data %lx (%d)\n", Connection, Connection->ReceiveSequence));
+
+ if ( (IndicateBytesTransferred >= DataAvailable)) {
+
+ CTEAssert (IndicateBytesTransferred == DataAvailable);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentIndicateOffset = 0;
+ if ( Last ) {
+ Connection->CurrentReceive.MessageOffset = 0;
+ } else {
+ Connection->CurrentReceive.MessageOffset+= IndicateBytesTransferred;
+ }
+
+
+ ++Connection->ConnectionInfo.ReceivedTsdus;
+
+ //
+ // If there is a send in progress, then we assume
+ // we are not in straight request-response mode
+ // and disable piggybacking of this ack.
+ //
+
+ Connection->NoPiggybackHeuristic = (BOOLEAN)
+ (Connection->SubState != CONNECTION_SUBSTATE_A_IDLE);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+ Connection->ReceiveRequest = NULL;
+
+ //
+ // This releases the lock.
+ //
+
+ NbiAcknowledgeReceive(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ //
+ // We will do the easiest thing here, which
+ // is to send an ack for the amount he
+ // took, and force a retransmit on the
+ // remote. For net netbios we make a note
+ // of how many bytes were taken and ask
+ // for a resend.
+ //
+ // BUGBUG: Handle this better??
+ //
+
+#if DBG
+ DbgPrint ("NBI: Client took partial indicate data\n");
+#endif
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->CurrentReceive.MessageOffset +=
+ IndicateBytesTransferred;
+ Connection->ReceiveUnaccepted =
+ DataAvailable - IndicateBytesTransferred;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+
+ if (Connection->NewNetbios) {
+ Connection->CurrentIndicateOffset = IndicateBytesTransferred;
+ //
+ // NOTE: We don't advance ReceiveSequence
+ //
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ Connection->NewNetbios ?
+ NbiAckResend : NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ } else {
+
+ //
+ // No IRP returned.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ Connection->ReceiveUnaccepted = DataAvailable;
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_DEBUG (RECEIVE, ("Indicate got no receive on %lx (%lx)\n", Connection, Status));
+
+ if (Connection->NewNetbios) {
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ } else {
+
+ //
+ // No receive handler.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_W_RCV;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ if (Connection->ReceiveUnaccepted == 0) {
+ NB_DEBUG (RECEIVE, ("No receive, no handler on %lx\n", Connection));
+ } else {
+ NB_DEBUG (RECEIVE, ("No receive, ReceiveUnaccepted %d on %lx\n",
+ Connection->ReceiveUnaccepted, Connection));
+ }
+
+ if (Connection->NewNetbios) {
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveSequence - 1);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ }
+
+ } else if (Connection->ReceiveState != CONNECTION_RECEIVE_ACTIVE) {
+
+ //
+ // If we have a transfer in progress, or are waiting for
+ // a receive to be posted, then ignore this frame.
+ //
+
+ NB_DEBUG2 (RECEIVE, ("Got data on %lx, state %d (%d)\n", Connection, Connection->ReceiveState, Connection->ReceiveSequence));
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ //
+ // At this point we have a receive and it is set to
+ // the correct current location.
+ //
+
+ DestBytes = Connection->ReceiveLength - Connection->CurrentReceive.Offset;
+ BytesToTransfer = DataAvailable - IndicateBytesTransferred;
+
+ if (DestBytes < BytesToTransfer) {
+
+ //
+ // If the data overflows the current receive, then make a
+ // note that we should complete the receive at the end of
+ // transfer data, but with EOR false.
+ //
+
+ EndOfMessage = FALSE;
+ CompleteReceive = TRUE;
+ PartialReceive = TRUE;
+ BytesToTransfer = DestBytes;
+
+ } else if (DestBytes == BytesToTransfer) {
+
+ //
+ // If the data just fills the current receive, then complete
+ // the receive; EOR depends on whether this is a DOL or not.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = TRUE;
+ PartialReceive = FALSE;
+
+ } else {
+
+ //
+ // Complete the receive if this is a DOL.
+ //
+
+ EndOfMessage = Last;
+ CompleteReceive = Last;
+ PartialReceive = FALSE;
+
+ }
+
+ //
+ // If we can copy the data directly, then update our
+ // pointers, send an ack, and do the copy.
+ //
+
+ if ((BytesToTransfer > 0) &&
+ (IndicateBytesTransferred + BytesToTransfer <= DataIndicated)) {
+
+ ULONG BytesNow, BytesLeft;
+ PUCHAR CurTarget, CurSource;
+ ULONG CurTargetLen;
+ PNDIS_BUFFER CurBuffer;
+ ULONG CurByteOffset;
+
+ NB_DEBUG2 (RECEIVE, ("Direct copy of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ CurBuffer = Connection->CurrentReceive.Buffer;
+ CurByteOffset = Connection->CurrentReceive.BufferOffset;
+
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurTarget += CurByteOffset;
+ CurTargetLen -= CurByteOffset;
+
+ CurSource = DataHeader + IndicateBytesTransferred;
+ BytesLeft = BytesToTransfer;
+
+ while (TRUE) {
+
+ if (CurTargetLen < BytesLeft) {
+ BytesNow = CurTargetLen;
+ } else {
+ BytesNow = BytesLeft;
+ }
+ TdiCopyLookaheadData(
+ CurTarget,
+ CurSource,
+ BytesNow,
+ CopyLookahead ? TDI_RECEIVE_COPY_LOOKAHEAD : 0);
+
+ if (BytesNow == CurTargetLen) {
+ BytesLeft -= BytesNow;
+ CurBuffer = CurBuffer->Next;
+ CurByteOffset = 0;
+ if (BytesLeft > 0) {
+ NdisQueryBuffer (CurBuffer, &CurTarget, &CurTargetLen);
+ CurSource += BytesNow;
+ } else {
+ break;
+ }
+ } else {
+ CurByteOffset += BytesNow;
+ CTEAssert (BytesLeft == BytesNow);
+ break;
+ }
+
+ }
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ Connection->CurrentReceive.Buffer = CurBuffer;
+ Connection->CurrentReceive.BufferOffset = CurByteOffset;
+
+ Connection->CurrentReceive.Offset += BytesToTransfer;
+ Connection->CurrentReceive.MessageOffset += BytesToTransfer;
+
+ if (CompleteReceive ||
+ (Connection->State != CONNECTION_STATE_ACTIVE)) {
+
+ if (EndOfMessage) {
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax; // harmless if NewNetbios is FALSE
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->CurrentIndicateOffset = 0;
+
+ } else if (Connection->NewNetbios) {
+
+ if (PartialReceive) {
+ Connection->CurrentIndicateOffset += BytesToTransfer;
+ } else {
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+ }
+ }
+
+ //
+ // This sends an ack and releases the connection lock.
+ // and CANCEL Lock.
+ //
+
+ NbiCompleteReceive(
+ Connection,
+ EndOfMessage,
+ CancelLH
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_SWAP_IRQL( CancelLH, LockHandle);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+ //
+ // CompleteReceive is FALSE, so EndOfMessage is FALSE.
+ //
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_ACTIVE;
+
+ //
+ // This releases the lock.
+ //
+
+ if (Connection->NewNetbios) {
+
+ //
+ // A partial receive should only happen if we are
+ // completing the receive.
+ //
+
+ CTEAssert (!PartialReceive);
+
+ ++Connection->ReceiveSequence;
+ ++Connection->LocalRcvSequenceMax;
+ Connection->CurrentIndicateOffset = 0;
+
+ if ((Connection->CurrentReceiveNoPiggyback) ||
+ ((Device->AckWindow != 0) &&
+ (++Connection->ReceivesWithoutAck >= Device->AckWindow))) {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ } else {
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ }
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+
+ //
+ // We have to set up a call to transfer data and send
+ // the ack after it completes (if it succeeds).
+ //
+
+ s = NbiPopReceivePacket (Device);
+ if (s == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ ++Connection->ConnectionInfo.ReceiveErrors;
+ ++Device->Statistics.DataFramesRejected;
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesRejected,
+ DataAvailable);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+ }
+
+ ReceiveReserved = CONTAINING_RECORD (s, NB_RECEIVE_RESERVED, PoolLinkage);
+ Packet = CONTAINING_RECORD (ReceiveReserved, NDIS_PACKET, ProtocolReserved[0]);
+
+ //
+ // Initialize the receive packet.
+ //
+
+ ReceiveReserved->u.RR_CO.Connection = Connection;
+ ReceiveReserved->u.RR_CO.EndOfMessage = EndOfMessage;
+ ReceiveReserved->u.RR_CO.CompleteReceive = CompleteReceive;
+ ReceiveReserved->u.RR_CO.PartialReceive = PartialReceive;
+
+ ReceiveReserved->Type = RECEIVE_TYPE_DATA;
+ CTEAssert (!ReceiveReserved->TransferInProgress);
+ ReceiveReserved->TransferInProgress = TRUE;
+
+ //
+ // if we've got zero bytes left, avoid the TransferData below and
+ // just deliver.
+ //
+
+ if (BytesToTransfer <= 0) {
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("TransferData of 0 bytes %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiTransferDataComplete(
+ Packet,
+ NDIS_STATUS_SUCCESS,
+ 0);
+
+ return;
+ }
+
+ //
+ // If needed, build a buffer chain to describe this
+ // to NDIS.
+ //
+
+ Connection->PreviousReceive = Connection->CurrentReceive;
+
+ if ((Connection->CurrentReceive.Offset == 0) &&
+ CompleteReceive) {
+
+ BufferChain = Connection->CurrentReceive.Buffer;
+ BufferChainLength = BytesToTransfer;
+ Connection->CurrentReceive.Buffer = NULL;
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = TRUE;
+
+ } else {
+
+ if (NbiBuildBufferChainFromBufferChain (
+ Device->NdisBufferPoolHandle,
+ Connection->CurrentReceive.Buffer,
+ Connection->CurrentReceive.BufferOffset,
+ BytesToTransfer,
+ &BufferChain,
+ &Connection->CurrentReceive.Buffer,
+ &Connection->CurrentReceive.BufferOffset,
+ &BufferChainLength) != NDIS_STATUS_SUCCESS) {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NB_DEBUG2 (RECEIVE, ("Could not build receive buffer chain %lx (%d)\n", Connection, Connection->ReceiveSequence));
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+ return;
+
+ }
+
+ ReceiveReserved->u.RR_CO.NoNdisBuffer = FALSE;
+
+ }
+
+
+ NdisChainBufferAtFront (Packet, BufferChain);
+
+ Connection->ReceiveState = CONNECTION_RECEIVE_TRANSFER;
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_DEBUG2 (RECEIVE, ("TransferData of %d bytes %lx (%d)\n", BytesToTransfer, Connection, Connection->ReceiveSequence));
+
+ (*Device->Bind.TransferDataHandler) (
+ &NdisStatus,
+ MacBindingHandle,
+ MacReceiveContext,
+ LookaheadBufferOffset + sizeof(NB_CONNECTION) +
+ Connection->CurrentIndicateOffset + IndicateBytesTransferred,
+ BytesToTransfer,
+ Packet,
+ (PUINT)&NdisBytesTransferred);
+
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+#if DBG
+ if (NdisStatus == STATUS_SUCCESS) {
+ CTEAssert (NdisBytesTransferred == BytesToTransfer);
+ }
+#endif
+
+ NbiTransferDataComplete (
+ Packet,
+ NdisStatus,
+ NdisBytesTransferred);
+
+ }
+
+ return;
+
+ }
+
+ } else if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
+ (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
+
+ //
+ // If this is the ack for the session initialize, then
+ // complete the pending connects. This routine releases
+ // the connection lock.
+ //
+
+ NbiProcessSessionInitAck(
+ Connection,
+ Sess
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ //
+ // This is a session initialize frame.
+ //
+ // BUGBUG: If there is more data than in the lookahead
+ // buffer, we won't be able to echo it back in the
+ // response.
+ //
+
+ NbiProcessSessionInitialize(
+ RemoteAddress,
+ MacOptions,
+ LookaheadBuffer,
+ LookaheadBufferSize);
+
+ }
+
+} /* NbiProcessSessionData */
+
+
+VOID
+NbiProcessDataAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess,
+ IN PIPX_LOCAL_TARGET RemoteAddress
+ NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine processes an ack on an active connection.
+
+ NOTE: THIS FUNCTION IS CALLED WITH CONNECTION->LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The session frame.
+
+ RemoteAddress - The local target this packet was received from.
+
+ LockHandle - The handle used to acquire the lock.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ BOOLEAN Resend;
+
+ //
+ // Make sure we expect an ack right now.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (((Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W)) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We are waiting for an ack (because we completed
+ // packetizing a send, or ran out of receive window).
+ //
+ // This will complete any sends that are acked by
+ // this receive, and if necessary readjust the
+ // send pointer and requeue the connection for
+ // packetizing. It release the connection lock.
+ //
+
+ if (Connection->ResponseTimeout) {
+ Resend = TRUE;
+ Connection->ResponseTimeout = FALSE;
+ } else {
+ Resend = (BOOLEAN)
+ ((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0);
+ }
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ Resend
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ //
+ // We had a probe outstanding and got a response. Restart
+ // the connection if needed (a send may have just been
+ // posted while the probe was outstanding).
+ //
+ // BUGBUG: We should check that the response is really
+ // correct.
+ //
+
+ if (Connection->NewNetbios) {
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ }
+
+ NbiRestartConnection (Connection);
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_PACKETIZE) &&
+ ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0)) {
+
+ if (Connection->NewNetbios) {
+
+ //
+ // We are packetizing, reframe. In the unlikely
+ // event that this acks everything we may packetize
+ // in this call, but that is OK (the other thread
+ // will exit if we finish up). More normally we
+ // will just advance UnAcked send a bit.
+ //
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ (BOOLEAN)((Sess->ConnectionControlFlag & NB_CONTROL_RESEND) != 0)
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+#if 0
+
+ //
+ // BUGBUG: Should handle this case (i.e. may be in W_PACKET).
+ //
+
+ } else if ((Sess->ConnectionControlFlag & NB_CONTROL_SEND_ACK) == 0) {
+
+ DbgPrint ("NWLNKNB: Ignoring ack, state is %d\n", Connection->SubState);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+#endif
+
+ } else {
+
+ //
+ // We got a probe from the remote. Some old DOS clients
+ // send probes that do not have the send ack bit on,
+ // so we respond to any probe if none of the conditions
+ // above are true. This call releases the lock.
+ //
+ // We use the IgnoreNextDosProbe flag to ignore every
+ // second probe of this nature, to avoid a data ack
+ // war between two machines who each think they are
+ // responding to the other. This flag is set to FALSE
+ // whenever we send an ack or a probe.
+ //
+
+ if (!Connection->IgnoreNextDosProbe) {
+
+ //
+ // Since this is a probe, check if the local
+ // target has changed.
+ //
+
+ if (!RtlEqualMemory (&Connection->LocalTarget, RemoteAddress, 8)) {
+#if DBG
+ DbgPrint ("NBI: Switch local target for %lx\n", Connection);
+#endif
+ Connection->LocalTarget = *RemoteAddress;
+ }
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+ Connection->IgnoreNextDosProbe = TRUE;
+
+ } else {
+
+ Connection->IgnoreNextDosProbe = FALSE;
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ return;
+
+ }
+
+} /* NbiProcessDataAck */
+
+
+VOID
+NbiProcessSessionInitialize(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION frames which have
+ a remote connection ID of 0xffff -- these are session
+ initialize frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ PacketBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ CONNECT_INDICATION TempConnInd;
+ PCONNECT_INDICATION ConnInd;
+ PCONNECTION Connection;
+ PADDRESS Address;
+ PREQUEST Request, ListenRequest, AcceptRequest;
+ PDEVICE Device = NbiDevice;
+ PLIST_ENTRY p;
+ ULONG Hash;
+ TA_NETBIOS_ADDRESS SourceName;
+ PIRP AcceptIrp;
+ CONNECTION_CONTEXT ConnectionContext;
+ NTSTATUS AcceptStatus;
+ PADDRESS_FILE AddressFile, ReferencedAddressFile;
+ PTDI_REQUEST_KERNEL_LISTEN ListenParameters;
+ PTDI_CONNECTION_INFORMATION ListenInformation;
+ PTDI_CONNECTION_INFORMATION RemoteInformation;
+ TDI_ADDRESS_NETBIOS UNALIGNED * ListenAddress;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+ NB_DEFINE_LOCK_HANDLE (LockHandle3)
+ CTELockHandle CancelLH;
+
+ //
+ // Verify that the whole packet is there.
+ //
+
+ if (PacketSize < (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT))) {
+#if DBG
+ DbgPrint ("NBI: Got short session initialize, %d/%d\n", PacketSize,
+ sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+#endif
+ return;
+ }
+
+ //
+ // Verify that MaximumDataSize that remote can support is > 0
+ // Bug # 19405
+ //
+ if ( SessInit->MaximumDataSize == 0 ) {
+ NB_DEBUG(CONNECTION, ("Connect request with MaximumDataSize == 0\n"
+));
+ return;
+ }
+
+ //
+ // Make sure this is for an address we care about.
+ //
+
+ if (Device->AddressCounts[SessInit->DestinationName[0]] == 0) {
+ return;
+ }
+
+ Address = NbiFindAddress (Device, (PUCHAR)SessInit->DestinationName);
+
+ if (Address == NULL) {
+ return;
+ }
+
+ //
+ // First see if we have a session to this remote. We check
+ // this in case our ack of the session initialize was dropped,
+ // we don't want to reindicate our client.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ for (Hash = 0; Hash < CONNECTION_HASH_COUNT; Hash++) {
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if ((RtlEqualMemory (&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (Connection->RemoteConnectionId == Sess->SourceConnectionId) &&
+ (Connection->State != CONNECTION_STATE_DISCONNECT)) {
+
+ //
+ // Yes, we are talking to this remote, if it is active then
+ // respond, otherwise we are in the process of connecting
+ // and we will respond eventually.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Got connect request on active connection %lx\n", Connection);
+#endif
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ NbiSendSessionInitAck(
+ Connection,
+ (PUCHAR)(SessInit+1),
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT)),
+ NULL); // lock is not held
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ Connection = Connection->NextConnection;
+ }
+ }
+
+
+ TdiBuildNetbiosAddress ((PUCHAR)SessInit->SourceName, FALSE, &SourceName);
+
+ //
+ // Scan the queue of listens to see if there is one that
+ // satisfies this request.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ListenQueue.Flink;
+ p != &Device->ListenQueue;
+ p = p->Flink) {
+
+ Request = LIST_ENTRY_TO_REQUEST (p);
+ Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
+
+ if (Connection->AddressFile->Address != Address) {
+ continue;
+ }
+
+ //
+ // Check that this listen is not specific to a different
+ // netbios name.
+ //
+
+ ListenParameters = (PTDI_REQUEST_KERNEL_LISTEN)REQUEST_PARAMETERS(Request);
+ ListenInformation = ListenParameters->RequestConnectionInformation;
+
+ if (ListenInformation &&
+ (ListenInformation->RemoteAddress) &&
+ (ListenAddress = NbiParseTdiAddress(ListenInformation->RemoteAddress, FALSE)) &&
+ (!RtlEqualMemory(
+ SessInit->SourceName,
+ ListenAddress->NetbiosName,
+ 16))) {
+ continue;
+ }
+
+ //
+ // This connection is valid, so we use it.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen %lx\n", Connection));
+
+ RemoveEntryList (REQUEST_LINKAGE(Request));
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ //
+ // Save this information now for whenever we complete the listen.
+ //
+
+ RemoteInformation = ListenParameters->ReturnConnectionInformation;
+
+ if (RemoteInformation != NULL) {
+
+ RtlCopyMemory(
+ (PTA_NETBIOS_ADDRESS)RemoteInformation->RemoteAddress,
+ &SourceName,
+ (RemoteInformation->RemoteAddressLength < sizeof(TA_NETBIOS_ADDRESS)) ?
+ RemoteInformation->RemoteAddressLength : sizeof(TA_NETBIOS_ADDRESS));
+ }
+
+
+ if (ListenParameters->RequestFlags & TDI_QUERY_ACCEPT) {
+
+ //
+ // We have to wait for an accept before sending the
+ // session init ack, so we complete the listen and wait.
+ //
+
+ ListenRequest = Request;
+ Connection->ListenRequest = NULL;
+
+ NB_DEBUG2 (CONNECTION, ("Queued listen on %lx awaiting accept\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ACCEPT;
+
+ NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_W_ACCEPT);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ } else {
+
+ //
+ // We are ready to go, so we send out the find route request
+ // for the remote. We keep the listen alive and the CREF_LISTEN
+ // reference on until this completes.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Activating queued listen on %lx\n", Connection));
+
+ ListenRequest = NULL;
+
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ }
+
+ //
+ // Complete the listen if needed.
+ //
+
+ if (ListenRequest != NULL) {
+
+ REQUEST_INFORMATION (ListenRequest) = 0;
+ REQUEST_STATUS (ListenRequest) = STATUS_SUCCESS;
+
+ NB_GET_CANCEL_LOCK ( &CancelLH );
+ IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ NbiCompleteRequest (ListenRequest);
+ NbiFreeRequest (Device, ListenRequest);
+
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+ return;
+
+ }
+
+ //
+ // We could not find a listen, so we indicate to every
+ // client. Make sure there is no session initialize for this
+ // remote being indicated. If there is not, we insert
+ // ourselves in the queue to block others.
+ //
+ // NOTE: The device lock is held here.
+ //
+
+ for (p = Device->ConnectIndicationInProgress.Flink;
+ p != &Device->ConnectIndicationInProgress;
+ p = p->Flink) {
+
+ ConnInd = CONTAINING_RECORD (p, CONNECT_INDICATION, Linkage);
+
+ if ((RtlEqualMemory(ConnInd->NetbiosName, SessInit->DestinationName, 16)) &&
+ (RtlEqualMemory(&ConnInd->RemoteAddress, Conn->IpxHeader.SourceNetwork, 12)) &&
+ (ConnInd->ConnectionId == Sess->SourceConnectionId)) {
+
+ //
+ // We are processing a request from this remote for
+ // the same ID, to avoid confusion we just exit.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Already processing connect to <%.16s>\n", SessInit->DestinationName);
+#endif
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NbiDereferenceAddress (Address, AREF_FIND);
+ return;
+ }
+
+ }
+
+ RtlCopyMemory (&TempConnInd.RemoteAddress, SessInit->DestinationName, 16);
+ RtlCopyMemory (&TempConnInd.RemoteAddress, Conn->IpxHeader.SourceNetwork, 12);
+ TempConnInd.ConnectionId = Sess->SourceConnectionId;
+
+ InsertTailList (&Device->ConnectIndicationInProgress, &TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+
+ //
+ // Now scan through the address to find someone who has
+ // an indication routine registed and wants this connection.
+ //
+
+
+ ReferencedAddressFile = NULL;
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ for (p = Address->AddressFileDatabase.Flink;
+ p != &Address->AddressFileDatabase;
+ p = p->Flink) {
+
+ //
+ // Find the next open address file in the list.
+ //
+
+ AddressFile = CONTAINING_RECORD (p, ADDRESS_FILE, Linkage);
+ if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
+ continue;
+ }
+
+ NbiReferenceAddressFileLock (AddressFile, AFREF_INDICATION);
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+ ReferencedAddressFile = AddressFile;
+
+ //
+ // No posted listen requests; is there a kernel client?
+ //
+
+ if (AddressFile->RegisteredHandler[TDI_EVENT_CONNECT]) {
+
+ if ((*AddressFile->ConnectionHandler)(
+ AddressFile->HandlerContexts[TDI_EVENT_CONNECT],
+ sizeof (TA_NETBIOS_ADDRESS),
+ &SourceName,
+ 0, // user data
+ NULL,
+ 0, // options
+ NULL,
+ &ConnectionContext,
+ &AcceptIrp) != STATUS_MORE_PROCESSING_REQUIRED) {
+
+ //
+ // The client did not return a request, go to the
+ // next address file.
+ //
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+ continue;
+
+ }
+
+ AcceptRequest = NbiAllocateRequest (Device, AcceptIrp);
+
+ IF_NOT_ALLOCATED(AcceptRequest) {
+
+ AcceptStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ //
+ // The client accepted the connect, so activate
+ // the connection and complete the accept.
+ // listen. This lookup references the connection
+ // so we know it will remain valid.
+ //
+
+ Connection = NbiLookupConnectionByContext (
+ AddressFile,
+ ConnectionContext);
+
+ if (Connection != NULL) {
+
+ ASSERT (Connection->AddressFile == AddressFile);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle2);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+
+ if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
+ (Connection->DisassociatePending == NULL) &&
+ (Connection->ClosePending == NULL)) {
+
+ NB_DEBUG2 (CONNECTION, ("Indication on %lx returned connection %lx\n", AddressFile, Connection));
+
+ Connection->State = CONNECTION_STATE_LISTENING;
+ Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
+
+ Connection->Retries = Device->KeepAliveCount;
+
+ RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, Conn->IpxHeader.SourceNetwork, 12);
+ RtlCopyMemory (Connection->RemoteName, SessInit->SourceName, 16);
+ Connection->LocalTarget = *RemoteAddress;
+
+ Connection->SessionInitAckDataLength =
+ PacketSize - (sizeof(IPX_HEADER) + sizeof(NB_SESSION) + sizeof(NB_SESSION_INIT));
+ if (Connection->SessionInitAckDataLength > 0) {
+ Connection->SessionInitAckData = NbiAllocateMemory(
+ Connection->SessionInitAckDataLength, MEMORY_CONNECTION, "SessionInitAckData");
+ RtlCopyMemory(
+ Connection->SessionInitAckData,
+ (PUCHAR)(SessInit+1),
+ Connection->SessionInitAckDataLength);
+ }
+
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+
+ (VOID)NbiAssignConnectionId (Device, Connection); // BUGBUG: Check return code.
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 0;
+ Connection->UnAckedSend.SendSequence = 0;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 1;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = Device->KeepAliveCount;
+ if (Device->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax = 4; // may get modified after ripping based on card
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 2;
+ if (Connection->RemoteRcvSequenceMax == 0) {
+ Connection->RemoteRcvSequenceMax = 1;
+ }
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_ACCEPT);
+ NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
+
+ Connection->AcceptRequest = AcceptRequest;
+ AcceptStatus = STATUS_PENDING;
+
+ //
+ // Take us out of this list now, we will jump to
+ // FoundConnection which is past the removal below.
+ //
+
+ RemoveEntryList (&TempConnInd.Linkage);
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Conn->IpxHeader.SourceNode,6);
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
+
+ //
+ // When this completes, we will send the session init
+ // ack. We don't call it if the client is for network 0,
+ // instead just fake as if no route could be found
+ // and we will use the local target we got here.
+ // The accept is completed when this completes.
+ //
+
+ if (*(UNALIGNED ULONG *)Conn->IpxHeader.SourceNetwork != 0) {
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ } else {
+
+ NbiFindRouteComplete(
+ &Connection->FindRouteRequest,
+ FALSE);
+
+ }
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned invalid connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle2);
+
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_BY_CONTEXT);
+
+ } else {
+
+ NB_DEBUG (CONNECTION, ("Indication on %lx returned unknown connection %lx\n", AddressFile, Connection));
+ AcceptStatus = STATUS_INVALID_CONNECTION;
+
+ }
+ }
+
+ //
+ // Complete the accept request in the failure case.
+ //
+
+ if (AcceptStatus != STATUS_PENDING) {
+
+ REQUEST_STATUS (AcceptRequest) = AcceptStatus;
+
+ NbiCompleteRequest (AcceptRequest);
+ NbiFreeRequest (Device, AcceptRequest);
+
+ } else {
+
+ //
+ // We found a connection, so we break; this is
+ // a jump since the while exit assumes the
+ // address lock is held.
+ //
+
+ goto FoundConnection;
+
+ }
+
+ }
+
+ NB_SYNC_GET_LOCK (&Address->Lock, &LockHandle1);
+
+ } // end of for loop through the address files
+
+ NB_SYNC_FREE_LOCK (&Address->Lock, LockHandle1);
+
+
+ //
+ // Take us out of the list that blocks other indications
+ // from this remote to this address.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle3);
+ RemoveEntryList (&TempConnInd.Linkage);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle3);
+
+FoundConnection:
+
+ if (ReferencedAddressFile != NULL) {
+ NbiDereferenceAddressFile (ReferencedAddressFile, AFREF_INDICATION);
+ }
+
+ NbiDereferenceAddress (Address, AREF_FIND);
+
+} /* NbiProcessSessionInitialize */
+
+
+VOID
+NbiProcessSessionInitAck(
+ IN PCONNECTION Connection,
+ IN NB_SESSION UNALIGNED * Sess
+ IN NB_LOCK_HANDLE_PARAM(LockHandle)
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles session init ack frames.
+
+ THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
+ AND RETURNS WITH IT RELEASED.
+
+Arguments:
+
+ Connection - The connection.
+
+ Sess - The netbios header for the received frame.
+
+ LockHandle - The handle with which Connection->Lock was acquired.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREQUEST Request;
+ NB_SESSION_INIT UNALIGNED * SessInit = (NB_SESSION_INIT UNALIGNED *)(Sess+1);
+ BOOLEAN TimerWasStopped = FALSE;
+ CTELockHandle CancelLH;
+
+ if ((Sess->ConnectionControlFlag & NB_CONTROL_SYSTEM) &&
+ (Sess->SendSequence == 0x0000) &&
+ (Sess->ReceiveSequence == 0x0001)) {
+
+ NB_DEBUG2 (CONNECTION, ("Completing connect on %lx\n", Connection));
+
+ if (CTEStopTimer (&Connection->Timer)) {
+ TimerWasStopped = TRUE;
+ }
+
+ Connection->State = CONNECTION_STATE_ACTIVE;
+ Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
+ Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
+
+ if (Connection->Retries == NbiDevice->ConnectionCount) {
+ ++NbiDevice->Statistics.ConnectionsAfterNoRetry;
+ } else {
+ ++NbiDevice->Statistics.ConnectionsAfterRetry;
+ }
+ ++NbiDevice->Statistics.OpenConnections;
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ NbiStartWatchdog (Connection);
+
+ Connection->RemoteConnectionId = Sess->SourceConnectionId;
+
+ Connection->CurrentSend.SendSequence = 1;
+ Connection->UnAckedSend.SendSequence = 1;
+ Connection->RetransmitThisWindow = FALSE;
+ Connection->ReceiveSequence = 0;
+ Connection->CurrentReceive.MessageOffset = 0;
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ if (NbiDevice->Extensions && ((Sess->ConnectionControlFlag & NB_CONTROL_NEW_NB) != 0)) {
+ Connection->NewNetbios = TRUE;
+ Connection->LocalRcvSequenceMax =
+ (USHORT)(Connection->ReceiveWindowSize - 1);
+ Connection->RemoteRcvSequenceMax = Sess->ReceiveSequenceMax;
+ Connection->SendWindowSequenceLimit = 3;
+ } else {
+ Connection->NewNetbios = FALSE;
+ }
+
+ if (Connection->MaximumPacketSize > SessInit->MaximumDataSize) {
+ Connection->MaximumPacketSize = SessInit->MaximumDataSize;
+ }
+
+ Request = Connection->ConnectRequest;
+
+#ifdef RASAUTODIAL
+ //
+ // Check to see if we have to notify
+ // the automatic connection driver about
+ // this connection.
+ //
+ if (fAcdLoadedG) {
+ BOOLEAN fEnabled;
+ CTELockHandle AcdHandle;
+
+ CTEGetLock(&AcdDriverG.SpinLock, &AcdHandle);
+ fEnabled = AcdDriverG.fEnabled;
+ CTEFreeLock(&AcdDriverG.SpinLock, AcdHandle);
+ if (fEnabled)
+ NbiNoteNewConnection(Connection);
+ }
+#endif // RASAUTODIAL
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ NB_GET_CANCEL_LOCK( &CancelLH );
+ IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
+ NB_FREE_CANCEL_LOCK( CancelLH );
+
+ REQUEST_STATUS (Request) = STATUS_SUCCESS;
+ NbiCompleteRequest (Request);
+ NbiFreeRequest (Device, Request);
+
+ NbiTransferReferenceConnection (Connection, CREF_CONNECT, CREF_ACTIVE);
+
+ if (TimerWasStopped) {
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiProcessSessionInitAck */
+
+
+VOID
+NbiProcessSessionEnd(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+ NB_DEFINE_LOCK_HANDLE (LockHandle2)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+
+ //
+ // We reply to any session end, even if we don't know the
+ // connection, to speed up the disconnect on the remote.
+ //
+
+ if (Connection == NULL) {
+
+ NB_DEBUG (CONNECTION, ("Session end received on unknown id %lx\n", Sess->DestConnectionId));
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+
+ if (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK) {
+
+ //
+ // We are waiting for an ack, so see if this acks
+ // anything. We do this in case a full send has been
+ // received by the remote but he did not send an
+ // ack before the session went down -- this will
+ // prevent us from failing a send which actually
+ // succeeded. If we are not in W_ACK this may ack
+ // part of a send, but in that case we don't care
+ // since StopConnection will abort it anyway and
+ // the amount successfully received by the remote
+ // doesn't matter.
+ //
+ // This releases the lock. BUGBUG: Fix this.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Session end at W_ACK, reframing %lx (%d)\n", Connection, Sess->ReceiveSequence));
+
+ NbiReframeConnection(
+ Connection,
+ Sess->ReceiveSequence,
+ Sess->BytesReceived,
+ FALSE
+ NB_LOCK_HANDLE_ARG(LockHandle1));
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on connection %lx\n", Connection));
+
+ }
+
+ //
+ // This call sets the state to DISCONNECT and
+ // releases the connection lock. It will also
+ // complete a disconnect wait request if one
+ // is pending, and indicate to our client
+ // if needed.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_REMOTE_DISCONNECT
+ NB_LOCK_HANDLE_ARG (LockHandle1));
+
+ } else {
+
+ NB_DEBUG2 (CONNECTION, ("Session end received on inactive connection %lx\n", Connection));
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ }
+
+ NbiSendSessionEndAck(
+ (TDI_ADDRESS_IPX UNALIGNED *)(Conn->IpxHeader.SourceNetwork),
+ RemoteAddress,
+ Sess);
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEnd */
+
+
+VOID
+NbiProcessSessionEndAck(
+ IN PIPX_LOCAL_TARGET RemoteAddress,
+ IN ULONG MacOptions,
+ IN PUCHAR PacketBuffer,
+ IN UINT PacketSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles NB_CMD_SESSION_END_ACK frames.
+
+Arguments:
+
+ RemoteAddress - The local target this packet was received from.
+
+ MacOptions - The MAC options for the underlying NDIS binding.
+
+ LookaheadBuffer - The packet data, starting at the IPX
+ header.
+
+ PacketSize - The total length of the packet, starting at the
+ IPX header.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NB_CONNECTION UNALIGNED * Conn = (NB_CONNECTION UNALIGNED *)PacketBuffer;
+ NB_SESSION UNALIGNED * Sess = (NB_SESSION UNALIGNED *)(&Conn->Session);
+ PCONNECTION Connection;
+ PDEVICE Device = NbiDevice;
+ ULONG Hash;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // This is an active connection, find it using
+ // our session id (BUGBUG: Make this a function).
+ //
+
+ Hash = (Sess->DestConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ Connection = Device->ConnectionHash[Hash].Connections;
+
+ while (Connection != NULL) {
+
+ if (Connection->LocalConnectionId == Sess->DestConnectionId) {
+ break;
+ }
+ Connection = Connection->NextConnection;
+ }
+
+ if (Connection == NULL) {
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+ return;
+ }
+
+ NbiReferenceConnectionLock (Connection, CREF_INDICATE);
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+ //
+ // See what is happening with this connection.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_DISCONNECT) {
+
+ //
+ // Stop the timer, when the reference goes away it
+ // will shut down. We set the substate so if the
+ // timer is running it will not restart (BUGBUG:
+ // there is a small window here, but it is not
+ // harmful, we will just have to timeout one
+ // more time).
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Got session end ack on %lx\n", Connection));
+
+ Connection->SubState = CONNECTION_SUBSTATE_D_GOT_ACK;
+ if (CTEStopTimer (&Connection->Timer)) {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ NbiDereferenceConnection (Connection, CREF_TIMER);
+ } else {
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_INDICATE);
+
+} /* NbiProcessSessionEndAck */
+
diff --git a/private/ntos/tdi/isnp/nb/sources.inc b/private/ntos/tdi/isnp/nb/sources.inc
new file mode 100644
index 000000000..f54b4918b
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/sources.inc
@@ -0,0 +1,69 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=nwlnknb
+
+TARGETNAME=nwlnknb
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\tdi.lib \
+ $(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+INCLUDES=..;..\inc;..\..\inc;..\..\..\..\inc;..\..\..\..\..\inc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+C_DEFINES=$(C_DEFINES) -D_NTDRIVER_ -D_PNP_POWER=1 -DRASAUTODIAL
+#-DRSRC_TIMEOUT_DBG
+
+!IFDEF BUILD_FOR_3_51
+C_DEFINES= $(C_DEFINES) -D_NTIFS_
+!ENDIF
+
+SOURCES= \
+ ..\action.c \
+ ..\address.c \
+ ..\autodial.c \
+ ..\bind.c \
+ ..\cache.c \
+ ..\config.c \
+ ..\connect.c \
+ ..\datagram.c \
+ ..\device.c \
+ ..\driver.c \
+ ..\event.c \
+ ..\frame.c \
+ ..\nwlnknb.rc \
+ ..\packet.c \
+ ..\query.c \
+ ..\receive.c \
+ ..\send.c \
+ ..\session.c \
+ ..\timer.c
+
+PRECOMPILED_INCLUDE=..\precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
+ \ No newline at end of file
diff --git a/private/ntos/tdi/isnp/nb/timer.c b/private/ntos/tdi/isnp/nb/timer.c
new file mode 100644
index 000000000..381b120e5
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/timer.c
@@ -0,0 +1,1233 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ timer.c
+
+Abstract:
+
+ This module contains code which implements the timers for
+ netbios.
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+ULONG NbiTickIncrement = 0;
+ULONG NbiShortTimerDeltaTicks = 0;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,NbiInitializeTimers)
+#endif
+
+
+VOID
+NbiStartRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the retransmit timer for the given connection.
+ The connection is inserted on the short list if it isn't on already.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+
+ //
+ // Insert us in the queue if we aren't in it.
+ //
+
+ Connection->Retransmit =
+ Device->ShortAbsoluteTime + Connection->CurrentRetransmitTimeout;
+
+ if (!Connection->OnShortList) {
+
+ CTEAssert (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnShortList) {
+ Connection->OnShortList = TRUE;
+ InsertTailList (&Device->ShortList, &Connection->ShortList);
+ }
+
+ if (!Device->ShortListActive) {
+ NbiStartShortTimer (Device);
+ Device->ShortListActive = TRUE;
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartRetransmit */
+
+
+VOID
+NbiStartWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the watchdog timer for a connection.
+
+ NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ Connection->Watchdog = Device->LongAbsoluteTime + Connection->WatchdogTimeout;
+
+ if (!Connection->OnLongList) {
+
+ ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (!Connection->OnLongList) {
+ Connection->OnLongList = TRUE;
+ InsertTailList (&Device->LongList, &Connection->LongList);
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ }
+
+} /* NbiStartWatchdog */
+
+#if DBG
+
+VOID
+NbiStopRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the retransmit timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Retransmit = 0;
+
+} /* NbiStopRetransmit */
+
+
+VOID
+NbiStopWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops the watchdog timer for a connection.
+
+Arguments:
+
+ Connection - pointer to the connection.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Connection->Watchdog = 0;
+
+} /* NbiStopWatchdog */
+#endif
+
+
+VOID
+NbiExpireRetransmit(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's retransmit timer
+ expires. It is called from NbiShortTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = NbiDevice;
+ BOOLEAN SendFindRoute;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ SendFindRoute = FALSE;
+
+ ++Device->Statistics.ResponseTimerExpirations;
+
+ if (!(Connection->NewNetbios) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Wait for ack timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ //
+ // Set our current packetize location back to the
+ // spot of the last ack, and start up again.
+ //
+ // BUGBUG: Should we send a probe here?
+ //
+
+ Connection->CurrentSend = Connection->UnAckedSend;
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NB_DEBUG2 (SEND, ("Connection %lx retransmit timeout\n", Connection));
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // This releases the lock.
+ //
+
+ NbiPacketizeSend(
+ Connection
+ NB_LOCK_HANDLE_ARG(LockHandle)
+ );
+
+ }
+
+ } else if ((Connection->SubState == CONNECTION_SUBSTATE_A_W_PROBE) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_REMOTE_W) ||
+ (Connection->SubState == CONNECTION_SUBSTATE_A_W_ACK)) {
+
+ if (--Connection->Retries == 0) {
+
+ //
+ // Shut down the connection. This will send
+ // out half the usual number of session end
+ // frames.
+ //
+
+ NB_DEBUG2 (CONNECTION, ("Probe timeout of active connection %lx\n", Connection));
+
+ //
+ // This free the connection lock.
+ //
+
+ NbiStopConnection(
+ Connection,
+ STATUS_LINK_FAILED
+ NB_LOCK_HANDLE_ARG (LockHandle)
+ );
+
+ } else {
+
+ Connection->RetransmitThisWindow = TRUE;
+ if (Connection->CurrentRetransmitTimeout < (Connection->BaseRetransmitTimeout*8)) {
+ Connection->CurrentRetransmitTimeout =
+ (Connection->CurrentRetransmitTimeout * 3) / 2;
+ }
+
+ NbiStartRetransmit (Connection);
+
+ //
+ // After half the retries, send a find route unless we
+ // are already doing one, or the connection is to network
+ // 0. When this completes we update the local target,
+ // for whatever good that does.
+ //
+
+ if ((!Connection->FindRouteInProgress) &&
+ (Connection->Retries == (Device->KeepAliveCount/2)) &&
+ (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0)) {
+
+ SendFindRoute = TRUE;
+ Connection->FindRouteInProgress = TRUE;
+ NbiReferenceConnectionSync (Connection, CREF_FIND_ROUTE);
+
+ }
+
+ //
+ // Set this so we know to retransmit when the ack
+ // is received.
+ //
+
+ if (Connection->SubState != CONNECTION_SUBSTATE_A_W_PROBE) {
+ Connection->ResponseTimeout = TRUE;
+ }
+
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ if (SendFindRoute) {
+
+ Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
+ *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
+ *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
+ RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
+ Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_FORCE_RIP;
+
+ (*Device->Bind.FindRouteHandler)(
+ &Connection->FindRouteRequest);
+
+ }
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireRetansmit */
+
+
+VOID
+NbiExpireWatchdog(
+ IN PCONNECTION Connection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the connection's watchdog timer
+ expires. It is called from NbiLongTimeout.
+
+Arguments:
+
+ Connection - Pointer to the connection whose timer has expired.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ //
+ // If we are not idle, then something else is happening
+ // so the watchdog is unnecessary.
+ //
+
+ if ((Connection->State == CONNECTION_STATE_ACTIVE) &&
+ (Connection->SubState == CONNECTION_SUBSTATE_A_IDLE)) {
+
+ Connection->Retries = NbiDevice->KeepAliveCount;
+ Connection->SubState = CONNECTION_SUBSTATE_A_W_PROBE;
+ NbiStartRetransmit (Connection);
+
+ //
+ // This releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckQuery
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+} /* NbiExpireWatchdog */
+
+
+VOID
+NbiShortTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the short connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY p, nextp;
+ PDEVICE Device = (PDEVICE)Context;
+ PCONNECTION Connection;
+ BOOLEAN RestartTimer = FALSE;
+ LARGE_INTEGER CurrentTick;
+ LARGE_INTEGER TickDifference;
+ ULONG TickDelta;
+ NB_DEFINE_LOCK_HANDLE (LockHandle);
+
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // This prevents anybody from starting the timer while we
+ // are in this routine (the main reason for this is that it
+ // makes it easier to determine whether we should restart
+ // it at the end of this routine).
+ //
+
+ Device->ProcessingShortTimer = TRUE;
+
+ //
+ // Advance the up-counter used to mark time in SHORT_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+
+ KeQueryTickCount (&CurrentTick);
+
+ TickDifference.QuadPart = CurrentTick.QuadPart -
+ Device->ShortTimerStart.QuadPart;
+
+ TickDelta = TickDifference.LowPart / NbiShortTimerDeltaTicks;
+ if (TickDelta == 0) {
+ TickDelta = 1;
+ }
+
+ Device->ShortAbsoluteTime += TickDelta;
+
+ if (Device->ShortAbsoluteTime >= 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->ShortAbsoluteTime -= 0xe0000000;
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ Timeout = Connection->Retransmit;
+ if (Timeout) {
+ Connection->Retransmit = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+ p = Device->ShortList.Flink;
+ while (p != &Device->ShortList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, ShortList);
+
+ ASSERT (Connection->OnShortList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Retransmit &&
+ (Device->ShortAbsoluteTime > Connection->Retransmit)) {
+
+ Connection->Retransmit = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireRetransmit (Connection); // no locks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnShortList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Retransmit == 0) {
+
+ Connection->OnShortList = FALSE;
+ RemoveEntryList(p);
+
+ //
+ // Do another check; that way if someone slipped in between
+ // the check of Connection->Tx and the OnShortList = FALSE and
+ // therefore exited without inserting, we'll catch that here.
+ //
+
+ if (Connection->Retransmit != 0) {
+ InsertTailList(&Device->ShortList, &Connection->ShortList);
+ Connection->OnShortList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ //
+ // If the list is empty note that, otherwise ShortListActive
+ // remains TRUE.
+ //
+
+ if (IsListEmpty (&Device->ShortList)) {
+ Device->ShortListActive = FALSE;
+ }
+
+
+ //
+ // Connection Data Ack timers. This queue is used to indicate
+ // that a piggyback ack is pending for this connection. We walk
+ // the queue, for each element we check if the connection has
+ // been on the queue for enough times through here,
+ // If so, we take it off and send an ack. Note that
+ // we have to be very careful how we walk the queue, since
+ // it may be changing while this is running.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ //
+ // Skip this connection if it is not queued or it is
+ // too recent to matter. We may skip incorrectly if
+ // the connection is just being queued, but that is
+ // OK, we will get it next time.
+ //
+
+ if (!Connection->DataAckPending) {
+ continue;
+ }
+
+ ++Connection->DataAckTimeouts;
+
+ if (Connection->DataAckTimeouts < Device->AckDelayTime) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_SHORT_D_ACK);
+
+ Device->DataAckQueueChanged = FALSE;
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ //
+ // Check the correct connection flag, to ensure that a
+ // send has not just taken him off the queue.
+ //
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
+
+ if (Connection->DataAckPending) {
+
+ //
+ // Yes, we were waiting to piggyback an ack, but no send
+ // has come along. Turn off the flags and send an ack.
+ // We set PiggybackAckTimeout to TRUE so that we won't try
+ // to piggyback a response until we get back traffic.
+ //
+
+ Connection->DataAckPending = FALSE;
+ Connection->PiggybackAckTimeout = TRUE;
+ ++Device->Statistics.AckTimerExpirations;
+ ++Device->Statistics.PiggybackAckTimeouts;
+
+ //
+ // This call releases the lock.
+ //
+
+ NbiSendDataAck(
+ Connection,
+ NbiAckResponse
+ NB_LOCK_HANDLE_ARG(LockHandle));
+
+ } else {
+
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
+
+ }
+
+ NbiDereferenceConnection (Connection, CREF_SHORT_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // If the list has changed, then we need to stop processing
+ // since p->Flink is not valid.
+ //
+
+ if (Device->DataAckQueueChanged) {
+ break;
+ }
+
+ }
+
+ if (IsListEmpty (&Device->DataAckConnections)) {
+ Device->DataAckActive = FALSE;
+ }
+
+
+ //
+ // Update the real counters from the temp ones. We have
+ // TimerLock here, which is good enough.
+ //
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesSent,
+ Device->TempFrameBytesSent);
+ Device->Statistics.DataFramesSent += Device->TempFramesSent;
+
+ Device->TempFrameBytesSent = 0;
+ Device->TempFramesSent = 0;
+
+ ADD_TO_LARGE_INTEGER(
+ &Device->Statistics.DataFrameBytesReceived,
+ Device->TempFrameBytesReceived);
+ Device->Statistics.DataFramesReceived += Device->TempFramesReceived;
+
+ Device->TempFrameBytesReceived = 0;
+ Device->TempFramesReceived = 0;
+
+
+ //
+ // Determine if we have to restart the timer.
+ //
+
+ Device->ProcessingShortTimer = FALSE;
+
+ if ((Device->ShortListActive || Device->DataAckActive) &&
+ (Device->State != DEVICE_STATE_STOPPING)) {
+
+ RestartTimer = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ if (RestartTimer) {
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ } else {
+
+ NbiDereferenceDevice (Device, DREF_SHORT_TIMER);
+
+ }
+
+} /* NbiShortTimeout */
+
+
+VOID
+NbiLongTimeout(
+ IN CTEEvent * Event,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called at regular intervals to see if any of
+ the long connection timers have expired, and if so to execute their
+ expiration routines.
+
+Arguments:
+
+ Event - The event controlling the timer.
+
+ Context - Points to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ PDEVICE Device = (PDEVICE)Context;
+ PLIST_ENTRY p, nextp;
+ LIST_ENTRY AdapterStatusList;
+ PREQUEST AdapterStatusRequest;
+ PCONNECTION Connection;
+ PNETBIOS_CACHE CacheName;
+ NB_DEFINE_LOCK_HANDLE (LockHandle)
+ NB_DEFINE_LOCK_HANDLE (LockHandle1)
+
+
+ //
+ // Advance the up-counter used to mark time in LONG_TIMER_DELTA units. If we
+ // advance it all the way to 0xf0000000, then reset it to 0x10000000.
+ // We also run all the lists, decreasing all counters by 0xe0000000.
+ //
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ if (++Device->LongAbsoluteTime == 0xf0000000) {
+
+ ULONG Timeout;
+
+ Device->LongAbsoluteTime = 0x10000000;
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ Timeout = Connection->Watchdog;
+ if (Timeout) {
+ Connection->Watchdog = Timeout - 0xe0000000;
+ }
+
+ p = p->Flink;
+ }
+
+ }
+
+
+ if ((Device->LongAbsoluteTime % 4) == 0) {
+
+ p = Device->LongList.Flink;
+ while (p != &Device->LongList) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, LongList);
+
+ ASSERT (Connection->OnLongList);
+
+ //
+ // To avoid problems with the refcount being 0, don't
+ // do this if we are in ADM.
+ //
+
+ if (Connection->State == CONNECTION_STATE_ACTIVE) {
+
+ if (Connection->Watchdog && (Device->LongAbsoluteTime > Connection->Watchdog)) {
+
+ Connection->Watchdog = 0;
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NbiExpireWatchdog (Connection); // no spinlocks held
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ }
+
+ }
+
+ if (!Connection->OnLongList) {
+
+ //
+ // The link has been taken out of the list while
+ // we were processing it. In this (rare) case we
+ // stop processing the whole list, we'll get it
+ // next time.
+ //
+
+#if DBG
+ DbgPrint ("NBI: Stop processing LongList, %lx removed\n", Connection);
+#endif
+ break;
+
+ }
+
+ nextp = p->Flink;
+
+ if (Connection->Watchdog == 0) {
+
+ Connection->OnLongList = FALSE;
+ RemoveEntryList(p);
+
+ if (Connection->Watchdog != 0) {
+ InsertTailList(&Device->LongList, &Connection->LongList);
+ Connection->OnLongList = TRUE;
+ }
+
+ }
+
+ p = nextp;
+
+ }
+
+ }
+
+
+ //
+ // Now scan the data ack queue, looking for connections with
+ // no acks queued that we can get rid of.
+ //
+ // Note: The timer spinlock is held here.
+ //
+
+ for (p = Device->DataAckConnections.Flink;
+ p != &Device->DataAckConnections;
+ p = p->Flink) {
+
+ Connection = CONTAINING_RECORD (p, CONNECTION, DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ continue;
+ }
+
+ NbiReferenceConnectionSync (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+ NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Have to check again, because the connection might
+ // just have been stopped, and it also might just have
+ // had a data ack queued.
+ //
+
+ if (Connection->OnDataAckQueue) {
+
+ Connection->OnDataAckQueue = FALSE;
+
+ RemoveEntryList (&Connection->DataAckLinkage);
+
+ if (Connection->DataAckPending) {
+ InsertTailList (&Device->DataAckConnections, &Connection->DataAckLinkage);
+ Connection->OnDataAckQueue = TRUE;
+ }
+
+ Device->DataAckQueueChanged = TRUE;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+ NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
+
+ NbiDereferenceConnection (Connection, CREF_LONG_D_ACK);
+
+ NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle);
+
+ //
+ // Since we have changed the list, we can't tell if p->Flink
+ // is valid, so break. The effect is that we gradually peel
+ // connections off the queue.
+ //
+
+ break;
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle);
+
+
+ //
+ // Scan for any uncompleted receive IRPs, this may happen if
+ // the cable is pulled and we don't get any more ReceiveComplete
+ // indications.
+
+ NbiReceiveComplete((USHORT)0);
+
+
+ //
+ // Check if any adapter status queries are getting old.
+ //
+
+ InitializeListHead (&AdapterStatusList);
+
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+
+ p = Device->ActiveAdapterStatus.Flink;
+
+ while (p != &Device->ActiveAdapterStatus) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+
+ p = p->Flink;
+
+ if (REQUEST_INFORMATION(AdapterStatusRequest) == 1) {
+
+ //
+ // BUGBUG: We should resend a certain number of times.
+ //
+
+ RemoveEntryList (REQUEST_LINKAGE(AdapterStatusRequest));
+ InsertTailList (&AdapterStatusList, REQUEST_LINKAGE(AdapterStatusRequest));
+
+ //
+ // We are going to abort this request, so dereference
+ // the cache entry it used.
+ //
+
+ CacheName = (PNETBIOS_CACHE)REQUEST_STATUS(AdapterStatusRequest);
+ if (--CacheName->ReferenceCount == 0) {
+
+ NB_DEBUG2 (CACHE, ("Free delete name cache entry %lx\n", CacheName));
+ NbiFreeMemory(
+ CacheName,
+ sizeof(NETBIOS_CACHE) + ((CacheName->NetworksAllocated-1) * sizeof(NETBIOS_NETWORK)),
+ MEMORY_CACHE,
+ "Name deleted");
+
+ }
+
+ } else {
+
+ ++REQUEST_INFORMATION(AdapterStatusRequest);
+
+ }
+
+ }
+
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+
+
+ for (p = AdapterStatusList.Flink; p != &AdapterStatusList; ) {
+
+ AdapterStatusRequest = LIST_ENTRY_TO_REQUEST(p);
+ p = p->Flink;
+
+ NB_DEBUG2 (QUERY, ("AdapterStatus %lx got name but no response\n", AdapterStatusRequest));
+
+ REQUEST_INFORMATION(AdapterStatusRequest) = 0;
+ REQUEST_STATUS(AdapterStatusRequest) = STATUS_IO_TIMEOUT;
+
+ NbiCompleteRequest(AdapterStatusRequest);
+ NbiFreeRequest (Device, AdapterStatusRequest);
+
+ NbiDereferenceDevice (Device, DREF_STATUS_QUERY);
+
+ }
+
+ //
+ // See if a minute has passed and we need to check for empty
+ // cache entries to age out. We check for 64 seconds to make
+ // the mod operation faster.
+ //
+
+#if defined(_PNP_POWER)
+ NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle);
+#endif _PNP_POWER
+
+ ++Device->CacheTimeStamp;
+
+ if ((Device->CacheTimeStamp % 64) == 0) {
+
+
+ //
+ // flush all the entries which have been around for ten minutes
+ // (LONG_TIMER_DELTA is in milliseconds).
+ //
+
+ FlushOldFromNetbiosCacheTable( Device->NameCache, (600000 / LONG_TIMER_DELTA) );
+
+ }
+
+
+ //
+ // Start up the timer again. Note that because we start the timer
+ // after doing work (above), the timer values will slip somewhat,
+ // depending on the load on the protocol. This is entirely acceptable
+ // and will prevent us from using the timer DPC in two different
+ // threads of execution.
+ //
+
+ if (Device->State != DEVICE_STATE_STOPPING) {
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+ } else {
+#if defined(_PNP_POWER)
+ Device->LongTimerRunning = FALSE;
+#endif _PNP_POWER
+ NbiDereferenceDevice (Device, DREF_LONG_TIMER);
+ }
+
+#if defined(_PNP_POWER)
+ NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle);
+#endif _PNP_POWER
+} /* NbiLongTimeout */
+
+
+VOID
+NbiStartShortTimer(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the short timer, if it is not already running.
+
+Arguments:
+
+ Device - Pointer to our device context.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // Start the timer unless it the DPC is already running (in
+ // which case it will restart the timer itself if needed),
+ // or some list is active (meaning the timer is already
+ // queued up).
+ //
+
+ if ((!Device->ProcessingShortTimer) &&
+ (!(Device->ShortListActive)) &&
+ (!(Device->DataAckActive))) {
+
+ NbiReferenceDevice (Device, DREF_SHORT_TIMER);
+
+ KeQueryTickCount(&Device->ShortTimerStart);
+
+ CTEStartTimer(
+ &Device->ShortTimer,
+ SHORT_TIMER_DELTA,
+ NbiShortTimeout,
+ (PVOID)Device);
+
+ }
+
+} /* NbiStartShortTimer */
+
+
+VOID
+NbiInitializeTimers(
+ IN PDEVICE Device
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the lightweight timer system for the transport
+ provider.
+
+Arguments:
+
+ Device - Pointer to our device.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+
+ //
+ // NbiTickIncrement is the number of NT time increments
+ // which pass between each tick. NbiShortTimerDeltaTicks
+ // is the number of ticks which should happen in
+ // SHORT_TIMER_DELTA milliseconds (i.e. between each
+ // expiration of the short timer).
+ //
+
+ NbiTickIncrement = KeQueryTimeIncrement();
+
+ if (NbiTickIncrement > (SHORT_TIMER_DELTA * MILLISECONDS)) {
+ NbiShortTimerDeltaTicks = 1;
+ } else {
+ NbiShortTimerDeltaTicks = (SHORT_TIMER_DELTA * MILLISECONDS) / NbiTickIncrement;
+ }
+
+ //
+ // The AbsoluteTime cycles between 0x10000000 and 0xf0000000.
+ //
+
+ Device->ShortAbsoluteTime = 0x10000000;
+ Device->LongAbsoluteTime = 0x10000000;
+
+ CTEInitTimer (&Device->ShortTimer);
+ CTEInitTimer (&Device->LongTimer);
+
+#if !defined(_PNP_POWER)
+ //
+ // One reference for the long timer.
+ //
+
+ NbiReferenceDevice (Device, DREF_LONG_TIMER);
+
+ CTEStartTimer(
+ &Device->LongTimer,
+ LONG_TIMER_DELTA,
+ NbiLongTimeout,
+ (PVOID)Device);
+
+#endif !_PNP_POWER
+
+ Device->TimersInitialized = TRUE;
+ Device->ShortListActive = FALSE;
+ Device->ProcessingShortTimer = FALSE;
+
+ InitializeListHead (&Device->ShortList);
+ InitializeListHead (&Device->LongList);
+
+ CTEInitLock (&Device->TimerLock.Lock);
+
+} /* NbiInitializeTimers */
+
diff --git a/private/ntos/tdi/isnp/nb/up/makefile b/private/ntos/tdi/isnp/nb/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/up/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/tdi/isnp/nb/up/sources b/private/ntos/tdi/isnp/nb/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/up/sources
@@ -0,0 +1,29 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+UP_DRIVER=yes
+
+TARGETPATH=obj
+
+!include ..\sources.inc
diff --git a/private/ntos/tdi/isnp/spx/dirs b/private/ntos/tdi/isnp/spx/dirs
new file mode 100644
index 000000000..0dab2f056
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/globals.c b/private/ntos/tdi/isnp/spx/globals.c
new file mode 100644
index 000000000..51fc80803
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/fwddecls.h b/private/ntos/tdi/isnp/spx/h/fwddecls.h
new file mode 100644
index 000000000..feda4e76b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/globals.h b/private/ntos/tdi/isnp/spx/h/globals.h
new file mode 100644
index 000000000..e4fcf39a8
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/isnspx.h b/private/ntos/tdi/isnp/spx/h/isnspx.h
new file mode 100644
index 000000000..6080b0423
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxaddr.h b/private/ntos/tdi/isnp/spx/h/spxaddr.h
new file mode 100644
index 000000000..b49a4791e
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxbind.h b/private/ntos/tdi/isnp/spx/h/spxbind.h
new file mode 100644
index 000000000..81ad6ac58
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxconn.h b/private/ntos/tdi/isnp/spx/h/spxconn.h
new file mode 100644
index 000000000..bb1173432
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxdev.h b/private/ntos/tdi/isnp/spx/h/spxdev.h
new file mode 100644
index 000000000..30c0adae5
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxerror.h b/private/ntos/tdi/isnp/spx/h/spxerror.h
new file mode 100644
index 000000000..761342512
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxmem.h b/private/ntos/tdi/isnp/spx/h/spxmem.h
new file mode 100644
index 000000000..717c69a6b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxntdef.h b/private/ntos/tdi/isnp/spx/h/spxntdef.h
new file mode 100644
index 000000000..60f9c9e54
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxpkt.h b/private/ntos/tdi/isnp/spx/h/spxpkt.h
new file mode 100644
index 000000000..b643ed95b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxquery.h b/private/ntos/tdi/isnp/spx/h/spxquery.h
new file mode 100644
index 000000000..68e0a1ca8
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxrecv.h b/private/ntos/tdi/isnp/spx/h/spxrecv.h
new file mode 100644
index 000000000..0ce382990
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/h/spxrecv.h
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1989-1993 Microsoft Corporation
+
+Module Name:
+
+ spxrecv.h
+
+Abstract:
+
+
+Author:
+
+ Nikhil Kamkolkar (nikhilk) 11-November-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+VOID
+SpxReceive(
+ 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
+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/isnp/spx/h/spxreg.h b/private/ntos/tdi/isnp/spx/h/spxreg.h
new file mode 100644
index 000000000..4e0cb469b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxsend.h b/private/ntos/tdi/isnp/spx/h/spxsend.h
new file mode 100644
index 000000000..40ef810ea
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxtimer.h b/private/ntos/tdi/isnp/spx/h/spxtimer.h
new file mode 100644
index 000000000..225037bd2
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/h/spxutils.h b/private/ntos/tdi/isnp/spx/h/spxutils.h
new file mode 100644
index 000000000..074a1649b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/mp/makefile b/private/ntos/tdi/isnp/spx/mp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/mp/sources b/private/ntos/tdi/isnp/spx/mp/sources
new file mode 100644
index 000000000..dc48d81bb
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/nwlnkspx.rc b/private/ntos/tdi/isnp/spx/nwlnkspx.rc
new file mode 100644
index 000000000..02175f21d
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/precomp.h b/private/ntos/tdi/isnp/spx/precomp.h
new file mode 100644
index 000000000..d227d02f9
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/precomp.h
@@ -0,0 +1 @@
+#include "isnspx.h"
diff --git a/private/ntos/tdi/isnp/spx/sources.inc b/private/ntos/tdi/isnp/spx/sources.inc
new file mode 100644
index 000000000..419f580f1
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxaddr.c b/private/ntos/tdi/isnp/spx/spxaddr.c
new file mode 100644
index 000000000..e9e85dc5c
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxbind.c b/private/ntos/tdi/isnp/spx/spxbind.c
new file mode 100644
index 000000000..7610939f7
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxbind.c
@@ -0,0 +1,600 @@
+/*++
+
+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);
+
+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
+ )
+
+{
+ 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/isnp/spx/spxconn.c b/private/ntos/tdi/isnp/spx/spxconn.c
new file mode 100644
index 000000000..4528b64a4
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxconn.c
@@ -0,0 +1,3862 @@
+/*++
+
+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));
+ //
+ // Currently SPX implements DS_TYPE in such a way that the DS_TYPE field in a packet
+ // takes on the latest value from the connectionfile. Some customers complained that
+ // their apps assume that the DS_TYPE field should reflect the value at the time of
+ // the send (and Novell does this).
+ //
+ // So, instead of keeping a global value, we copy over the DS_TYPE value into the
+ // request if it pends. Look at spxpkt.c:SpxBuildData.
+ //
+ REQUEST_PARAMETERS(pRequest)->Others.Argument3 = (PVOID)pSpxConnFile->scf_DataType;
+
+ }
+ 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 = 0;
+ pSpxConnFile->scf_AckLocalTarget.NicHandle.NicId = 0;
+#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;
+ 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/isnp/spx/spxcpkt.c b/private/ntos/tdi/isnp/spx/spxcpkt.c
new file mode 100644
index 000000000..deb185201
--- /dev/null
+++ b/private/ntos/tdi/isnp/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 == 0) {
+#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) &&
+ (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/isnp/spx/spxcutil.c b/private/ntos/tdi/isnp/spx/spxcutil.c
new file mode 100644
index 000000000..3f85b2281
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxcutil.c
@@ -0,0 +1,1738 @@
+/*++
+
+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));
+
+ // Make sure Stacy is always wearing a particular
+ // kind of dress if she isn't already.
+ 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/isnp/spx/spxdev.c b/private/ntos/tdi/isnp/spx/spxdev.c
new file mode 100644
index 000000000..431498686
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxdrvr.c b/private/ntos/tdi/isnp/spx/spxdrvr.c
new file mode 100644
index 000000000..0e9935d1a
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxerror.c b/private/ntos/tdi/isnp/spx/spxerror.c
new file mode 100644
index 000000000..7d2cc7444
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxmem.c b/private/ntos/tdi/isnp/spx/spxmem.c
new file mode 100644
index 000000000..9cd400e5b
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxpkt.c b/private/ntos/tdi/isnp/spx/spxpkt.c
new file mode 100644
index 000000000..5f472d8cd
--- /dev/null
+++ b/private/ntos/tdi/isnp/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 = (UCHAR)REQUEST_PARAMETERS(pSpxConnFile->scf_ReqPkt)->Others.Argument3;
+ 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/isnp/spx/spxquery.c b/private/ntos/tdi/isnp/spx/spxquery.c
new file mode 100644
index 000000000..047ecabe8
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxrecv.c b/private/ntos/tdi/isnp/spx/spxrecv.c
new file mode 100644
index 000000000..2408f25e8
--- /dev/null
+++ b/private/ntos/tdi/isnp/spx/spxrecv.c
@@ -0,0 +1,2837 @@
+/*++
+
+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
+
+VOID
+SpxReceive(
+ 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
+ )
+
+{
+ 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;
+ }
+
+ ++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;
+}
+
+
+
+
+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/isnp/spx/spxreg.c b/private/ntos/tdi/isnp/spx/spxreg.c
new file mode 100644
index 000000000..4389dca5f
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxsend.c b/private/ntos/tdi/isnp/spx/spxsend.c
new file mode 100644
index 000000000..6b856953d
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxtimer.c b/private/ntos/tdi/isnp/spx/spxtimer.c
new file mode 100644
index 000000000..bdb4e1d7f
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/spxutils.c b/private/ntos/tdi/isnp/spx/spxutils.c
new file mode 100644
index 000000000..024a36988
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/up/makefile b/private/ntos/tdi/isnp/spx/up/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/tdi/isnp/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/isnp/spx/up/sources b/private/ntos/tdi/isnp/spx/up/sources
new file mode 100644
index 000000000..85cdb3764
--- /dev/null
+++ b/private/ntos/tdi/isnp/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