/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

	node.h

Abstract:

	This module contains support for the Appletalk Node structure.

Author:

	Jameel Hyder (jameelh@microsoft.com)
	Nikhil Kamkolkar (nikhilk@microsoft.com)

Revision History:
	19 Jun 1992		Initial Version

Notes:	Tab stop: 4
--*/

#ifndef	_NODE_
#define	_NODE_

#define ANY_ROUTER_NODE		 		0
#define UNKNOWN_NODE				0
#define MAX_ATALK_NODES				256
#define MIN_USABLE_ATALKNODE  		1
#define MAX_USABLE_ATALKNODE  		254
#define MAX_EXT_ATALKNODE			253
#define HIGHEST_WORKSTATION_NODE	127
#define LOWEST_SERVER_NODE	  		128
#define ATALK_BROADCAST_NODE		((BYTE)0xFF)
#define	NUM_USER_NODES				2


//  NODE STATES
#define	AN_OPEN						0x01
#define	AN_ROUTER_NODE				0x02
#define	AN_ORPHAN_NODE				0x04
#define AN_CLOSING					0x80

// values under which pram nodes are stored
#define	ROUTER_NODE_VALUE			L"RouterPramNode"
#define	USER_NODE1_VALUE			L"UserPramNode1"
#define	USER_NODE2_VALUE			L"UserPramNode2"

//	Number of slots in the socket hash table stored per node
#define		NODE_DDPAO_HASH_SIZE	8

#define	AN_SIGNATURE			(*(PULONG)"ANOD")
#if	DBG
#define	VALID_ATALK_NODE(pNode)	(((pNode) != NULL) &&	\
								 ((pNode)->an_Signature == AN_SIGNATURE))
#else
#define	VALID_ATALK_NODE(pNode)	((pNode) != NULL)
#endif
typedef struct _ATALK_NODE
{

#if DBG
	ULONG					an_Signature;
#endif

	//	List for all active nodes on a port
	struct _ATALK_NODE *	an_Next;

	ULONG  					an_RefCount;

	//	Backpointer to the port for this node
	struct _PORT_DESCRIPTOR	*an_Port;

	//  State of the node
	BYTE 					an_Flags;

	//	Next dynamic socket number to create on this node.
	BYTE					an_NextDynSkt;

	//	Nbp Id & Enumerator to use on the next NbpAction
	BYTE					an_NextNbpId;
	BYTE					an_NextNbpEnum;

	//	Hash List of ddp address objects (accessed by the
	//	Appletalk socket address) on this node
	struct _DDP_ADDROBJ	*	an_DdpAoHash[NODE_DDPAO_HASH_SIZE];

	//	Address of this node
	ATALK_NODEADDR			an_NodeAddr;

	//	Lock
	ATALK_SPIN_LOCK			an_Lock;
} ATALK_NODE, *PATALK_NODE;

//	Exports

VOID
AtalkNodeRefByAddr(
	IN	PPORT_DESCRIPTOR		pPortDesc,
	IN  PATALK_NODEADDR     	pNodeAddr,
	OUT	PATALK_NODE			*	pNode,
	OUT	PATALK_ERROR			pErr
);

// VOID
// AtalkNodeRefByPtr(
// 	IN	OUT	PATALK_NODE			Node,
// 	OUT		PATALK_ERROR		pErr
// );
#define	AtalkNodeRefByPtr(_pNode, _pErr)				\
	{													\
		KIRQL	OldIrql;								\
														\
		ASSERT(VALID_ATALK_NODE(_pNode));				\
														\
		ACQUIRE_SPIN_LOCK(&(_pNode)->an_Lock, &OldIrql);\
		AtalkNodeRefByPtrNonInterlock(_pNode, _pErr);	\
		RELEASE_SPIN_LOCK(&(_pNode)->an_Lock, OldIrql);	\
	}

// VOID
// AtalkNodeRefByPtrNonInterlock(
//	IN	OUT	PATALK_NODE			Node,
//	OUT		PATALK_ERROR		pErr
// );

#define	AtalkNodeRefByPtrNonInterlock(_pNode, _pErr)	\
	{													\
		ASSERT(VALID_ATALK_NODE(_pNode));				\
														\
		if (((_pNode)->an_Flags & AN_CLOSING) == 0)		\
		{												\
			(_pNode)->an_RefCount++;					\
			*(_pErr) = ATALK_NO_ERROR;					\
		}												\
		else											\
		{												\
			*(_pErr) = ATALK_NODE_CLOSING;				\
			DBGPRINT(DBG_COMP_NODE, DBG_LEVEL_WARN,		\
					("AtalkNodeRefByPtrNonInterlock: Attempt to ref a closing node %lx (%x.%x)\n",\
					_pNode, (_pNode)->an_NodeAddr.atn_Network, (_pNode)->an_NodeAddr.atn_Node));\
		}												\
	}

VOID
AtalkNodeRefNextNc(
	IN	PATALK_NODE				pNode,
	IN	PATALK_NODE		*		ppNode,
	OUT	PATALK_ERROR			pErr
);

VOID
AtalkNodeDeref(
	IN	OUT	PATALK_NODE			pNode
);

ATALK_ERROR
AtalkInitNodeCreateOnPort(
	IN  PPORT_DESCRIPTOR		pPortDesc,
	IN  BOOLEAN					AllowStartupRange,
	IN  BOOLEAN					RouterNode,
	IN  PATALK_NODEADDR			pNodeAddr
);

ATALK_ERROR
AtalkNodeReleaseOnPort(
	IN  PPORT_DESCRIPTOR		pPortDesc,
	IN  PATALK_NODE				pNode
);

BOOLEAN
AtalkNodeExistsOnPort(
	IN  PPORT_DESCRIPTOR		pPortDesc,
	IN  PATALK_NODEADDR			pNodeAddr
);

ATALK_ERROR
AtalkInitNodeAllocate(
	IN	PPORT_DESCRIPTOR		pPortDesc,
	OUT PATALK_NODE			*	ppNode
);

//	MACROS

#if DBG
#define	AtalkNodeReferenceByAddr(pPortDesc,NodeAddr,Node, pErr)	\
		{														\
			AtalkNodeRefByAddr(pPortDesc,NodeAddr,Node, pErr);	\
			if (ATALK_SUCCESS(*pErr))							\
			{													\
				DBGPRINT(DBG_COMP_NODE,	DBG_LEVEL_REFNODE,		\
				("AtalkNodeRefByAddr : %s %d PostCount %d\n",	\
				__FILE__, __LINE__,(*Node)->an_RefCount));		\
			}													\
		}

#define	AtalkNodeReferenceByPtr(Node, pErr)						\
		{														\
			AtalkNodeRefByPtr(Node, pErr);						\
			DBGPRINT(DBG_COMP_NODE,	DBG_LEVEL_REFNODE,			\
			("AtalkNodeRefByPtr : %s %d PostCount %d\n",		\
			__FILE__, __LINE__, Node->an_RefCount))				\
		}

#define	AtalkNodeReferenceByPtrNonInterlock(Node, pErr)			\
		{														\
			AtalkNodeRefByPtrNonInterlock(Node, pErr);			\
			DBGPRINT(DBG_COMP_NODE,	DBG_LEVEL_REFNODE,			\
			("AtalkNodeRefByPtrNi : %s %d PostCount %d\n",		\
				__FILE__, __LINE__,Node->an_RefCount));			\
		}

#define	AtalkNodeReferenceNextNc(pNode, ppNode, pErr)			\
		{														\
			AtalkNodeRefNextNc(pNode, ppNode, pErr);			\
			if (ATALK_SUCCESS(*pErr))							\
			{													\
				DBGPRINT(DBG_COMP_NODE,	DBG_LEVEL_REFNODE, 		\
				("AtalkNodeRefByPtrNc : %s %d PostCount %d\n",	\
				__FILE__, __LINE__, (*ppNode)->an_RefCount));	\
			}													\
		}

#define	AtalkNodeDereference(Node)								\
		{														\
			DBGPRINT(DBG_COMP_NODE,	DBG_LEVEL_REFNODE, 			\
			("AtalkNodeDerefByPtr : %s %d PreCount %d\n",		\
			__FILE__, __LINE__,Node->an_RefCount));				\
			AtalkNodeDeref(Node);								\
		}

#else
#define	AtalkNodeReferenceByAddr(pPortDesc,NodeAddr,Node, pErr)	\
			AtalkNodeRefByAddr(pPortDesc,NodeAddr,Node, pErr)

#define	AtalkNodeReferenceByPtr(Node, pErr)						\
			AtalkNodeRefByPtr(Node, pErr)

#define	AtalkNodeReferenceByPtrNonInterlock(Node, pErr)			\
			AtalkNodeRefByPtrNonInterlock(Node, pErr)		

#define	AtalkNodeReferenceNextNcNonInterlock(pNode, ppNode, pErr)\
			AtalkNodeRefNextNcNonInterlock(pNode, ppNode, pErr)	

#define	AtalkNodeReferenceNextNc(pNode, ppNode, pErr)			\
			AtalkNodeRefNextNc(pNode, ppNode, pErr);

#define	AtalkNodeDereference(Node)	AtalkNodeDeref(Node)							
#endif


VOID
AtalkInitNodeSavePramAddr(
	IN	PPORT_DESCRIPTOR	pPortDesc,
	IN	PWSTR				RegValue,
	IN	PATALK_NODEADDR		Node
);

VOID
AtalkInitNodeGetPramAddr(       	
	IN	PPORT_DESCRIPTOR	pPortDesc,
	IN	PWSTR				RegValue,
	OUT	PATALK_NODEADDR		Node
);


VOID
AtalkZapPramValue(
	IN	PPORT_DESCRIPTOR	pPortDesc,
	IN	PWSTR				RegValue
);

#endif	// _NODE_

