[comp.protocols.appletalk] TCP specification

saf@CITI.UMICH.EDU (10/23/87)

A number of people have complained about the wide-body format
of CITI's specification documents for IP, UDP, TCP, and IF,
so I am reposting them here in a narrower format.

Steve Fram
saf@citi.umich.edu

-------------------------------------------------------------


TCP DRIVER INTERFACE SPECIFICATION
Final Draft


MacIP project
University of Michigan, CITI
2901 Hubbard
Ann Arbor, MI 48103

macip@citi.umich.edu



ABOUT THE TCP DRIVER

The TCP driver layer, one of the CITI MacIP drivers, implements the 
Transmission Control Protocol [RFC 793].  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];	/* Spec 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 "TCP CONSTANTS."

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 
"TCP NOTIFICATION."  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 
"TCP DATA STRUCTURES."

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 [RFC 792].  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.