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

680 lines
18 KiB
C

/*+++
Copyright (c) 1992 Microsoft Corporation
Module Name:
ddp.h
Abstract:
This module contains the DDP address object and ddp 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 _DDP_
#define _DDP_
// Network number information.
#define FIRST_VALID_NETWORK 0x0001
#define LAST_VALID_NETWORK 0xFFFE
#define FIRST_STARTUP_NETWORK 0xFF00
#define LAST_STARTUP_NETWORK 0xFFFE
#define NULL_NETWORK 0x0000
#define UNKNOWN_NETWORK NULL_NETWORK
#define CABLEWIDE_BROADCAST_NETWORK NULL_NETWORK
// Appletalk Sockets Definitions
#define UNKNOWN_SOCKET 0
#define DYNAMIC_SOCKET UNKNOWN_SOCKET
#define LAST_VALID_SOCKET 254
#define FIRST_DYNAMIC_SOCKET 128
#define LAST_DYNAMIC_SOCKET LAST_VALID_SOCKET
#define FIRST_STATIC_SOCKET 1
#define FIRST_VALID_SOCKET FIRST_STATIC_SOCKET
#define LAST_STATIC_SOCKET 127
// "Well known" sockets:
#define RTMP_SOCKET 1 // RTMP
#define NAMESINFORMATION_SOCKET 2 // NBP
#define ECHOER_SOCKET 4 // EP
#define ZONESINFORMATION_SOCKET 6 // ZIP
#define LAST_APPLE_RESD_SOCKET 0x3F // Apple reserves 1 thru 0x3F
// DDP Datagram Definitions
#define MAX_DGRAM_SIZE 586
#define MAX_LDDP_PKT_SIZE 600 // Really 599, but even is nicer
#define MAX_SDDP_PKT_SIZE 592 // Again, really 591
// Define temporary buffer sizes, these must be big enough to hold both all
// of the packet data plus any link/hardware headers...
#define MAX_PKT_SIZE (MAX_HDR_LEN + MAX_LDDP_PKT_SIZE)
#define DDP_LEN_MASK1 0x03 // High order 3 bits of length
#define DDP_LEN_MASK2 0xFF // Next byte of length
// DDP packet offsets (skipping Link/Hardware headers):
#define SDDP_HDR_LEN 5
#define SDDP_LEN_OFFSET 0
#define SDDP_DEST_SOCKET_OFFSET 2
#define SDDP_SRC_SOCKET_OFFSET 3
#define SDDP_PROTO_TYPE_OFFSET 4
#define SDDP_DGRAM_OFFSET 5
#define LDDP_HDR_LEN 13
#define LDDP_LEN_OFFSET 0
#define LDDP_CHECKSUM_OFFSET 2
#define LDDP_DEST_NETWORK_OFFSET 4
#define LDDP_SRC_NETWORK_OFFSET 6
#define LDDP_DEST_NODE_OFFSET 8
#define LDDP_SRC_NODE_OFFSET 9
#define LDDP_DEST_SOCKET_OFFSET 10
#define LDDP_SRC_SOCKET_OFFSET 11
#define LDDP_PROTO_TYPE_OFFSET 12
#define LDDP_DGRAM_OFFSET 13
#define LEADING_UNCHECKSUMED_BYTES 4
#define LDDP_HOPCOUNT_MASK 0x3C
#define DECIMAL_BASE 10
// DDP protocol types:
#define DDPPROTO_ANY 0 // Used to allow any protocol packet
#define DDPPROTO_DDP 0
#define DDPPROTO_RTMPRESPONSEORDATA 1
#define DDPPROTO_NBP 2
#define DDPPROTO_ATP 3
#define DDPPROTO_EP 4
#define DDPPROTO_RTMPREQUEST 5
#define DDPPROTO_ZIP 6
#define DDPPROTO_ADSP 7
#define DDPPROTO_MAX 255
typedef struct _DDPEVENT_INFO
{
// Event handler routines: DDP Only has RecvDatagram/Error handlers
// The following function pointer always points to a TDI_IND_RECEIVE_DATAGRAM
// event handler for the address.
PTDI_IND_RECEIVE_DATAGRAM ev_RcvDgramHandler;
PVOID ev_RcvDgramCtx;
// The following function pointer always points to a TDI_IND_ERROR
// handler for the address.
PTDI_IND_ERROR ev_ErrHandler;
PVOID ev_ErrCtx;
PVOID ev_ErrOwner;
// Winsock assumes a buffering transport. So we buffer the last datagram
// indicated that was not accepted.
BYTE ev_IndDgram[MAX_DGRAM_SIZE];
int ev_IndDgramLen;
int ev_IndProto;
// Source address of buffered datagram
ATALK_ADDR ev_IndSrc;
} DDPEVENT_INFO, *PDDPEVENT_INFO;
// Handler type for the DDP address object
typedef VOID (*DDPAO_HANDLER)(
IN PPORT_DESCRIPTOR pPortDesc,
IN struct _DDP_ADDROBJ *pAddr,
IN PBYTE pPkt,
IN USHORT pPktLen,
IN PATALK_ADDR pSrcAddr,
IN PATALK_ADDR pActDest,
IN ATALK_ERROR ErrorCode,
IN BYTE pDdpType,
IN PVOID pHandlerCtx,
IN BOOLEAN OptimizedPath,
IN PVOID OptimizeCtx);
// DDP Address Object
// This is the basic address object in the stack. All other address objects
// eventually resolve to this one. It also holds the AppletalkSocket opened
// as its actual address. One address object corresponds to one address.
// DDP ADDRESS OBJECT STATES
#define DDPAO_DGRAM_EVENT 0x00000001
#define DDPAO_DGRAM_ACTIVE 0x00000002
#define DDPAO_DGRAM_PENDING 0x00000004
#define DDPAO_SOCK_INTERNAL 0x00000008
#define DDPAO_SOCK_PNPZOMBIE 0x00000010
#define DDPAO_CLOSING 0x80000000
#define DDPAO_SIGNATURE (*(PULONG)"DDPA")
#define VALID_DDP_ADDROBJ(pDdpAddr) (((pDdpAddr) != NULL) && \
(((struct _DDP_ADDROBJ *)(pDdpAddr))->ddpao_Signature == DDPAO_SIGNATURE))
typedef struct _DDP_ADDROBJ
{
ULONG ddpao_Signature;
// This will be a hash overflow list. Hash on the internet address.
// List of address objects on the node linkage
struct _DDP_ADDROBJ * ddpao_Next;
ULONG ddpao_RefCount;
// State of the address object
ULONG ddpao_Flags;
// Backpointer to the node on which this socket exists
struct _ATALK_NODE * ddpao_Node;
// The Appletalk address number for this object
ATALK_ADDR ddpao_Addr;
// List of NBP names registered on this socket
struct _REGD_NAME * ddpao_RegNames;
// List of NBP names being looked up, registered or confirmed on
// this socket.
struct _PEND_NAME * ddpao_PendNames;
// Linked list of pending ddp reads
LIST_ENTRY ddpao_ReadLinkage;
// The protocol type to use for datagrams sent on this socket and
// which can be received on this socket. 0 => no restrictions.
BYTE ddpao_Protocol;
ATALK_SPIN_LOCK ddpao_Lock;
PATALK_DEV_CTX ddpao_DevCtx;
// The handler below is an listener for the upper layers. Note that
// this will take precedence over a incoming datagram event handler
// which would be set in ddpao_EventInfo.
DDPAO_HANDLER ddpao_Handler;
PVOID ddpao_HandlerCtx;
// This structure is allocated when setting an event handler
// on this socket. All the event handler addresses are part of this
// structure.
PDDPEVENT_INFO ddpao_EventInfo;
// Completion routine to be called when socket is closed
GENERIC_COMPLETION ddpao_CloseComp;
PVOID ddpao_CloseCtx;
} DDP_ADDROBJ, *PDDP_ADDROBJ;
// Receive datagram completion: This will return the mdl we pass in along
// with the received length written into the mdl. Also, the protocol type
// and the RemoteAddress are passed back. The receive context will be the
// irp for the request. As will be the send context.
typedef VOID (*RECEIVE_COMPLETION)(
IN ATALK_ERROR ErrorCode,
IN PAMDL OpaqueBuffer,
IN USHORT LengthReceived,
IN PATALK_ADDR RemoteAddress,
IN PVOID ReceiveContext);
typedef VOID (FASTCALL *WRITE_COMPLETION)(
IN NDIS_STATUS Status,
IN PVOID Ctx);
typedef VOID (FASTCALL *TRANSMIT_COMPLETION)(
IN NDIS_STATUS Status,
IN struct _SEND_COMPL_INFO * pInfo);
// If the above routine was set in the AtalkDdpSend(), then
// then context values would be:
// Ctx1 = pddp address object
// Ctx2 = pbuffer descriptor
// Ctx3 = Only for DdpWrite calls, this will be a pointer to the
// write structure enqueued in the ddp address object.
//
// If the above routine was set in the AtalkDdpTransmit(), then
// the context values would be (as specified by the client of
// course):
// Ctx1 = pport descriptor
// Ctx2 = pbuffer descriptor
// Ctx3 = not used.
//
// These are only suggested ideas, but probably is what the internal
// stack routines will use.
// This is used to store a pending read on a particular socket.
typedef struct _DDP_READ
{
// Linkage chain for reads on a socket.
LIST_ENTRY dr_Linkage;
PAMDL dr_OpBuf;
USHORT dr_OpBufLen;
RECEIVE_COMPLETION dr_RcvCmp;
PVOID dr_RcvCtx;
} DDP_READ, *PDDP_READ;
// This is used to store a pending write on a particular socket
// DDP will create a buffer descriptor for the header
// and will chain it in front of the buffer descriptor passed in.
// A pointer to this structure will then be passed as a completion
// context to DdpSend.
typedef struct _DDP_WRITE
{
// Linkage chain for writes on a socket.
LIST_ENTRY dw_Linkage;
// The buffer descriptor chain, including the ddp buffer
// descriptor containing the ddp/optional/link headers.
PBUFFER_DESC dw_BufferDesc;
// Write completion
// This will be called with the context (which will be a pointer
// to the write irp) after the write completes.
WRITE_COMPLETION dw_WriteRoutine;
PVOID dw_WriteCtx;
} DDP_WRITE, *PDDP_WRITE;
//
// CANCEL IRP Functionality for NT:
//
// We have decided that if we receive a cancel irp for a particular request,
// we will shutdown the file object associated with that request, whether it
// be a connection object or an address object. This implies that the socket/
// connection/listener will be closed, thus cancelling *all* pending requests.
//
ATALK_ERROR
AtalkDdpOpenAddress(
IN PPORT_DESCRIPTOR pPortDesc,
IN BYTE Socket,
IN OUT PATALK_NODEADDR pDesiredNode OPTIONAL,
IN DDPAO_HANDLER pSktHandler OPTIONAL,
IN PVOID pSktCtx OPTIONAL,
IN BYTE ProtoType OPTIONAL,
IN PATALK_DEV_CTX pDevCtx,
OUT PDDP_ADDROBJ * pAddr);
ATALK_ERROR
AtalkDdpCloseAddress(
IN PDDP_ADDROBJ pAddr,
IN GENERIC_COMPLETION pCloseCmp OPTIONAL,
IN PVOID pCloseCtx OPTIONAL);
ATALK_ERROR
AtalkDdpPnPSuspendAddress(
IN PDDP_ADDROBJ pDdpAddr);
ATALK_ERROR
AtalkDdpCleanupAddress(
IN PDDP_ADDROBJ pAddr);
ATALK_ERROR
AtalkDdpInitCloseAddress(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR pAtalkAddr);
ATALK_ERROR
AtalkInitDdpOpenStaticSockets(
IN PPORT_DESCRIPTOR pPortDesc,
IN OUT PATALK_NODE pNode);
ATALK_ERROR
AtalkDdpReceive(
IN PDDP_ADDROBJ pAddr,
IN PAMDL pAmdl,
IN USHORT AmdlLen,
IN ULONG RecvFlags,
IN RECEIVE_COMPLETION pRcvCmp,
IN PVOID pRcvCtx);
ATALK_ERROR
AtalkDdpSend(
IN PDDP_ADDROBJ pDdpAddr,
IN PATALK_ADDR DestAddr,
IN BYTE ProtoType,
IN BOOLEAN DefinitelyRemoteAddr,
IN PBUFFER_DESC pBufDesc,
IN PBYTE pOptHdr OPTIONAL,
IN USHORT OptHdrLen OPTIONAL,
IN PBYTE pZoneMcastAddr OPTIONAL,
IN struct _SEND_COMPL_INFO * pInfo OPTIONAL);
ATALK_ERROR
AtalkDdpTransmit(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR SrcAddr,
IN PATALK_ADDR DestAddr,
IN BYTE ProtoType,
IN PBUFFER_DESC pBufDesc,
IN PBYTE pOptHdr OPTIONAL,
IN USHORT OptHdrLen OPTIONAL,
IN USHORT HopCnt,
IN PBYTE pMcastAddr OPTIONAL,
IN PATALK_NODEADDR pXmitDestNode OPTIONAL,
IN struct _SEND_COMPL_INFO * pInfo OPTIONAL);
VOID
AtalkDdpSendComplete(
IN NDIS_STATUS Status,
IN PBUFFER_DESC pBufDesc,
IN struct _SEND_COMPL_INFO * pInfo OPTIONAL);
VOID
AtalkDdpPacketIn(
IN PPORT_DESCRIPTOR pPortDesc,
IN PBYTE pLinkHdr,
IN PBYTE pPkt,
IN USHORT PktLen,
IN BOOLEAN fWanPkt);
VOID
AtalkDdpQuery(
IN PDDP_ADDROBJ pDdpAddr,
IN PAMDL pAmdl,
OUT PULONG BytesWritten);
VOID
AtalkDdpRefByAddr(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR pAtalkAddr,
OUT PDDP_ADDROBJ * ppDdpAddr,
OUT PATALK_ERROR pErr);
VOID
AtalkDdpRefByAddrNode(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR pAtalkAddr,
IN PATALK_NODE pAtalkNode,
OUT PDDP_ADDROBJ * ppDdpAddr,
OUT PATALK_ERROR pErr);
VOID
AtalkDdpRefNextNc(
IN PDDP_ADDROBJ pDdpAddr,
IN PDDP_ADDROBJ * ppDdpAddr,
OUT PATALK_ERROR pErr);
VOID FASTCALL
AtalkDdpDeref(
IN OUT PDDP_ADDROBJ pDdpAddr,
IN BOOLEAN AtDpc);
VOID
AtalkDdpOutBufToNodesOnPort(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR pSrc,
IN PATALK_ADDR pDest,
IN BYTE ProtoType,
IN PBUFFER_DESC pBufDesc,
IN PBYTE pOptHdr,
IN USHORT OptHdrLen,
OUT PBOOLEAN Delivered);
VOID
AtalkDdpInPktToNodesOnPort(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_ADDR pDest,
IN PATALK_ADDR pSrc,
IN BYTE ProtoType,
IN PBYTE pPkt,
IN USHORT PktLen,
OUT PBOOLEAN Routed);
VOID
AtalkDdpInvokeHandlerBufDesc(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr,
IN PATALK_ADDR pSrcAddr,
IN PATALK_ADDR pActDest,
IN BYTE ProtoType,
IN PBUFFER_DESC pBufDesc,
IN PBYTE pOptHdr,
IN USHORT OptHdrLen);
VOID
AtalkDdpInvokeHandler(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr,
IN PATALK_ADDR pSrcAddr,
IN PATALK_ADDR pActDest,
IN BYTE ProtoType,
IN PBYTE pPkt,
IN USHORT PktLen);
USHORT
AtalkDdpCheckSumBuffer(
IN PBYTE Buffer,
IN USHORT BufLen,
IN USHORT CurrentCheckSum);
USHORT
AtalkDdpCheckSumBufferDesc(
IN PBUFFER_DESC pBuffDesc,
IN USHORT Offset);
USHORT
AtalkDdpCheckSumPacket(
IN PBYTE pHdr,
IN USHORT HdrLen,
IN PBYTE pPkt,
IN USHORT PktLen);
VOID
AtalkDdpNewHandlerForSocket(
IN PDDP_ADDROBJ pDdpAddr,
IN DDPAO_HANDLER pSktHandler,
IN PVOID pSktHandlerCtx);
// MACROS
#define DDP_MSB_LEN(L) (((L) >> 8) & 0x03)
#define DDP_GET_LEN(P) ((((*P) & 0x03) << 8) + *(P+1))
#define DDP_GET_HOP_COUNT(P) (((*P) >> 2) & 0x0F)
#define DDP_HOP_COUNT(H) (((H) & 0x0F) << 2)
#if DBG
#define AtalkDdpReferenceByPtr(pDdpAddr, pErr) \
{ \
KIRQL OldIrql; \
\
ACQUIRE_SPIN_LOCK(&(pDdpAddr)->ddpao_Lock, &OldIrql); \
AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr); \
RELEASE_SPIN_LOCK(&(pDdpAddr)->ddpao_Lock, OldIrql); \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpReferenceByPtr: %s %d PostCount %d\n",\
__FILE__, __LINE__,pDdpAddr->ddpao_RefCount)); \
}
#define AtalkDdpReferenceByPtrDpc(pDdpAddr, pErr) \
{ \
ACQUIRE_SPIN_LOCK_DPC(&(pDdpAddr)->ddpao_Lock); \
AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr); \
RELEASE_SPIN_LOCK_DPC(&(pDdpAddr)->ddpao_Lock); \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpReferenceByPtr: %s %d PostCount %d\n",\
__FILE__, __LINE__,pDdpAddr->ddpao_RefCount)); \
}
#define AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr) \
{ \
ASSERT (VALID_DDP_ADDROBJ(pDdpAddr)); \
\
*pErr = ATALK_DDP_CLOSING; \
\
if ((pDdpAddr->ddpao_Flags & DDPAO_CLOSING) == 0) \
{ \
pDdpAddr->ddpao_RefCount++; \
*pErr = ATALK_NO_ERROR; \
} \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpReferenceByPtrNonInterlock: %s %d PostCount %d\n",\
__FILE__, __LINE__, \
pDdpAddr->ddpao_RefCount)); \
}
#define AtalkDdpReferenceNextNc(pDdpAddr, ppDdpAddr, pErr) \
{ \
AtalkDdpRefNextNc(pDdpAddr, ppDdpAddr, pErr); \
if (ATALK_SUCCESS(*pErr)) \
{ \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("DdpRefNextNc : %s %d PostCount %d\n", \
__FILE__, __LINE__, \
(*ppDdpAddr)->ddpao_RefCount)); \
} \
}
#define AtalkDdpReferenceByAddr(pPortDesc, pAddr, ppDdpAddr, pErr) \
{ \
AtalkDdpRefByAddr(pPortDesc, pAddr, ppDdpAddr, pErr); \
if (ATALK_SUCCESS(*pErr)) \
{ \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpReferenceByAddr: %s %d PostCount %d\n",\
__FILE__, __LINE__, \
(*ppDdpAddr)->ddpao_RefCount)); \
} \
}
#define AtalkDdpDereference(pDdpAddr) \
{ \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpDereference: %s %d PreCount %d\n", \
__FILE__, __LINE__,pDdpAddr->ddpao_RefCount)); \
AtalkDdpDeref(pDdpAddr, FALSE); \
}
#define AtalkDdpDereferenceDpc(pDdpAddr) \
{ \
DBGPRINT(DBG_COMP_DDP, DBG_LEVEL_REFDDP, \
("AtalkDdpDereferenceDpc: %s %d PreCount %d\n", \
__FILE__, __LINE__,pDdpAddr->ddpao_RefCount)); \
AtalkDdpDeref(pDdpAddr, TRUE); \
}
#else
#define AtalkDdpReferenceByPtr(pDdpAddr, pErr) \
{ \
KIRQL OldIrql; \
\
ACQUIRE_SPIN_LOCK(&(pDdpAddr)->ddpao_Lock, &OldIrql); \
AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr); \
RELEASE_SPIN_LOCK(&(pDdpAddr)->ddpao_Lock, OldIrql); \
}
#define AtalkDdpReferenceByPtrDpc(pDdpAddr, pErr) \
{ \
ACQUIRE_SPIN_LOCK_DPC(&(pDdpAddr)->ddpao_Lock); \
AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr); \
RELEASE_SPIN_LOCK_DPC(&(pDdpAddr)->ddpao_Lock); \
}
#define AtalkDdpRefByPtrNonInterlock(pDdpAddr, pErr) \
{ \
*pErr = ATALK_DDP_CLOSING; \
\
if ((pDdpAddr->ddpao_Flags & DDPAO_CLOSING) == 0) \
{ \
pDdpAddr->ddpao_RefCount++; \
*pErr = ATALK_NO_ERROR; \
} \
}
#define AtalkDdpReferenceByAddr(pPortDesc, pAddr, ppDdpAddr, pErr) \
AtalkDdpRefByAddr(pPortDesc, pAddr, ppDdpAddr, pErr)
#define AtalkDdpReferenceNextNc(pDdpAddr, ppDdpAddr, pErr) \
AtalkDdpRefNextNc(pDdpAddr, ppDdpAddr, pErr)
#define AtalkDdpDereference(pDdpAddr) \
AtalkDdpDeref(pDdpAddr, FALSE)
#define AtalkDdpDereferenceDpc(pDdpAddr) \
AtalkDdpDeref(pDdpAddr, TRUE)
#endif
#define NET_ON_NONEXTPORT(pPort) \
(pPort->pd_LtNetwork)
#define NODE_ON_NONEXTPORT(pPort) \
(((pPort)->pd_Nodes != NULL) ? \
(pPort)->pd_Nodes->an_NodeAddr.atn_Node : 0)
ATALK_ERROR
atalkDdpAllocSocketOnNode(
IN PPORT_DESCRIPTOR pPortDesc,
IN BYTE Socket,
IN PATALK_NODE pAtalkNode,
IN DDPAO_HANDLER pSktHandler OPTIONAL,
IN PVOID pSktCtx OPTIONAL,
IN BYTE ProtoType OPTIONAL,
IN PATALK_DEV_CTX pDevCtx,
OUT PDDP_ADDROBJ pDdpAddr);
VOID
atalkDdpInitCloseComplete(
IN ATALK_ERROR Error,
IN PVOID Ctx);
/*
PBRE
atalkDdpFindInBrc(
IN PPORT_DESCRIPTOR pPortDesc,
IN PATALK_NODEADDR pDestNodeAddr);
*/
#define atalkDdpFindInBrc(_pPortDesc, _Network, _ppBre) \
{ \
USHORT index; \
KIRQL OldIrql; \
PBRE pBre; \
\
index = (_Network) & (PORT_BRC_HASH_SIZE - 1); \
\
ACQUIRE_SPIN_LOCK(&(_pPortDesc)->pd_Lock, &OldIrql); \
\
for (pBre = (_pPortDesc)->pd_Brc[index]; \
pBre != NULL; \
pBre = pBre->bre_Next) \
{ \
if ((_Network) == pBre->bre_Network) \
{ \
break; \
} \
} \
\
RELEASE_SPIN_LOCK(&(_pPortDesc)->pd_Lock, OldIrql); \
\
*(_ppBre) = pBre; \
}
BOOLEAN
atalkDdpFindAddrOnList(
IN PATALK_NODE pAtalkNode,
IN ULONG Index,
IN BYTE Socket,
OUT PDDP_ADDROBJ * ppDdpAddr);
#define IS_VALID_SOCKET(Socket) \
((Socket == DYNAMIC_SOCKET) || \
(Socket == LAST_DYNAMIC_SOCKET) || \
((Socket >= FIRST_STATIC_SOCKET) && \
(Socket <= LAST_STATIC_SOCKET)))
#endif // _DDP_