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.