/*+++ 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_