Hook-based callback function extensions for SANA-II (SANA-IIR5)
by Olaf Barthel and Heinz Wrobel
The last changes proposed for the SANA-II networking driver standard were intended to address the demands of dial-up networking. A new issue has come up which concerns the application and deployment of PowerPC native networking drivers. So far the SANA-II standard only caters well for the Motorola 68000 platform, and the only way to support it on the PowerPC involves a considerable overhead. This is what the following proposal intends to address.
Please feel free to comment; you can contact me through the e-mail address given in the headline of this document. Note that the issues discussed in this document are just a list of proposed changes.
The SANA-II driver interface is intended to transform data between the hardware layer and the link layer, to be used by networking software such as TCP/IP stacks. This transformation is performed by call-back functions which are supplied by the networking software at the time the device driver is opened. The device driver then invokes these functions later in order to transfer data received and data to be sent.
These copying functions are designed for low overhead. They use up to three
parameters and are documented in the copybuff.doc file which comes with
the SANA-II specification. Here is an excerpt which describes the
CopyFromBuff function, which is associated with the S2_CopyFromBuff
tag:
any_sana2_protocol/CopyFromBuff any_sana2_protocol/CopyFromBuff
NAME
CopyFromBuff -- Copy n bytes from an abstract data structure.
SYNOPSIS
success = CopyFromBuff(to, from, n)
d0 a0 a1 d0
BOOL CopyToBuff(VOID *, VOID *, ULONG);
FUNCTION
This function copies 'n' bytes of data in the abstract data structure
pointed to by 'from' into the contigous memory pointed to by 'to'.
'to' must contain at least 'n' bytes of usable memory or innocent
memory will be overwritten.
INPUTS
to - pointer to contiguous memory to copy to.
from - pointer to abstract structure to copy from.
n - number of bytes to copy.
RESULT
success - TRUE if operation was successful, else FALSE.
NOTES
This function must be callable from interupts. In particular, this
means that this function may not directly or indirectly call any
system memory functions (since those functions rely on Forbid() to
protect themselves) and that you must not compile this function
with stack checking enabled. See the RKM:Libraries Exec:Interupts
chapter for more details on what is legal in a routine called from
an interupt handler.
'C' programmers should not compile with stack checking (option '-v'
in SAS) and should geta4() or __saveds.
As one can see, the function parameters are passed in 68000 registers.
Compare this to the packet filter function, which is associated with the
S2_PacketFilter tag: it is intended to be invoked as a hook function, as
part of the Hook interface in utility.library/CallHookPkt.
The problem with 68000 register parameters is that on the PowerPC platform, this form of parameter passing may require the use of emulation code. This is costly and may incur a severe performance penalty. It is an even greater problem if PowerPC native networking software is calling PowerPC native networking driver software and the other way round. In both cases the runtime environment will have to enter emulation mode, return to to PowerPC native execution, dip into emulation mode and return to native PowerPC execution. It would be much better if the chain of execution would stay in PowerPC mode all the time.
However, if a hook function is used (such as for the packet filter), the
operating system may be able to decide whether the function to be invoked
needs emulating or could be called straight away. The Hook effectively
works as an abstraction which makes the function invocation platform
independent.
The following proposal therefore intends to wrap the copying functions into
the standardized Hook interface.
The SANA-IIR4 proposal lists ten copying functions, which can be grouped into two categories: data copying and direct memory access. These functions are:
S2_CopyToBuff
S2_CopyFromBuff
S2_CopyToBuff16
S2_CopyFromBuff16
S2_CopyToBuff32
S2_CopyFromBuff32
S2_DMACopyToBuff32
S2_DMACopyFromBuff32
S2_DMACopyToBuff64
S2_DMACopyFromBuff64
There are three 'flavours' of the data copying functions. These cater for certain buffer memory alignment requirements which the underlying hardware requires or which can be used to boost transfer efficiency. For the direct memory access functions there are two variants which cater for certain memory alignment requirements in the same manner as the copying functions.
All these functions are using basically the same set of parameters and
68000 registers. The parameters and result codes are used for different
purposes, though. In order to translate the parameters for use with the
Hook interface one needs to define a 'hook message' and a set of parameters
the hook function is invoked with.
I propose the following hook messages to be used :
struct SANA2HookMsg
{
ULONG shm_Method;
ULONG shm_MsgSize;
};
In this data structure the shm_Method field would indicate the task to
be performed. This can a be request to copy data or to store a log message.
The shm_MsgSize field tells you how large the data structure is (for future
enhancements which may cause the data structure to grow).
For copying operations the message would look like this:
struct SANA2CopyHookMsg
{
ULONG schm_Method;
ULONG schm_MsgSize;
APTR schm_To;
APTR schm_From;
ULONG schm_Size;
};
The structure members would be used as follows:
schm_Method
This must be one S2_CopyToBuff, S2_CopyFromBuff, S2_CopyToBuff16,
S2_CopyFromBuff16, S2_CopyToBuff32, S2_CopyFromBuff32,
S2_DMACopyToBuff32, S2_DMACopyFromBuff32, S2_DMACopyToBuff64
or S2_DMACopyFromBuff64 to identify the function to be performed.
schm_MsgSize
Size of this message data structure in bytes. This must be >= 20 for this message type.
The driver shall set schm_MsgSize always correctly to be compliant.
The protocol stack shall use this field to validate the message and
to reject/ignore bad messages via a FALSE hook function return value.
For DMA related hooks, a FALSE return value is equivalent to a NULL
pointer.
schm_To
Equivalent to the to parameter of the CopyFromBuff, CopyToBuff
and DMACopyToBuff functions.
schm_From
Equivalent to the from parameter of the CopyFromBuff and CopyToBuff
functions.
schm_Size
Equivalent to the n parameter of the CopyFromBuff, CopyToBuff,
functions.
For logging operations the message would look like this:
struct SANA2LogHookMsg
{
ULONG slhm_Method;
ULONG slhm_MsgSize;
ULONG slhm_Priority;
STRPTR slhm_Name;
STRPTR slhm_Message;
};
The structure members would be used as follows:
slhm_Method
This must be S2_Log, as defined in the SANA-IIR4 specification.
slhm_MsgSize
Size of this message data structure in bytes. This must be >= 20 for this message type.
The driver shall set slhm_MsgSize always correctly to be compliant.
The protocol stack shall use this field to validate the message and
to reject/ignore bad messages via a FALSE hook function return value.
For DMA related hooks, a FALSE return value is equivalent to a NULL
pointer.
slhm_Priority
The smaller this value, the more important the message to be logged or displayed. The following priority levels are defined (similar to the Unix syslog() mechanism):
#define S2LOG_Emergency 0
A panic condition.
#define S2LOG_Alert 1
A condition that should be corrected immediately.
#define S2LOG_Critical 2
Critical conditions.
#define S2LOG_Error 3
A plain error.
#define S2LOG_Warning 4
A warning message.
#define S2LOG_Notice 5
Conditions that are not error conditions, but should possibly be handled specially.
#define S2LOG_Information 6
An informational message.
#define S2LOG_Debug 7
Messages that contain information normally of use only when debugging.
Only these priority values may be used by a driver. It is suggested
that a driver is configurable to generate different types of messages
or not, e.g., a driver may be configured to only emit S2LOG_Emergency
and S2LOG_Debug messages.
slhm_Name
Pointer to a NUL-terminated string which identifies the source of this
message. This can be NULL in which case the OS device name of the driver
shall be used by the protocol stack.
slhm_Message
Pointer to a NUL-terminated string which contains the log message. The
text should not contain any formatting characters such as line feeds
or carriage returns. The slhm_Message member must never be NULL.
All message texts shall preferrably be formatted in the current user's
locale. If that is not possible, the english language shall be used.
slhm_Name and slhm_Message shall only contain printable characters.
The hook function itself would be invoked with the following parameters:
result = hook_function(hook,sana2req,sana2hookmsg)
D0 A0 A2 A1
ULONG hook_function(struct Hook *hook,
struct IOSana2Req *sana2req,
struct SANA2HookMsg *sana2hookmsg);
Note that the result would not necessarily be of type ULONG. It would be
a 32 bit value, which would either be a boolean result code (for
CopyFromBuff, CopyToBuff and their like) or the pointer to a memory address
(for DMACopyToBuff, DMACopyFromBuff and their like).
The 'traditional' copy call-back functions are installed at OpenDevice() time,
and they are found in a TagItem list which is passed along with the
IOSana2Req. For the new Hook-based call-back functionality, I propose to
introduce a new command. This command would take care of installing one single
Hook which will be invoked with the parameters described in section 3.1. The
hook function can key off the SANA2HookMsg->schm_Method field to figure out
which function should be performed. Once the Hook is installed via the command
as follows, the driver shall ignore any and all tags passed to it during
OpenDevice() time.
The command is tentatively defined as follows:
sana2.device/S2_SANA2HOOK sana2.device/S2_SANA2HOOK
NAME
S2_SANA2HOOK -- Install a Hook to perform operations such as copying,
overriding the call-back functions installed at
OpenDevice() time.
FUNCTION
The S2_SANA2HOOK command is to replace the 'traditional' call-back
functions installed through the TagItem list found in the
IOSana2Req->ios2_BufferManagement field. Instead of assigning a
function pointer for each copying function, all operations are
to be performed through a Hook. This is intended to make the
interface more portable and less dependant on a certain hardware
architecture.
The hook message and the hook data structures allow for more than
copying to be done.
IO REQUEST
ios2_Command - S2_SANA2HOOK
ios2_Data - Points to a struct Sana2Hook, which looks
like this:
struct Sana2Hook
{
struct Hook s2h_Hook;
Tag * s2h_Methods;
};
The structure fields have the following purposes:
s2h_Hook
A standard Hook structure, ready to be
called. Once installed, the complete Hook
structure including its Node structure is
off limits! The s2h_Hook remains installed
until CloseDevice().
s2h_Methods
Points to a table of Tag values, each
identifying a copy method supported
(S2_CopyToBuff, S2_CopyFromBuff,
S2_CopyToBuff16, S2_CopyFromBuff16,
S2_CopyToBuff32, S2_CopyFromBuff32,
S2_DMACopyToBuff32, S2_DMACopyFromBuff32,
S2_DMACopyToBuff64 or S2_DMACopyFromBuff64)
or the logging facility (S2_Log).
The table must be terminated by TAG_END.
The driver will check the table and
verify that the mandatory S2_CopyToBuff
and S2_CopyFromBuff commands are present.
Additional functionality is used as
available if the driver supports it.
ios2_DataLength - Must be >= 20, which is the default length of
the Sana2Hook structure. This may grow in
the future, and larger values for ios2_DataLength
may indicate additional functionality associated
with the Sana2Hook.
RESULTS
ios2_Error - IOERR_NOCMD if this command is not supported
by the driver.
IOERR_BADLENGTH if IOSana2Req->ios2_DataLength
is < 20.
IOERR_UNITBUSY if the Hook was already
installed or if any of the CMD_READ, CMD_WRITE,
S2_MULTICAST or S2_BROADCAST have already been
invoked.
S2WERR_FUNCTIONS_MISSING if the table pointed
to by Sana2Hook->s2h_Methods does not
include the S2_CopyToBuff and S2_CopyFromBuff
tags.
NOTES
The S2_SANA2HOOK command shall be invoked right after OpenDevice()
as very first command.
When the command has been executed, the driver must use the
newly installed Hook for all its copying or logging and cease to
use the call-back functions provided at OpenDevice() time.
The contents of the Sana2Hook structure, as passed to the
driver, must not be modified. This includes the MinNode
at the beginning of the Hook structure which the driver may
need to use for its own purposes.
The table pointed to by Sana2Hook->s2h_Methods must
include at least the S2_CopyToBuff and S2_CopyFromBuff tags.
It must be valid until CloseDevice() is called.
This field is to be treated as private by a protocol stack.
IOSana2Req structures may be duplicated by copying
ios2_BufferManagement, io_Device, and io_Unit.
The new command value is defined as follows:
#define S2_SANA2HOOK 0xC008
The new error code is defined as follows:
#define S2WERR_FUNCTIONS_MISSING 24 /* mandatory copy functions are missing */
Since plenty of software exists which uses the 'traditional' TagItem list
provided at OpenDevice() time it is recommend that drivers always examine
these parameters and do not expect a S2_SANA2HOOK command to be sent later.
If the new Hook-based callback functions are to be used, then the driver must
invoke the Hooks via utility.library/CallHookPkt. It must not invoke the hook
functions through local assembly language stubs or the amiga.lib/CallHook and
amiga.lib/CallHookA functions.
The functionality proposed above suggests that one could do entirely without
the TagItem list passed in at OpenDevice() time. However, at this time it is
hard to tell how existing driver software will react to empty TagItem lists
or even a NULL pointer in the IOSana2Req->ios2_BufferManagement field. It
is therefore recommend to always provide for a TagItem list which includes
proper (i.e. they must point to working functions and may not be NULL) function
pointers for the S2_CopyToBuff and S2_CopyFromBuff tags. Once the device
has been opened successfully, the next step is to try and install the copy
Hook through the proposed S2_SANA2HOOK command. If the command fails, the
application can still expect that the S2_CopyToBuff and S2_CopyFromBuff tags
supplied at OpenDevice() time will work.
Note that the ios2_BufferManagement field provided by the driver on
OpenDevice() time in conjunction with io_Device and io_Unit is the unique
identifier for all requests coming from this protocol stack until
CloseDevice(). The driver must not ever change the ios2_BufferManagement field
for a protocol stack at run time, even if S2_SANAHOOK is called to request
extended features.
22-Mar-2004:
21-Jan-2004:
schm_MsgSize, slhm_MsgSize, slhm_Priority,
slhm_Name, slhm_Message and s2h_Hook.
S2_SANA2HOOK documentation.
30-Nov-2003:
Hook to logging.
S2_COPYHOOK to S2_SANA2HOOK, which matches the extended
scope it should cover.
Hook now includes a size field which
holds the size of the message, expressed in bytes.
06-Oct-2003:
Hook, which
is installed through a new command.
TagItem
(sections 3.2.1 through 3.2.10)