LAPD implementation common part

## Files

file | lapd_core.h
file | lapd_core.c

## Data Structures

struct | mdl_error_ind_param
| for MDL-ERROR.ind More...
struct | dl_rel_req_param
| for DL-REL.req More...
struct | osmo_dlsap_prim
| primitive header for LAPD DL-SAP primitives More...
struct | lapd_msg_ctx
| LAPD message context. More...
struct | lapd_cr_ent
struct | lapd_history
struct | lapd_datalink
| LAPD datalink. More...
struct | l2downstate

## Macros

#define | MDL_CAUSE_T200_EXPIRED 0x01
#define | MDL_CAUSE_REEST_REQ 0x02
#define | MDL_CAUSE_UNSOL_UA_RESP 0x03
#define | MDL_CAUSE_UNSOL_DM_RESP 0x04
#define | MDL_CAUSE_UNSOL_DM_RESP_MF 0x05
#define | MDL_CAUSE_UNSOL_SPRV_RESP 0x06
#define | MDL_CAUSE_SEQ_ERR 0x07
#define | MDL_CAUSE_UFRM_INC_PARAM 0x08
#define | MDL_CAUSE_SFRM_INC_PARAM 0x09
#define | MDL_CAUSE_IFRM_INC_MBITS 0x0a
#define | MDL_CAUSE_IFRM_INC_LEN 0x0b
#define | MDL_CAUSE_FRM_UNIMPL 0x0c
#define | MDL_CAUSE_SABM_MF 0x0d
#define | MDL_CAUSE_SABM_INFO_NOTALL 0x0e
#define | MDL_CAUSE_FRMR 0x0f
#define | LAPD_U_SABM 0x7
#define | LAPD_U_SABME 0xf
#define | LAPD_U_DM 0x3
#define | LAPD_U_UI 0x0
#define | LAPD_U_DISC 0x8
#define | LAPD_U_UA 0xC
#define | LAPD_U_FRMR 0x11
#define | LAPD_S_RR 0x0
#define | LAPD_S_RNR 0x1
#define | LAPD_S_REJ 0x2
#define | CR_USER2NET_CMD 0
#define | CR_USER2NET_RESP 1
#define | CR_NET2USER_CMD 1
#define | CR_NET2USER_RESP 0
#define | LAPD_HEADROOM 56
#define | SBIT(a) (1 << a)
#define | ALL_STATES 0xffffffff
#define | L2DOWNSLLEN (sizeof(l2downstatelist) / sizeof(struct l2downstate))

## Enumerations

enum | osmo_dl_prim { PRIM_DL_UNIT_DATA, PRIM_DL_DATA, PRIM_DL_EST, PRIM_DL_REL, PRIM_DL_SUSP, PRIM_DL_RES, PRIM_DL_RECON, PRIM_MDL_ERROR }
| LAPD related primitives (L2<->L3 SAP) More...
enum | lapd_mode { LAPD_MODE_USER, LAPD_MODE_NETWORK }
| LAPD mode/role. More...
enum | lapd_state { LAPD_STATE_NULL = 0, LAPD_STATE_TEI_UNASS, LAPD_STATE_ASS_TEI_WAIT, LAPD_STATE_EST_TEI_WAIT, LAPD_STATE_IDLE, LAPD_STATE_SABM_SENT, LAPD_STATE_DISC_SENT, LAPD_STATE_MF_EST, LAPD_STATE_TIMER_RECOV }
| LAPD state (Figure B.2/Q.921)
enum | lapd_format { LAPD_FORM_UKN = 0, LAPD_FORM_I, LAPD_FORM_S, LAPD_FORM_U }
| LAPD message format (I / S / U)

## Functions

void | lapd_dl_init (struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf)
void | lapd_dl_exit (struct lapd_datalink *dl)
void | lapd_dl_reset (struct lapd_datalink *dl)
int | lapd_set_mode (struct lapd_datalink *dl, enum lapd_mode mode)
| Set the lapdm_mode of a LAPDm entity.
int | lapd_ph_data_ind (struct msgb *msg, struct lapd_msg_ctx *lctx)
int | lapd_recv_dlsap (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static void | lapd_t200_cb (void *data)
static void | lapd_t203_cb (void *data)
static int | lapd_send_i (struct lapd_msg_ctx *lctx, int line)
static int | lapd_est_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
struct msgb * | lapd_msgb_alloc (int length, const char *name)
static uint8_t | do_mod (uint8_t x, uint8_t m)
static uint8_t | inc_mod (uint8_t x, uint8_t m)
static uint8_t | add_mod (uint8_t x, uint8_t y, uint8_t m)
static uint8_t | sub_mod (uint8_t x, uint8_t y, uint8_t m)
static void | lapd_dl_flush_send (struct lapd_datalink *dl)
static void | lapd_dl_flush_hist (struct lapd_datalink *dl)
static void | lapd_dl_flush_tx (struct lapd_datalink *dl)
static void | lapd_start_t200 (struct lapd_datalink *dl)
static void | lapd_start_t203 (struct lapd_datalink *dl)
static void | lapd_stop_t200 (struct lapd_datalink *dl)
static void | lapd_stop_t203 (struct lapd_datalink *dl)
static void | lapd_dl_newstate (struct lapd_datalink *dl, uint32_t state)
static int | send_dl_l3 (uint8_t prim, uint8_t op, struct lapd_msg_ctx *lctx, struct msgb *msg)
static int | send_dl_simple (uint8_t prim, uint8_t op, struct lapd_msg_ctx *lctx)
static int | mdl_error (uint8_t cause, struct lapd_msg_ctx *lctx)
static int | lapd_send_ua (struct lapd_msg_ctx *lctx, uint8_t len, uint8_t *data)
static int | lapd_send_dm (struct lapd_msg_ctx *lctx)
static int | lapd_send_rr (struct lapd_msg_ctx *lctx, uint8_t f_bit, uint8_t cmd)
static int | lapd_send_rnr (struct lapd_msg_ctx *lctx, uint8_t f_bit, uint8_t cmd)
static int | lapd_send_rej (struct lapd_msg_ctx *lctx, uint8_t f_bit)
static int | lapd_send_resend (struct lapd_datalink *dl)
static int | lapd_reestablish (struct lapd_datalink *dl)
static void | lapd_acknowledge (struct lapd_msg_ctx *lctx)
static int | lapd_rx_u (struct msgb *msg, struct lapd_msg_ctx *lctx)
static int | lapd_rx_s (struct msgb *msg, struct lapd_msg_ctx *lctx)
static int | lapd_rx_i (struct msgb *msg, struct lapd_msg_ctx *lctx)
static int | lapd_udata_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static int | lapd_data_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static int | lapd_susp_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static int | lapd_res_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static int | lapd_rel_req (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
static int | lapd_rel_req_idle (struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)

## Variables

const char * | lapd_state_names []
static void * | tall_lapd_ctx = NULL
static const struct l2downstate | l2downstatelist []

## Detailed Description

## Macro Definition Documentation

## LAPD_U_SABM

#define LAPD_U_SABM 0x7

Notes on Buffering: rcv_buffer, tx_queue, tx_hist, send_buffer, send_queue

RX data is stored in the rcv_buffer (pointer). If the message is complete, it is removed from rcv_buffer pointer and forwarded to L3. If the RX data is received while there is an incomplete rcv_buffer, it is appended to it.

TX data is stored in the send_queue first. When transmitting a frame, the first message in the send_queue is moved to the send_buffer. There it resides until all fragments are acknowledged. Fragments to be sent by I frames are stored in the tx_hist buffer for resend, if required. Also the current fragment is copied into the tx_queue. There it resides until it is forwarded to layer 1.

In case we have SAPI 0, we only have a window size of 1, so the unack- nowledged message resides always in the send_buffer. In case of a suspend, it can be written back to the first position of the send_queue.

The layer 1 normally sends a PH-READY-TO-SEND. But because we use asynchronous transfer between layer 1 and layer 2 (serial link), we must send a frame before layer 1 reaches the right timeslot to send it. So we move the tx_queue to layer 1 when there is not already a pending frame, and wait until acknowledge after the frame has been sent. If we receive an acknowledge, we can send the next frame from the buffer, if any.

The moving of tx_queue to layer 1 may also trigger T200, if desired. Also it will trigger next I frame, if possible.

T203 is optional. It will be stated when entering MF EST state. It will also be started when I or S frame is received in that state . It will be restarted in the lapd_acknowledge() function, in case outstanding frames will not trigger T200. It will be stoped, when T200 is started in MF EST state. It will also be stoped when leaving MF EST state.

## Enumeration Type Documentation

## lapd_mode

enum lapd_mode

LAPD mode/role.

Enumerator
LAPD_MODE_USER | behave like user
LAPD_MODE_NETWORK | behave like network

## osmo_dl_prim

enum osmo_dl_prim

LAPD related primitives (L2<->L3 SAP)

Enumerator
PRIM_DL_UNIT_DATA | DL-UNIT-DATA.
PRIM_DL_DATA | DL-DATA.
PRIM_DL_EST | DL-ESTABLISH.
PRIM_DL_REL | DL-RLEEASE.
PRIM_DL_SUSP | DL-SUSPEND.
PRIM_DL_RES | DL-RESUME.
PRIM_DL_RECON | DL-RECONNECT.
PRIM_MDL_ERROR | MDL-ERROR.

## Variable Documentation

## lapd_state_names

const char* lapd_state_names[]

Initial value:
= {
"LAPD_STATE_NULL",
"LAPD_STATE_TEI_UNASS",
"LAPD_STATE_ASS_TEI_WAIT",
"LAPD_STATE_EST_TEI_WAIT",
"LAPD_STATE_IDLE",
"LAPD_STATE_SABM_SENT",
"LAPD_STATE_DISC_SENT",
"LAPD_STATE_MF_EST",
"LAPD_STATE_TIMER_RECOV",
}