Revision: 1.11
Release date: Thursday, June 02, 1994
Print date: Thursday, June 02, 1994
Developed by: FTP Software
2 High Street
North Andover, MA 01845
(508) 685-4000
Copyright (c) 1986-1994 FTP Software, Inc. 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 FTP Software's permission. FTP
Software's name and this notice must appear on any reproduction
of this document. This specification was originally developed at
FTP Software by John Romkey.
Support of a hardware interface or mention of an interface
manufacturer by the Packet Driver Specification does not
necessarily indicate that the manufacturer endorses this
specification.
1. Document Conventions
All numbers in this document are given in C-style
representation. Decimal is expressed as 11, hexadecimal
is expressed as 0x0B, octal is expressed as 013. All
reference to network hardware addresses (source,
destination and multicast) and demultiplexing information
for the packet headers assumes they are represented as
they would be in a MAC-level packet header being passed
to the send_pkt() function.
2. Introduction and Motivation
This document describes the programming interface to FTP
Software Packet Drivers. Packet drivers provide a simple,
common programming interface that allows multiple
applications to share a network interface at the data
link level. The packet drivers demultiplex incoming
packets among the applications by using the network
media's standard packet type or service access point
field(s).
The intent of this specification is to allow protocol
stack implementations to be independent of the actual
brand or model of the network interface in use on a
particular machine. Different versions of various
protocol stacks still must exist for different network
media (Ethernet, 802.5 ring, serial lines), because of
differences in protocol-to-physical address mapping,
header formats, maximum transmission units (MTUs) and so
forth.
The packet driver provides calls to initiate access to a
specific packet type, to end access to it, to send a
packet, to get statistics on the network interface and to
get information about the interface.
Protocol implementations that use the packet driver can
completely coexist on a PC and can make use of one
another's services, whereas multiple applications which
do not use the driver do not coexist on one machine
properly. Through use of the packet driver, a user could
run TCP/IP, XNS, and a proprietary protocol
implementation such as DECnet, Banyan's, LifeNet's,
Novell's or 3Com's without the difficulties associated
with preempting the network interface.
Applications which use the packet driver can also run on
new network hardware of the same class without being
modified; only a new packet driver need be supplied.
Several levels of packet drivers are described in this
specification. The first is the basic packet driver,
which provides minimal functionality but should be simple
to implement and which uses very few host resources. The
basic driver provides operations to broadcast and receive
packets. The second driver is the extended packet driver,
which is a superset of the basic driver. The extended
driver supports less commonly used functions of the
network interface such as multicast, and also gathers
statistics on use of the interface and makes these
available to the application. The third level, the high-
performance functions, support performance improvements
and tuning.
Functions which are available in only the extended packet
driver are noted as such in their descriptions. All basic
packet driver functions are available in the extended
driver. The high-performance functions may be available
with either basic or extended drivers.
3. Identifying network interfaces
Network interfaces are named by a triplet of integers,
<class, type, number>. The first number is the class of
interface. The class tells what kind of media the
interface supports: DEC/Intel/Xerox (DIX or Bluebook)
Ethernet, IEEE 802.3 Ethernet, IEEE 802.5 Token Ring,
ProNET-10, Appletalk, serial line, etc.
The second number is the type of interface: this
specifies a particular instance of an interface
supporting a class of network medium. Interface types for
Ethernet might name these interfaces: 3Com 3C503 or
3C505, InterLan NI5210, Univation, BICC Data Networks
ISOLAN, Ungermann-Bass NIC, etc. Interface types for IEEE
802.5 might name these interfaces: IBM Token Ring
adapter, Proteon p1340, etc.
The last number is the interface number. This was
orginally intended to allow support of multiple
interfaces by a single Packet Driver. However, given that
the send_pkt() function doesn't get passed either an
interface number or a handle, this can't be implemented
in the spec as it presently exists.
An appendix details constants for classes and types. The
class of an interface is an 8-bit integer, and its type
is a 16 bit integer. Class and type constants are managed
by FTP Software. Contact FTP to register a new class or
type number. See the section on Specific Characteristics
of Classes for details of packet header format, MTU and
demultiplexing information for the various classes.
The type 0xFFFF is a wildcard type which matches any
interface in the specified class. It is unnecessary to
wildcard interface numbers, as 0 will always correspond
to the first interface of the specified class and type.
This specification has no provision for the support of
multiple network interfaces (with similar or different
characteristics) via a single Packet Driver and
associated interrupt. We feel that this issue is best
addressed by loading several Packet Drivers, one per
interface, with different interrupts (although all may be
included in a single TSR software module). Applications
software must check the class and type returned from a
driver_info() call in any case, to make sure that the
Packet Driver is for the correct media and packet format.
This can easily be generalized by searching for another
Packet Driver if the first is not of the right kind.
4. Initiating driver operations
The packet driver is invoked via a software interrupt in
the range 0x20 through 0xFF (in versions prior to 1.10,
the low and high limits were 0x60 and 0x80,
respectively). This document does not specify a
particular interrupt, but describes a mechanism for
locating which interrupt the driver uses. The interrupt
must be configurable to avoid conflicts with other pieces
of software that also use software interrupts. The
program which installs the packet driver should provide
some mechanism for the user to specify the interrupt.
The handler for the interrupt is assumed to start with 3
bytes of executable code; this can either be a 3-byte
jump instruction, or a 2-byte jump followed by a NOP (do
not specify "jmp short" unless you also specify an
explicit NOP). This must be followed by the null-
terminated ASCII text string
To find the interrupt being used by the driver, an
application should scan through the handlers for vectors
0x20 through 0xFF until it finds one with the text string
"PKT DRVR" in the proper location.
5. Link-layer demultiplexing
If a network media standard is to support simultaneous
use by different transport protocols (e.g. TCP/IP, XNS,
OSI), it must define some link-level mechanism which
allows a host to decide which protocol a packet is
intended for. In DIX Ethernet, this is the 16-bit
Ethertype field immediately following the 6-byte
destination and source addresses. In IEEE 802.3 where
802.2 headers are used, this information is in the
variable-length 802.2 header. In Proteon's ProNET-10,
this is done via the 8-bit "type" field. Other media
standards may demultiplex via a method of their own, or
802.2 headers as in 802.3.
Our access_type() function provides access to this
link-layer demultiplexing. Each call establishes a
destination for a particular type of link-layer packet,
which remains in effect until release_type() is called
with the handle returned by that particular
access_type(). The link-layer demultiplexing information
is passed via the type and typelen fields, but values and
interpretation depend on the class of packet driver (and
thus on the media in use).
A class 1 driver (DIX Ethernet) should expect type to
point at an Ethertype value (in network byte order, and
greater than 0x05EE), and might reasonably require
typelen to equal either 2 (a 16-bit Ethertype) or 0 (if
it supports match all types mode). A class 2 driver could
require 1 byte. However, a class 3 (802.5) or 11
(Ethernet with 802.2 headers) driver should be prepared
for typelen values between 1 (for the DSAP field only)
and 8 (3 byte 802.2 header plus 3-byte Sub-Network Access
Protocol extension header plus 2-byte Ethertype as
defined in RFC 1042).
6. Programming interface
All functions are accessed via the software interrupt
determined to be the driver's via the mechanism described
earlier. On entry, register AH contains the code of the
function desired.
Driver implementors are warned that a number of protocol
stacks exist that support multiple active network
interfaces simultaneously, notably Phil Karn's KA9Q,
which can function as an IP Router. For this reason it is
necessary to use coding techniques which will allow
multiple drivers (possibly for the same type of board) to
be active at once. At a minimum, this requires that the
driver's vector be configurable, and that it avoid
issuing non-specific EOIs to the interrupt controller.
6.1. Handles
The handle is an arbitrary 16-bit integer value
associated with each MAC-level demultiplexing type that
has been established via the access_type() call.
Internally to the packet driver, it will probably be a
pointer, or a table offset.
As of version 1.10 of this specification, the handle
values 0x0000 and 0xFFFF (-1) has been reserved for use
by this specification (and applications) as an "invalid
handle" indication. There is reason to believe that no
older Packet Drivers will ever return these handles,
because existing protocol stacks already use one or the
other as an "invalid handle" indication.
Other than the reserved values named above, the
application calling the packet driver cannot depend on a
handle assuming any particular range, or any other
characteristics. In particular, if an application uses
two or more packet drivers, handles returned by different
drivers for the same or different types may have the same
value.
6.2. Levels of Functionality
Note that some of the functions defined below are
labelled as extended driver functions and high-
performance functions. Because these are not required for
basic network operations, their implementation may be
considered optional. Programs wishing to use these
functions should use the driver_info() function to
determine if they are available in a given packet driver.
6.3. Entry conditions
FTP Software applications which call the packet driver
are coded in Microsoft C and assembly language. All
necessary registers are saved by FTP's routines before
the INT instruction to call the packet driver is
executed. Our current receiver() functions behave as
follows: DS, BP, SS, SP and the flags are saved and
restored. All other registers may be modified, and
should be saved by the packet driver, if necessary.
Processor interrupts may be enabled while in the upcall,
but the upcall doesn't assume interrupts are disabled on
entry. On entry, receiver() switches to a local stack,
and switches back before returning.
Note that some older versions of PC/TCP may enable
interrupts during the upcall, and leave them enabled on
return to the Packet Driver. Note also that while some
drivers (notably the Clarkson/Crynwr collection) save all
registers on entry, others don't. Application developers
should take care save their own registers to ensure
interoperability.
6.4. Number of Handles Opened
When using a class 1 driver, PC/TCP will normally make 5
access_type() calls for IP, ARP and 3 kinds of Berkeley
Trailer encapsulation packets (LANWatch will only make
one, with typelen equal to 0). On other media, the number
of handles we open will vary, but it is usually at least
two (IP and ARP). Implementors should make their tables
large enough to allow two protocol stacks to co-exist. We
recommend support for at least 10 open handles
simultaneously.
6.5. Byte and Bit ordering
Developers should note that, on many networks and
protocol families, the byte-ordering of 16-bit and 32-bit
quantities on the network is different from the native
byte-order of integers on the PC. This means, among other
things, that DEC-Intel-Xerox Ethertype values passed to
access_type() must be byte-swapped (passed in network
order). The IEEE 802.3 length field needs similar
handling, and care should be taken with packets passed to
send_pkt(), so all fields are in the proper order.
Developers working with 802.5 should be aware that it
does not use the same bit-order as Ethernet - where the
'group' bit is the most significant bit of a MAC address
on 802.5, it is the least significant bit of the first
byte on Ethernet. IEEE Organizationally Unique
Identifiers (Ethernet manufacturer codes) also change
bit-order between the two media. FDDI uses the same bit-
order as 802.5 on the physical medium, but current
practice requires that it be converted to match Ethernet
by the MAC-layer driver before presentation to protocol
stacks.
6.6. Byte Alignment
Because some packet drivers can provide greater
performance if packet buffers are double word aligned,
protocol stack developers should double word align the
packet buffers. However this is not an absolute
requirement.
possible errors:
BAD_HANDLE /* older drivers only */
non-error return:
carry clear
BX version
CH class
DX type
CL number
DS:SI name
AL functionality
1 == basic functions present.
2 == basic and extended present.
5 == basic and high-performance.
6 == basic, high-performance, extended.
255 == not installed.
This function returns information about the interface.
The version is assumed to be an internal hardware driver
identifier. In earlier versions of this spec, the handle
argument (which must have been obtained via
access_type()) was required. It is now optional, but
drivers developed according to versions of this spec
previous to 1.07 may require it, so implementers should
take care.
6.8. access_type()
int access_type(if_class, if_type, if_number, type,
typelen, receiver)
AH 2
AL if_class
BX if_type
DL if_number
DS:SI type
CX typelen
ES:DI receiver
error return:
carry set
DH error code
possible errors:
NO_CLASS
NO_TYPE
NO_NUMBER
BAD_TYPE
NO_SPACE
TYPE_INUSE
non-error return:
carry clear
AX handle
receiver call:
(*receiver)(handle, flag, len [[, lah_len], buffer])
BX handle
AX flag
if AX == 0,
DX lah_len
DS:SI lah_buffer /* if DX != 0 */
Returns:
ES:DI buffer /* If 0, no buffer */
CX buffer_len /* May not equal entry CX */
Initiates access to packets of the specified type. The
argument type is a pointer to a packet type
specification. The argument typelen is the length in
bytes of the type field. The argument receiver is a
pointer to a subroutine which is called when a packet is
received. If the typelen argument is 0, this indicates
that the caller wants to match all packets (match all
requests may be refused by packet drivers developed to
conform to versions of this spec previous to 1.07).
When a packet is received, receiver is called twice by
the packet driver. The first time it is called to request
a buffer from the application to copy the packet into. AX
== 0 on this call. The application may return a pointer
to a buffer to which the packet should be copied by the
driver in ES:DI. If the application has no buffers, it
may return 0:0 in ES:DI, and the driver should throw away
the packet and not perform the second call.
It is important that the packet length (CX) be valid on
the AX == 0 call, so that the receiver can allocate a
buffer of the proper size. This length (as well as the
copy performed prior to the AX == 1 call) must include
the MAC header and all received data, but not the
trailing Frame Check Sequence (if any), except in the
case of asynchronous PPP, where space for the Frame Check
Sequence may be included, even though the protocol stack
will make no use of the information. The driver must
never copy more bytes than CX specifies; if the hardware
requires that the copy length be even, the initial CX
value must be rounded up to reflect this. On the second
call, AX == 1. This call indicates that the copy has been
completed, and the application may do as it wishes with
the buffer. The buffer that the packet was copied into is
pointed to by DS:SI. As discussed in the "Entry
Conditions" section, the driver is expected to save the
registers it cares about before calling receiver().
Protocol stacks should not expect more than about 20
bytes of stack to be available, and must switch to a
stack of its own before using more, or enabling
interrupts.
Version 1.10 of this spec (use the get_parameters()
function to determine the version of a given driver),
specifies three enhancements to the receiver mechanism:
First, on the AX == 0 call, a non-zero value in DX is the
length of the data in a "look-ahead buffer" pointed to by
DS:SI. The application may inspect this data to determine
where to put the packet. Second, on the return from the
AX == 0 call, the value of CX is the actual length of the
application's buffer. The driver must truncate the packet
to fit as it copies it. Third, on the AX == 1 upcall, CX
contains the number of bytes actually copied by the
driver.
Note that the functionality defined in the paragraph
above must be present in drivers which indicate version
1.10 or greater in the values returned by
get_parameters(), and will not be found in drivers
indicating 1.09 or previous. It is advisable not to be
completely dependent on the presence of a 1.10 driver,
given the number of older drivers in the field.
Note that many drivers are not re-entrant, and so are
unable to process functions (particularly send_pkt())
while either receiver() upcall is in progress. Queue any
transmits or other packet driver calls for execution
later, possibly via hooking the int_num vector returned
by get_parameters().
6.9. release_type()
int release_type(handle)
AH 3
BX handle
error return:
carry set
DH error code
possible errors:
BAD_HANDLE
non-error return:
carry clear
This function ends access to packets associated with a
handle returned by access_type(). The handle is no longer
valid.
Transmits length bytes of data, starting at buffer. The
application must supply the entire packet, including
local network headers. Any MAC or LLC information in use
for packet demultiplexing (e.g. the DEC-Intel-Xerox
Ethertype) must be filled in by the application as well.
This cannot be performed by the driver, as no handle is
specified in a call to the send_packet() function.
Note that when transmitting to a group destination MAC
address (broadcast or multicast), the hardware may
receive the packet itself. Protocol stack implementors
are advised to check for this in situations where the
stack would otherwise be confused by seeing a copy of its
own broadcast (e.g. RARP or broadcast name-defense
schemes).
possible errors:
BAD_HANDLE /* older drivers only */
CANT_TERMINATE
non-error return:
carry clear
Terminates the driver associated with handle. If
possible, the driver will exit and allow MS-DOS to
reclaim the memory it was using. In earlier versions of
this spec, the handle argument (which must have been
obtained via access_type()) was required. It is now
optional, but drivers developed according to versions of
this spec previous to 1.10 may require it, so
implementers should take care.
possible errors:
BAD_HANDLE /* older drivers only */
NO_SPACE
non-error return:
carry clear
CX length
Copies the current local net address of the interface
into buf. The buffer buf is len bytes long. The actual
number of bytes copied is returned in CX. If the NO_SPACE
error is returned, this indicates that len was
insufficient to hold the local net address. If the
address has been changed by set_address(), the station
address presently in effect should be returned. In
earlier versions of this spec, the handle argument (which
must have been obtained via access_type()) was required.
It is now optional, but drivers developed according to
versions of this spec previous to 1.10 may require it, so
implementers should take care.
possible errors:
BAD_HANDLE /* older drivers only */
CANT_RESET
non-error return:
carry clear
Resets the interface associated with handle to a known
state, aborting any transmits in process and
reinitializing the receiver. The local net address is
reset to the default (from ROM), the multicast list is
cleared, and the receive mode is set to 3 (own address &
broadcasts). If multiple handles are open, these actions
might seriously disrupt other applications using the
interface, so CANT_RESET should be returned. In earlier
versions of this spec, the handle argument (which must
have been obtained via access_type()) was required. It is
now optional, but drivers developed according to versions
of this spec previous to 1.10 may require it, so
implementers should take care.
6.14. get_parameters() high-performance driver function
get_parameters()
AH 10
error return:
carry set
DH error code
possible errors:
BAD_COMMAND /* No high-performance support */
non error return:
carry clear
ES:DI param
struct param {
unsigned char major_rev; /* Revision of Packet Driver
spec */
unsigned char minor_rev; /* this driver conforms to. */
unsigned char length; /* Length of structure in
bytes */
unsigned char addr_len; /* Length of a MAC-layer
address */
unsigned short mtu; /* MTU, including MAC headers
*/
unsigned short multicast_aval; /* Buffer size for
multicast addr */
unsigned short rcv_bufs; /* (# of back-to-back MTU
rcvs) - 1 */
unsigned short xmt_bufs; /* (# of successive xmits) - 1
*/
unsigned short int_num; /* Interrupt # to hook for
post-EOI
processing, 0 == none */
};
The performance of an application may benefit from using
get_parameters() to obtain a number of driver parameters.
This function was added to v1.09 of this specification,
and may not be implemented by all drivers (see
driver_info()).
The major_rev and minor_rev fields are the major and
minor revision numbers of the version of this
specification the driver conforms to. For this document,
major_rev is 1 and minor_rev is 10. The length field may
be used to determine which values are valid, should a
later revision of this specification add more values at
the end of this structure. For this document, length is
14. The addr_len field is the length of a MAC address, in
bytes. Note the param structure is assumed to be packed,
such that these fields occupy four consecutive bytes of
storage.
In the param structure, the mtu is the maximum MAC-level
packet the driver can handle (on Ethernet this number is
fixed at 1514 bytes, but it may vary on other media, e.g.
802.5 or FDDI). This value should include all MAC-layer
data that the application must supply to a send_pkt()
call (for class 1, source and destination addresses, and
Ethertype), but not framing normally generated by the
hardware (preamble, FCS, etc.). The multicast_aval field
is the number of bytes required to store all the
multicast addresses supported by any "perfect filter"
mechanism in the hardware. Calling set_multicast_list()
with its len argument equal to this value should not fail
with a NO_SPACE error. A value of zero implies no
multicast support.
The rcv_bufs and xmt_bufs indicate the number of back-to-
back receives or transmits the card/driver combination
can accomodate, minus 1. The application can use this
information to adjust flow-control or transmit
strategies. A single-buffered card (for example, an
InterLan NI5010) would normally return 0 in both fields.
A value of 0 in rcv_bufs could also be used by a driver
author to indicate that the hardware has limitations
which prevent it from receiving as fast as other systems
can send, and to recommend that the upper-layer protocols
invoke lock-step flow control to avoid packet loss.
The int_num field should be set to an interrupt that the
application can hook in order to perform interrupt-time
protocol processing after the EOI has been sent to the
8259 interrupt controller and the card is ready for more
interrupts. Because software adapter modules may not have
a hardware interrupt available, this value is specified
as corresponding to the argument to an INT instruction,
rather than the specific hardware interrupt line. A value
of zero indicates that there is no such interrupt. Any
application hooking this interrupt and finding a non-zero
value in the vector must pass the interrupt down the
chain and wait for its predecessors to return before
performing any processing or stack switches. Any driver
which implements this function via a separate INT
instruction and vector, instead of just using the
hardware interrupt, must prevent any saved context from
being overwritten by a later interrupt. In other words,
if the driver switches to its own stack, it must either
support re-entrancy, or detect and prevent it.
6.15. old_as_send_pkt() high-performance driver function
old_as_send_pkt()
AH 11
error return:
carry set
DH error code
possible errors:
BAD_COMMAND
This function was added in v1.09 of this specification in
order to provide an asynchronous version of send_pkt().
The specification of this function was found to be
deficient, and no implementations of it were created.
This function was removed in v1.10 of this specification
in favor of the new improved as_send_pkt() (AH = 12).
6.16. as_send_pkt() high-performance driver function
int as_send_pkt(iocb)
AH 12
ES:DI struct iocb far* iocb
Name Bit Value Meaning
DONE 0 0x01 the packet driver is done with this
iocb.
UPCALL 1 0x02 the application requests an upcall
when the
buffer is re-usable.
error return:
carry set
DH error code
possible errors:
CANT_SEND /* transmit error, re-entered,
etc. */
BAD_COMMAND /* Level 0 or level 1 driver */
non-error return:
carry clear
transmitter upcall:
void (*transmitter)(iocb)
ES:DI struct iocb far *iocb
as_send_pkt() provides an asynchronous mechanism for the
transmission of packets. It differs from the the
synchronous send_pkt() in two major ways. First, all
parameters including the normal length and buffer
parameters are passed within an iocb (I/O Control Block)
structure rather than being passed directly in registers.
Second, as_send_pkt() never blocks awaiting buffer re-
usability. For example, send_pkt() returns to the
calling application only after the application's data has
been copied out of the buffer and the application can
safely modify or re-use the buffer. as_send_pkt() returns
to the calling application immediately and signals buffer
availability by setting a bit in the flagbits field of
the iocb and optionally by making an application
specified upcall.
as_send_pkt() takes a single argument, a far pointer to
an iocb structure. The buffer and length fields of the
iocb structure have exactly the same meaning as those
passed to send_pkt(). The flagbits field currently has
two flag bits defined: DONE and UPCALL. The DONE bit is
used by the packet driver to signal re-usability of an
iocb and associated buffer. It MUST be cleared to zero by
the calling application before passing the iocb to the
packet driver. Once the packet driver is done with an
iocb -- either because the buffer has been transmitted or
because an error was asynchronously detected -- it will
set the DONE bit to one. The UPCALL bit is used by the
calling application to request an upcall from the packet
driver after the DONE bit is set to one. If the UPCALL
bit is set to zero, no upcall will be made and the
application must poll the DONE bit to determine iocb re-
usability. If the UPCALL bit is set to one, then the
packet driver will call the routine specified in the
transmitter field of the iocb after setting the DONE bit
to one. The application may change the state of the
UPCALL bit at any time, but care should be taken to avoid
introducing race conditions. Specifically, the
application should be careful when examining and
modifying application level queues of iocbs, if such
queues exist. Depending on the strategy implemented, it
may be necessary to disable interrupts while testing
queue lengths and testing or modifying iocb flag bits.
All other flag bits should be set to zero by the calling
application.
If the driver detects an error on the initial call to
as_send_pkt(), it will return the error using the
standard carry flag/DH register mechanism, the iocb is
left in an indeterminant state (in particular the code
field and DONE bit should not be relied on), and any
requested upcall will not be made. However, if
as_send_pkt() detects an error later asynchronously, it
will return the error in the iocb code field, set the
DONE bit, and if requested, make an upcall. Successful
packet transmission is indicated by a code of zero.
The structure field iocb->reserved is for the purposes of
implementing a future scatter/gather capability. This
field must be set to zero.
The final field in the structure, iocb->private, is for
the private use of the packet driver. It will typically
be used to maintain a queue of iocbs. The application
must not reference or modify this field in any way. This
function was added in v1.10 of this specification, and
may not be implemented by all drivers (see
driver_info()).
6.17. drop_pkt() high-performance driver function
int drop_pkt(iocb)
AH 13
ES:DI struct iocb far* iocb
error return:
carry set
DH error code
possible errors:
BAD_COMMAND /* Level 0 or level 1 driver */
non-error return:
carry clear
Searches the as_send_pkt() asynchronous transmission
queue for the specified iocb, and if found, drops it from
the queue. To avoid race conditions, if the iocb is not
found no error is signaled. After return from drop_pkt(),
the calling application may consider the specified iocb
and buffer to be safely re-usable. This function provides
an application a way to implement any desired congestion
control algorithms (such as random drop).
Sets the receive mode on the interface associated with
handle. The following values are accepted for mode:
mode meaning
1 turn off receiver (no packets)
2 receive only packets sent to this interface's
station address
3 mode 2 plus broadcast destination address
4 mode 3 plus multicast addresses as set via
set_multicast_list()
5 mode 3 plus all multicast packets
6 all packets
7 raw mode (new in 1.10 for serial line only)
Note that not all interfaces support all modes. The
receive mode affects all packets received by this
interface, not just packets associated with the handle
argument. See the extended driver functions
get_multicast_list() and set_multicast_list() for
programming hardware hash filters to receive specific
multicast addresses.
Most drivers do not allow set_rcv_mode() if more than one
handle is open, to avoid confusing a stack with packets
it doesn't expect. If a driver does not return BAD_MODE
when more than one handle is open, it must maintain
separate receive modes on a per-handle basis, and filter
incoming traffic as appropriate to each handle's mode.
Note that mode 3 is the default, and if the
set_rcv_mode() function is not implemented, mode 3 is
assumed to be in force as long as any handles are open
(from the first access_type() to the last
release_type()).
The handle argument (which must have been obtained via
access_type()) is required on this function in order to
allow drivers to limit the effect of this function to the
handle specified. Accordingly, protocol stacks must not
depend on a change effecting all handles.
Returns the current receive mode of the interface
associated with handle.
6.20. set_multicast_list() extended driver function
set_multicast_list(addrlst, len)
AH 22
ES:DI char far* addrlst
CX len
error return:
carry set
DH error code
possible errors:
NO_MULTICAST
NO_SPACE
BAD_ADDRESS
non-error return:
carry clear
The addrlst argument is assumed to point to an len-byte
buffer containing a number of multicast addresses.
BAD_ADDRESS is returned if len modulo the size of an
address is not equal to 0, or the data is unacceptable
for some reason. NO_SPACE is returned (and no addresses
from the current list are set while any previously-set
addresses remain in effect) if there are more addresses
than the hardware or driver supports.
The recommended procedure for setting multicast addresses
is to issue a get_multicast_list(), copy the information
to a local buffer, add any addresses desired, and issue a
set_multicast_list(). This should be reversed when the
application exits. If the set_multicast_list() fails due
to NO_SPACE, use set_rcv_mode() to set mode 5 instead.
Note that most hardware multicast filters use hashing
techniques, and may pass addresses not specified in the
addrlst. For this reason, stacks using multicast must
check the destination MAC address if there is any chance
they'll become confused by a packet they weren't
expecting.
6.21. get_multicast_list() extended driver function
get_multicast_list()
AH 23
error return:
carry set
DH error code
possible errors:
NO_MULTICAST
NO_SPACE
non-error return:
carry clear
ES:DI char far* addrlst;
CX len
On a successful return, addrlst points to len bytes of
multicast addresses currently in use. The application
program must not modify this information in-place. A
NO_SPACE error indicates that there wasn't enough room
for all active multicast addresses.
struct statistics {
unsigned long packets_in; /* Totals across all
handles */
unsigned long packets_out;
unsigned long bytes_in; /* Including MAC headers */
unsigned long bytes_out;
unsigned long errors_in; /* Totals across all error
types */
unsigned long errors_out;
unsigned long packets_lost; /* No buffer from
receiver(), card */
/* out of resources, etc.
*/
};
Returns a pointer to a statistics structure for the
interface. The values are stored so as to be normal
80x86 32-bit integers. Stacks should assume that this
structure is dynamic, and copy it to local storage with
interrupts disabled. In earlier versions of this spec,
the handle argument (which must have been obtained via
access_type()) was required. It is now optional, but
drivers developed according to versions of this spec
previous to 1.10 may require it, so implementers should
take care.
6.23 set_address() extended driver function
set_address(addr, len)
AH 25
ES:DI char far* addr
CX len
error return:
carry set
DH error code
possible errors:
CANT_SET
BAD_ADDRESS
non-error return:
carry clear
CX length
This call is used when the application or protocol stack
needs to use a specific LAN address. For instance, DECnet
protocols on Ethernet encode the protocol address in the
Ethernet address, requiring that it be set when the
protocol stack is loaded. A BAD_ADDRESS error indicates
that the Packet Driver doesn't like the len (too short or
too long), or the data itself (a driver may refuse a
station address with the 'group' bit set, for instance).
Note that packet drivers should refuse to change the
address (with a CANT_SET error) if more than one handle
is open (lest it be changed out from under another
protocol stack).
possible errors:
BAD_MODE /* Not in raw mode */
BAD_COMMAND /* Not a serial line driver */
non-error return:
carry flag clear
Transmits the string of bytes in buffer for the given
count out the serial port. This routine does not return
until the last transmit interrupt for the last byte of
the string has been successfully processed. It is assumed
that the packet driver has been placed in raw mode before
the call is made. If not, a BAD_MODE error is returned.
6.25 flush_raw_bytes() extended driver function
flush_raw_bytes()
AH 27
error return:
carry set
DH error code
possible errors:
BAD_MODE /* Not in raw mode */
BAD_COMMAND /* Not a serial line driver */
non-error return:
carry clear
Flushes the receive ring buffer of any characters it may
have received. It is assumed that the packet driver has
been placed in raw mode before the call is made. If not,
a BAD_MODE error is returned.
Fetch bytes from the serial port until either the timeout
expires, or the specifed count of bytes has been
received. The timeout is measured in clock ticks
(~18/sec). It is assumed that the packet driver has been
placed in raw mode before the call is made. If not, a
BAD_MODE error is returned.
6.27. signal
int signal (signal_number, data)
AH 29
AL signal_number
= 1 REGISTER_UPCALL
= 2 UNREGISTER_UPCALL
= 3 THIS_LAYER_START
= 4 THIS_LAYER_FINISH
= 5 PHYSICAL_UP_EVENT
= 6 PHYSICAL_DOWN_EVENT
if AL = 1 or AL = 2, data is:
ES:DI int (far *signal_handler)();
error return:
carry set
DH error code
possible errors:
BAD_COMMAND /* The command is not implemented
*/
BAD_SIGNAL /* The signal is not
implemented */
if AL = 2
BAD_ARGUMENT /* The upcall was not registered */
non-error return:
carry clear
signal handler upcall:
(*signal_handler)(event)
AX event
= 1 THIS_LAYER_DOWN
= 2 THIS_LAYER_UP
No return value
The signal() call allows the client application to
register an upcall which can be used for signalling
events. This mechanism was designed to accomodate the
requirements of a PPP packet driver, however the
mechanism was also designed to be as generic as possible
so that it hopefully may be used for other as yet unknown
purposes in the future.
Before a client application can expect event signals from
the packet driver, the client application must register
its signal_handler() upcall with the packet driver. This
is accomplished by calling signal() with a signal_number
of REGISTER_UPCALL and also supplying the function
pointer of the signal_handler() upcall as the data. The
packet driver then records this upcall pointer in a table
and uses it to signal an event to the client application.
Before the client application exits, the client
application must unregister its signal_handler() upcall.
This is accomplished by calling signal() with a
signal_number of UNREGISTER_UPCALL and also supplying the
function pointer of the upcall as the data. If the upcall
is not unregistered, the packet driver may call the
unloaded routine with unpredictable results, (ie. the
machine will likely hang).
For the purposes of a PPP packet driver, this call allows
the NCP layers and the LCP layer to send signals to one
another. An NCP layer sends signals to the LCP layer by
calling signal(). The LCP layer sends signals to the NCP
layers by calling the signal_handler() upcall.
For the purposes of PPP, the NCP layers use the signal()
call to send the THIS_LAYER_START and THIS_LAYER_FINISH
signals to the LCP layer. The LCPlayer uses the
registered signal_handler upcall to send the
THIS_LAYER_UP and THIS_LAYER_DOWN signals to the NCP
layers.
In the case where the LCP layer is a standalone packet
driver seperate from the physical layer packet driver,
the LCP layer uses the signal() call to send the
THIS_LAYER_START and THIS_LAYER_FINISH signals to the
physical layer. The physical layer uses the registered
signal_handler upcall to send the THIS_LAYER_UP and
THIS_LAYER_DOWN signals to the LCP layer.
See the description of PPP (Class 16/18) under "Specific
Characteristics of Classes" for more detail.
Returns a pointer to the structure indicated in the
structure_type argument. The format of the structure
varies with the value of structure_type. Packet drivers
should implement the structures which are most relevant,
and must return BAD_ARGUMENT for any structure not
implemented.
The client application should assume that the structures
are dynamic, and copy them to local storage with
interrupts disabled.
7. Specific Characteristics of Classes
Packet Drivers have been developed for the following
media classes, and interpretations of demultiplexing
criteria, MTU etc. have stabilized. If you wish to
implement a Packet Driver for a class which isn't listed
below, you should contact FTP Software to make sure that
your interpretation
agrees with any other work we may be aware of.
7.1. DIX Ethernet (Class 1)
Class 1 is demultiplexed by the 'ethertype', a 16-bit
value (MSB first) transmitted as the thirteenth and
fourteenth bytes of a frame. typelen is normally 2. The
maximum length allowed by send_pkt() is 1514, 1500 bytes
of data preceded by the 14-byte MAC header (source
address, destination address, ethertype). The minimum
"look-ahead buffer" length allowed is 60 bytes. If the
typelen is 0, requesting promiscuous mode, the driver
should pass both Class 1 and Class 11 packets to the
protocol stack.
7.2. 802.5 Token Ring (Class 3)
Class 3 is demultiplexed according to the contents of the
IEEE 802.2 header which follows the 802.5 header in the
packet. typelen values may vary between 1 (for
demultiplexing on the Destination SAP only) and 8 (for
demultiplexing on a complete RFC 1042 header: SNAP, OUI
and 'ethertype'). In any comparison which, like RFC 1042,
includes the 802.2 'control' field, the driver must mask
the 'poll/final' bit in the 'control' byte prior to the
comparison.
On the wire, 802.5 headers are variable-length,
consisting of the 14-byte 802.5 MAC header, an optional
Routing Information Field (used by source-routing
bridges), and finally the variable-length 802.2 header.
Across the Packet Driver interface (in receiver() upcalls
and in calls to send_pkt()), the RIF remains unmodified
(unlike Class 17). The 802.2 header remains variable-
length.
If an application needs to determine if a RIF is actually
present in a received packet, it must examine the
RIF_present bit in the source MAC address (this occupies
the same location as the global bit in the destination
MAC address). If an application needs to send a RIF, the
'RIF length' and other components of the RIF must be
inserted between the MAC addresses and the 802.2 header.
The user is responsible for setting the RIF_present bit
in the source MAC address if necessary.
The MTU on 802.5 is variable, negotiated during the
initial exchange of RIFs. Several existing
implementations of IP over 802.5 require that the value
encoded in the RIF be 2052 bytes. The minimum "look-ahead
buffer" length allowed is 100 bytes.
7.3. Appletalk (Class 5)
Class 5 provides access to an ATALK.SYS driver, for
forwarding IP packets to and from an Internet Router on
an Appletalk net. As such, there is no demultiplexing
taking place within the Packet Driver, and typelen is 0.
No header is prefixed to the IP datagram on transmission.
The MTU is 568 bytes, derived from the underlying
Appletalk DDP service.
7.4. SLIP (Class 6)
SLIP as defined in RFC 1055 does not include any packet
demultiplexing information. Thus, type and typelen are
irrelevant, and all open handles receive the same
packets. Many implementations assume an MTU (not
including any byte-stuffing required to escape in-band
control characters found in the data stream) of 1006
bytes, but there are exceptions.
Note that the get_address() function is not applicable to
Class 6.
7.5. AX.25 Amateur Radio (Class 9)
The AX.25 frame structure looks like this (taken from
version 2.0 of the spec):
U and S frame:
First Bit Sent
Flag Address Control FCS Flag
01111110 112/560 Bits 8 Bits 16 Bits 01111110
Information frame:
Flag Address Control PID Info. FCS
Flag
01111110 112/560 Bits 8 Bits 8 Bits N*8 Bits 16 Bits
01111110
The Address field has a variable length because it is
used to hold the source and destination callsigns, and 0
to seven callsigns of radio stations which are used to
repeat the packet. The control field contains N(r) and
N(s), a poll/final bit, and some other stuff not relevant
to this discussion. The information field is an integral
number of octets long. AX.25 doesn't specify the MTU; my
driver will handle 2k. The FCS is CRC-16. The PID field
specifies the layer 3 protocol in use, such as AX.25
layer 3, IP, ARP, NET/ROM, etc.
Phil Karn's KA9Q implementation calls the packet driver
with typelen set to zero. It is proposed that the driver
should accept a pointer to a PID field with typelen set
to 1 byte, in the future.
Note that the get_address() function is not applicable to
Class 9.
7.6. 802.3 with 802.2 headers (Class 11)
Class 11 is demultiplexed according to the contents of
the IEEE 802.2 header which follows the 14-byte 802.3
header in the packet. typelen values may vary between 1
(for demultiplexing on the Destination SAP only) and 8
(for demultiplexing on a complete RFC 1042 header: SNAP,
OUI and 'ethertype'). The MTU is fixed at 1514 bytes, the
same as DIX ethernet, but because of the presence of the
802.2 header, the usable data length is at least 3 bytes
shorter. The minimum "look-ahead buffer" length allowed
is 60 bytes.
7.7. FDDI with 802.2 headers (Class 12)
Class 12 is demultiplexed according to the contents of
the IEEE 802.2 header which follows the FDDI header in
the packet. typelen values may vary between 1 (for
demultiplexing on the Destination SAP only) and 8 (for
demultiplexing on a complete RFC 1042 header: SNAP, OUI
and 'ethertype'). In any comparison which, like RFC 1042,
includes the 802.2 'control' field, the driver must mask
the 'poll/final' bit in the 'control' byte prior to the
comparison. The MTU is variable, The Packet Driver must
perform the bit-swap on all MAC addresses, because while
the bit order on the physical FDDI media matches 802.5,
the bit order handled by the protocol stacks is specified
as matching 802.3.
7.8. Internet X.25 (Class 13)
Class 13 is a special case: It is designed to allow X.25
to be used as a transport for IP and other datagrams.
Each packet of data sent by the protocol stack is
preceded by a protocol specific header; the first byte is
protocol type and the meaning of the rest of the header
varies with protocol type. IP's protocol type is 1, and
its header is defined as follows:
struct x25_pd_hdr {
unsigned char type; /* Type: 1 indicates IP
*/
unsigned char tos; /* IP Type Of Service value to use
*/
unsigned long dest; /* IP next hop address
*/
unsigned long src; /* IP Source address
*/
};
Header layouts specific to other protocol families will
be defined as the need arises. The typelen value passed
to access_type() is always 1, and the type pointer points
at a byte defining the protocol to be received; 1 for IP
as above. On receiver() upcalls, the header specified for
transmission is present, but only the type value is set.
The MTU is variable, depending on the configuration of
the attached network. The minimum "look-ahead buffer"
length is 40 bytes.
7.9. Northern Telecom LANSTAR encapsulating DIX (Class 14)
Class 14 is a "simulated ethernet" class, and the MTU,
demultiplexing and other characteristics are similar to
Class 1.
7.10. Point to Point Protocol MAC layer driver (Class 16)
Note: Class 16 drivers are obselete and should not be
used, with the exception for very special cases (such as
LANWatch). PC/TCP uses a class 18 driver to do PPP.
The MTU of a PPP link is determined at link startup
through the negotiation of the Maximum-Receive-Unit
(MRU). The MRU of the link is the size of the info field
of a PPP frame, and does not include the two byte
protocol field in the header. Thus, just as the MTU of an
ethernet frame is 1500 for the data area, plus 14 bytes
for the header, the MTU of a PPP link is equal to the
negotiated MRU plus 2 for its header.
Class 16 is demultiplexed based on the two byte protocol
field in the PPP frame header. The packet driver passes
to the protocol stack the PPP protocol field, followed by
the info field. The stack can examine this field to
determine the protocol type of the incoming packet.
In packets passed to send_packet, the protocol stack must
set an appropriate value in the PPP protocol field ahead
of the PPP info field. The packet driver will add the
flag, address, control, and FCS bytes as it sends the
packet.
During PPP frame reception, the flag, address, control,
and FCS bytes of a PPP frame are all consumed by the
packet driver before the packet is passed up to the
protocol stack.
During PPP frame reception, the total incoming length
cannot be determined at the time that only the PPP header
has been successfully parsed. The entire frame must be
received before the actual length can be determined.
Since for performance reasons it is preferable to receive
the incoming frame into a protocol stack buffer rather
than into a local buffer, the only recourse is to request
a full size buffer from the protocol stack just after the
frame header has been fully received, but before the info
field has been received.
The buffer size requested from the protocol stack would
be at least MRU+2 where the two extra bytes hold the two
byte protocol field. However, in order to simplify the
implementation of an async PPP packet driver, the size
requested must be MRU+4, which allows not only two bytes
for the protocol field, but also two more bytes to hold
the FCS field which occurs at the end of the frame. Once
the closing flag has been received, the length must be
decreased by 2 to adjust for the FCS field.
Thus a class 16 protocol stack must be capable of
supplying buffers which total MRU+4 bytes, so as to
accomodate the needs of an asynchronous PPP packet
driver.
7.11. 802.5 Token Ring w/expanded RIFs (Class 17)
Class 17 is demultiplexed in the same way as Class 3, and
has the same MTU and minimum "look-ahead buffer" length.
The significant difference is that across the Packet
Driver interface (in receiver() upcalls and in calls to
send_pkt()), the RIF is padded to its maximum size, 18
bytes, while the 802.2 header remains variable-length.
This was defined this way to streamline RIF handling in
protocol implementations where fixed buffer offsets are
used to increase performance.
If an application needs to determine if a RIF is actually
present in a received packet, it must examine the
RIF_present bit in the source MAC address (this occupies
the same location as the global bit in the destination
MAC address). If an application needs to send a RIF, the
'RIF length' and other components of the RIF must be
left-justified in the RIF area. Because it must perform
RIF expansion, send_pkt() is responsible for setting the
RIF_present bit in the source MAC address if necessary.
Note that the RIF expansion on received packets is
specified to take place during the data copy, so the
"look-ahead buffer" will contain a compressed RIF on the
AX == 0 receiver() upcall.
7.12. Point to Point Protocol with LLC layer (Class 18)
WARNING: The information presented on the class 18 packet
driver is a documentation of how FTP Software wrote it's
PPP16550 packet driver that shipped with PC/TCP version
3.0 and OnNet version 1.1. It is presented purely for
historical and/or compatibility reasons, and should be
implemented only when compatibility is desired with these
versions of software. Future drivers from FTP Software
will likely not utilize the class 18 packet driver for
PPP communications.
Note: Much of the text below assumes familiarity with
the PPP RFC's, notably RFCs 1548 and 1549.
Components
All class 18 packet drivers contain an LCP option
negotiation layer. This layer allows them to perform
common link level option negotiation on behalf of the
client applications. All NCP option negotiation layers
are provided by the client applications.
All class 18 packet drivers except type 1 contain a
physical link driver in addition to the LCP layer. The
class 18 type 1 packet driver contains an LCP layer but
no physical link level driver. The class 18 type 1 packet
driver instead relies on a class 16 packet driver to
supply the physical link driver functionality. The
purpose behind this arrangement is to avoid the
reimplementation of the LCP layer in each PPP packet
driver written.
Because there must be only one LCP entity but perhaps
multiple NCP entities, client applications which provide
network layer service such as IP/IPCP or IPX/IPXCP should
avoid including an LCP layer. Client applications should
rely on and share the services of this LCP equipped class
18 packet driver.
Packet Processing
PPP frames received are demultiplexed based on the two
byte protocol field found in the PPP header. Valid
protocol field values are defined in RFC1548. If the
sender used protocol field compression to reduce the
protocol field ot one byte, the field must be expanded
again to two bytes before demultiplexing.
The info field of the PPP frame contains the higher layer
protocol data. The length of the info field varies from
frame to frame, and is not indicated in the PPP frame
header. However the maximum length (called the MRU) is
negotiated at link startup using LCP packets and is
guaranteed not to change for the duration of the link, or
until LCP negotiation reoccurs. Thus, the MTU of the link
is determined by the LCP layer during option negotiation.
In packets passed to send_pkt(), the client application
must set an appropriate value in the PPP protocol field
ahead of the PPP info field. The packet driver will add
the flag, address, control and FCS bytes as it sends the
packet.
The packet driver passes to the client application the
PPP protocol field followed by the info field. The flag,
address, control and FCS bytes of a PPP frame are all
consumed by the packet driver before the packet is passed
up to the client application.
The FCS is verified by the physical link driver in the
packet driver. If the FCS is valid, the packet driver
passes the frame to the client application for
processing. The client application can examine the
protocol field to determine the protocol type of the
packet. If the FCS is invalid, the frame is discarded and
the packet driver returns the buffer to the client
application with a zero length.
During receiver() upcall processing, a client application
should be prepared to honor a request from the packet
driver for a packet size of up to MRU+4. The extra 4
bytes include 2 for the protocol field, and 2 for the FCS
field. Although the contents of the 2 byte FCS field will
not be interesting to the client application, the extra 2
bytes for the FCS are useful in implementing async byte-
oriented packet drivers. Because there is no length
field, a byte-oriented frame parser implemented in
software can only determine the position of the FCS field
once it has received the end-of-frame flag. Using the
default MRU size of 1500 bytes, the application should
allocate 1504-byte buffers. If the MTU is negotiated to
some size smaller or larger than 1500 bytes, then the
client application should take this alternate MTU value,
add 4 and use this number as the buffer size to offer the
packet driver.
Layer Signalling and Packet Type Registration
The RFC1548 PPP option negotiation automaton specifies
the following events for use in driving the negotiation
process: START, FINISH, UP, DOWN. Notification of these
events must be passed between the NCP and LCP layers (and
between the LCP and physical link driver layers, if they
are different drivers). The signal() call defined in this
spec is used to pass these indications between the TSR's
which implement the NCP, LCP, and physical link driver
layers.
At startup, the NCP layer and the network protocol layer
should not call access_type() in the packet driver to
hook their protocol types, but should make instead a call
to the LCP layer using signal() with a REGISTER_UPCALL
signal in order to register a signal_handler() upcall
with the LCP layer. It should then call signal() again
with a THIS_LAYER_START signal. Then it must wait for the
LCP layer to signal a THIS_LAYER_UP event via the
signal_handler() upcall. Once the THIS_LAYER_UP signal is
received, the NCP layer can hook its protocol type value
(ie. 0x8021 for IPCP) and begin negotiation with the
peer. Once the NCP has reached an OPENED state (see
RFC1331) the network layer can hook its protocol type
(ie. 0x0021 for IP) and begin passing packets.
If at any point the NCP layer receives a THIS_LAYER_DOWN
event from the LCP layer, the NCP layer must notify the
network layer, and both the NCP layer and the network
layer must unhook their protocol types using
release_type() until the LCP layer again signals a
THIS_LAYER_UP event.
When the NCP/network layer exits, it must unhook its
protocol types, signal a THIS_LAYER_FINISH event to the
LCP layer using the signal() call, and unregister the
signal_handler() using the signal() call with an
UNREGISTER_HANDLER signal.
When a class 18 packet driver starts up, it must be
prepared to begin negotiating LCP options regardless of
whether any client applications have or have not
registered a signal_handler(). As client applications
register signal_handler() upcalls and send
THIS_LAYER_START signals, the packet driver must save the
upcall routine pointers in a table. After registering a
signal upcall for a new client application in the table,
the packet driver should check the LCP layer current
state. If the LCP layer is currently in an OPENED state,
the packet driver should send a THIS_LAYER_UP signal to
the client application immediately before returning.
Each time the LCP layer transitions into an OPENED state,
it must traverse the table of registered signal_handler()
upcalls and send a THIS_LAYER_UP signal to each in
succession. Each time the LCP layer transitions out of an
OPENED state, it must traverse the table of registered
signal_handler() upcalls and send a THIS_LAYER_DOWN
signal to each in succession. This corresponds with the
PPP automaton table's tlu and tld events.
In order to simplify the implementation of the protocol-
reject mechanism defined in RFC1548, the LCP layer of the
class 18 to class 16 converter will call access_type()
with typelen of zero to receive packets with unregistered
protocol types. When the class 16 packet driver receives
a access_type() call with a typelen argument value of
zero, the receiver() upcall function must be passed every
subsequently received packet for which there is not a
registered protocol type receiver. The LCP layer in the
converter can then send protocol-reject frames in
response to packets with unrecognized protocols.
LCP Option Configuration
Before LCP layer option negotiation begins, the LCP layer
must be configured with a set of initial option
parameters. There may be a requirement that the values of
these parameters vary from one connection to the next.
The get_structure() call is used to retrieve a pointer to
a structure within the LCP layer in the class 18 packet
driver. Using this pointer, the client application can
copy the desired values into the LCP layer data space.
See Appendix E for structure layout.
After the LCP layer option negotiation completes, the LCP
layer must reconfigure the physical link driver with the
final negotiated values. The get_structure() call is used
to retrieve a pointer to the structure within the
physical link driver in the class 16 (or 18) packet
driver which holds the current operating values. The LCP
layer uses this pointer to copy in the new operating
values. See Appendix E for structure layout.
When the LCP layer transitions out of the OPENED state,
the LCP layer must reset the current operating values in
the physical link driver to the default values as
specified in RFC1548. The get_structure() call is used to
retrieve a pointer to the structure within the physical
link driver in the class 16 (or 18) packet driver which
holds the current operating values. The LCP layer uses
this pointer to copy in the default operating values. See
Appendix E for structure layout.
Appendix A. Interface classes and types
The following are defined as network interface classes,
with their individual types listed immediately following
the class.
Note: This class was consumed by the Ethernet class
(class 1).
Class 8 ArcNet
Datapoint RIM ...........................................1
Class 9 AX.25
Ottawa PI card ..........................................1
Eicon Technologies ......................................2
Class 10 KISS
Class 11 IEEE 802.3 w/802.2 hdrs
Types as given under Class 1 (DIX Ethernet)
Class 12 FDDI w/802.2 hdrs
Class 13 Internet X.25
Western Digital .........................................1
Frontier Technology .....................................2
Emerging Technologies ...................................3
The Software Forge ......................................4
Link Data Intelligent X.25 ..............................5
Eicon Technologies ......................................6
Class 14 N.T. LANSTAR (encapsulating DIX)
NT LANSTAR/8 ............................................1
NT LANSTAR/MC ...........................................2
Types as given under Class 3 (802.5 with verbatim RIFs)
Class 18 Point to Point Protocol (with LCP)
Class 16 to class 18 converter ..........................1
PC/TCP's PPP16550.COM ...................................2
Appendix B. Function call numbes
The following decimal numbers are used to specify which
operation the packet driver should perform. The number is
stored in register AH on call to the packet driver.
+ indicates a high-performance packet driver function
* indicates an extended packet driver function
AH values from 128 through 255 (0x80 through 0xFF) are
reserved for user-developed extensions to this
specification. While FTP Software cannot support user
extensions, we are willing to act as a clearing house for
information about them. For more information, contact us.
The following values have been allocated to the listed
organizations:
233 Crynwr Software autoselect transceiver
Appendix C. Error codes
Packet driver calls indicate error by setting the carry
flag on return. The error code is returned in register DH
(a register not used to pass values to functions must be
used to return the error code). The following error codes
are defined:
1 BAD_HANDLE Invalid handle number
2 NO_CLASS No interfaces of specified class found
3 NO_TYPE No interfaces of specified type found
4 NO_NUMBER No interfaces of specified number found
5 BAD_TYPE Bad packet type specified
6 NO_MULTICAST This interface does not support
multicast
7 CANT_TERMINATE This packet driver cannot terminate
8 BAD_MODE An invalid receiver mode was specified
9 NO_SPACE Operation failed because of insufficient
space
10 TYPE_INUSE The type had previously been accessed,
and not released
11 BAD_COMMAND The command was out of range, or not
implemented
12 CANT_SEND The packet couldn't be sent (usually
hardware error)
13 CANT_SET Hardware address couldn't be changed
(more than 1handle open)
14 BAD_ADDRESS Hardware address has bad length or
format
15 CANT_RESET Couldn't reset interface (more than 1
handle open)
Appendix D. 802.3 vs. Blue Book Ethernet
An issue concerning the present specification is that
there is no provision for simultaneous support of 802.3
and Blue Book (the old DEC-Intel-Xerox standard) Ethernet
headers via a single Packet Driver (as defined by its
interrupt). The problem is that the Ethertype of Blue
Book packets is in bytes 12 and 13 of the header, and in
802.3 the corresponding bytes are interpreted as a
length. In 802.3, the field which would appear to be most
useful to begin the type check in is the 802.2 header,
starting at byte 14. This is only a problem on Ethernet
and variants (e.g. Starlan), where 802.3 headers and Blue
Book headers are likely to need co-exist for many years
to come.
One solution is to redefine class 1 as Blue Book
Ethernet, and define a parallel class for 802.3 with
802.2 packet headers. This requires that a 2nd Packet
Driver (as defined by its interrupt) be implemented where
it is necessary to handle both kinds of packets, although
they could both be part of the same TSR module.
As of v1.07 of this specification, class 11 was assigned
to 802.3 using 802.2 headers, to implement the above.
Note: According to this scheme, an application wishing to
receive IP encapsulated with an 802.2 SNAP header and
Ethertype of 0x800, per RFC 1042, would specify an
typelen argument of 8, and type would point to:
Appendix E. Structure layout for get_structure call
The packet driver structures detailed below have been
created to allow a client application to access data held
within the packet driver in a generalized manner. Each
structure has a structure_type which serves as an
identifying tag. This tag is used in the get_structure()
call to specify the structure requested.
The following structure_types have been defined. The
corresponding structure layouts are also detailed.
STRUCT_IO_STATS 1
struct io_statistics {
unsigned long packets_in;
unsigned long packets_out;
unsigned long bytes_in;
unsigned long bytes_out;
unsigned long errors_in;
unsigned long errors_out;
unsigned long packets_lost;
};
STRUCT_LCP_INITIAL_CONFIG 2
struct lcp_options {
unsigned mru;
unsigned long int rcvaccm;
unsigned long int sndaccm;
unsigned long int magic;
unsigned char acfc;
unsigned char pfc;
unsigned authprot;
};
STRUCT_LCP_CURRENT_CONFIG 3
struct lcp_options {
unsigned mru;
unsigned mtu;
unsigned long int rcvaccm;
unsigned long int sndaccm;
unsigned long int magic;
unsigned char acfc;
unsigned char pfc;
unsigned authprot;
};
STRUCT_UART_STATS 11
struct uart_stats {
unsigned long int rcv_ints;
unsigned long int xmt_ints;
unsigned long int modem_ints;
unsigned long int line_ints;
unsigned long int fifo_ints;
unsigned xmt_tmo;
unsigned breaks;
unsigned framing;
unsigned parity;
unsigned overruns;
unsigned rb_overflow;
unsigned char modem_status;
};
STRUCT_HDLC_STATS 12
struct hdlc_stats {
unsigned long int mode1_bytes_rcvd;
unsigned long int mode6_bytes_rcvd;
unsigned long int mode7_bytes_rcvd;
unsigned over_mtu;
unsigned pkts_disc_no_bufs;
unsigned over_buffer;
unsigned max_len_pkt;
unsigned pkts_disc_no_lcp_bufs;