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.