[My Home Page] [Library] [Net] [TCPDRV]

TCPDRV Version 2.01

Preliminary Specification for a TCP/IP
Application Binary Interface (ABI) to run over MS-DOS.
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.

Introduction

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.

Finding the TCP/IP ABI.

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 address
netmask
gateway IP address(es)
domain name server IP address(es) - available for a higher layer than this driver.

General notes

All calls return dl = error code (0 if none) (carry set if <> 0) except for the driver existence determination

All 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, recv
udp: recv, (send blocks only if arp required)
ip: recv, (send blocks only if arp required)

All 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.

Driver hooks

driver_info

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))

driver_unload

Unload driver from memory.

    call
      ah   = 01H
    return
      dl   = error code

driver_doio

Perform 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 code

driver_critical_flag

Return the driver's critical flag

    call
      ah    = 03H
    return
      es:di = pointer to critical flag byte
      dl    = error code

copy driver info

Copy the driver info to a user

buffer
    call
      ah    = 04H
      cx    = size of buffer
      es:di = pointer to local buffer
    return
      cx    = bytes stored

TCP hooks

tcp_open

Open 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_session

tcp_close

Close 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_session

Note: 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.

tcp_get

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

tcp_put

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

tcp_status

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)

UDP Hooks

udp_open

    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

udp_close

    call
      ah   = 21H
      al   = option flags
             0    = normal
             128  = asynchronous. Notify by event_call
      bx   = handle
    return
      dl   = error code
               bad_handle

udp_recv

    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)

udp_send

    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

udp_status

    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)

IP Hooks

ip_open

    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

ip_close

    call
      ah   = 31H
      bx   = handle
    return
      dl   = error code
               bad_handle

ip_recv

    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)

ip_send

    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

ip_status

    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)

Event handlers (optional)

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.

Attach_event_global

Allow chaining, but check for duplicates

    call
      ax    = 4000H
      es:di = address of event handler upcall
    return
      dl    = error code
                already_attached

Detach_event_global

    call
      ax    = 4100H
      es:di = address of event handler upcall
    return
      dl    = error code
                not_attached

Attach_event_local

No 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

Detach_event_local

    call
      ax   = 4300H
      bx   = handle
    return
      dl   = error code
               bad_handle
               not_attached

event_call

    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

Error Codes

    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:

Copyright © 1998 Priidu Paomets
Design & Test Center