/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

	atktdi.h

Abstract:

	This module contains tdi related definitions.

Author:

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

Revision History:
	19 Jun 1992		Initial Version

Notes:	Tab stop: 4
--*/

#ifndef	_ATKTDI_
#define	_ATKTDI_

#define DFLAG_ADDR		0x0001
#define DFLAG_CONN		0x0002
#define DFLAG_CNTR		0x0004
#define DFLAG_MDL		0x0008

struct _ActionReq;

// Typedef for the worker routine used in the dispatch tables
typedef VOID		(*GENERIC_COMPLETION)(IN ATALK_ERROR	ErrorCode,
										  IN PIRP			pIrp);
typedef VOID		(*ACTION_COMPLETION)(IN ATALK_ERROR		ErrorCode,
										 IN struct _ActionReq *pActReq);
typedef ATALK_ERROR	(*DISPATCH_ROUTINE)(IN PVOID			pObject,
										IN struct _ActionReq *pActReq);

typedef VOID		(*GENERIC_WRITE_COMPLETION)(
									IN ATALK_ERROR	ErrorCode,
									IN PAMDL		WriteBuf,
									IN USHORT		WriteLen,
									IN PIRP			pIrp);

typedef VOID		(*GENERIC_READ_COMPLETION)(
									IN ATALK_ERROR	ErrorCode,
									IN PAMDL		ReadBuf,
									IN USHORT		ReadLen,
									IN ULONG		ReadFlags,
									IN PIRP			pIrp);

// Define the Action dispatch table here.
//
// *IMPORTANT*
// This table is tightly integrated with the action codes defined in
// ATALKTDI.H.
//
// Order is NBP/ZIP/ADSP/ATP/ASP/PAP
//
// Each element of the array contains:
// _MinBufLen - The minimum length of the MdlAddress buffer for the request
// _OpCode - The action code of the request (sanity check)
// _OpInfo - Bit flags give more information about the request
//		DFLAG_ADDR - Object for request must be an address object
//		DFLAG_CONN - Object for request must be connection object
//		DFLAG_CNTR - Object for request must be control channel
//		DFLAG_MDL1 - Request uses an mdl (submdl of MdlAddress)
//		DFLAG_MDL2 - Request uses a second mdl (submdl of MdlAddress)
// _ActionBufSize  - The size of the action header buffer for request
//					 (beginning of the buffer described by MdlAddress)
// _DeviceType	   - Valid device types for the request
//					 ATALK_DEV_ANY => Any device
// _MdlSizeOffset  - Offset in action buffer where the size for the first
//					 mdl can be found. Non-zero only when DFLAG_MDL2 is set.
// _Dispatch	   - The dispatch routine for the request
//
typedef struct _ActionDispatch {
	USHORT				_MinBufLen;
	USHORT				_OpCode;
	USHORT				_Flags;
	USHORT				_ActionBufSize;
	ATALK_DEV_TYPE		_DeviceType;
	DISPATCH_ROUTINE	_Dispatch;
} ACTION_DISPATCH, *PACTION_DISPATCH;

extern	ACTION_DISPATCH	AtalkActionDispatch[];

#define	ACTREQ_SIGNATURE	(*(PULONG)"ACRQ")
#if	DBG
#define	VALID_ACTREQ(pActReq)	(((pActReq) != NULL) &&	\
								 ((pActReq)->ar_Signature == ACTREQ_SIGNATURE))
#else
#define	VALID_ACTREQ(pActReq)	((pActReq) != NULL)
#endif
typedef	struct _ActionReq
{
#if	DBG
	ULONG				ar_Signature;
#endif
	PIRP				ar_pIrp;					// Irp for the request
	PVOID				ar_pParms;					// Action parameter block
	PAMDL				ar_pAMdl;					// Mdl (OPTIONAL)
	SHORT				ar_MdlSize;					// And its size
	ULONG				ar_ActionCode;				// TDI Action code
	SHORT				ar_DevType;					// Which device ?
	ACTION_COMPLETION	ar_Completion;				// Tdi Completion routine
} ACTREQ, *PACTREQ;

typedef	enum {
	ATALK_INDICATE_DISCONNECT,
	ATALK_TIMER_DISCONNECT,
	ATALK_REMOTE_DISCONNECT,
	ATALK_LOCAL_DISCONNECT
} ATALK_DISCONNECT_TYPE;
#define DISCONN_STATUS(DiscType)												\
			(((DiscType == ATALK_TIMER_DISCONNECT) ? ATALK_CONNECTION_TIMEOUT : \
			(DiscType == ATALK_REMOTE_DISCONNECT)) ? ATALK_REMOTE_CLOSE :   	\
			ATALK_NO_ERROR)

extern
NTSTATUS
AtalkTdiOpenAddress(
	IN 		PIRP					Irp,
	IN 		PIO_STACK_LOCATION		IrpSp,
	IN 		PTA_APPLETALK_ADDRESS	TdiAddress,
	IN 		UCHAR					ProtocolType,
	IN 		UCHAR					SocketType,
	IN OUT 	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiOpenConnection(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN 		CONNECTION_CONTEXT		ConnectionContext,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiOpenControlChannel(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiCleanupAddress(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiCleanupConnection(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiCloseAddress(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiCloseConnection(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiCloseControlChannel(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
VOID
AtalkTdiCancel(
	IN OUT	PATALK_DEV_OBJ			pDevObj,
	IN		PIRP					Irp
);

extern
NTSTATUS
AtalkTdiAssociateAddress(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiDisassociateAddress(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiConnect(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiDisconnect(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiAccept(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiListen(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiSendDgram(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiReceiveDgram(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiSend(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiReceive(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiAction(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiQueryInformation(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiSetInformation(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);

extern
NTSTATUS
AtalkTdiSetEventHandler(
	IN		PIRP					Irp,
	IN 		PIO_STACK_LOCATION 		IrpSp,
	IN OUT	PATALK_DEV_CTX			Context
);


extern
ATALK_ERROR
AtalkStatTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkNbpTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkZipTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkAdspTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkAspCTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkPapTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
ATALK_ERROR
AtalkAspTdiAction(
	IN	PVOID						pObject,	// Address or Connection object
	IN	PACTREQ						pActReq		// Pointer to action request
);

extern
VOID
atalkTdiGenericWriteComplete(
	IN	ATALK_ERROR					ErrorCode,
	IN 	PAMDL						WriteBuf,
	IN 	USHORT						WriteLen,
	IN	PIRP						pIrp
);

typedef	struct
{
	LONG	ls_LockCount;
	PVOID	ls_LockHandle;
} LOCK_SECTION, *PLOCK_SECTION;

#define	AtalkLockAdspIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ADSP_SECTION])
#define	AtalkUnlockAdspIfNecessary()	AtalkLockUnlock(FALSE,							\
														&AtalkPgLkSection[ADSP_SECTION])

#define	AtalkLockPapIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[PAP_SECTION])
#define	AtalkUnlockPapIfNecessary()		AtalkLockUnlock(FALSE,							\
														&AtalkPgLkSection[PAP_SECTION])

#define	AtalkLockNbpIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[NBP_SECTION])
#define	AtalkUnlockNbpIfNecessary()		AtalkLockUnlock(FALSE,							\
														&AtalkPgLkSection[NBP_SECTION])

#define	AtalkLockZipIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ZIP_SECTION])
#define	AtalkUnlockZipIfNecessary()		AtalkLockUnlock(FALSE,							\
														&AtalkPgLkSection[ZIP_SECTION])

#define	AtalkLockRouterIfNecessary()	AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ROUTER_SECTION])
#define	AtalkUnlockRouterIfNecessary()	AtalkLockUnlock(FALSE,							\
														&AtalkPgLkSection[ROUTER_SECTION])

#define	AtalkLockTdiIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[TDI_SECTION])
#define	AtalkUnlockTdiIfNecessary()		AtalkLockUnlock(FALSE,			        		\
														&AtalkPgLkSection[TDI_SECTION])

#define	AtalkLockAspIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ASP_SECTION])
#define	AtalkUnlockAspIfNecessary()		AtalkLockUnlock(FALSE,			        		\
														&AtalkPgLkSection[ASP_SECTION])

#define	AtalkLockAspCIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ASPC_SECTION])
#define	AtalkUnlockAspCIfNecessary()	AtalkLockUnlock(FALSE,			        		\
														&AtalkPgLkSection[ASPC_SECTION])

#define	AtalkLockAtpIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[ATP_SECTION])
#define	AtalkUnlockAtpIfNecessary()		AtalkLockUnlock(FALSE,			        		\
														&AtalkPgLkSection[ATP_SECTION])

#define	AtalkLockInitIfNecessary()		AtalkLockUnlock(TRUE,							\
														&AtalkPgLkSection[INIT_SECTION])
#define	AtalkUnlockInitIfNecessary()		AtalkLockUnlock(FALSE,		            		\
														&AtalkPgLkSection[INIT_SECTION])

extern
VOID
AtalkLockInit(
	IN	PLOCK_SECTION	pLs,
	IN	PVOID			Address
);

extern
VOID
AtalkLockUnlock(
	IN		BOOLEAN						Lock,
	IN		PLOCK_SECTION				pLs
);

#define	ROUTER_SECTION					0
#define	NBP_SECTION						1	// NBP & ZIP share the sections
#define	ZIP_SECTION						1
#define	TDI_SECTION						2
#define	ATP_SECTION						3
#define	ASP_SECTION						4
#define	PAP_SECTION						5
#define	ADSP_SECTION					6
#define	ASPC_SECTION					7
#define	INIT_SECTION					8
#define	LOCKABLE_SECTIONS				9
GLOBAL	KMUTEX							AtalkPgLkMutex						EQU { 0 };
GLOBAL	ATALK_SPIN_LOCK					AtalkPgLkLock						EQU { 0 };
GLOBAL	LOCK_SECTION					AtalkPgLkSection[LOCKABLE_SECTIONS]	EQU { 0 };

#ifdef	ATKTDI_LOCALS

// Used by AtalkLockUnlock & atalkQueuedLockUnlock to communicate. The latter is queued
// up by the former whenever it is called at DISPACTH to unlock
typedef	struct
{
	WORK_QUEUE_ITEM		qlu_WQI;
	PLOCK_SECTION		qlu_pLockSection;
	PPORT_DESCRIPTOR	qlu_pPortDesc;
} QLU, *PQLU;

LOCAL VOID FASTCALL
atalkTdiSendDgramComplete(
	IN	NDIS_STATUS						Status,
	IN	struct _SEND_COMPL_INFO	*		pSendInfo
);

LOCAL VOID
atalkTdiRecvDgramComplete(
	IN	ATALK_ERROR						ErrorCode,
	IN	PAMDL							pReadBuf,
	IN	USHORT							ReadLen,
	IN	PATALK_ADDR						pSrcAddr,
	IN	PIRP							pIrp);

LOCAL VOID
atalkTdiActionComplete(
	IN	ATALK_ERROR						ErrorCode,
	IN	PACTREQ							pActReq
);

LOCAL VOID
atalkTdiGenericComplete(
	IN	ATALK_ERROR						ErrorCode,
	IN	PIRP							pIrp
);

LOCAL VOID
atalkTdiCloseAddressComplete(
	IN	ATALK_ERROR						ErrorCode,
	IN	PIRP							pIrp
);

LOCAL VOID
atalkTdiGenericReadComplete(
	IN	ATALK_ERROR						ErrorCode,
	IN 	PAMDL							ReadBuf,
	IN 	USHORT							ReadLen,
	IN 	ULONG							ReadFlags,
	IN 	PIRP							pIrp
);

LOCAL VOID
atalkQueuedLockUnlock(
	IN	PQLU		pQLU
);

VOID
atalkWaitDefaultPort(
	VOID
);

#endif	// ATKTDI_LOCALS

#endif	// _ATKTDI_

