Programming with STinG


This section comprises information on how additional software for STinG can be written. Additional software may be net clients and servers, but STX modules too. Clients and servers are the same class of applications from STinG's point of view, they may make use of the first collection of function managers (see below). STX modules may use supplementary calls from the second set of managers.

If you want to start writing software, you are strongly encouraged to contact the STinG developers mailing group, the address being
stik@on-luebeck.de

Here you'll get additional information, skeleton source code, debugging tools and can discuss various STinG related topics with other people.
The STinG
API can be reached via the STinG cookie. If STinG is installed then a cookie with the name "STiK" is present, it's value is a pointer to
the DRV_LIST structure, that contains a few more pointers providing access to the API . There is some magic string that must be checked, and a pointer `get dftab' to a function that returns another pointer to the API structures. To that end a pointer to a string must be passed, the latter being either "TRANSPORT_TCPIP" or "MODULE_LAYER".

The various functions of the STinG API are arranged in groups that are called Managers. Here is which managers are available from STinG.

The first collection is declared in TRANSPRT.H. It contains all the calls that might be needed for any program using STinG services. The functions are grouped to a structure, a pointer to which can be obtained by calling get_dftab ("TRANSPORT_TCPIP") :


The Memory Manager
The TCP Manager
The UDP Manager
The ICMP Manager
The Connection Manager
The Port Manager
The Miscellaneous Manager
The Dummy Manager


The second assembly is declared in both PORT.H and LAYER.H. These calls should only be used by STX modules. They are grouped to a structure, a pointer to which is returned by get_dftab ("MODULE_LAYER") :

The System Manager
The IP Manager
The Protocol Manager
The Timing Manager

A table showing all possible error codes is provided too.

API

The acronym API means Application Programming Interface. It refers to a collection of all services that are provided for programming applications. It comprises mainly calls, but also variables, structures, etc.

DRV_LIST

typedef struct drv_list {
char magic[10];
DRV_HDR * cdecl (*get_dftab) (char *string);
int16 cdecl (*ETM_exec) (char *string);
void *cfg;
BASPAG *sting_basepage;
} DRV_LIST;

The System Memory Manager


The System Memory Manager contains all those functions that are used to deal with internal memory. Basically the code from
Kernighan & Ritchie is used, but there are some minor differences. Morecore is never called. The functions use a big block of memory that is allocated at boot time. They are mainly for storing datagrams, receive and send queues, and internal structures that are created and destroyed by the interupt driven IP core. Thus internal memory is a precious resource, and should not be wasted. STinG clients should whenever possible use the normal TOS Malloc and Mfree functions.

These calls are :

void * cdecl KRmalloc (int32);
void cdecl KRfree (void *);
int32 cdecl KRgetfree (int16);
void * cdecl KRrealloc (void *, int32);

Kernighan and Ritchie

This is the standard reference book for C programmers :

The C programming language
Brian W. Kernighan and Dennis M. Ritchie
(c) 1978 1988 by Bell Telephone Laboratories, Incorporated
(p) Prentice Hall International, New Jersey

The `KRmalloc' Function



void * cdecl KRmalloc (int32 length);


Function :
Allocates system memory.


This function is used to allocate a chunk of memory for exclusive use by the caller. The required size of the block is passed as the parameter. The block must be freed again later, this will not automagically happen on termination of the caller ! Use
KRfree with the address returned by KRmalloc to achieve that.

Returns the address of the allocated block, or NULL if memory is low.

The `KRfree' Function



void cdecl KRfree (void *block);


Function :
Frees a block of system memory.


This function is used to release blocks of system memory that have been allocated via
KRmalloc or KRrealloc before. Passing a NULL pointer does not crash the system.

The `KRgetfree' Function



int32 cdecl KRgetfree (int16 which);


Function :
Returns the amount of free system memory.


This function is used to inquire about the space that is left in the internal memory. The parameter determines if the size of the largest block (`which' is TRUE), or the total amount (FALSE) is returned.

The `KRrealloc' Function



void * cdecl KRrealloc (void *block, int32 new_length);


Function :
Changes the size of an already allocated block of system memory.


This function changes the size of a block that has been allocated before using
KRmalloc. The call tries to not move the block even if `new_length' is larger than the old size. Sometimes this is not possible, the `block' parameter will contain the new address in that case, and the contents will be copied into the new block. If `new_length' is zero then the block will be released as if KRfree was called. With `block' containing NULL the call behaves like KRmalloc, but zeros the contents of the new block.

Returns the address of the new block.

The TCP Manager


The
TCP Manager contains all those functions that are needed for all normal stream communication via the net. In addition to data transfer functions, means for synchronizing with the other end of the connection are provided.

Note that only dummy functions are available if TCP.STX is not loaded.

These calls are :

int16 cdecl TCP_open (uint32, int16, int16, uint16);
int16 cdecl TCP_close (int16, int16);
int16 cdecl TCP_send (int16, char *, int16);
int16 cdecl TCP_wait_state (int16, int16, int16);
int16 cdecl TCP_ack_wait (int16, int16);

The UDP Manager


The
UDP Manager contains all those functions that are required for basic datagram traffic. This is basically the IP interface for user applications.

Note that only dummy functions are available if UDP.STX is not loaded.

These calls are :

int16 cdecl UDP_open (uint32, int16);
int16 cdecl UDP_close (int16);
int16 cdecl UDP_send (int16, char *, int16);

The ICMP Manager


The ICMP Manager contains all those functions that are required when
ICMP functionality is to be utilized. As ICMP datagrams must be handled with priority, a callback scheme is employed for processing arriving datagrams.

These calls are :

int16 cdecl ICMP_send (uint32, uint8, uint8, void *, uint16);
int16 cdecl ICMP_handler (int16 cdecl (*) (IP_DGRAM *), int16);
void cdecl ICMP_discard (IP_DGRAM *datagram);

The `ICMP_send' Function



int16 cdecl ICMP_send (uint32 dest_host, uint8 type, uint8 code,
void *data, uint16 length);


Function :
Send off ICMP datagrams.


This function sends an ICMP message. `dest_host' is the IP address of the destination machine, `type' is the ICMP packet type. `code' is a type dependent control code for ICMP. `data' is a pointer to data which is to be send after the ICMP header, `length' is the length of the data block in bytes.

Note that after calling this function the calling code keeps ownership of the data block.

Returns E_BADDNAME, E_PARAMETER, E_NOMEM or E_NORMAL.

The `ICMP_handler' Function



int16 cdecl ICMP_handler (int16 cdecl (* handler) (IP_DGRAM *),
int16 install_code);


Function :
Install and deinstall handlers for ICMP datagrams.


A handler function for dealing immediately with incoming ICMP datagrams can be installed using this call. The handler will be called for each ICMP datagram that comes in, regardless whether it is bound for the calling application, or not. The handler has to check for that. If the datagram is not of interest for the calling application, the handler must return FALSE ! Otherwise the handler should process the datagram and return TRUE. It must also discard the datagram in this case via the
ICMP_discard call.

Note that some types of ICMP datagrams are processed internally and thus are never passed to any installed handlers.

The installed function is called from the main interupt, thus may use only a very limited amount of CPU time. Hence waiting for any event is not allowed. The call is done asynchronously in Supervisor mode, thus care must be execised with using any operating system call within the handler function.

The `install code' can be

HNDLR_SET :
HNDLR_FORCE :
Unlike IP_handler , with ICMP_handler these codes have the same
meaning. They install another ICMP handler callback function.
Returns TRUE, if successfull, and FALSE, if there was a memory
problem, or the function has been installed before.

HNDLR_REMOVE :
Declare a handler, that has been installed earlier, as invalid. This handler won't be called anymore. This must be done when a program that installed a handler, terminates. Returns FALSE if the specified handler was not installed.

HNDLR_QUERY :
Inquire whether the specified handler is installed, without changing it. Returns TRUE if it is there, and FALSE, if not.

The `ICMP_discard' Function



void cdecl ICMP_discard (IP_DGRAM *datagram);


Function :
Discards an ICMP datagram.


An ICMP datagram processed by a handler function must be discarded afterwards. This call provides the means for it. In the current implementation this call is identical to
IP_discard (datagram, TRUE);.

The Connection Manager


The Connection Manager contains all those functions that are provided by high level protocols, such as TCP and UDP, to receive data by a client. Functions to receive single bytes or whole chunks of data are there, and to inquire about connection parameters.

These calls are :

int16 cdecl CNkick (int16);
int16 cdecl CNbyte_count (int16);
int16 cdecl CNget_char (int16);
NDB * cdecl CNget_NDB (int16);
int16 cdecl CNget_block (int16, char *, int16);
CIB * cdecl CNgetinfo (int16);
int16 cdecl
CNgets (int16, uint8 *, int16, uint8);

The `CNgets' Function



int16 cdecl CNgets (int16 cn, uint8 *buffer, int16 len, uint8 delim);


Function :
Receives a delimited block of data.


Similar to the stdio's gets() call, this function receives data until a
specified delimiter is encountered. For text streams, `delim' will be most
often '\r' or '\n'. For the former case, for instance, all data until the
'\r' byte will be transferred to the specified buffer, if `len' specifies
it to be long enough. The '\r' will not be transferred, but read, and in
the buffer the block will be terminated by a '\0' byte. The call returns
the number of bytes read until the delimiter was found, i.e. the length of
the buffer contents without the final '\0' byte.

Note that when reading "\r\n" delimited streams, the call will not filter
the '\n' if `delim' is '\r', and vice versa.

The call returns E_NODATA if there is not enough data in the input buffer
to find the delimiter, or E_BIGBUF if the buffer is not large enough to
hold the whole block of data. In both cases no data is read.

The Port Manager


The Port Manager contains all those functions that are used for dealing
with STinG ports. Ports can be switched on or off, and their state may
be inquired.

These calls are :

int16 cdecl on_port (char *);
void cdecl off_port (char *);
int16 cdecl query_port (char *);

The Miscellaneous Manager


The Miscellaneous Manager contains all those functions that do not fit
easily into other managers. Thus this collection of calls is a little
arbitrary.

These calls are :

char * cdecl
get_err_text (int16);
char * cdecl getvstr (char *);
int16 cdecl setvstr (char *, char *);
int16 cdecl set_flag (int16);
void cdecl clear_flag (int16);
int16 cdecl resolve (char *, char **, uint32 *, int16);

The `get_err_text' Function



char * cdecl get_err_text (int16 error_code);


Function :
Returns error description for a given error number.


Many functions of the STinG
API return negative error codes after a problem
happened during execution. It is a tedious task to provide a corresponding
error text in a client for every error that may happen. STinG thus provides
text descriptions of the errors, if the error code is passed to this call.
A pointer to a text line that is ready for output to a status line will be
returned. The lines are a maximum of 40 characters long.

STinG Error Codes


The following error codes may be returned by STinG
API functions.

The text in quotes behind the symbolic error code is the text returned by
the get_err_text function.

0 E_NORMAL "No error."
-1 E_OBUFFULL "Can't send, output buffer is full."
-2 E_NODATA "No data available."
-3 E_EOF "EOF received from a remote host."
-4 E_RRESET "RESET received from a remote host."
-5 E_UA "Unacceptable packet, sending RESET."
-6 E_NOMEM "No more memory available."
-7 E_REFUSE "Connection refused by remote host."
-8 E_BADSYN "TCP received SYN in window."
-9 E_BADHANDLE "Bad connection handle used."
-10 E_LISTEN "The connection is in LISTEN state."
-11 E_NOCCB "No free CCBs available."
-12 E_NOCONNECTION "A packet matches no connection."
-13 E_CONNECTFAIL "Failure to connect to remote port."
-14 E_BADCLOSE "Invalid TCP_close() requested."
-15 E_USERTIMEOUT "User timeout expired."
-16 E_CNTIMEOUT "Connection timed out."
-17 E_CANTRESOLVE "DNS query, can't resolve hostname."
-18 E_BADDNAME "Bad format in domain name / dotted quad."
-19 E_LOSTCARRIER "Modem lost carrier signal."
-20 E_NOHOSTNAME "Hostname does not exist."
-21 E_DNSWORKLIMIT "Resolver reached work limit."
-22 E_NONAMESERVER "No nameserver found for query."
-23 E_DNSBADFORMAT "DNS query, bad format received."
-24 E_UNREACHABLE "Destination host is unreachable."
-25 E_DNSNOADDR "No address records found for hostname."
-26 E_NOROUTINE "Routine is unavailable."
-27 E_LOCKED "Locked by another application."
-28 E_FRAGMENT "Error during fragmentation."
-29 E_TTLEXCEED "Time To Live exceeded, discarded."
-30 E_PARAMETER "Problem with a parameter."
-31 E_BIGBUF "Input buffer is too small for data."

The `getvstr' Function



char * cdecl getvstr (char *specifier);


Function :
Inquires about a configuration string.


This function is used to read the configuration strings from the file
DEFAULT.CFG. For instance if the line

THREADING = 200

exists in the DEFAULT.CFG, then the call

getvstr ("THREADING");

returns a pointer to the string "200". The lookup is not case sensitive,
so that inquiring "threading" leads to the same result. The pointer is
to the first non blank character after the `=' character.

If the specified variable does not exist, a pointer to "0" is returned,
the same result is returned if no non blank character follows after the
`=' character. If even the `=' does not exit, the mere presence of the
variable is indicated by returning a pointer to "1".

See also
setvstr ()

The `setvstr' Function



int16 cdecl setvstr (char *specifier, char *value);


Function :
Sets configuration strings.


This function is used to create or modify a specified configuration
string. A new variable named by the text the `specifier' points to is
created if it did not exist. The new value is the text `value' points
to. For example, to achieve the same as if the line

DIALER = 10.11.12.13

were present in DEFAULT.CFG at boot time, simply call

setvstr ("DIALER", "10.11.12.13");

and later calls to
getvstr with the `specifier' "DIALER" will return
a pointer to the text "10.11.12.13".

The `set_flag' Function



int16 cdecl set_flag (int16 flag_number);


Function :
Requests a semaphore.


This function uses the noninteruptable MC680X0 instruction "TAS" to set a
semaphore which is specified by the number passed to the call. If it has
been called before with the same semaphore number (i.e. lock denied), the
function returns TRUE. Otherwise the caller got the lock, and FALSE will
be returned.

The lock numbers will be assigned each for a special purpose. Anyone who
wants a new lock to be defined, must coordinate with us !

See also
clear_flag ()

The `clear_flag' Function



void cdecl clear_flag (int16 flag_number);


Function :
Releases a semaphore.


This function releases a semaphore regardless of it's current status. It
should be called after the lock has been succesfully requested via the
set_flag call, and access is finished. The calls returns nothing.

The `resolve' Function



int16 cdecl resolve (char *inp, char **real, uint32 *lst, int16 len);


Function :
Carries out DNS queries.


This function does a DNS query to find out the dotted quad IP address for
a given domain name, and vice versa. The parameter `inp' is a pointer to
the input string, which is either a dotted quad IP address, or a domain
name. The `real' is either NULL, or a pointer to a character pointer that
will be filled in with a pointer to the found domain name. If `inp' points
to a domain name, it is checked if this is an alias, and the real domain
name is returned via `real'. All found dotted quad IP addresses are filled
into the address array pointed to by `lst', the maximum length of the list
is specified by `len'.

If `real' is not NULL, a pointer is filled into `*real'. When the string
it points to has been evaluated, it's space must be freed by using the
KRfree () call :

KRfree (*real);

Returns the number of dotted quad IP addresses filled in, or an error.

Note that only a dummy function is available if RESOLVE.STX is not loaded.
This dummy always returns E_CANTRESOLVE.

The Dummy Manager


The Dummy Manager contains all those functions that are obsolete in
STinG. They're merely remnants from old STiK, and they are implemen-
ted in STinG for compatibility reasons only.

These calls are :

int16 cdecl
carrier_detect (void);
void cdecl housekeep (void);
void cdecl ser_disable (void);
void cdecl ser_enable (void);

The `carrier_detect' Function



int16 cdecl carrier_detect (void);


Function :
Does nothing.


This function is only required because some old clients written for STiK
might use it. In STinG it exists only for compatibility. In those good ole
days this call was used to determine the state of the only port's DCD line.

Returns always +1, meaning carrier is always on.

The `housekeep' Function



void cdecl housekeep (void);


Function :
Does nothing.


This function is only required because some old clients written for STiK
might use it. In STinG it exists only for compatibility. STiK only operated
from an application, there was no interupt driving mechanism. In order to
not loose any datagrams this function had to be called from time to time.

The `ser_disable' Function



void cdecl ser_disable (void);


Function :
Does nothing.


This function is only required because some old clients written for STiK
might use it. In STinG it exists only for compatibility. It was intented
to disable the serial port for short periods of time if parallel DMA was
not available. After the DMA operation the port had to be activated again
using
ser_enable .

The `ser_enable' Function



void cdecl ser_enable (void);


Function :
Does nothing.


This function is only required because some old clients written for STiK
might use it. In STinG it exists only for compatibility. In STiK this call
was used to enable the port again after is has been desactivated via the
ser_disable call.

The System Manager


The System Manager contains all the functions that are designed for
miscellaneous use by modules and access the IP core. Two functions
manage a datagram's time-to-live, another one reloads the core's
routing table, and calls for setting and inquiring internal varia-
bles are provided.

These calls are :

void cdecl
set_dgram_ttl (IP_DGRAM *);
int16 cdecl check_dgram_ttl (IP_DGRAM *);
int16 cdecl load_routing_table (void);
int32 cdecl set_sysvars (int16, int16);
void cdecl query_chains (PORT **, DRIVER **, LAYER **);

The `set_dgram_ttl' Function



void cdecl set_dgram_ttl (IP_DGRAM *datagram);


Function :
Enables time-to-live checking for a datagram.


The function reads the IP header ttl field, and sets up an internal timeout
variable accordingly. The function must be called by a port driver module
whenever it receives a complete IP datagram, in order to enable checking of
the time-to-live timeout for the specified datagram by the kernel.

The `check_dgram_ttl' Function



int16 cdecl check_dgram_ttl (IP_DGRAM *datagram);


Function :
Checks a datagram for time-to-live expired, and discards if appropriate.


The function checks the remaining time to live for the specified datagram.
It should be called by port drivers just before the datagram gets send, in
order to avoid the cost of sending datagrams that will be discarded at the
other end anyway. If the time to live is okay then the function will return
without having changed anything. If the time to live has expired the data-
gram will be discarded, and an ICMP-ttl-exceeded reply will be send if the
datagram was no ICMP packet itself. In the latter case the `datagram' poin-
ter must be considered invalid.

Returns either E_NORMAL or E_TTLEXCEED.

The `load_routing_table' Function



int16 cdecl load_routing_table (void);


Function :
Reloads the IP core routing table.


The function just causes the IP core to load again the routing table from
the file "
ROUTE.TAB ". It must be located in the STinG directory .

Returns E_NORMAL, or E_NODATA (problems reading the file), or E_NOMEM.

The STinG directory

The directory STinG loads all DEFAULT.CFG, ROUTE.TAB and
*.STX modules from. It is specified by the STING.INF file
that accompanies STING.PRG in the AUTO folder. This file
contains one line with the path to the mentioned directory.

The routing table


The routing table is a set of parameters for the router that enables it to
determine which port is to be used for passing on a datagram. To that end
the core uses the destination IP address of the datagram, and runs through
the table to find a suitable entry. For each entry the IP address will be
ANDed with a subnet mask and the result compared to the subnet address. In
case of equality the entry provides the port the datagram will be forwarded
to, and a gateway to be used in case the destination host cannot be reached
directly via that port.

The contents of the routing table are loaded from the file ROUTE.TAB from
the
STinG directory . This is a human readable ASCII format text file. Each
line that does not start with a digit is ignored. From the remaining lines
each one with consistent information forms one entry for the routing table,
called a "route". The lines contain four entries, separated by tab charac-
ters (ASCII 9). Spaces must not be used to separate entries ! This is for
having spaces available for data. The four entries are :

- First the network (subnet address) which can be reached by using this
route.
- Next the subnet mask associated with that network.
- Then the port name follows. This is the name as listed by ConfSTinG or
STNGPORT.CPX.
- Last entry is the IP address of a host on the attached network that
can act as a gateway. For point to point connections this entry can
be set to any arbitrary address.

The network specified may be directly attached to the specified port, in
that case no gateway is needed, as the datagram can be routed directly.
For a route to a network that is directly attached therefore the gateway
entry should be set to 0.0.0.0. For an attached Ethernet the gateway entry
specifies the gateway out of the Ethernet, for a serial line it is simply
the host at the other end. However, the entry is not used in the case of
a serial line.

It is advisable to finish the table by a default route. This route is most
easily obtained by specifying a network 0.0.0.0 with a netmask of 0.0.0.0.
Routes with invalid addresses or absent ports are ignored.

An example ROUTE.TAB file contains the following lines :

192.68.0.0 255.255.255.240 Modem 1 192.68.0.1
130.75.75.16 255.255.255.255 Serial 2 0.0.0.0
0.0.0.0 0.0.0.0 Serial 2 130.75.75.16

Here we have a point to point connection to the host 192.68.0.1 via the
Modem 1 port, this host is part of the network 192.68.0.0. Any host on
that network can be reached via Modem 1. The next line specifies a single
host 130.75.75.16 at the other end of the point to point connection via
SERIAL2. The last line is the default route that will be used if none of
the other entries fit. Normally this is the route out into the Internet.
The beforementioned host 130.75.75.16 acts as a gateway at the other end
of the point to point connection at SERIAL2.

The `set_sysvars' Function



int32 cdecl set_sysvars (int16 new_active, int16 new_fraction);


Function :
Inquires and sets the STinG active flag and calling frequency.


The function sets `new_active' as the new active flag for STinG, if not
-1, and sets `new_fraction' as the new call delay, if not -1. STinG is
active if the active flag is set TRUE. Then with a specified frequency
the STinG core gets called, and IP datagrams can be send, received and
distributed. The time between successive calls of the core is specified
by the `new_fraction' parameter in 5 ms units. The intial value is 10,
thus the core is called each 50 ms. Usage of this function is restricted
to configuration tools, like ConfSTinG and STING.CPX.

The function returns the settings that were active before the call was
done. The upper word of the return value contains the former active flag,
while the lower word contains the former setting of the call delay.

The `query_chains' Function



void cdecl query_chains (PORT **port, DRIVER **drv, LAYER **layer);


Function :
Get addresses of module chains.


Returns pointers to the first elements of the chains of
PORT , DRIVER , and
LAYER structures. Each of the structures contain a link that points to the
next element. Pointers to variables are passed with the call. The function
fills in the appropriate addresses. For addresses that are not needed a
NULL pointer may be passed.

PORT


The port structure. One of these is provided by a hardware driver for each
port the driver handles.

typedef struct port_desc {
char *name; /* Name of port */
int16 type; /* Type of port */
int16 active; /* Flag for port active or not */
uint32 flags; /* Type dependent operational flags */
uint32 ip_addr; /* IP address of this network adapter */
uint32 sub_mask; /* Subnet mask of attached network */
int16 mtu; /* Maximum packet size to go through */
int16 max_mtu; /* Maximum allowed value for mtu */
int32 stat_sd_data; /* Statistics of sent data */
IP_DGRAM *send; /* Link to first entry in send queue */
int32 stat_rcv_data; /* Statistics of received data */
IP_DGRAM *receive; /* Link to first entry in receive queue */
int16 stat_dropped; /* Statistics of dropped datagrams */
struct drv_desc *driver; /* Driver program to handle this port */
struct port_desc *next; /* Next port in port chain */
} PORT;

DRIVER

typedef struct drv_desc {
int16 cdecl (* set_state) (PORT *, int16); /* Init */
void cdecl (* send) (PORT *); /* Send */
void cdecl (* receive) (PORT *); /* Receive */
char *name; /* Name of driver */
char *version; /* Version as "xx.yy" */
uint16 date; /* Compile date */
char *author; /* Name of programmer */
struct drv_desc *next; /* Next driver in chain */
} DRIVER;

LAYER

typedef struct lay_desc {
char *name; /* Name of layer */
char *version; /* Version as xx.yy */
uint32 flags; /* Private data */
uint16 date; /* Compile date */
char *author; /* Name of programmer */
int16 stat_dropped; /* Statistics */
struct lay_desc *next; /* Next layer in chain */
} LAYER;

The IP Manager


The
IP Manager contains all those functions that are required by high
level protocol modules to do the low level net traffic. This might be
urgent traffic, so a callback scheme can be employed by programmers
choice. Functions for sending, receiving and discarding datagrams are
provided.

These calls are :

int16 cdecl IP_send (uint32, uint32, uint8, uint16, uint8,
uint8, uint16, void *, uint16, void *,
uint16);
IP_DGRAM * cdecl IP_fetch (int16);
int16 cdecl IP_handler (int16,
int16 cdecl (*) (IP_DGRAM *), int16);
void cdecl IP_discard (IP_DGRAM *, int16);

The `IP_send' Function



int16 cdecl IP_send (uint32 src_host, uint32 dest_host, uint8 tos,
uint16 dont_frag, uint8 ttl, uint8 protocol,
uint16 ident, void *data, uint16 data_length,
void *options, uint16 options_length);


Function :
Sends off IP datagrams.


This function sends an
IP datagram from host `src_host' (that's us) to
the host `dest_host'. `src_host' may be zero, in that case the function
determines the appropriate IP address. `tos' is the IP type of servive,
`dont_frag' is a flag specifying whether to allow fragmentation (TRUE :
don't allow). `ttl' is the datagram's time-to-live in seconds, `protocol'
is either P_TCP, P_UDP or P_ICMP. `ident' is a unique identification
number, `data' is a pointer to the data to be transferred, `data_length'
is the data's length in bytes. `options' is a pointer to the IP options,
`options_length' is their length in bytes. Both `data' and `options' are
pointers that either contain NULL, or point to blocks that must have been
allocated via KRmalloc . The call inserts all these parameters into the
IP header , and links the resulting datagram into the send queue.

If the call has been successful (i.e. E_NORMAL was returned) then access
to the data or the options is not allowed anymore, as if

KRfree (data); KRfree (options);

had been executed by IP_send. Thus these pointers have to be considered
invalid in that case.

Returns either E_NORMAL or E_NOMEM or E_UNREACHABLE.

IP_DGRAM

typedef struct ip_packet {
IP_HDR hdr; /* Header of IP packet */
void *options; /* Options data block */
int16 opt_length; /* Length of options */
void *pkt_data; /* IP packet data block */
int16 pkt_length; /* Length of IP packet */
uint32 timeout; /* Timeout of packet life */
uint32 ip_gateway; /* Gateway for forwarding */
struct port_desc *recvd; /* Receiving port */
struct ip_packet *next; /* Next IP packet in queue */
} IP_DGRAM;

IP_HDR


The IP header structure. This structure is a part of the internal IP
packet
representation .

typedef struct ip_header {
unsigned version : 4; /* IP Version */
unsigned hd_len : 4; /* Internet Header Length */
unsigned tos : 8; /* Type of Service */
uint16 length; /* Total of all header, options and data */
uint16 ident; /* Identification for fragmentation */
unsigned reserved : 1; /* Reserved : Must be zero */
unsigned dont_frg : 1; /* Don't fragment flag */
unsigned more_frg : 1; /* More fragments flag */
unsigned frag_ofst : 13; /* Fragment offset */
uint8 ttl; /* Time to live */
uint8 protocol; /* Protocol */
uint16 hdr_chksum; /* Header checksum */
uint32 ip_src; /* Source IP address */
uint32 ip_dest; /* Destination IP address */
} IP_HDR;

The `IP_fetch' Function



IP_DGRAM * cdecl IP_fetch (int16 protocol);


Function :
Fetches an IP datagram from the receive queue.


The function fetches an IP datagram from the queue associated with the
protocol specified. It returns NULL if there is none, otherwise a pointer
to the datagram is returned. The datagram is now under complete control
of the calling code. Particularly it must be discarded via the
IP_discard
call after use.

The `IP_handler' Function



int16 cdecl IP_handler (int16 protocol,
int16 cdecl (* handler) (IP_DGRAM *),
int16 install_code);


Function :
Install and deinstall handlers for high level protocols.


A handler function for dealing immediately with incoming datagrams for
a specific protocol can be installed using this call. The handler will
be called for each datagram that comes in and that is bound for that
protocol. The handler shall return with TRUE, if the datagram has been
completely processed, then the datagram will be discarded by the kernel
afterwards. If the handler returns FALSE the datagram will be linked
into the receive queue for that protocol, and can be fetched later via
IP_fetch .

Do not try to install a handler for ICMP using this function, use the
ICMP_handler call instead.

The installed function is called from the main interupt, thus may use
only a very limited amount of CPU time. Hence waiting for any event is
not allowed. The call is done asynchronously in Supervisor mode, thus
care must be execised with using any operating system call within the
handler function.

The `install code' can be

HNDLR_SET :
Install a new handler. The call returns TRUE if there was no
handler installed before, and the new handler has been put in
place.

HNDLR_FORCE :
Install a new handler, not caring whether there was a handler
already installed or not. Returns TRUE. Apply with care !

HNDLR_REMOVE :
Declare a handler, that has been installed earlier, as invalid.
This handler won't be called anymore. This must be done when a
program that installed a handler, terminates.

HNDLR_QUERY :
Inquire whether there is a handler installed, without changing
it. Returns TRUE if there is one already, and FALSE, if not.

The `IP_discard' Function



void cdecl IP_discard (IP_DGRAM *datagram, int16 all_flag);


Function :
Discards an IP datagram.


There are several occasions when IP datagrams must be discarded. This
is only for releasing the memory the datagram occupied. A pointer to
the datagram must be passed. After calling this the address the poin-
ter `datagram' points to is not valid anymore.

High level protocols often need to discard just the IP overhead, but
need to keep the data, in order to not need to copy it to some other
place. For this purpose the extra parameter `all_flag' can be set to
FALSE. In that case the memory occupied by both IP header and options
is freed, but the memory block the `datagram->pkt_data' points too is
not released, but stays allocated and is owned by the caller.

The Protocol Manager


The Protocol Manager contains all those functions that are specifically
used by modules implementing high lebel protocols. There are functions
for announcing the presence, for inquiring about special parameters, and
for managing connection handles.

These calls are :

int16 cdecl
PRTCL_announce (int16);
int16 cdecl PRTCL_get_parameters (uint32, uint32 *, int16 *, uint16 *);
int16 cdecl PRTCL_request (void *, CN_FUNCS *);
void cdecl PRTCL_release (int16);
void * cdecl PRTCL_lookup (int16, CN_FUNCS *);

The `PRTCL_announce' Function



int16 cdecl PRTCL_announce (int16 protocol);


Function :
Announces that a high level protocol is active.


Modules implementing high level protocols, like TCP or UDP, must call
this function in order to receive any datagrams. If this function is
not called, the IP core sends back an `ICMP destination unreachable'
message upon reception of any datagram that is bound for that protocol,
and discards the datagram.

Returns a flag indicating if PRTCL_announce has been called with that
protocol number before (TRUE) or if this is the first call (FALSE). If
TRUE is returned the module should refrain of installing itself.

The `PRTCL_get_parameters' Function



int16 cdecl PRTCL_get_parameters (uint32 rem_IP, uint32 *lcl_IP,
int16 *ttl, uint16 *mtu);


Function :
Fetch high level protocol parameters from the STinG core.


High level protocols usually include the source (local) IP address in
their packets. A time-to-live (ttl) must be specified too when sending
the packet off via the
IP_send call. Occasionly it is useful to adjust
packet size to the maximum value in order to avoid unnecessary fragmen-
tation. To provide some means to inquire about these parameters this
call has been implemented. The destination host's IP address is passed
via the first parameter. The `lcl_IP', `ttl' and `mtu' parameters are
pointers to appropriate variables that are filled in by this function.
For pointers to unused parameters NULL can be used.

Returns either E_NORMAL or E_UNREACHABLE.

The `PRTCL_request' Function



int16 cdecl PRTCL_request (void *connect, CN_FUNCS *functions);


Function :
Fetches a new connection handle from the handle pool.


High level protocols share a common set of receive data functions. Thus
their connection handles must be kept unique. This is achieved by the
corresponding module using the PRTCL_request, the
PRTCL_release and the
PRTCL_lookup function for managing the handle pool.

PRTCL_request is used to get a new connection handle out of a pool of
32765 handles. By passing the parameter `connect' a pointer to a struc-
ture with connection related data is associated with the handle, thus
the module does not need to keep track of handles and associated data.
The data structure is completely internal to the module, it may contain
any data. The `functions' parameter is a pointer to a CN_FUNCS struc-
ture which contains a set of pointers to receive functions, which are
called when any client calls an API function from the connection manager
with a handle that belongs to the protocol supported by the module.

A value of NULL is acceptable for `connect', but `functions' must have
a meaning. It is suggested to have a CN_FUNCS structure in the code with
the appropriate function pointers, and pass the address of that struc-
ture whenever PRTCL_request is to be used.

Any function of the module that is passed a connection handle, can use
the PRTCL_lookup function to retrieve the pointer to the associated data.
Any function from the CN_FUNCS structure is called directly with this
pointer as the first argument. After use, when closing the connection,
the handle must be returned using the PRTCL_release call.

PRTCL_request returns a new handle, or -1 if an error occurred.

The `PRTCL_release' Function



void cdecl PRTCL_release (int16 handle);


Function :
Returns a used connection handle to the handle pool.


High level protocols share a common set of receive data functions. Thus
their connection handles must be kept unique. This is achieved by the
corresponding module using the
PRTCL_request , the PRTCL_release and the
PRTCL_lookup function for managing the handle pool.

Every handle that has been fetched via the PRTCL_request call must be
returned eventually to avoid handle pool exhaustion. Thus any module
that implements a protocol that uses the connection manager must call
PRTCL_release from it's close function, and pass the handle it got from
calling PRTCL_request .

The `PRTCL_lookup' Function



void * cdecl PRTCL_lookup (int16 handle, CN_FUNCS *functions);


Function :
Looks up the data for a given connection handle.


High level protocols share a common set of receive data functions. Thus
their connection handles must be kept unique. This is achieved by the
corresponding module using the
PRTCL_request , the PRTCL_release and the
PRTCL_lookup function for managing the handle pool.

Any function declared in the CN_FUNCS structure gets the address of the
connection related data passed directly as the first argument. A module
wishing to implement other API calls (for instance a `send' call) that
are independent from the connection manager , must do a separate lookup
to retrieve this address. To save the module the effort of keeping track
of handle - connection data relations, the address can be looked up using
this call. The handle is passed as the first parameter, the address of
the CN_FUNCS structure for the connection must be passed too to ensure
only the right module accesses the data.

For speed a quick hash retrieval scheme is used by PRTCL_lookup.

PRTCL_lookup returns the address of connection related data, or NULL if
the handle does not exist or belongs to a different module.

CN_FUNCS

typedef struct cn_funcs {
int16 cdecl (* CNkick) (void *cn);
int16 cdecl (* CNbyte_count) (void *cn);
int16 cdecl (* CNget_char) (void *cn);
NDB * cdecl (* CNget_NDB) (void *cn);
int16 cdecl (* CNget_block) (void *cn, void *buf,
int16 len);
CIB * cdecl (* CNgetinfo) (void *cn);
int16 cdecl (* CNgets) (void *cn, char *buf,
int16 len, char delim);
} CN_FUNCS;

The Timing Manager


The Timing Manager provides functionality for regularly called functions
and for timing purposes, i.e. timeout counters etc. For timing, functions
for inquiring about time, and elapsed time since a given moment, are pro-
vided.

These calls are :

int16 cdecl
TIMER_call (void cdecl (*) (void), int16);
int32 cdecl TIMER_now (void);
int32 cdecl TIMER_elapsed (int32);

The `TIMER_call' Function



int16 cdecl TIMER_call (void cdecl (* handler) (void),
int16 install_code);


Function :
Install and deinstall handlers for timer interupt events.


High level protocols very often require a function to be executed on a
regular basis. As the STinG core is called regularly, it can be asked to
execute a user specified function too. This call is used to install or
deinstall those functions, which are called like timer interupt handlers
then. They are called each time STinG polls the ports for sending and
receiving data.

The installed function is called from the main interupt, thus may use
only a very limited amount of CPU time. Hence waiting for any event is
not allowed. The call is done asynchronously in Supervisor mode, thus
care must be execised with using any operating system call within the
handler function.

The `install code' can be

HNDLR_SET :
HNDLR_FORCE :
Unlike
IP_handler , with TIMER_call these codes have the same
meaning. They install another timer interupt callback function.
Returns TRUE, if successfull, and FALSE, if there was a memory
problem, or the function has been installed before.

HNDLR_REMOVE :
Declare a handler, that has been installed earlier, as invalid.
This handler won't be called anymore. This must be done when a
program that installed a handler, terminates. Returns FALSE if
the specified handler was not installed.

HNDLR_QUERY :
Inquire whether the specified handler is installed, without
changing it. Returns TRUE if it is there, and FALSE, if not.

The `TIMER_now' Function



int32 cdecl TIMER_now (void);


Function :
Returns the number of milliseconds elapsed since last midnight.


For timing processes, a timebase is required. This function provides a
timebase in milliseconds, with a resolution of five milliseconds. That
means the return value is a multiple of five. The value is in the range
from zero (inclusive) to 86,400,000 (exclusive).

The `TIMER_elapsed' Function



int32 cdecl TIMER_elapsed (int32 moment);


Function :
Calculates the number of milliseconds elapsed since a given moment.


For timing processes, time intervals must be measured. The procedure
is to inquire the time via the
TIMER_now call, when the process has
started, and feeding the resulting value into TIMER_elapsed when the
process has finished. The TIMER_elapsed call returns the time inter-
val in milliseconds, again with a resolution of five milliseconds.

Note that the return value is always modulo the past 24 hours. So if
a value is fed into TIMER_elapsed that lies in the future, it will be
treated as if the same moment 24 hours earlier was meant. The same
applies if moments are passed to TIMER_elapsed that are earlier than
24 hours ago.



Opening Page