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