aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2022-11-29 22:33:54 +0100
committerHarald Welte <laforge@gnumonks.org>2023-01-21 22:41:57 +0100
commitd55a209d1c1eaf48d11d851c6a5082af7df36d69 (patch)
treef6395ad8e875a619354e9687951af086b5e3cee1 /include/osmocom
parent88955fb5506280a82860b026f8d7db9ad57bb504 (diff)
create libosmoisdn sub-library
There are some parts of libosmogsm which are not really GSM specific, but rather ISDN bits that were inherited by GSM. This includes the I.460 multiplex as well as the core LAPD protocol. Let's move those bits to its own libosmoisdn library, before we add more ISDN specific bits to the wrong place. Backwards-compatibility is created by making libosmogsm depend on libosmoisdn, and by providing wrapper include files for source compatibility. Change-Id: Ib1a6c762322fd5047be3188b1df22408ef06aa50
Diffstat (limited to 'include/osmocom')
-rw-r--r--include/osmocom/Makefile.am1
-rw-r--r--include/osmocom/gsm/i460_mux.h116
-rw-r--r--include/osmocom/gsm/lapd_core.h177
-rw-r--r--include/osmocom/isdn/Makefile.am6
-rw-r--r--include/osmocom/isdn/i460_mux.h116
-rw-r--r--include/osmocom/isdn/lapd_core.h176
6 files changed, 301 insertions, 291 deletions
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
index 1cc3fb7f..33538094 100644
--- a/include/osmocom/Makefile.am
+++ b/include/osmocom/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = \
vty \
codec \
gsm \
+ isdn \
crypt \
coding \
gprs \
diff --git a/include/osmocom/gsm/i460_mux.h b/include/osmocom/gsm/i460_mux.h
index 770b1e15..7c2f4af3 100644
--- a/include/osmocom/gsm/i460_mux.h
+++ b/include/osmocom/gsm/i460_mux.h
@@ -1,116 +1,2 @@
-/*! \file i460_mux.h
- * ITU-T I.460 sub-channel multiplexer + demultiplexer */
-/*
- * (C) 2020 by Harald Welte <laforge@gnumonks.org>
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
#pragma once
-#include <stdint.h>
-#include <osmocom/core/bits.h>
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/msgb.h>
-
-/* I.460 sub-slot rate */
-enum osmo_i460_rate {
- OSMO_I460_RATE_NONE, /* disabled */
- OSMO_I460_RATE_64k,
- OSMO_I460_RATE_32k,
- OSMO_I460_RATE_16k,
- OSMO_I460_RATE_8k,
-};
-
-struct osmo_i460_subchan;
-
-typedef void (*out_cb_bits_t)(struct osmo_i460_subchan *schan, void *user_data,
- const ubit_t *bits, unsigned int num_bits);
-typedef void (*out_cb_bytes_t)(struct osmo_i460_subchan *schan, void *user_data,
- const uint8_t *bytes, unsigned int num_bytes);
-
-struct osmo_i460_subchan_demux {
- /*! bit-buffer for output bits */
- uint8_t *out_bitbuf;
- /*! size of out_bitbuf in bytes */
- unsigned int out_bitbuf_size;
- /*! offset of next bit to be written in out_bitbuf */
- unsigned int out_idx;
- /*! callback to be called once we have received out_bitbuf_size bits */
- out_cb_bits_t out_cb_bits;
- out_cb_bytes_t out_cb_bytes;
- void *user_data;
-};
-
-typedef void (*in_cb_queue_empty_t)(struct osmo_i460_subchan *schan, void *user_data);
-
-struct osmo_i460_subchan_mux {
- /*! list of to-be-transmitted message buffers */
- struct llist_head tx_queue;
- in_cb_queue_empty_t in_cb_queue_empty;
- void *user_data;
-};
-
-struct osmo_i460_subchan {
- struct osmo_i460_timeslot *ts; /* back-pointer */
- enum osmo_i460_rate rate; /* 8/16/32/64k */
- uint8_t bit_offset; /* bit offset inside each byte of the B-channel */
- struct osmo_i460_subchan_demux demux;
- struct osmo_i460_subchan_mux mux;
-};
-
-struct osmo_i460_timeslot {
- struct osmo_i460_subchan schan[8];
-};
-
-/*! description of a sub-channel; passed by caller */
-struct osmo_i460_schan_desc {
- enum osmo_i460_rate rate;
- uint8_t bit_offset;
- struct {
- /* size (in bits) of the internal buffer; determines granularity */
- size_t num_bits;
- /*! call-back function called whenever we received num_bits */
- out_cb_bits_t out_cb_bits;
- /*! out_cb_bytes call-back function called whenever we received num_bits.
- * The user is usually expected to provide either out_cb_bits or out_cb_bytes. If only
- * out_cb_bits is provided, output data will always be provided as unpacked bits; if only
- * out_cb_bytes is provided, output data will always be provided as packet bits (bytes). If
- * both are provided, it is up to the I.460 multiplex to decide if it calls either of the two,
- * depending on what can be provided without extra conversion. */
- out_cb_bytes_t out_cb_bytes;
- /* opaque user data pointer to pass to out_cb */
- void *user_data;
- } demux;
-
- struct {
- /* call-back function whenever the muxer requires more input data from the sub-channels,
- * but has nothing enqueued yet. A typical function would then call osmo_i460_mux_enqueue() */
- in_cb_queue_empty_t in_cb_queue_empty;
- /* opaque user data pointer to pass to in_cb */
- void *user_data;
- } mux;
-};
-
-void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len);
-
-void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg);
-int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len);
-
-void osmo_i460_ts_init(struct osmo_i460_timeslot *ts);
-
-struct osmo_i460_subchan *
-osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd);
-
-void osmo_i460_subchan_del(struct osmo_i460_subchan *schan);
-
-/*! @} */
+#include <osmocom/isdn/i460_mux.h>
diff --git a/include/osmocom/gsm/lapd_core.h b/include/osmocom/gsm/lapd_core.h
index 3f31881d..a4dc2505 100644
--- a/include/osmocom/gsm/lapd_core.h
+++ b/include/osmocom/gsm/lapd_core.h
@@ -1,177 +1,2 @@
-/*! \file lapd_core.h
- * primitive related stuff
- */
#pragma once
-
-#include <stdint.h>
-
-#include <osmocom/core/timer.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/prim.h>
-
-/*! \defgroup lapd LAPD implementation common part
- * @{
- * \file lapd_core.h
- */
-
-#define LOGDL(dl, level, fmt, args...) \
- LOGP(DLLAPD, level, "(%s) " fmt, (dl)->name, ## args)
-
-/*! LAPD related primitives (L2<->L3 SAP)*/
-enum osmo_dl_prim {
- 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 */
-};
-
-/* Uses the same values as RLL, so no conversion for GSM is required. */
-#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
-
-/*! for MDL-ERROR.ind */
-struct mdl_error_ind_param {
- uint8_t cause; /*!< generic cause value */
-};
-
-/*! for DL-REL.req */
-struct dl_rel_req_param {
- uint8_t mode; /*!< release mode */
-};
-
-/*! primitive header for LAPD DL-SAP primitives */
-struct osmo_dlsap_prim {
- struct osmo_prim_hdr oph; /*!< generic primitive header */
- union {
- struct mdl_error_ind_param error_ind;
- struct dl_rel_req_param rel_req;
- } u; /*!< request-specific data */
-};
-
-/*! LAPD mode/role */
-enum lapd_mode {
- LAPD_MODE_USER, /*!< behave like user */
- LAPD_MODE_NETWORK, /*!< behave like network */
-};
-
-/*! LAPD state (Figure B.2/Q.921)*/
-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 message format (I / S / U) */
-enum lapd_format {
- LAPD_FORM_UKN = 0,
- LAPD_FORM_I,
- LAPD_FORM_S,
- LAPD_FORM_U,
-};
-
-/*! LAPD message context */
-struct lapd_msg_ctx {
- struct lapd_datalink *dl;
- int n201;
- /* address */
- uint8_t cr;
- uint8_t sapi;
- uint8_t tei;
- uint8_t lpd;
- /* control */
- uint8_t format;
- uint8_t p_f; /* poll / final bit */
- uint8_t n_send;
- uint8_t n_recv;
- uint8_t s_u; /* S or repectivly U function bits */
- /* length */
- int length;
- uint8_t more;
-};
-
-struct lapd_cr_ent {
- uint8_t cmd;
- uint8_t resp;
-};
-
-struct lapd_history {
- struct msgb *msg; /* message to be sent / NULL, if histoy is empty */
- int more; /* if message is fragmented */
-};
-
-/*! LAPD datalink */
-struct lapd_datalink {
- int (*send_dlsap)(struct osmo_dlsap_prim *dp,
- struct lapd_msg_ctx *lctx);
- int (*send_ph_data_req)(struct lapd_msg_ctx *lctx, struct msgb *msg);
- int (*update_pending_frames)(struct lapd_msg_ctx *lctx);
- struct {
- /*! filled-in once we set the lapd_mode above */
- struct lapd_cr_ent loc2rem;
- struct lapd_cr_ent rem2loc;
- } cr;
- enum lapd_mode mode; /*!< current mode of link */
- int use_sabme; /*!< use SABME instead of SABM */
- int reestablish; /*!< enable reestablish support */
- int n200, n200_est_rel; /*!< number of retranmissions */
- struct lapd_msg_ctx lctx; /*!< LAPD context */
- int maxf; /*!< maximum frame size (after defragmentation) */
- uint8_t k; /*!< maximum number of unacknowledged frames */
- uint8_t v_range; /*!< range of sequence numbers */
- uint8_t v_send; /*!< seq nr of next I frame to be transmitted */
- uint8_t v_ack; /*!< last frame ACKed by peer */
- uint8_t v_recv; /*!< seq nr of next I frame expected to be received */
- uint32_t state; /*!< LAPD state (\ref lapd_state) */
- int seq_err_cond; /*!< condition of sequence error */
- uint8_t own_busy; /*!< receiver busy on our side */
- uint8_t peer_busy; /*!< receiver busy on remote side */
- int t200_sec, t200_usec; /*!< retry timer (default 1 sec) */
- int t203_sec, t203_usec; /*!< retry timer (default 10 secs) */
- struct osmo_timer_list t200; /*!< T200 timer */
- struct osmo_timer_list t203; /*!< T203 timer */
- uint8_t retrans_ctr; /*!< re-transmission counter */
- struct llist_head tx_queue; /*!< frames to L1 */
- struct llist_head send_queue; /*!< frames from L3 */
- struct msgb *send_buffer; /*!< current frame transmitting */
- int send_out; /*!< how much was sent from send_buffer */
- struct lapd_history *tx_hist; /*!< tx history structure array */
- uint8_t range_hist; /*!< range of history buffer 2..2^n */
- struct msgb *rcv_buffer; /*!< buffer to assemble the received message */
- struct msgb *cont_res; /*!< buffer to store content resolution data on network side, to detect multiple phones on same channel */
- char *name; /*!< user-provided name */
-};
-
-void lapd_dl_init(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf)
- OSMO_DEPRECATED("Use lapd_dl_init2() instead");
-void lapd_dl_init2(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf, const char *name);
-void lapd_dl_set_name(struct lapd_datalink *dl, const char *name);
-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);
-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);
-
-/*! @} */
+#include <osmocom/isdn/lapd_core.h>
diff --git a/include/osmocom/isdn/Makefile.am b/include/osmocom/isdn/Makefile.am
new file mode 100644
index 00000000..bf33623a
--- /dev/null
+++ b/include/osmocom/isdn/Makefile.am
@@ -0,0 +1,6 @@
+osmoisdn_HEADERS = \
+ i460_mux.h \
+ lapd_core.h \
+ $(NULL)
+
+osmoisdndir = $(includedir)/osmocom/isdn
diff --git a/include/osmocom/isdn/i460_mux.h b/include/osmocom/isdn/i460_mux.h
new file mode 100644
index 00000000..770b1e15
--- /dev/null
+++ b/include/osmocom/isdn/i460_mux.h
@@ -0,0 +1,116 @@
+/*! \file i460_mux.h
+ * ITU-T I.460 sub-channel multiplexer + demultiplexer */
+/*
+ * (C) 2020 by Harald Welte <laforge@gnumonks.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#pragma once
+#include <stdint.h>
+#include <osmocom/core/bits.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+
+/* I.460 sub-slot rate */
+enum osmo_i460_rate {
+ OSMO_I460_RATE_NONE, /* disabled */
+ OSMO_I460_RATE_64k,
+ OSMO_I460_RATE_32k,
+ OSMO_I460_RATE_16k,
+ OSMO_I460_RATE_8k,
+};
+
+struct osmo_i460_subchan;
+
+typedef void (*out_cb_bits_t)(struct osmo_i460_subchan *schan, void *user_data,
+ const ubit_t *bits, unsigned int num_bits);
+typedef void (*out_cb_bytes_t)(struct osmo_i460_subchan *schan, void *user_data,
+ const uint8_t *bytes, unsigned int num_bytes);
+
+struct osmo_i460_subchan_demux {
+ /*! bit-buffer for output bits */
+ uint8_t *out_bitbuf;
+ /*! size of out_bitbuf in bytes */
+ unsigned int out_bitbuf_size;
+ /*! offset of next bit to be written in out_bitbuf */
+ unsigned int out_idx;
+ /*! callback to be called once we have received out_bitbuf_size bits */
+ out_cb_bits_t out_cb_bits;
+ out_cb_bytes_t out_cb_bytes;
+ void *user_data;
+};
+
+typedef void (*in_cb_queue_empty_t)(struct osmo_i460_subchan *schan, void *user_data);
+
+struct osmo_i460_subchan_mux {
+ /*! list of to-be-transmitted message buffers */
+ struct llist_head tx_queue;
+ in_cb_queue_empty_t in_cb_queue_empty;
+ void *user_data;
+};
+
+struct osmo_i460_subchan {
+ struct osmo_i460_timeslot *ts; /* back-pointer */
+ enum osmo_i460_rate rate; /* 8/16/32/64k */
+ uint8_t bit_offset; /* bit offset inside each byte of the B-channel */
+ struct osmo_i460_subchan_demux demux;
+ struct osmo_i460_subchan_mux mux;
+};
+
+struct osmo_i460_timeslot {
+ struct osmo_i460_subchan schan[8];
+};
+
+/*! description of a sub-channel; passed by caller */
+struct osmo_i460_schan_desc {
+ enum osmo_i460_rate rate;
+ uint8_t bit_offset;
+ struct {
+ /* size (in bits) of the internal buffer; determines granularity */
+ size_t num_bits;
+ /*! call-back function called whenever we received num_bits */
+ out_cb_bits_t out_cb_bits;
+ /*! out_cb_bytes call-back function called whenever we received num_bits.
+ * The user is usually expected to provide either out_cb_bits or out_cb_bytes. If only
+ * out_cb_bits is provided, output data will always be provided as unpacked bits; if only
+ * out_cb_bytes is provided, output data will always be provided as packet bits (bytes). If
+ * both are provided, it is up to the I.460 multiplex to decide if it calls either of the two,
+ * depending on what can be provided without extra conversion. */
+ out_cb_bytes_t out_cb_bytes;
+ /* opaque user data pointer to pass to out_cb */
+ void *user_data;
+ } demux;
+
+ struct {
+ /* call-back function whenever the muxer requires more input data from the sub-channels,
+ * but has nothing enqueued yet. A typical function would then call osmo_i460_mux_enqueue() */
+ in_cb_queue_empty_t in_cb_queue_empty;
+ /* opaque user data pointer to pass to in_cb */
+ void *user_data;
+ } mux;
+};
+
+void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len);
+
+void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg);
+int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len);
+
+void osmo_i460_ts_init(struct osmo_i460_timeslot *ts);
+
+struct osmo_i460_subchan *
+osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd);
+
+void osmo_i460_subchan_del(struct osmo_i460_subchan *schan);
+
+/*! @} */
diff --git a/include/osmocom/isdn/lapd_core.h b/include/osmocom/isdn/lapd_core.h
new file mode 100644
index 00000000..e4e8b469
--- /dev/null
+++ b/include/osmocom/isdn/lapd_core.h
@@ -0,0 +1,176 @@
+/*! \file lapd_core.h
+ * primitive related stuff
+ */
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/prim.h>
+
+/*! \defgroup lapd LAPD implementation common part
+ * @{
+ * \file lapd_core.h
+ */
+
+#define LOGDL(dl, level, fmt, args...) \
+ LOGP(DLLAPD, level, "(%s) " fmt, (dl)->name, ## args)
+
+/*! LAPD related primitives (L2<->L3 SAP)*/
+enum osmo_dl_prim {
+ 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 */
+};
+
+/* Uses the same values as RLL, so no conversion for GSM is required. */
+#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
+
+/*! for MDL-ERROR.ind */
+struct mdl_error_ind_param {
+ uint8_t cause; /*!< generic cause value */
+};
+
+/*! for DL-REL.req */
+struct dl_rel_req_param {
+ uint8_t mode; /*!< release mode */
+};
+
+/*! primitive header for LAPD DL-SAP primitives */
+struct osmo_dlsap_prim {
+ struct osmo_prim_hdr oph; /*!< generic primitive header */
+ union {
+ struct mdl_error_ind_param error_ind;
+ struct dl_rel_req_param rel_req;
+ } u; /*!< request-specific data */
+};
+
+/*! LAPD mode/role */
+enum lapd_mode {
+ LAPD_MODE_USER, /*!< behave like user */
+ LAPD_MODE_NETWORK, /*!< behave like network */
+};
+
+/*! LAPD state (Figure B.2/Q.921)*/
+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 message format (I / S / U) */
+enum lapd_format {
+ LAPD_FORM_UKN = 0,
+ LAPD_FORM_I,
+ LAPD_FORM_S,
+ LAPD_FORM_U,
+};
+
+/*! LAPD message context */
+struct lapd_msg_ctx {
+ struct lapd_datalink *dl;
+ int n201;
+ /* address */
+ uint8_t cr;
+ uint8_t sapi;
+ uint8_t tei;
+ uint8_t lpd;
+ /* control */
+ uint8_t format;
+ uint8_t p_f; /* poll / final bit */
+ uint8_t n_send;
+ uint8_t n_recv;
+ uint8_t s_u; /* S or repectivly U function bits */
+ /* length */
+ int length;
+ uint8_t more;
+};
+
+struct lapd_cr_ent {
+ uint8_t cmd;
+ uint8_t resp;
+};
+
+struct lapd_history {
+ struct msgb *msg; /* message to be sent / NULL, if histoy is empty */
+ int more; /* if message is fragmented */
+};
+
+/*! LAPD datalink */
+struct lapd_datalink {
+ int (*send_dlsap)(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
+ int (*send_ph_data_req)(struct lapd_msg_ctx *lctx, struct msgb *msg);
+ int (*update_pending_frames)(struct lapd_msg_ctx *lctx);
+ struct {
+ /*! filled-in once we set the lapd_mode above */
+ struct lapd_cr_ent loc2rem;
+ struct lapd_cr_ent rem2loc;
+ } cr;
+ enum lapd_mode mode; /*!< current mode of link */
+ int use_sabme; /*!< use SABME instead of SABM */
+ int reestablish; /*!< enable reestablish support */
+ int n200, n200_est_rel; /*!< number of retranmissions */
+ struct lapd_msg_ctx lctx; /*!< LAPD context */
+ int maxf; /*!< maximum frame size (after defragmentation) */
+ uint8_t k; /*!< maximum number of unacknowledged frames */
+ uint8_t v_range; /*!< range of sequence numbers */
+ uint8_t v_send; /*!< seq nr of next I frame to be transmitted */
+ uint8_t v_ack; /*!< last frame ACKed by peer */
+ uint8_t v_recv; /*!< seq nr of next I frame expected to be received */
+ uint32_t state; /*!< LAPD state (\ref lapd_state) */
+ int seq_err_cond; /*!< condition of sequence error */
+ uint8_t own_busy; /*!< receiver busy on our side */
+ uint8_t peer_busy; /*!< receiver busy on remote side */
+ int t200_sec, t200_usec; /*!< retry timer (default 1 sec) */
+ int t203_sec, t203_usec; /*!< retry timer (default 10 secs) */
+ struct osmo_timer_list t200; /*!< T200 timer */
+ struct osmo_timer_list t203; /*!< T203 timer */
+ uint8_t retrans_ctr; /*!< re-transmission counter */
+ struct llist_head tx_queue; /*!< frames to L1 */
+ struct llist_head send_queue; /*!< frames from L3 */
+ struct msgb *send_buffer; /*!< current frame transmitting */
+ int send_out; /*!< how much was sent from send_buffer */
+ struct lapd_history *tx_hist; /*!< tx history structure array */
+ uint8_t range_hist; /*!< range of history buffer 2..2^n */
+ struct msgb *rcv_buffer; /*!< buffer to assemble the received message */
+ struct msgb *cont_res; /*!< buffer to store content resolution data on network side, to detect multiple phones on same channel */
+ char *name; /*!< user-provided name */
+};
+
+void lapd_dl_init(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf)
+ OSMO_DEPRECATED("Use lapd_dl_init2() instead");
+void lapd_dl_init2(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf, const char *name);
+void lapd_dl_set_name(struct lapd_datalink *dl, const char *name);
+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);
+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);
+
+/*! @} */