Modelling LAPD with the unix's socket layer has been quite challenging. The layer subdivision, addressing and transmission modes hardly map TCP/IP.
The Terminal Equipment Indentifier (TEI) stands somewhat between an IP address and a MAC-address, can change dynamically but is used on the link layer protocol, but it's neither (or both) a source address nor a destination address.
Sockets usually use different protocols to handle different modes of transmission, UDP and TCP are used to handle SOCK_DGRAM and SOCK_STREAM modes respectively. With LAPD, reliable and unreliable transmission of frames is just a mode of transmission inside the same data link connection.
What is as Data Link Connection? In q.921 terms a Data Link Connection (DLC) is a point-to-point connection between two Service Access Points (SAP) which, in turn, are logical endpoints for a particular service.
A DLC is identified through a tuple made of TEI and SAPI. This tuple is called DLCI.
I've decided that a good modeling would be to map sockets with DLCs in a one-to-one fashion. Each socket represent a DLC and vice-versa.
The lapd.ko kernel module provides a new AF_LAPD
address family to the userland.
An application whishing to communicate over the D-channel should create
a socket with the AF_LAPD address family:
socket(AF_LAPD, SOCK_DGRAM, sapi);
Currently, SOCK_DGRAM is the type to use,
SOCK_SEQPACKET would be more meaningful and may be the right
socket type in the future. Anyway, there will only be a single type.
The SAPI value should be sepcified in the socket(2)'s
protocol field. I'm still deciding if this is the right place
or a bind(2) call would be better.
The only available SAPI is number 0 which stands for q.931.
There is preliminary support for x.25 SAPI, but still in developement.
After being bound to an interface, the socket inherits its role (network or user) from it and it starts working accordingly.
The next step is to configure all the needed socket parameters and finally
bind the socket to an interface with setsockopt(3).
Binding to an interface is mandatory as all the addressing has just local
meaning to an interface.
From now on, we will describe sockets usage in network role and in user role separately since the usage itself becomes quite different.
Only a single socket may be bound to an interface running in network mode at the same time. Attempting to bind a second socket will result in EBUSY.
The socket bound to a network mode interface will act as a master socket
similarly to a listening, TCP/IP based socket. It should be put in listening
mode by calling accept(2) on it.
You may subsequently start a select/accept loop in which each
accept(2) return a socket associated with any new DLC
discovered. Unlike TCP, there is no actual protocol to establish/release a
DLC therefore a successful accept(2) is not the result of any
transaction between enpoints. It is instead the result of a simple
algorithm:
When LAPD code receives a frame and notices it doesn't belong to any socket, a new socket is created and associated to that new DLC, the master socket is notified and the user may accept that new socket. socket closure is yet to be designed, it will probably be based on a timeout
[TODO]
When an interface acting in the network role is brought up, a TEI management entity gets bound to that interface and is immediately ready to manage TEIs, without the need of a user-mode application. Active TEI assignments are not lost when the user application is restarted.
Socket usage in user mode is simpler than in NT mode. A user just needs to bind the socket and transmit/receive on it via recvmsg/sendmsg,
[TODO]
The vISDN LAPD stack supports multiple TEI management entities on the same TE interface. An user my decide to create a new TEI management entity every time he binds the socket to an interface or re-use another TEI management entity. Of corse, two distinct sockets may not use the same TEI management entity and the SAPI at the same time.