|
Device Drivers (Deprecated)
Introduction
Writing SS7 device drivers is similar to writing device drivers for serial
device drivers for WAN IP interfaces. Many of the facilities of the SS7
interface are borrowed from the Linux IP NET4 distribution by Alan Cox, et al.
Some of these facilities are as follows:
- the device structure,
struct device ;
- the device notifier,
- the packet scheduler,
- the packet filter and packet socket,
- the netdevice register,
- socket buffers,
General Notes
For an example of how to use the facilities of the SS7/LINK ss7 signalling
link interface facility, see acb56.c in drivers/net
(or here). The file acb56.c is a complete working example of a
serial interface card implementation to this driver interface for the Sealevel
ACB56 card.
You must use the struct device structure from
include/linux/netdevice.h in the kernel sources. This device
structure is shared by IP and SS7.
Registration and Deregistration of SS7 Devices
There are three ways to register a device as an SS7 interface and attach a
level 2 SS7 link state machine to a device (in order of preference):
Fill out your device structure wtih all the necessary interface service
routines (as per IP) and set the dev->type to
ARPHRD_SS7, and then register the device with
register_netdevice(). The netdevice notifier will invoke the
attach automagically via the ss7mtp module.
This is the preferred method because the netdevice notifier is for
notification of other changes to the SS7/MTP protocol layer. In
particular, it has the ability to be extended to provide notification of
card insertion and removal events for cPCI, and is consistent with the
approach used for IP network devices.
Fill out your device structure with all necessary interface service
routines (as per IP) and call the exported ss7if_attach()
routine from the ss7link module.
This is a BSD-like approach and is preferrable for device drivers which
are attempting to maintain consistency with future BSD implementations of
OpenSS7.
Fill out an ss7if_regs structure with the interface
service routines which would normally be in the device structure and call
ss7if_register() from the ss7link module with a
master device and the register structure.
This approach is particularly useful for multichannel devices which do not
require or maintain a full device structure per channel.
There are only two ways to detach from an SS7 interface and undo what was done
during the attach:
Deregister the device with the unregister_netdevice() which
will automagically detach (from the destructor of the device structure
which was set by the attach operation).
Call either ss7if_unregister() or ss7if_detach()
(which are really the same function call).
NOTE: devices should be closed with dev_close() before calling
unregister_netdevice(). dev_close() should not be
called on an operating signalling link (you'll get lots of error messages, but
the device will close and unregister correctly).
Driver Service Routines
As shown in Figure 1, below, the SS7 LINK interface attaches itself
between the struct device provided or allocated for the device
driver and the device driver itself. The device driver's private interface
service routines are saved in the struct ss7if_regs structure in
the SS7 LINK state machine and used to invoke the driver. The SS7 MTP or
SCCP protocol layers communicate to the SS7 LINK interface through the
replaced device service routines.
Figure 1 - Interface Service Routines
Pertinent driver service routines are those routines which are normally
completed against the struct device structure as follows:
destructor() |
The device driver can have a private destructor service routine. The SS7 LINK
interface will interpose its own destructor service routine which is used by
unregister_netdev to automagically detach the SS7 LINK interface
from the driver. This also results in a call to the driver's private
destructor function (if any).
|
open() |
The device driver provides its own open service routine. The SS7 LINK
interface will interpose its own open service routine which will initialize
the L2 state machines associated with the driver.
|
stop() |
The device driver provides its own close service routine. The SS7 LINK
interface will interpose its own close service routine which will gracefully
shut-down the SS7 LINK state machines associated with the driver before
calling the driver's private close service routine.
|
hard_start_xmit() |
The device driver must provide a hard start transmit service routine. This
service routine must follow the behavior specified later under Transmit
Interrupt Service Routine. The SS7 LINK interface interposes its own hard
start transmit service routine which is responsible for queuing and processing
frames and service primitives for processing in the L2 state machine. Only
when the L2 state machine deems it necessary to transmit a frame does it call
the device's private hard start transmit service routine.
|
do_ioctl() |
The device driver may (if necessary) provide its own ioctl service routine.
The SS7 LINK interface interposes its own ioctl service routine which is used
to control characteristics and attributes of the SS7 LINK state machines;
however, this interface will call the device private ioct service routine for
all device private ioctls within the private range.
|
get_stats() |
The device driver should (if possible) provide its own statistics service
routine. The SS7 LINK interposes its own statistics service routine which is
responsible for gathering statistics collected by the SS7 LINK state machines
on L2 operation. This interposed routine; however, calls the device driver
private routine to collect information which is not possible to collect in the
L2 state machines (such as compressed FISUs, repeated FISUs, types of errors,
etc).
|
The SS7 LINK interface interposes its own driver service routines by replacing
the service routines in the device's struct device structure and
saving the device drivers private service routines in an interface
registration structure (struct ss7if_regs ) at the time of
registration or attachment. At the time that the driver is deregistered or
detached from the SS7 LINK interface, these driver service routines are
reinstated back into the device driver's struct device structure
and the internal registration structure and associated link state machine
structures are freed.
Receive Interrupt Service Routine Interface
When delivering received packets in the driver, the driver should not call
netif_rx() as it would in the IP case, but, instead, should call
ss7if_rx() so that the SS7 L2 state machine has a crack at the
packet. Failing to do so will result in erroneous operation.
ss7if_rx() processes each frame through the L2 state machines
which is part of the ss7link module, before ultimately delivering
each packet up using the actual netif_rx() call.
Please see the acb56.c file in drivers/net for more
detail.
Rx ISR API
Following is the Rx ISR API to the SS7 LINK state machines. There are four
functions which must be called in different circumstances and have different
behaviors which must be followed in the driver. These are a diversion from
the calls which one would normally see in an IP WAN driver. To summarize,
they are:
ss7if_rx() | |
Called with an sk_buff when the driver has a valid received
frame. A valid received frame is a frame which was received without error
and is between 3 and dev->mtu in length and has a valid
length indicator in the frame. If the driver is in octet counting
mode, it must stop octet counting.
The sk_buff must have skb->dev,
skb->protocol, skb->pkt_type and
skb->protocol appropriately set. That is,
skb->dev is set to the device structure of the receiving
device, skb->protocol is set to AF_SS7,
skb->pkt_type is set to ETH_P_SS7, and
skb->priority is set to TC_PRIO_BESTEFFORT.
|
ss7if_los() | |
Called with the device pointer when the driver loses flag syncrhonization
on the line. The driver must enter octet counting mode after
sending this indication.
|
ss7if_err() | |
Called with the device pointer when the driver detects frame-related error
such as an abort, residue error, framing error, CRC error. The driver
must enter octet counting mode after sending this indication.
|
ss7if_oct() | |
Called wtih the device pointer when the driver is in octet counting
mode. It must be called every 16 octet times (128 bit times) when
the driver is in octet counting mode.
|
ss7if_rpt() | |
Called with the device pointer when the driver receives a repeat of the
last received FISU or LSSU (while not in octet counting mode).
This is used because the driver has extremely critical timings while the
line is idling FISUs or LSSUs. The state machine does not do its own
FISU/LSSU compression, it must be done in the driver.
|
All in all, these calls to the SS7 interface are sufficient to meet the
requirements of the SS7 Level 2 driver interface and provide full SS7 Level 2
capabilities.
The driver receivers can be in one of three states as illustrated in
Figure 2, below. The driver receiver must move throught the
proscribed states in the proscribed manner for the SS7 L2 state machines to
operate correctly.
Figure 2 - Receiver State Diagram
The receivers can be in one of three modes as illustrated in Figure
2 above, and described as follows:
Normal Mode
In this state, the receivers are synchronized on frames and unique frames are
being received. This is the normal situation which corresponds to the state
of the receivers in most IP WAN drivers. This is also the power-on reset
state of the driver receivers.
Whenever a correct MSU is received (as contrasted with a FISU or LSSU), the
ss7if_rx() interface method is called with the received frame and
the receivers stay in the normal mode. Whenever a correct FISU or LSSU is
received, the driver calls ss7if_rx() with the received frame and
moves to the compression mode. Whenever an erroneous frame (aborted frame,
frame with residual bits, frames greater than SS7_MTU in length, frames with
erroneous length indicators) or a loss of synchronization wtih flags occurs,
the receiver calls ss7if_err() or ss7if_los() and
moves to the octet counting mode state.
Compression Mode
In this state, a FISU or LSSU has been received and the receiver is
compressing repeating occurences of identical FISU or LSSU frames.
One of the reasons for requiring the driver to peform this function is that
the overhead associated with compressing repeating FISUs or LSSUs can be most
efficiently achieved from within the Rx ISR itself, rather than in the SS7
interface L2 state machines.
For example, the acb56.c driver keeps an sk_buff as
a compression buffer and compares the 3 to 5 bytes of the previously received
FISU or LSSU with the currently received FISU or LSSU to determine whether to
call ss7if_rx() with the received frame or
ss7if_rpt() and discard the frame.
Whenever a correct MSU is received, the driver calls ss7if_rx()
with the received frame and moves to the normal mode. Whenever a correct FISU
or LSSU is received, the driver calls ss7if_rx() with the
received frame and moves to the compression mode. When no correct SU has been
received, the driver calls ss7if_oct() every 16 octet times (or
128 line rate bit times).
Octet Counting Mode
In this state, the receivers have lost synchronization with flags and are
generating an erroneous SU indication to the L2 state machines every 16 octets
(or 128 bit times) at the line rate.
One of the major reasons for requiring the driver to perform this function is
the lack of a sub-millisecond timing reference in the Linux kernel. Most
device drivers are capable of generating a higher precision interrupt which is
used to generate the erroneous SU indications to the L2 state machines when in
this mode. Furthermore, some chips support octet counting mode
directly.
For example, the acb56.c driver sets an interrupt which is based
on the Baud Rate Generator in the Z80530 which generates an interrupt every
bit time at 56 kbps. The ISR for this interrupt counts the bits until 128
bit times have been accumulated and then calls the ss7if_oct()
interface method while in octet counting mode. When not in octet
counting mode the driver does not request that the chip generate the
interrupt (to reduce ISR overheads).
Whenever a correct and duplicate FISU or LSSU is received, the driver calls
ss7if_rpt() and discards the repeated frame and stays in the
compression mode. Whenever a correct and unique FISU or LSSU is received, the driver
calls ss7if_rx() with the received frame and stays in the
compression mode. Whenever a correct MSU is received, the driver calls
ss7if_rx() with the received frame and moves to the normal mode.
Whenever an erroneous frame (see above) or loss of synchronization with flags
occurs, the driver calls ss7if_err() or ss7if_los()
and moves to the octet counting mode.
Transmit Interrupt Service Routine Interface
When transmitting packets provided to the driver for transmission using the
driver's hard_start_xmit() driver service routine, the driver
must behave somewhat differently that for normal IP WAN operation. This is
because the transmitters in SS7 are always busy and must idle FISUs or repeat
LSSUs as required to fill times when there are no packets available for
transmission.
All retransmissions are handled within the L2 state machines and MSUs which
are to be retransmitted are provided to the driver using the driver's
hard_start_xmit() routine in the same manner that new frames for
transmission are provided (in an sk_buff with the level 2 header
already provided).
Tx ISR API
The interface to the tranmitters in the device driver is the driver's
hard_start_xmit() driver method which the device driver filled
into the struct device structure at registration with the SS7
LINK interface. This is the method that the SS7 LINK interface uses to send
frames for transmission to the device driver.
When an new or retransmitted SU is available for transmission or
retransmission, the SS7 LINK interface will call the device driver's
hard_start_xmit() driver service routine with an
sk_buff which contains the frame for transmission. The driver
should queue the frame (if possible) and return the depth of the driver's
queue. The SS7 LINK interface should not let this queue depth increase beyond
1; however, for short sequences, the SS7 LINK interface may send 2 or 3 frames
win rapid succession.
When the transmitters are available to transmit a new frame (at the completion
of the previous frame which was transmitted), the driver should check the
internal queue to see if there are new frames for transmission. If there are
no frames for transmission, the transmitter behaviour depends on the previous
frame which was transmitted, as illustrated in Figure 3 below.
Figure 3 - Transmitter State Diagram
The behavior of the transmitters in the driver are dependent upon the last
transmitted frame as illustrated in Figure 3 above, and described as
follows:
- No frame previously transmitted: power-on situation.
-
In this situation, and this situation only, the transmitters are permitted to
idle mark or flags depending upon the implementation. At the first receipt
of a frame for transmission (normally LSSU SIOS) the transmitters must start
generating flags and transmit the frame, moving to one of the non-reset
states.
- Previous frame was an MSU (Message Signal Unit).
-
If the previous frame transmitted was an MSU and there are no frames for
transmission, a FISU is generated using the
BSN/BIB and
FSN/FIB of the last transmitted MSU and the FISU is transmitted
(moving to the Transmit FISU state). If a frame is available for
transmission, that frame is transmitted and the appropriate state entered.
- Previous frame was a FISU (Fill In Signal Unit).
-
If the previous frame transmitted was a FISU and there are no frames for
transmission, the FISU is simply repeated. If a frame is available for
transmission, that frame is transmitted and the appropriate state entered.
- Previous frame was an LSSU (Link Status Signal Unit).
-
If the previous frame transmitted was an LSSU (and not a SIB) and there are no
frames for transmission, that LSSU (not a SIB) is simply repeated. If the
previous frame transmitted was an LSSU (and a SIB) and there are no frames for
transmission, a FISU is generated using the
BSN/BIB and
FSN/FIB of the last transmitted SIB and the FISU is transmitted
(moving to the Transmit FISU state). If a frame is available for
transmission, that frame is transmitted and the appropriate state entered.
With this approach, it is possible for the SS7 LINK interface and state
machines to interface to the driver through the single
hard_start_xmit() function.
Summary
The SS7 LINK interface provides a simple and straightforward mechanism for
attaching an SS7 L2 state machine onto a device driver and providing and
interface mechanism which permits the simplified design of an SS7 LINK device
driver. This design permits a simple and straightforward DAEDR and DEADT
implemenation in the device driver, without the driver having to worry about
the other details of the SS7 LINK state machine.
The writing of SS7 LINK device drivers is somewhat different from the
development of IP WAN drivers for synchronous serial interfaces, because of
the need to peform octet counting mode and SU Compression
capabilities in the receiver and FISU/LSSU Idling capabilities in the
transmitter; however, these mechanisms are simple and straightforward to
implement.
For an example implementation of a synchronous serial SS7 LINK interface
driver, see the Sealevel ACB56 driver in acb56.c in the
drivers/net directory.
|