Copyright (c) 1992 by Peter R. Tattam, University of Tasmania. Permission is granted to reproduce and distribute this document without restriction or fee. This document may be re-formatted or translated, but the functional specification of the programming interface described herein may not be changed without the author's permission. The author's name and this notice must appear on any reproduction of this document.
There has been a need for a standard TCP/IP binary interface for the MS-DOS operating system. Although there are many proprietary specifications for such a system, not one has been accepted as universal. This specification attempts to address the major hurdles facing applications developers writing network applications using TCP/IP on MS-DOS machines. Some applications access the network via the packet driver specification. Although this solution solves the problem of the multiplicity of network hardware, it is unsatisfactory when more than one application wishes to access the same network protocol (TCP/IP) simultaneously. What is required by an application is a standard way of seeing the TCP/IP layer in a manner similar to the machine's file system. This document provides a possible mechanism to provide the TCP/IP services in any application running on MS-DOS.
The TSR (Terminate and Stay Resident) program can attach to an interrupt vector in the range 60H-7FH in a similar manner to a packet driver. The first instruction of the hook should be a JMP NEAR instruction and have after it the string 'TCP_DRVR' (for want of a better name). The vector to attach to should be specifyable since it may not be possible to determine if the vector is free. Calls to the TSR are made using the standard 8086/88 software interrupt calls through this vector.
Upon loading the TSR, the IP address, netmask, gateway etc are determined by a suitable method, either directly, or using RARP or BOOTP. One should also be able to pass this information via the command-line, or use the environment variables. The packet layer could be any of a variety of mechanisms. How this is done is totally open to question, but the following information should be accurate once the ABI is loaded and active. This specification is to provide the next layer above the packet driver interface.
my IP addressAll handles returned are a word value corresponding to an index into a table or list. They can be guaranteed to be unique only, and 0 is allowable. If no handles are available then the returned handle of an open call is 0FFFFH. Handles are also reusable. The current implementation of Trumpet TCP returns handles in steps of 1 starting at 0. This can be useful for a general purpose status program to interrogate the status of TCP connections.
Most calls have AL register set to option flags. A standard call has the value 0 and may block the processor.
A timeout is provided via DX. If DX = FFFFH then the operation will proceed until done. All timeouts are measured in terms of PC clock ticks (18.2 Hz) A timeout of 0 specifies a non-blocking call and will not return an error if operation times out. One can usually use the status call to determine the status of the tcp connection. The Trumpet TCP implements timeouts. The following calls may block.
tcp: open, close, send, recvAll other calls don't block and do not require a timeout.
If the option flag 128 (80H) is set then an asynchronous I/O is done. On completion of I/O, an event handler is called. Other options are relevant to the call concerned. Care needs to be taken in multi-program environments such as Windows 3 that the event-handler address is valid. Event handlers are assigned by the attach/detach event operation. Implementation of asynchronous I/O is optional. At present the Trumpet TCP does not implement this function.
All register values will be preserved across calls except for those which return values.
Determine if driver is valid and the functionality of the driver
call
ah = 00H
al = FFH
return
al = FFH no driver loaded
al = 0 driver loaded
dh = additional functionality flags
1 = implements timeouts
2 = implements async I/O via events
ds:si = pointer to "TCP_DRVR"
es:di = pointer to driver info
(including IP address, net params, etc)
driver_info_rec:
myip dword
netmask dword
gateway dword
dnsserver dword
timeserver dword
mtu word
def_ttl byte
def_tos byte
unknown word ; <-- This field here is missing from the original
; specification and has meaning unknown to me.
tcp_mss word
tcp_rwin word
debug word
domain string[255] (db 0,255 dup(0))Unload driver from memory.
call
ah = 01H
return
dl = error codePerform driver processing
Will call event handlers as required Must be called regularly to process packets Can be attached to timer interrupt. Care must be taken with reentrancy.
call
ah = 02H
return
ax = no. of free pkts on IP input queue
cx = no. of free pkts on IP output queue
dl = error codeReturn the driver's critical flag
call
ah = 03H
return
es:di = pointer to critical flag byte
dl = error codeCopy the driver info to a user
buffer
call
ah = 04H
cx = size of buffer
es:di = pointer to local buffer
return
cx = bytes storedOpen an active/passive tcp session
call
ah = 10H
al = option flags
0 = normal
1 = listener
128 = asynchronous. Notify by event_call
bx = tcp_srce (0 = allocate unused port)
cx = tcp_dest (0 = any port when listener)
dx = timeout (0 = non-blocking, FFFF = infinite)
si:di = ip_dest (dword)(0 = any when listener)
return
ax = local port no.
bx = handle
dl = error code
no_handles
timed_out
invalid_sessionClose a tcp session
call
ah = 11H
al = option flags
0 = normal
1 = abort session
128 = asynchronous. Notify by event_call
bx = handle
dx = timeout (0 = non-blocking, FFFF = infinite)
return
dl = error code
bad_handle
timed_out
invalid_sessionNote: a session closed with a timeout of 0 will not release the handle. It must either be closed with a non-zero timeout. A non-zero timeout will always release the handle, as will an abort option. A listen for any connection will revert back to an IP address of FFFFFFFF when the connection returns back to the listen state. The handling of listener sessions may change in the future to accomodate compatibility with "socket" implementations.
Read data into buffer
call
ah = 12H
al = option flags
0 = normal (wait till buffer full)
1 = get as much as possible & return
2 = read to (don't include)
128 = asynchronous. Notify by event_call
bx = handle
es:di = pointer to buffer
cx = size of buffer
dx = timeout (0 = non-blocking, FFFF = infinite)
return
buffer has data transferred to it
ax = no. bytes transferred
dl = error code
bad_handle
timed_out
invalid_session
dh = returned flags
2 = read in option 2
8 = urgent data present Write data to buffer
call
ah = 13H
al = option flags
0 = normal (wait till buffer delivered)
1 = put as much as possible & return
2 = append to data
4 = push (wait till data acknowledged)
8 = urgent data
128 = asynchronous. Notify by event_call
bx = handle
es:di = pointer to buffer
cx = size of buffer
dx = timeout (0 = non-blocking, FFFF = infinite)
return
ax = no. bytes transferred
dl = error code
bad_handle
timed_out
invalid_session Get status of a TCP session
call
ah = 14H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
bx = handle
return
dl = error code
bad_handle
dh = tcp_state
ax = bytes available for reading
cx = bytes still being transmitted
es:di = pointer to session info
ip_srce dword
ip_dest dword
ip_prot byte
active byte (> 0 is active)
call
ah = 20H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
bx = udp_srce (0 = allocate next unused)
cx = udp_dest (0 = listen for any)
si:di = ip_dest (0/FFFFFFFF = listen for any)
return
ax = local port no.
bx = handle
dl = error code
no_handles
call
ah = 21H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
bx = handle
return
dl = error code
bad_handle
call
ah = 22H
al = option flags
0 = normal
128 = asynchronous I/O signal via event_call
bx = handle
es:di = pointer to buffer
cx = length
dx = timeout (FFFF = infinite)
return
ax = no. bytes transferred
dl = error code
bad_handle
timed_out
bp = ttl & tos (ttl = lo byte, tos = hi byte)
0 = default ttl & tos
si = id(note that the IP address of the most recent packet read is available with a status call, if receiving all)
call
ah = 23H
al = option flags
0 = normal
128 = asynchronous I/O signal via event_call
bx = handle
es:di = pointer to buffer
cx = length
bp = ttl & tos (ttl = lo byte, tos = hi byte)
0 = default ttl & tos
si = id
return
ax = no. bytes transferred
dl = error code
bad_handle
call
ah = 24H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
bx = handle (<-- This was missing from the original paper)
return
ax = number of packets available
cx = size of next packet (0 if none)
dl = error code
bad_handle
es:di = pointer to session info
ip_srce dword
ip_dest dword
ip_prot byte
active byte (> 0 is active)
call
ah = 30H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
bl = protocol
si:di = ip_dest (0/FFFFFFFF = listen for any)
return
ax = handle
dl = error code
no_handles
call
ah = 31H
bx = handle
return
dl = error code
bad_handle
call
ah = 32H
al = option flags
0 = normal
128 = asynchronous I/O signal via event_call
bx = handle
es:di = pointer to buffer
cx = length
dx = timeout (FFFF = infinite)
return
ax = no. bytes transferred
dl = error code
bad_handle
timed_out
bp = ttl & tos (ttl = lo byte, tos = hi byte)
0 = default ttl & tos
si = id(note that the IP address of the most recent packet read is available with a status call, if receiving all)
call
ah = 33H
al = option flags
0 = normal
128 = asynchronous I/O signal via event_call
bx = handle
es:di = pointer to buffer
cx = length
bp = ttl & tos (ttl = lo byte, tos = hi byte)
0 = default ttl & tos
si = id
return
ax = no. bytes transferred
dl = error code
bad_handle
call
ah = 34H
al = option flags
0 = normal
128 = asynchronous. Notify by event_call
return
ax = number of packets available
cx = size of next packet (0 if none)
dl = error code
bad_handle
es:di = pointer to session info
ip_srce dword
ip_dest dword
ip_prot byte
active byte (> 0 is active)All registers are saved before event handler called, and restored after event handler done. Information returned is call dependent. Note that DS undefined, so that it is the users responsibility to set up the called environment. Note also that Windows 3.0 has to be managed suitably when performing up-calls asynchronously.
Allow chaining, but check for duplicates
call
ax = 4000H
es:di = address of event handler upcall
return
dl = error code
already_attached
call
ax = 4100H
es:di = address of event handler upcall
return
dl = error code
not_attachedNo chaining allowed, only 1 per handle
call
ax = 4200H
bx = handle
es:di = address of event handler upcall
return
dl = error code
bad_handle
already_attached
call
ax = 4300H
bx = handle
return
dl = error code
bad_handle
not_attached
upcal
ax = event-id (ah = same as int call, al = subfunction)
bx = handle (FFFF if general failure)
cx:dx = info (e.g. no of bytes transferred)
return
registers not preserved
no_error = 0;
err_badcall = 1;
err_critical = 2;
err_nohandles = 3;
err_badhandle = 4;
err_timeout = 5;
err_badsession = 6;| [My Home Page] [Library] [Net] [TCPDRV] | Last Updated: |