windows-nt/Source/XPSP1/NT/net/sfm/atalk/sys/atp.h
2020-09-26 16:20:57 +08:00

899 lines
24 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
atp.h
Abstract:
This module contains definitions for the ATP code.
Author:
Jameel Hyder (jameelh@microsoft.com)
Nikhil Kamkolkar (nikhilk@microsoft.com)
Revision History:
19 Jun 1992 Initial Version
Notes: Tab stop: 4
--*/
#ifndef _ATP_
#define _ATP_
// Command/control bit masks.
#define ATP_REL_TIMER_MASK 0x07
#define ATP_STS_MASK 0x08
#define ATP_EOM_MASK 0x10
#define ATP_XO_MASK 0x20
// Values for function code
#define ATP_REQUEST 0x40
#define ATP_RESPONSE 0x80
#define ATP_RELEASE 0xC0
#define ATP_FUNC_MASK 0xC0
#define ATP_CMD_CONTROL_OFF 0
#define ATP_BITMAP_OFF 1
#define ATP_SEQ_NUM_OFF 1
#define ATP_TRANS_ID_OFF 2
#define ATP_USER_BYTES_OFF 4
#define ATP_DATA_OFF 8
#define ATP_MAX_RESP_PKTS 8
#define ATP_USERBYTES_SIZE 4
#define ATP_HEADER_SIZE 8
// NOTE: Event handler routines- ATP has no event handling support
// ATP Address Object
#define ATP_DEF_MAX_SINGLE_PKT_SIZE 578
#define ATP_MAX_TOTAL_RESPONSE_SIZE (ATP_MAX_RESP_PKTS * ATP_DEF_MAX_SINGLE_PKT_SIZE)
#define ATP_DEF_SEND_USER_BYTES_ALL ((BOOLEAN)FALSE)
#define ATP_DEF_RETRY_INTERVAL 20 // 2 seconds in 100ms units
#define ATP_INFINITE_RETRIES -1
#define ATP_REQ_HASH_SIZE 29
#define ATP_RESP_HASH_SIZE 37
// Values for the release timer (.5, 1, 2, 4, 8 minutes).
typedef LONG RELEASE_TIMERVALUE;
#define FIRSTVALID_TIMER 0
#define THIRTY_SEC_TIMER 0
#define ONE_MINUTE_TIMER 1
#define TWO_MINUTE_TIMER 2
#define FOUR_MINUTE_TIMER 3
#define EIGHT_MINUTE_TIMER 4
#define LAST_VALID_TIMER 4
#define MAX_VALID_TIMERS 5
// Different subtypes for ATP indication type.
#define ATP_ALLOC_BUF 0
#define ATP_USER_BUF 1
#define ATP_USER_BUFX 2 // Do not indicate the packet to Atp with this.
struct _ATP_RESP;
typedef VOID (*ATPAO_CLOSECOMPLETION)(
IN ATALK_ERROR CloseResult,
IN PVOID CloseContext
);
typedef VOID (*ATP_REQ_HANDLER)(
IN ATALK_ERROR Error,
IN PVOID CompletionContext,
IN struct _ATP_RESP * pAtpResp,
IN PATALK_ADDR SourceAddress,
IN USHORT RequestLength,
IN PBYTE RequestPacket,
IN PBYTE RequestUserBytes // 4 bytes of user bytes
);
typedef VOID (*ATP_RESP_HANDLER)(
IN ATALK_ERROR Error,
IN PVOID CompletionContext,
IN PAMDL RequestBuffer,
IN PAMDL ResponseBuffer,
IN USHORT ResponseSize,
IN PBYTE ResponseUserBytes // 4 bytes of user bytes
);
typedef VOID (FASTCALL *ATP_REL_HANDLER)(
IN ATALK_ERROR Error,
IN PVOID CompletionContext
);
// ATP ADDRESS OBJECT STATES
#define ATPAO_OPEN 0x00000001
#define ATPAO_SENDUSERBYTESALL 0x00000002
#define ATPAO_CACHED 0x00000004
#define ATPAO_TIMERS 0x00000008
#define ATPAO_CLEANUP 0x40000000
#define ATPAO_CLOSING 0x80000000
#define ATPAO_SIGNATURE (*(PULONG)"ATPA")
#if DBG
#define VALID_ATPAO(pAtpAddr) (((pAtpAddr) != NULL) && \
((pAtpAddr)->atpao_Signature == ATPAO_SIGNATURE))
#else
#define VALID_ATPAO(pAtpAddr) ((pAtpAddr) != NULL)
#endif
typedef struct _ATP_ADDROBJ
{
#if DBG
ULONG atpao_Signature;
#endif
LONG atpao_RefCount;
// State of the address object
ULONG atpao_Flags;
// We pass a pointer to the ATP Address object to the upper layers to
// use as the endpoint, and this same pointer is passed to DDP Open
// Address as the ATP address handler context.
// Linkage list for all responses to AtLeastOnce (ALO) transactions.
// These are not kept in the resp hash table for efficiency. These
// happen very infrequently and only exist on the list until the
// SENDs complete.
struct _ATP_RESP * atpao_AloRespLinkage;
// next Transaction id to be used
USHORT atpao_NextTid;
// Maximum single packet size to be used (PAP needs this to be 512)
USHORT atpao_MaxSinglePktSize;
// Pointer to the DDP address object that this will create
PDDP_ADDROBJ atpao_DdpAddr;
// Completion routine to be called when socket is closed
ATPAO_CLOSECOMPLETION atpao_CloseComp;
PVOID atpao_CloseCtx;
// Hash table of pending ATP PostReq
struct _ATP_REQ * atpao_ReqHash[ATP_REQ_HASH_SIZE];
LIST_ENTRY atpao_ReqList; // List of requests for retry timer
TIMERLIST atpao_RetryTimer; // Retry timer for ALL requests
// Hash table of pending ATP PostResponses
struct _ATP_RESP * atpao_RespHash[ATP_RESP_HASH_SIZE];
LIST_ENTRY atpao_RespList; // List of requests for release timer
TIMERLIST atpao_RelTimer; // Release timer for ALL XO responses
// handler and corres. contexts for requests
ATP_REQ_HANDLER atpao_ReqHandler;
PVOID atpao_ReqCtx;
PATALK_DEV_CTX atpao_DevCtx;
ATALK_SPIN_LOCK atpao_Lock;
} ATP_ADDROBJ, *PATP_ADDROBJ;
#define ATP_REQ_EXACTLY_ONCE 0x0001
#define ATP_REQ_RETRY_TIMER 0x0002
#define ATP_REQ_REMOTE 0x0004
#define ATP_REQ_RESPONSE_COMPLETE 0x0008
#define ATP_REQ_CLOSING 0x8000
#define ATP_REQ_SIGNATURE (*(PULONG)"ATRQ")
#if DBG
#define VALID_ATPRQ(pAtpReq) (((pAtpReq) != NULL) && \
((pAtpReq)->req_Signature == ATP_REQ_SIGNATURE))
#else
#define VALID_ATPRQ(pAtpReq) ((pAtpReq) != NULL)
#endif
typedef struct _ATP_REQ
{
#if DBG
ULONG req_Signature;
#endif
LONG req_RefCount;
// Linkage of requests on this address object (hash overflow)
struct _ATP_REQ * req_Next;
struct _ATP_REQ ** req_Prev;
LIST_ENTRY req_List; // List of requests for retry timer
// BackPointer to the ATP address object. Need for reference/Dereference.
PATP_ADDROBJ req_pAtpAddr;
// State of the request
USHORT req_Flags;
// ATP Bitmap showing the response packets we are waiting for/expect.
BYTE req_Bitmap;
BYTE req_RecdBitmap;
// Destination of this request
ATALK_ADDR req_Dest;
// Request buffer for retransmission
PAMDL req_Buf;
USHORT req_BufLen;
// Transaction id
USHORT req_Tid;
union
{
BYTE req_UserBytes[ATP_USERBYTES_SIZE];
DWORD req_dwUserBytes;
};
// User's response buffer
PAMDL req_RespBuf;
// Buffer descriptors for parts of the resp buf.
PNDIS_BUFFER req_NdisBuf[ATP_MAX_RESP_PKTS];
USHORT req_RespBufLen;
// Received response length
USHORT req_RespRecdLen;
BYTE req_RespUserBytes[ATP_USERBYTES_SIZE];
LONG req_RetryInterval;
LONG req_RetryCnt;
// Release timer value to send to the remote end.
RELEASE_TIMERVALUE req_RelTimerValue;
// Retry time stamp, time at which the request will be retried if no response
LONG req_RetryTimeStamp;
// Completion routine to be called when request is done
ATALK_ERROR req_CompStatus;
ATP_RESP_HANDLER req_Comp;
PVOID req_Ctx;
ATALK_SPIN_LOCK req_Lock;
} ATP_REQ, *PATP_REQ;
// ATP_RESP_REMOTE indicates that the response is not to a local socket in which
// case we can avoid trying to deliver to our sockets
#define ATP_RESP_EXACTLY_ONCE 0x0001
#define ATP_RESP_ONLY_USER_BYTES 0x0002
#define ATP_RESP_REL_TIMER 0x0004
#define ATP_RESP_VALID_RESP 0x0008
#define ATP_RESP_SENT 0x0010
#define ATP_RESP_TRANSMITTING 0x0020
#define ATP_RESP_REMOTE 0x0040
#define ATP_RESP_HANDLER_NOTIFIED 0x0080
#define ATP_RESP_CANCELLED 0x0100
#define ATP_RESP_RELEASE_RECD 0x0200
#define ATP_RESP_CLOSING 0x8000
#define ATP_RESP_SIGNATURE (*(PULONG)"ATRS")
#if DBG
#define VALID_ATPRS(pAtpResp) (((pAtpResp) != NULL) && \
((pAtpResp)->resp_Signature == ATP_RESP_SIGNATURE))
#else
#define VALID_ATPRS(pAtpResp) ((pAtpResp) != NULL)
#endif
typedef struct _ATP_RESP
{
#if DBG
ULONG resp_Signature;
#endif
LONG resp_RefCount;
// Linkage of responses on this address object (hash overflow)
struct _ATP_RESP * resp_Next;
struct _ATP_RESP ** resp_Prev;
LIST_ENTRY resp_List; // List of resp for release timer
// BackPointer to the ATP address object
PATP_ADDROBJ resp_pAtpAddr;
// Transaction id
USHORT resp_Tid;
// ATP Bitmap from corresponding request
BYTE resp_Bitmap;
BYTE resp_UserBytesOnly;
// Destination of this request
ATALK_ADDR resp_Dest;
// State of the response
USHORT resp_Flags;
// User's response buffer
USHORT resp_BufLen;
PAMDL resp_Buf;
union
{
BYTE resp_UserBytes[ATP_USERBYTES_SIZE];
DWORD resp_dwUserBytes;
};
// Release timer value, How long do we wait before release.
LONG resp_RelTimerTicks;
// Release time stamp, time at which the request arrived.
LONG resp_RelTimeStamp;
// Routine to call when release comes in, or release timer expires
ATALK_ERROR resp_CompStatus;
ATP_REL_HANDLER resp_Comp;
PVOID resp_Ctx;
ATALK_SPIN_LOCK resp_Lock;
} ATP_RESP, *PATP_RESP;
#define ATP_RETRY_TIMER_INTERVAL 10 // 1 second in 100ms units
// NOTE: This will essentially put dampers on
// the RT stuff. Thats not too bad since
// we are guaranteed to try every second atleast
#define ATP_RELEASE_TIMER_INTERVAL 300 // 30 seconds in 100ms units
// Values for the 0.5, 1, 2, 4, 8 minute timer in ATP_RELEASE_TIMER_INTERVAL units.
extern SHORT AtalkAtpRelTimerTicks[MAX_VALID_TIMERS];
// Bitmaps for the sequence numbers in response packets.
extern BYTE AtpBitmapForSeqNum[ATP_MAX_RESP_PKTS];
extern BYTE AtpEomBitmapForSeqNum[ATP_MAX_RESP_PKTS];
typedef struct
{
BYTE atph_CmdCtrl;
union
{
BYTE atph_SeqNum;
BYTE atph_Bitmap;
};
USHORT atph_Tid;
union
{
BYTE atph_UserBytes[ATP_USERBYTES_SIZE];
DWORD atph_dwUserBytes;
};
} ATP_HEADER, *PATP_HEADER;
// Exported prototypes
#define AtalkAtpGetDdpAddress(pAtpAddr) ((pAtpAddr)->atpao_DdpAddr)
extern
ATALK_ERROR
AtalkAtpOpenAddress(
IN PPORT_DESCRIPTOR pPort,
IN BYTE Socket,
IN OUT PATALK_NODEADDR pDesiredNode OPTIONAL,
IN USHORT MaxSinglePktSize,
IN BOOLEAN SendUserBytesAll,
IN PATALK_DEV_CTX pDevCtx OPTIONAL,
IN BOOLEAN CacheSocket,
OUT PATP_ADDROBJ * ppAtpAddr);
extern
ATALK_ERROR
AtalkAtpCleanupAddress(
IN PATP_ADDROBJ pAtpAddr);
extern
ATALK_ERROR
AtalkAtpCloseAddress(
IN PATP_ADDROBJ pAddr,
IN ATPAO_CLOSECOMPLETION pCloseCmp OPTIONAL,
IN PVOID pCloseCtx OPTIONAL);
extern
ATALK_ERROR
AtalkAtpPostReq(
IN PATP_ADDROBJ pAddr,
IN PATALK_ADDR pDest,
OUT PUSHORT pTid,
IN USHORT Flags,
IN PAMDL pReq,
IN USHORT ReqLen,
IN PBYTE pUserBytes OPTIONAL,
IN OUT PAMDL pResp OPTIONAL,
IN USHORT RespLen,
IN SHORT RetryCnt,
IN LONG RetryInterval,
IN RELEASE_TIMERVALUE timerVal,
IN ATP_RESP_HANDLER pCmpRoutine OPTIONAL,
IN PVOID pCtx OPTIONAL);
extern
VOID
AtalkAtpSetReqHandler(
IN PATP_ADDROBJ pAddr,
IN ATP_REQ_HANDLER ReqHandler,
IN PVOID ReqCtx OPTIONAL);
extern
ATALK_ERROR
AtalkAtpPostResp(
IN PATP_RESP pAtpResp,
IN PATALK_ADDR pDest,
IN OUT PAMDL pResp,
IN USHORT RespLen,
IN PBYTE pUbytes OPTIONAL,
IN ATP_REL_HANDLER pCmpRoutine,
IN PVOID pCtx OPTIONAL);
extern
ATALK_ERROR
AtalkAtpCancelReq(
IN PATP_ADDROBJ pAtpAddr,
IN USHORT Tid,
IN PATALK_ADDR pDest);
extern
BOOLEAN
AtalkAtpIsReqComplete(
IN PATP_ADDROBJ pAtpAddr,
IN USHORT Tid,
IN PATALK_ADDR pDest);
extern
ATALK_ERROR
AtalkAtpCancelResp(
IN PATP_RESP pAtpResp);
extern
ATALK_ERROR
AtalkAtpCancelRespByTid(
IN PATP_ADDROBJ pAtpAddr,
IN PATALK_ADDR pDest,
IN USHORT Tid);
extern
VOID
AtalkAtpPacketIn(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr,
IN PBYTE pPkt,
IN USHORT PktLen,
IN PATALK_ADDR pSrcAddr,
IN PATALK_ADDR pDstAddr,
IN ATALK_ERROR ErrorCode,
IN BYTE DdpType,
IN PATP_ADDROBJ pAtpAddr,
IN BOOLEAN OptimizePath,
IN PVOID OptimizeCtx);
#define AtalkAtpAddrReference(_pAtpAddr, _pError) \
{ \
KIRQL OldIrql; \
\
ACQUIRE_SPIN_LOCK(&(_pAtpAddr)->atpao_Lock, &OldIrql); \
atalkAtpAddrRefNonInterlock((_pAtpAddr), _pError); \
RELEASE_SPIN_LOCK(&(_pAtpAddr)->atpao_Lock, OldIrql); \
}
#define AtalkAtpAddrReferenceDpc(_pAtpAddr, _pError) \
{ \
ACQUIRE_SPIN_LOCK_DPC(&(_pAtpAddr)->atpao_Lock); \
atalkAtpAddrRefNonInterlock((_pAtpAddr), _pError); \
RELEASE_SPIN_LOCK_DPC(&(_pAtpAddr)->atpao_Lock); \
}
#define atalkAtpAddrRefNonInterlock(_pAtpAddr, _pError) \
{ \
*(_pError) = ATALK_NO_ERROR; \
if (((_pAtpAddr)->atpao_Flags & (ATPAO_CLOSING|ATPAO_OPEN))==ATPAO_OPEN)\
{ \
ASSERT((_pAtpAddr)->atpao_RefCount >= 1); \
(_pAtpAddr)->atpao_RefCount++; \
} \
else \
{ \
*(_pError) = ATALK_ATP_CLOSING; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("atalkAtpAddrRefNonInterlock: %lx %s (%ld) Failure\n", \
_pAtpAddr, __FILE__, __LINE__)); \
} \
}
VOID FASTCALL
AtalkAtpAddrDeref(
IN OUT PATP_ADDROBJ pAtpAddr,
IN BOOLEAN AtDpc);
#define AtalkAtpAddrDereference(_pAtpAddr) \
AtalkAtpAddrDeref(_pAtpAddr, FALSE)
#define AtalkAtpAddrDereferenceDpc(_pAtpAddr) \
AtalkAtpAddrDeref(_pAtpAddr, TRUE)
VOID FASTCALL
AtalkAtpRespDeref(
IN PATP_RESP pAtpResp,
IN BOOLEAN AtDpc);
#define AtalkAtpRespDereference(_pAtrpResp) \
AtalkAtpRespDeref(_pAtrpResp, FALSE)
#define AtalkAtpRespDereferenceDpc(_pAtrpResp) \
AtalkAtpRespDeref(_pAtrpResp, TRUE)
#define AtalkAtpRespReferenceByPtr(_pAtpResp, _pError) \
{ \
KIRQL OldIrql; \
\
*(_pError) = ATALK_NO_ERROR; \
\
ACQUIRE_SPIN_LOCK(&(_pAtpResp)->resp_Lock, &OldIrql); \
if (((_pAtpResp)->resp_Flags & ATP_RESP_CLOSING) == 0) \
{ \
(_pAtpResp)->resp_RefCount++; \
} \
else \
{ \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("AtalkAtpRespReferenceByPtr: %lx %s (%ld) Failure\n", \
_pAtpResp, __FILE__, __LINE__)); \
*(_pError) = ATALK_ATP_RESP_CLOSING; \
} \
RELEASE_SPIN_LOCK(&(_pAtpResp)->resp_Lock, OldIrql); \
}
#define AtalkAtpRespReferenceByPtrDpc(_pAtpResp, _pError) \
{ \
*(_pError) = ATALK_NO_ERROR; \
\
ACQUIRE_SPIN_LOCK_DPC(&(_pAtpResp)->resp_Lock); \
if (((_pAtpResp)->resp_Flags & ATP_RESP_CLOSING) == 0) \
{ \
(_pAtpResp)->resp_RefCount++; \
} \
else \
{ \
*(_pError) = ATALK_ATP_RESP_CLOSING; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("atalkAtpRespRefByPtrDpc: %lx %s (%ld) Failure\n", \
_pAtpResp, __FILE__, __LINE__)); \
} \
RELEASE_SPIN_LOCK_DPC(&(_pAtpResp)->resp_Lock); \
}
ATALK_ERROR
AtalkIndAtpPkt(
IN PPORT_DESCRIPTOR pPortDesc,
IN PBYTE pLookahead,
IN USHORT PktLen,
IN OUT PUINT pXferOffset,
IN PBYTE pLinkHdr,
IN BOOLEAN ShortDdpHdr,
OUT PBYTE SubType,
OUT PBYTE * ppPacket,
OUT PNDIS_PACKET * pNdisPkt);
ATALK_ERROR
AtalkIndAtpCacheSocket(
IN struct _ATP_ADDROBJ * pAtpAddr,
IN PPORT_DESCRIPTOR pPortDesc);
VOID
AtalkIndAtpUnCacheSocket(
IN struct _ATP_ADDROBJ * pAtpAddr);
VOID FASTCALL
AtalkAtpGenericRespComplete(
IN ATALK_ERROR ErrorCode,
IN PATP_RESP pAtpResp
);
VOID FASTCALL
AtalkIndAtpSetupNdisBuffer(
IN OUT PATP_REQ pAtpReq,
IN ULONG MaxSinglePktSize
);
VOID FASTCALL
AtalkIndAtpReleaseNdisBuffer(
IN OUT PATP_REQ pAtpReq
);
// ATALK_ERROR
// AtalkIndAtpCacheLkUpSocket(
// IN PATALK_ADDR pDestAddr,
// OUT struct _ATP_ADDROBJ ** ppAtpAddr,
// OUT ATALK_ERROR * pError);
//
#define AtalkIndAtpCacheLkUpSocket(pDestAddr, ppAtpAddr, pError) \
{ \
USHORT i; \
struct ATALK_CACHED_SKT *pCachedSkt; \
\
*(pError) = ATALK_FAILURE; \
\
if (((pDestAddr)->ata_Network == AtalkSktCache.ac_Network) && \
((pDestAddr)->ata_Node == AtalkSktCache.ac_Node)) \
{ \
ACQUIRE_SPIN_LOCK_DPC(&AtalkSktCacheLock); \
\
for (i = 0, pCachedSkt = &AtalkSktCache.ac_Cache[0]; \
i < ATALK_CACHE_SKTMAX; \
i++, pCachedSkt++) \
{ \
if ((pCachedSkt->Type == (ATALK_CACHE_INUSE | ATALK_CACHE_ATPSKT)) && \
(pCachedSkt->Socket == (pDestAddr)->ata_Socket))\
{ \
AtalkAtpAddrReferenceDpc(pCachedSkt->u.pAtpAddr,\
pError); \
\
if (ATALK_SUCCESS(*pError)) \
{ \
*(ppAtpAddr) = pCachedSkt->u.pAtpAddr; \
} \
break; \
} \
} \
\
RELEASE_SPIN_LOCK_DPC(&AtalkSktCacheLock); \
} \
}
VOID FASTCALL
atalkAtpReqDeref(
IN PATP_REQ pAtpReq,
IN BOOLEAN AtDpc);
// MACROS
// Top byte of network number is pretty static so we get rid of it and add
// in the tid.
#define ATP_HASH_TID_DESTADDR(_tid, _pAddr, _BucketSize) \
(((_pAddr)->ata_Node+((_pAddr)->ata_Network & 0xFF)+_tid)%(_BucketSize))
#define atalkAtpReqReferenceByAddrTidDpc(_pAtpAddr, _pAddr, _Tid, _ppAtpReq, _pErr) \
{ \
PATP_REQ __p; \
ULONG __i; \
\
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_INFO, \
("atalkAtpReqRefByAddrTid: %lx.%lx.%lx tid %lx\n", \
(_pAddr)->ata_Network, (_pAddr)->ata_Node, \
(_pAddr)->ata_Socket, (_Tid))); \
\
__i = ATP_HASH_TID_DESTADDR((_Tid), (_pAddr), ATP_REQ_HASH_SIZE); \
for (__p = (_pAtpAddr)->atpao_ReqHash[(__i)]; \
__p != NULL; \
__p = __p->req_Next) \
{ \
if ((ATALK_ADDRS_EQUAL(&__p->req_Dest, (_pAddr))) && \
(__p->req_Tid == (_Tid))) \
{ \
AtalkAtpReqReferenceByPtrDpc(__p, _pErr); \
if (ATALK_SUCCESS(*(_pErr))) \
{ \
*(_ppAtpReq) = __p; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_INFO, \
("atalkAtpReqRefByAddrTid: FOUND %lx\n", __p)); \
} \
break; \
} \
} \
if (__p == NULL) \
*(_pErr) = ATALK_ATP_NOT_FOUND; \
}
#define AtalkAtpReqReferenceByPtr(_pAtpReq, _pErr) \
{ \
KIRQL OldIrql; \
\
*(_pErr) = ATALK_NO_ERROR; \
\
ACQUIRE_SPIN_LOCK(&(_pAtpReq)->req_Lock, &OldIrql); \
if (((_pAtpReq)->req_Flags & ATP_REQ_CLOSING) == 0) \
{ \
(_pAtpReq)->req_RefCount++; \
} \
else \
{ \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("AtalkAtpReqReferenceByPtr: %lx %s (%ld) Failure\n", \
_pAtpReq, __FILE__, __LINE__)); \
*(_pErr) = ATALK_ATP_REQ_CLOSING; \
} \
RELEASE_SPIN_LOCK(&(_pAtpReq)->req_Lock, OldIrql); \
}
#define AtalkAtpReqReferenceByPtrDpc(_pAtpReq, _pErr) \
{ \
*(_pErr) = ATALK_NO_ERROR; \
\
ACQUIRE_SPIN_LOCK_DPC(&(_pAtpReq)->req_Lock); \
if (((_pAtpReq)->req_Flags & ATP_REQ_CLOSING) == 0) \
{ \
(_pAtpReq)->req_RefCount++; \
} \
else \
{ \
*(_pErr) = ATALK_ATP_REQ_CLOSING; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("AtalkAtpReqReferenceByPtrDpc: %lx %s (%ld) Failure\n", \
_pAtpReq, __FILE__, __LINE__)); \
} \
RELEASE_SPIN_LOCK_DPC(&(_pAtpReq)->req_Lock); \
}
#define atalkAtpRespReferenceNDpc(_pAtpResp, _N, _pError) \
{ \
*(_pError) = ATALK_NO_ERROR; \
ACQUIRE_SPIN_LOCK_DPC(&(_pAtpResp)->resp_Lock); \
if (((_pAtpResp)->resp_Flags & ATP_RESP_CLOSING) == 0) \
{ \
(_pAtpResp)->resp_RefCount += _N; \
} \
else \
{ \
*(_pError) = ATALK_ATP_RESP_CLOSING; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_WARN, \
("atalkAtpRespReferenceNDpc: %lx %d %s (%ld) Failure\n", \
_pAtpResp, _N, __FILE__, __LINE__)); \
} \
RELEASE_SPIN_LOCK_DPC(&(_pAtpResp)->resp_Lock); \
}
// THIS SHOULD BE CALLED WITH ADDRESS LOCK HELD !!!
#define atalkAtpRespReferenceByAddrTidDpc(_pAtpAddr, _pAddr, _Tid, _ppAtpResp, _pErr)\
{ \
PATP_RESP __p; \
ULONG __i; \
\
__i = ATP_HASH_TID_DESTADDR((_Tid), (_pAddr), ATP_RESP_HASH_SIZE); \
\
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_INFO, \
("atalkAtpRespRefByAddrTid: %lx.%lx.%lx tid %lx\n", \
(_pAddr)->ata_Network, (_pAddr)->ata_Node, \
(_pAddr)->ata_Socket, (_Tid))); \
\
for (__p = (_pAtpAddr)->atpao_RespHash[__i]; \
__p != NULL; \
__p = __p->resp_Next) \
{ \
if (ATALK_ADDRS_EQUAL(&__p->resp_Dest, _pAddr) && \
(__p->resp_Tid == (_Tid))) \
{ \
AtalkAtpRespReferenceByPtrDpc(__p, _pErr); \
if (ATALK_SUCCESS((*(_pErr)))) \
{ \
*(_ppAtpResp) = __p; \
DBGPRINT(DBG_COMP_ATP, DBG_LEVEL_INFO, \
("atalkAtpRespRefByAddrTid: FOUND %lx\n", __p)); \
} \
break; \
} \
} \
if (__p == NULL) \
*(_pErr) = ATALK_ATP_NOT_FOUND; \
}
#define AtalkAtpReqDereference(_pAtpReq) \
atalkAtpReqDeref(_pAtpReq, FALSE)
#define AtalkAtpReqDereferenceDpc(_pAtpReq) \
atalkAtpReqDeref(_pAtpReq, TRUE)
VOID FASTCALL
atalkAtpTransmitReq(
IN PATP_REQ pAtpReq);
VOID FASTCALL
atalkAtpTransmitResp(
IN PATP_RESP pAtpResp);
VOID FASTCALL
atalkAtpTransmitRel(
IN PATP_REQ pAtpReq);
VOID
atalkAtpGetNextTidForAddr(
IN PATP_ADDROBJ pAtpAddr,
IN PATALK_ADDR pRemoteAddr,
OUT PUSHORT pTid,
OUT PULONG pIndex);
LOCAL LONG FASTCALL
atalkAtpReqTimer(
IN PTIMERLIST pTimer,
IN BOOLEAN TimerShuttingDown);
LOCAL LONG FASTCALL
atalkAtpRelTimer(
IN PTIMERLIST pTimer,
IN BOOLEAN TimerShuttingDown);
#define atalkAtpBufferSizeToBitmap(_Bitmap, _BufSize, _SinglePktSize) \
{ \
SHORT __bufSize = (_BufSize); \
\
(_Bitmap) = 0; \
while(__bufSize > 0) \
{ \
(_Bitmap) = ((_Bitmap) <<= 1) | 1; \
__bufSize -= (_SinglePktSize); \
} \
}
#define atalkAtpBitmapToBufferSize(_Size, _Bitmap, _SinglePktSize) \
{ \
BYTE __bitmap = (_Bitmap); \
BOOLEAN __bitOn; \
\
_Size = 0; \
while (__bitmap) \
{ \
__bitOn = (__bitmap & 1); \
__bitmap >>= 1; \
if (__bitOn) \
{ \
(_Size) += (_SinglePktSize); \
} \
else \
{ \
if (__bitmap) \
{ \
(_Size) = -1; \
} \
break; \
} \
} \
}
VOID FASTCALL
atalkAtpSendReqComplete(
IN NDIS_STATUS Status,
IN PSEND_COMPL_INFO pSendInfo);
VOID FASTCALL
atalkAtpSendRespComplete(
IN NDIS_STATUS Status,
IN PSEND_COMPL_INFO pSendInfo);
VOID FASTCALL
atalkAtpSendRelComplete(
IN NDIS_STATUS Status,
IN PSEND_COMPL_INFO pSendInfo);
VOID
atalkAtpRespRefNextNc(
IN PATP_RESP pAtpResp,
OUT PATP_RESP * ppNextNcResp,
OUT PATALK_ERROR pError);
VOID
atalkAtpReqRefNextNc(
IN PATP_REQ pAtpReq,
OUT PATP_REQ * pNextNcReq,
OUT PATALK_ERROR pError);
VOID FASTCALL
atalkAtpRespComplete(
IN OUT PATP_RESP pAtpResp,
IN ATALK_ERROR CompletionStatus);
VOID FASTCALL
atalkAtpReqComplete(
IN OUT PATP_REQ pAtpReq,
IN ATALK_ERROR CompletionStatus);
#endif // _ATP_