Linux Native Device Drivers (Deprecated)
Description: OpenSS7 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.