/* Copyright (c) 1998 Microsoft Corporation Module Name: tcp.h Abstract: This module contains definitions, declarations relevant to AFP/TCP Author: Shirish Koti Revision History: 22 Jan 1998 Initial Version --*/ #ifndef _TCP_ #define _TCP_ #define INVALID_HANDLE_VALUE ((HANDLE)(-1)) #define AFP_TCP_BINDNAME L"\\Device\\Tcp" #define AFP_TCP_PORT 548 #define DSI_ADAPTER_SIGNATURE *(DWORD *)"TADP" #define DSI_CONN_SIGNATURE *(DWORD *)"TCON" #define DSI_REQUEST_SIGNATURE *(DWORD *)"DREQ" // number of connections on the free list #define DSI_INIT_FREECONNLIST_SIZE 10 typedef ULONG IPADDRESS; // let's not send more than 10 ipaddresses to the Mac #define DSI_MAX_IPADDR_COUNT 10 #define DSI_NETWORK_ADDR_LEN 6 #define DSI_NETWORK_ADDR_IPTAG 0x01 #define ATALK_NETWORK_ADDR_LEN 6 #define ATALK_NETWORK_ADDR_ATKTAG 0x03 #define DSI_HEADER_SIZE 16 #define DSI_TICKLE_TIMER 30 // every 30 seconds, see who needs a tickle #define DSI_TICKLE_TIME_LIMIT 30 // if 30+ seconds since we last heard, send tickle // the only DSI packets (i.e. packets that originate from the DSI layer) are // for DsiOpenSession, DsiCloseSession and DsiTickle. DsiOpenSession is the // largest of these because it has the 6 bytes of options. The spec says that // this is a variable length field, but it only has given one option (Server // Request Quantum) that the server can send. If more options are ever defined, // this define will have to change. For now, only 6 additional bytes // #define DSI_MAX_DSI_OPTION_LEN 6 #define DSI_OPENSESS_OPTION_LEN 4 #define DSI_OPTION_FIXED_LEN 2 #define DSI_MAX_DSI_PKT_SIZE (DSI_HEADER_SIZE + DSI_MAX_DSI_OPTION_LEN) // round off to dword-align #define DSI_BUFF_SIZE ((DSI_MAX_DSI_PKT_SIZE) + (4 - (DSI_MAX_DSI_PKT_SIZE%4))) // // the htonX macros 'lifted' from sockets\netinet\in.h // #if (defined(_M_IX86) && (_MSC_FULL_VER > 13009037)) || ((defined(_M_AMD64) || defined(_M_IA64)) && (_MSC_FULL_VER > 13009175)) #define htons(x) _byteswap_ushort((USHORT)(x)) #define htonl(x) _byteswap_ulong((ULONG)(x)) #else #define htons(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) #define htonl(x) ((((x) >> 24) & 0x000000FFL) | \ (((x) >> 8) & 0x0000FF00L) | \ (((x) << 8) & 0x00FF0000L) | \ (((x) << 24) & 0xFF000000L)) #endif #define ntohs(x) htons(x) #define ntohl(x) htonl(x) typedef NTSTATUS (FASTCALL *DSI_WORKER)(IN PVOID Context); typedef struct _IpAddrEntity { LIST_ENTRY Linkage; IPADDRESS IpAddress; } IPADDRENTITY, *PIPADDRENTITY; typedef struct _TcpAdptr { DWORD adp_Signature; DWORD adp_RefCount; DWORD adp_State; LIST_ENTRY adp_ActiveConnHead; LIST_ENTRY adp_FreeConnHead; DWORD adp_NumFreeConnections; AFP_SPIN_LOCK adp_SpinLock; HANDLE adp_FileHandle; PFILE_OBJECT adp_pFileObject; } TCPADPTR, *PTCPADPTR; // values for the adp_State field of TCPADPTR #define TCPADPTR_STATE_INIT 0x1 #define TCPADPTR_STATE_BOUND 0x2 #define TCPADPTR_STATE_CLOSING 0x4 #define TCPADPTR_STATE_CLEANED_UP 0x8 // // the DSI Commands // #define DSI_COMMAND_CLOSESESSION 1 #define DSI_COMMAND_COMMAND 2 #define DSI_COMMAND_GETSTATUS 3 #define DSI_COMMAND_OPENSESSION 4 #define DSI_COMMAND_TICKLE 5 #define DSI_COMMAND_WRITE 6 #define DSI_COMMAND_ATTENTION 8 // // call-ins into AFP // #define AfpCB_SessionNotify AfpSdaCreateNewSession #define AfpCB_RequestNotify afpSpHandleRequest #define AfpCB_GetWriteBuffer AfpGetWriteBuffer #define AfpCB_ReplyCompletion afpSpReplyComplete #define AfpCB_AttnCompletion afpSpAttentionComplete #define AfpCB_CloseCompletion afpSpCloseComplete typedef struct _DsiReq { LIST_ENTRY dsi_Linkage; DWORD dsi_Signature; struct _TcpConn *dsi_pTcpConn; // the connection that this req belongs to REQUEST dsi_AfpRequest; // the request structure for AFP's use DWORD dsi_RequestLen; // how many bytes in the DSI command DWORD dsi_WriteLen; // total bytes to write (only in DSIWrite) USHORT dsi_RequestID; // what's the request ID BYTE dsi_Command; // what command is it BYTE dsi_Flags; // is this a request or a response? PBYTE dsi_PartialBuf; // buffer, in case partial data arrives DWORD dsi_PartialBufSize; // number of bytes in the partial buffer DWORD dsi_PartialWriteSize; // number of bytes of the Write got so far PMDL dsi_pDsiAllocedMdl; // our mdl, if afp doesn't give us one PVOID dsi_AttnContext; // afp's context for SendAttention BYTE dsi_RespHeader[DSI_BUFF_SIZE]; // header during response } DSIREQ, *PDSIREQ; typedef struct _TcpConn { LIST_ENTRY con_Linkage; DWORD con_Signature; PTCPADPTR con_pTcpAdptr; DWORD con_RefCount; USHORT con_State; USHORT con_RcvState; DWORD con_BytesWithTcp; DWORD con_LastHeard; IPADDRESS con_DestIpAddr; PDSIREQ con_pDsiReq; LIST_ENTRY con_PendingReqs; PSDA con_pSda; PIRP con_pRcvIrp; DWORD con_MaxAttnPktSize; USHORT con_OutgoingReqId; USHORT con_NextReqIdToRcv; HANDLE con_FileHandle; PFILE_OBJECT con_pFileObject; AFP_SPIN_LOCK con_SpinLock; } TCPCONN, *PTCPCONN; // values for the con_State field of TCPCONN #define TCPCONN_STATE_INIT 0x001 #define TCPCONN_STATE_CONNECTED 0x002 #define TCPCONN_STATE_AFP_ATTACHED 0x004 #define TCPCONN_STATE_NOTIFY_AFP 0x008 #define TCPCONN_STATE_NOTIFY_TCP 0x010 #define TCPCONN_STATE_PARTIAL_DATA 0x020 #define TCPCONN_STATE_TCP_HAS_IRP 0x040 #define TCPCONN_STATE_TICKLES_STOPPED 0x080 #define TCPCONN_STATE_CLOSING 0x100 #define TCPCONN_STATE_ABORTIVE_DISCONNECT 0x200 #define TCPCONN_STATE_RCVD_REMOTE_CLOSE 0x400 #define TCPCONN_STATE_CLEANED_UP 0x800 // values for con_RcvState field of TCPCONN #define DSI_NEW_REQUEST 0 // waiting for new request #define DSI_PARTIAL_HEADER 1 // got 1 or more but, less than 16 bytes of hdr #define DSI_HDR_COMPLETE 2 // got full header, but 0 data #define DSI_PARTIAL_COMMAND 3 // got full hdr, and part of data #define DSI_COMMAND_COMPLETE 4 // got hdr and all the data with it #define DSI_AWAITING_WRITE_MDL 5 // awaiting write mdl from afp server #define DSI_PARTIAL_WRITE 6 // write command in progress #define DSI_WRITE_COMPLETE 7 // all write bytes are in #define DSI_REQUEST 0 #define DSI_REPLY 1 #define DSI_OFFSET_FLAGS 0 #define DSI_OFFSET_COMMAND 1 #define DSI_OFFSET_REQUESTID 2 #define DSI_OFFSET_DATAOFFSET 4 #define DSI_OFFSET_ERROROFFSET 4 #define DSI_OFFSET_DATALEN 8 #define DSI_OFFSET_RESERVED 12 #define DSI_OFFSET_OPTION_TYPE 0 #define DSI_OFFSET_OPTION_LENGTH 1 #define DSI_OFFSET_OPTION_OPTION 2 #define DSI_OPTION_SRVREQ_QUANTUM 0 #define DSI_SERVER_REQUEST_QUANTUM 65535 // // get the relevant info from the DSI header. If it's a Write // request, the Enclosed Data Offset field contains how big the // request part is. The Total Data Length field contains how many // bytes follow the DSI header. The difference between the two // is the size of the Write. // #define DSI_PARSE_HEADER(_pDsiReq, _Buffer) \ { \ (_pDsiReq)->dsi_Flags = (_Buffer)[DSI_OFFSET_FLAGS]; \ (_pDsiReq)->dsi_Command = (_Buffer)[DSI_OFFSET_COMMAND]; \ \ GETSHORT2SHORT((&((_pDsiReq)->dsi_RequestID)), \ (&(_Buffer)[DSI_OFFSET_REQUESTID])); \ \ if ((_pDsiReq)->dsi_Command == DSI_COMMAND_WRITE) \ { \ GETDWORD2DWORD((&((_pDsiReq)->dsi_RequestLen)), \ (&(_Buffer)[DSI_OFFSET_DATAOFFSET])); \ \ GETDWORD2DWORD((&((_pDsiReq)->dsi_WriteLen)), \ (&(_Buffer)[DSI_OFFSET_DATALEN])); \ \ (_pDsiReq)->dsi_WriteLen -= (_pDsiReq)->dsi_RequestLen; \ } \ else \ { \ GETDWORD2DWORD((&((_pDsiReq)->dsi_RequestLen)), \ (&(_Buffer)[DSI_OFFSET_DATALEN])); \ } \ } typedef struct _DsiHeader { BYTE Flags; BYTE Command; USHORT RequestID; DWORD DataOffset; DWORD TotalLength; DWORD Reserved; } DSIHEADER, *PDSIHEADER; typedef struct _TcpWorkItem { WORK_ITEM tcp_WorkItem; DSI_WORKER tcp_Worker; PVOID tcp_Context; } TCPWORKITEM, *PTCPWORKITEM; #define VALID_TCPCONN(_pTcpConn) \ ((_pTcpConn->con_Signature == DSI_CONN_SIGNATURE) && \ (_pTcpConn->con_RefCount > 0 && _pTcpConn->con_RefCount < 5000)) \ #define DsiTerminateConnection(pTcpConn) \ DsiKillConnection(pTcpConn, 0) #define DsiAbortConnection(pTcpConn) \ DsiKillConnection(pTcpConn, TDI_DISCONNECT_ABORT) // // the globals // GLOBAL PTCPADPTR DsiTcpAdapter EQU NULL; GLOBAL AFP_SPIN_LOCK DsiAddressLock; GLOBAL LIST_ENTRY DsiIpAddrList; GLOBAL PBYTE DsiStatusBuffer EQU NULL; GLOBAL DWORD DsiStatusBufferSize EQU 0; GLOBAL BOOLEAN DsiTcpEnabled EQU TRUE; GLOBAL AFP_SPIN_LOCK DsiResourceLock; GLOBAL LIST_ENTRY DsiFreeRequestList; GLOBAL DWORD DsiFreeRequestListSize EQU 0; GLOBAL DWORD DsiNumTcpConnections EQU 0; GLOBAL KEVENT DsiShutdownEvent EQU {0}; // // prototypes for functions in dsi.c // NTSTATUS DsiAfpSetStatus( IN PVOID Context, IN PUCHAR pStatusBuf, IN USHORT StsBufSize ); NTSTATUS DsiAfpCloseConn( IN PTCPCONN pTcpConn ); NTSTATUS DsiAfpFreeConn( IN PTCPCONN pTcpConn ); NTSTATUS FASTCALL DsiAfpListenControl( IN PVOID Context, IN BOOLEAN Enable ); NTSTATUS FASTCALL DsiAfpWriteContinue( IN PREQUEST pRequest ); NTSTATUS FASTCALL DsiAfpReply( IN PREQUEST pRequest, IN PBYTE pResultCode ); NTSTATUS DsiAfpSendAttention( IN PTCPCONN pTcpConn, IN USHORT AttentionWord, IN PVOID pContext ); NTSTATUS DsiAcceptConnection( IN PTCPADPTR pTcpAdptr, IN IPADDRESS MacIpAddr, OUT PTCPCONN *ppRetTcpConn ); NTSTATUS DsiProcessData( IN PTCPCONN pTcpConn, IN ULONG BytesIndicated, IN ULONG BytesAvailable, IN PBYTE pDsiData, OUT PULONG pBytesAccepted, OUT PIRP *ppRetIrp ); BOOLEAN DsiValidateHeader( IN PTCPCONN pTcpConn, IN PDSIREQ pDsiReq ); NTSTATUS DsiAfpReplyCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID pContext ); NTSTATUS DsiAcceptConnectionCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ); BOOLEAN DsiKillConnection( IN PTCPCONN pTcpConn, IN DWORD DiscFlag ); NTSTATUS DsiDisconnectWithTcp( IN PTCPCONN pTcpConn, IN DWORD DiscFlag ); NTSTATUS DsiDisconnectWithAfp( IN PTCPCONN pTcpConn, IN NTSTATUS Reason ); NTSTATUS DsiTcpDisconnectCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID Context ); NTSTATUS DsiTcpRcvIrpCompletion( IN PDEVICE_OBJECT Unused, IN PIRP pIrp, IN PVOID pContext ); NTSTATUS DsiExecuteCommand( IN PTCPCONN pTcpConn, IN PDSIREQ pDsiReq ); NTSTATUS DsiOpenSession( IN PTCPCONN pTcpConn, IN PDSIREQ pDsiReq ); NTSTATUS DsiSendDsiRequest( IN PTCPCONN pTcpConn, IN DWORD DataLen, IN USHORT AttentionWord, IN PVOID AttentionContext, IN BYTE Command ); NTSTATUS DsiSendDsiReply( IN PTCPCONN pTcpConn, IN PDSIREQ pDsiReq, IN NTSTATUS OpStatus ); NTSTATUS DsiSendStatus( IN PTCPCONN pTcpConn, IN PDSIREQ pDsiReq ); AFPSTATUS FASTCALL DsiSendTickles( IN PVOID pUnUsed ); NTSTATUS DsiSendCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP pIrp, IN PVOID pContext ); // // prototypes for functions in tcptdi.c // NTSTATUS DsiOpenTdiAddress( IN PTCPADPTR pTcpAdptr, OUT PHANDLE pRetFileHandle, OUT PFILE_OBJECT *ppRetFileObj ); NTSTATUS DsiOpenTdiConnection( IN PTCPCONN pTcpConn ); NTSTATUS DsiAssociateTdiConnection( IN PTCPCONN pTcpConn ); NTSTATUS DsiSetEventHandler( IN PDEVICE_OBJECT pDeviceObject, IN PFILE_OBJECT pFileObject, IN ULONG EventType, IN PVOID EventHandler, IN PVOID Context ); NTSTATUS DsiTdiSynchronousIrp( IN PIRP pIrp, PDEVICE_OBJECT pDeviceObject ); NTSTATUS DsiTdiCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); NTSTATUS DsiTdiSend( IN PTCPCONN pTcpConn, IN PMDL pMdl, IN DWORD DataLen, IN PVOID pCompletionRoutine, IN PVOID pContext ); VOID DsiIpAddressCameIn( IN PTA_ADDRESS Address, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context2 ); VOID DsiIpAddressWentAway( IN PTA_ADDRESS Address, IN PUNICODE_STRING DeviceName, IN PTDI_PNP_CONTEXT Context2 ); NTSTATUS DsiTdiConnectHandler( IN PVOID EventContext, IN int MacIpAddrLen, IN PVOID pSrcAddress, IN int DsiDataLength, IN PVOID pDsiData, IN int OptionsLength, IN PVOID pOptions, OUT CONNECTION_CONTEXT *pOurConnContext, OUT PIRP *ppOurAcceptIrp ); NTSTATUS DsiTdiReceiveHandler( IN PVOID EventContext, IN PVOID ConnectionContext, IN USHORT RcvFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT PULONG pBytesAccepted, IN PVOID pDsiData, OUT PIRP *ppIrp ); NTSTATUS DsiTdiDisconnectHandler( IN PVOID EventContext, IN PVOID ConnectionContext, IN ULONG DisconnectDataLength, IN PVOID pDisconnectData, IN ULONG DisconnectInformationLength, IN PVOID pDisconnectInformation, IN ULONG DisconnectIndicators ); NTSTATUS DsiTdiErrorHandler( IN PVOID EventContext, IN NTSTATUS Status ); NTSTATUS DsiCloseTdiAddress( IN PTCPADPTR pTcpAdptr ); NTSTATUS DsiCloseTdiConnection( IN PTCPCONN pTcpConn ); // // prototypes for functions in tcputil.c // VOID DsiInit( IN VOID ); NTSTATUS FASTCALL DsiCreateAdapter( IN VOID ); BOOLEAN IsThisOnAppletalksDefAdapter( IN PUNICODE_STRING pBindDeviceName ); NTSTATUS FASTCALL DsiCreateTcpConn( IN PTCPADPTR pTcpAdptr ); NTSTATUS DsiAddIpaddressToList( IN IPADDRESS IpAddress ); BOOLEAN DsiRemoveIpaddressFromList( IN IPADDRESS IpAddress ); PDSIREQ DsiGetRequest( IN VOID ); PBYTE DsiGetReqBuffer( IN DWORD BufLen ); VOID DsiFreeRequest( PDSIREQ pDsiReq ); VOID DsiFreeReqBuffer( IN PBYTE pBuffer ); VOID DsiDereferenceAdapter( IN PTCPADPTR pTcpAdptr ); VOID DsiDereferenceConnection( IN PTCPCONN pTcpConn ); NTSTATUS DsiDestroyAdapter( IN VOID ); NTSTATUS FASTCALL DsiFreeAdapter( IN PTCPADPTR pTcpAdptr ); NTSTATUS FASTCALL DsiFreeConnection( IN PTCPCONN pTcpConn ); NTSTATUS DsiGetIpAddrBlob( IN DWORD *pIpAddrCount, IN PBYTE *ppIpAddrBlob ); PIRP DsiGetIrpForTcp( IN PTCPCONN pTcpConn, IN PBYTE pBuffer, IN PMDL pInputMdl, IN DWORD ReadSize ); PMDL DsiMakePartialMdl( IN PMDL pOrgMdl, IN DWORD dwOffset ); NTSTATUS FASTCALL DsiUpdateAfpStatus( IN PVOID Unused ); NTSTATUS DsiScheduleWorkerEvent( IN DSI_WORKER WorkerRoutine, IN PVOID Context ); VOID FASTCALL DsiWorker( IN PVOID Context ); PTCPADPTR DsiRefAdptrByBindName( IN PUNICODE_STRING pBindDeviceName ); VOID DsiShutdown( IN VOID ); #endif