saf@CITI.UMICH.EDU (10/06/87)
TCP DRIVER INTERFACE SPECIFICATION (final draft 10/6/87) ABOUT THE TCP DRIVER -------------------- The TCP driver layer, one of the CITI MacIP drivers, implements the Transmission Control Protocol [RFCJ793]. This document describes the interface to TCP. TCP DATA STRUCTURES ------------------- The reader should be familiar with the common C derived types, such as those described in <sys/types.h>, <sys/time.h>, MPW C, and Inside Macintosh. Version information on the TCP driver is returned in the following structure: typedef struct tcp_version { unsigned char version[32]; /* Version number */ unsigned char specdesc[32]; /* Specification description */ unsigned char site[32]; /* Originating site */ } tcp_version_t, *tcp_version_p; If TCP is configured to collect statistics, that information is returned in the following structure (NOTE: this structure is not finalized!): typedef struct tcp_stats { /* Not yet defined */ } tcp_stats_t, *tcp_stats_p; TCP FUNCTIONS ------------- The following functions provide a program interface to the TCP driver layer. Each function returns success (0) or an error code. Error code identifiers are defined in net_errno.h. The return type for all functions is long. TCP may notify clients of asynchronous events by executing a client-supplied notification routine. Execution of the notification routine is called delivery of notification. Clients are notified of an event if and only if they have specifically requested notification of that event. Clients request and cancel notification of events by setting a mask and passing it to tcp_request and tcp_cancel, respectively. Some functions accept io_timeout as a parameter. For these routines, if io_timeout is NULL, the function blocks forever, or until the call can be completed. If io_timeout is not NULL, the function blocks until the timeout value expires or the call can be completed. Implementation-dependent restrictions may apply as to when a client can block. If it is illegal for a call to block, the error E_CANTBLOCK is returned. Certain functions can operate synchronously or asynchronously. For these routines, if the TCP_FLAG_ASYNC bit in io_flags is cleared, the routine operates synchronously, either completing the operation within the timeout period or giving up. If the TCP_FLAG_ASYNC bit is set, the function returns immediately and performs the operation asynchronously. Some functions accept (and in certain cases return) io_flags as a parameter. io_flags is a long-word bitmask of control flags. A list of all flags is given in "TCPJCONSTANTS." Right and left arrows indicate values passed to and from the driver functions, respectively. tcp_create (io_stream, io_lport, io_snd_buffer, io_snd_buflen, io_rcv_buffer, io_rcv_buflen) <- Ptr *io_stream TCP stream descriptor -> unsigned short io_lport Local TCP port -> Ptr io_snd_buffer Pointer to send buffer -> long io_snd_buflen Length of send buffer -> Ptr io_rcv_buffer Pointer to receive buffer -> long io_rcv_buflen Length of receive buffer tcp_create creates a TCP stream. If io_lport is non-zero, the local port is set for io_stream, otherwise, a subsequent call to tcp_setport must set the local port. TCP clients may specify send/receive buffer pointers io_snd_buffer/ io_rcv_buffer. They must be non-relocatable blocks of size io_snd_buflen/ io_rcv_buflen, respectively, that remain fixed while this stream is open. If io_snd_buffer/ io_rcv_buffer is NULL, or if io_snd_buflen/ io_rcv_buflen is zero, TCP will internally allocate a send/receive buffer. Errors returned are: E_NOMEM tcp_delete (io_stream) -> Ptr io_stream TCP stream descriptor tcp_delete deletes a TCP stream. If the stream is connected tcp_delete aborts the connection. If the client supplied send and/or receive buffers when the stream was created, the client may now free them; buffer memory allocated by TCP is deallocated by TCP. This call will fail if called from a notification routine, but only if notifying on the same stream. Errors returned are: E_BADSTREAM E_NOTIFYING tcp_request (io_stream, io_nclass, io_notify, io_userdata, io_flags) -> Ptr io_stream TCP stream descriptor -> unsigned long io_nclass Set of events to notify on -> ProcPtr io_notify Notification routine -> unsigned long io_userdata Passed to notification routine -> unsigned long io_flags Control flags tcp_request sets up notification for a stream. io_notify is a pointer to the client's notification routine. io_userdata is passed to the client's notification routine. io_nclass is the bitwise or of the notification identifiers to notify on. So that clients may request to add to current notifications, io_nclass is bitwise ored to the existing bits. Values for io_nclass are defined in the section "TCPJNOTIFICATION." When a TCP stream is created, the default value for io_nclass is TCP_NT_NONE (i.e., no notification). Special behavior can be specified with io_flags. The following flags are defined: TCP_FLAG_NEWNOTIFY io_notify should replace the previous io_notify. Clients may disable notification by passing NULL for io_notify and setting this flag. Notification may be re-enabled later by setting IP_FLAG_NEWNOTIFY and io_notify. TCP_FLAG_NEWUDATA io_userdata should replace the previous io_userdata. Errors returned are: E_BADSTREAM E_BADNOTIFICATION E_BADFLAG tcp_cancel (io_stream, io_nclass) -> Ptr io_stream TCP stream descriptor -> unsigned long io_nclass Events not to notify on tcp_cancel subtracts from the set of events for which the client accepts notification. Errors returned are: E_BADSTREAM tcp_setport (io_stream, io_lport) -> Ptr io_stream TCP stream descriptor <> unsigned short *io_lport Local TCP port tcp_setport binds a port to a TCP stream. If io_lport is zero TCP will assign an unused port number. Errors returned are: E_BADSTREAM E_STREAMCONNECTED tcp_connect (io_stream, io_timeout, io_fhost, io_fport, io_flags) -> Ptr io_stream TCP stream descriptor -> unsigned long io_fhost Foreign IP address -> unsigned short io_fport Foreign TCP port -> struct timeval *io_timeout Timeout value -> unsigned long io_flags Control flags tcp_connect attempts to connect to io_fport on io_fhost. If the TCP_FLAG_ASYNC bit in io_flags is clear tcp_connect operates synchronously. If the connection cannot be established in io_timeout, TCP gives up, returning the stream to its initial state. This is an illegal operation if called from a notification routine. If the TCP_FLAG_ASYNC bit in io_flags is set tcp_connect operates asynchronously. The client is notified when the connection is established. If the connection cannot be established in io_timeout TCP gives up and delivers a TCP_NT_ERROR notification. As with the synchronous case, the stream is returned to its initial state. Errors returned are: E_BADSTREAM E_TIMEDOUT E_NOTIFYING E_CANTBLOCK E_STREAMCONNECTED E_REMOTEABORT E_SERVICEFAIL tcp_listen (io_stream, io_timeout, io_fhost, io_fport, io_flags) -> Ptr io_stream TCP stream descriptor <> unsigned long *io_fhost Foreign IP address <> unsigned short *io_fport Foreign TCP port -> struct timeval *io_timeout Timeout value -> unsigned long io_flags Control flags tcp_listen listens for connection requests on io_stream. If io_fport(io_fhost) is non-zero, connection requests are accepted only if they originate at the specified port(host). If the TCP_FLAG_ASYNC bit in io_flags is clear, tcp_listen blocks until a connection request arrives. When a connection is established, the foreign host and port are returned in io_fhost and io_fport. If no request arrives within io_timeout, tcp_listen returns an error, and the stream is returned to its initial state. This is an illegal operation if called from a notification routine. If the TCP_FLAG_ASYNC bit in io_flags is set, the TCP stream enters a listening state and tcp_listen returns immediately. When TCP accepts a connection request for io_stream, TCP notifies the client by delivering a TCP_NT_CONNECT notification. If a connection cannot be established in io_timeout TCP gives up and delivers a TCP_NT_ERROR notification. As with the synchronous case, the stream is returned to its initial state. Errors returned are: E_BADSTREAM E_TIMEDOUT E_NOTIFYING E_CANTBLOCK E_STREAMCONNECTED E_REMOTEABORT E_SERVICEFAIL tcp_close (io_stream, io_timeout, io_flags) -> Ptr io_stream TCP stream descriptor -> struct timeval *io_timeout Timeout value -> unsigned long io_flags Control flags tcp_close negotiates the termination of a connection. All outstanding data is delivered (i.e., clients may continue to call tcp_get until all input buffers are read. If the TCP_FLAG_ASYNC bit in io_flags is clear,TCP operates synchronously. If TCP cannot negotiate the close within io_timeout, an error is returned and the connection is aborted. This is an illegal operation if called from a notification routine. If the TCP_FLAG_ASYNC bit in io_flags is set, TCP operates asynchronously. When the connection is closed or the timeout expires the client is notified with TCP_NT_CLOSED or TCP_NT_ERROR, respectively. If the connection was not closed within the timeout the connection is aborted. Errors returned are: E_BADSTREAM E_TIMEDOUT E_NOTIFYING E_CANTBLOCK E_STREAMCLOSING E_STREAMCLOSED E_REMOTEABORT E_SERVICEFAIL tcp_abort (io_stream) -> Ptr io_stream TCP stream descriptor tcp_abort aborts a connection. Any data in transit is lost. The stream returns to the closed state. Errors returned are: E_BADSTREAM E_STREAMCLOSED tcp_put (io_stream, io_buffer, io_buflen, io_flags) -> Ptr io_stream TCP stream descriptor -> Ptr io_buffer Pointer to data -> unsigned long io_buflen Length of data (bytes) -> unsigned long io_flags Control flags tcp_put sends io_buflen bytes of io_buffer on io_stream. The TCP_FLAG_PUSH and TCP_FLAG_URG bits in io_flags correspond to the "data stream push" and "urgent data signalling" facilities of TCP (e.g., setting TCP_FLAG_URG marks the data as urgent). tcp_put returns immediately; the TCP driver schedules actual data delivery. Errors returned are: E_BADSTREAM E_BADFLAG E_NOMEM E_STREAMCLOSING E_STREAMCLOSED tcp_get (io_stream, io_timeout, io_buffer, io_buflen, io_flags) -> Ptr io_stream TCP stream descriptor -> Ptr io_buffer Pointer to data <> unsigned long *io_buflen Length of data (bytes) -> struct timeval *io_timeout Timeout value <> unsigned long *io_flags Control flags tcp_get requests data on a TCP stream. io_buffer points to a client-supplied buffer. io_rcv_buflen specifies the length of that buffer in bytes. tcp_get blocks until one of the following conditions occurs: - io_timeout expires. - urgent data is outstanding. - push data arrives. - io_buflen bytes are available. When tcp_get returns it passes back all available data. io_buflen indicates how much data was actually read. On return, if the TCP_FLAG_URG bit of io_flags is set, there is outstanding urgent data on io_stream. The client should "urgently" read data from TCP until all urgent data has been read. tcp_get sets the TCP_FLAG_MARK bit of io_flags when the last of the urgent data is delivered. TCP will not deliver both urgent and non-urgent data in the same buffer. Similarly, if pushed data exists, only data up to the push marker is delivered; more non- pushed data may be available. Errors returned are: E_BADSTREAM E_TIMEDOUT E_CANTBLOCK E_STREAMCLOSING E_STREAMCLOSED tcp_control (io_stream, io_buffer, io_buflen, io_control) -> Ptr io_stream TCP stream descriptor <> Ptr io_buffer Data used by control call <> long *io_buflen Size of io_buffer (bytes) -> unsigned long io_control Specifies control operation tcp_control performs various operations for a TCP stream. io_control selects an operation and is the only mandatory parameter. Parameters that are not required by individual control operations may be passed as NULL. General errors returned by tcp_control are: E_BADSTREAM E_BADCONTROL Currently defined control operations are: TCP_CTL_VERSION -> io_stream TCP stream descriptor <> io_buffer Pointer to tcp_version_t structure -> io_control Control operation Returns version information. Clients pass a pointer to a structure of type tcp_version_t, as defined in the section "TCPJDATAJSTRUCTURES." No specific errors are returned for this control. TCP_CTL_STATS -> io_stream TCP stream descriptor <> io_buffer Pointer to tcp_stats_t structure -> io_control Control operation No specific errors are returned for this control. TCP_CTL_PERM_STREAM -> io_stream TCP stream descriptor -> io_control Control operation This stream should never be deallocated by the system. No specific errors are returned for this control. tcp_task () tcp_task allots time to TCP for asynchronous processing. Errors returned are: E_CANTBLOCK TCP NOTIFICATION ---------------- Clients may request and cancel notification of asynchronous events by calling tcp_request and tcp_cancel, respectively. As asynchronous events occur, the notification routine io_notify is called with the following parameters: (*io_notify)(io_stream, io_fhost, io_fport, io_lhost, io_lport, io_flags, io_nclass, io_ndata, io_userdata) -> Ptr io_stream TCP stream descriptor -> unsigned long io_fhost Foreign IP address -> unsigned short io_fport Foreign TCP port -> unsigned long io_lhost Local IP address -> unsigned short io_lport Local TCP port -> unsigned long io_flags TCP flags -> unsigned long io_nclass Class of async notification -> unsigned long io_ndata Notification data -> unsigned long io_userdata User-data field io_nclass is the type of event that caused this notification. io_userdata was passed to tcp_request by the client. io_ndata contains additional specification for the event. The following describes the valid notification classes (io_nclass): TCP_NT_CONNECT: Connection Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_userdata Connection notification is delivered when a connection is established with io_fport on io_fhost. To receive connection notification, the client must be listening for connections (see tcp_listen). TCP_NT_DATA: Data Arrival Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_flags -> io_nclass -> io_ndata -> io_userdata Data arrival notification is delivered when a data segment arrives from io_fport on io_fhost. io_ndata is the number of bytes currently available in the steam's input buffers. The TCP_FLAG_PUSH and TCP_FLAG_URG bits in io_flags will be set if there is push data or urgent data in the stream. If a client is accepting TCP_NT_DATA they will not receive TCP_NT_URG. TCP_NT_URGENT: Urgent Data Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_ndata -> io_userdata Urgent data notification is delivered when there is outstanding urgent data somewhere in the stream. io_ndata indicates the number of bytes available in the input buffers. The notification is delivered just once, when the foreign host first puts urgent data in the stream. Once all urgent data has been read, TCP will again be ready to deliver urgent data notification. TCP_NT_RETRANS: Retransmit Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_userdata The client is notified when TCP retransmits data destined for io_fport on io_fhost. TCP_NT_CLOSING: Closing Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_userdata The client is notified when the foreign host begins negotiating closing a connection with io_fport on io_fhost. TCP_NT_CLOSED: Closed Notification -> io_stream -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_userdata The client is notified when the connection with io_fport on io_fhost has been gracefully closed. TCP_NT_ERROR: Error Notification -> io_stream -> io_buffer -> io_buflen -> io_fhost -> io_fport -> io_lhost -> io_lport -> io_nclass -> io_ndata -> io_userdata The client is notified when an asynchronous error occurs, (e.g., destination unreachable messages, connection resets). io_ndata identifies the error. For some errors, an ICMP destination unreachable datagram is returned in io_buffer. io_buflen is the length of that datagram. For more information on ICMP, refer to [RFCJ792]. If the error is not based on an ICMP message, io_buffer is NULL. Errors delivered are: E_NETUN E_HOSTUN E_PROTOUN E_PORTUN E_REMOTEABORT E_SERVICEFAIL E_OPENFAIL E_TIMEDOUT TCP ERROR CODES --------------- Following is a description of all possible error codes returned by TCP: E_NOMEM Not enough memory to perform operation. E_BADSTREAM Stream descriptor was not found in this driver's list of streams. E_BADNOTIFICATION Invalid notification class. E_BADFLAG Invalid control flag bit is set in io_flags. E_BADCONTROL Invalid control identifier. E_BADWDS Invalid WDS structure or pointer. E_CANTRESOLVEADDR Unable to determine the next destination IP address that leads to the requested destination IP address. E_HWWRITEERR Hardware failed in writing datagram to network. E_CANTBLOCK Current context does not allow a blocking call. E_NOTIFYING Cannot perform operation on stream while notifying on same stream. E_STREAMCONNECTED Invalid operation; stream is already connected or synchronizing to connect. E_STREAMCLOSING Invalid operation; stream is already synchronizing to close. E_STREAMCLOSED Invalid operation; stream is already closed. E_TIMEDOUT Could not perform operation within requested timeout period. E_REMOTEABORT Foreign host has aborted connection. E_SERVICEFAIL Invalid data from foreign host. E_OPENEFAIL Could not open connection to foreign host. OUTSTANDING ISSUES ------------------ Synchronous routines that take timeout values should decrement the timeout structure by the elapsed time so the client can determine how much of the timeout period was used and how much remains. This would not work for asynchronous operations because the routine does not hold on to the timeval structure. Perhaps the time remaining could be passed as part of the notification.