aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2023-11-09 12:33:13 +0100
committerlaforge <laforge@osmocom.org>2023-11-27 16:25:53 +0000
commit49b7087360e7f4401ee63b1edd8576f57e0a2c6a (patch)
tree68db9b30bab77617fcbc1ef121aa2ae70e3ffd22
parent0266b531c5f261e3e3a0235d2681bedd8b9e0f31 (diff)
LAPD: Add support for RTS based polling and T200
The T200 timer is started when the current frame is polled at PH-READY-TO-SEND event. A flag is used to enable this feature. The user of LAPD core must track frame numbers to check the timeout condition. Then it must call the external timeout function. Related: OS#4074 Change-Id: Ib961b5a44911b99b0487641533301749c0286995
-rw-r--r--TODO-RELEASE1
-rw-r--r--include/osmocom/isdn/lapd_core.h15
-rw-r--r--src/isdn/lapd_core.c113
-rw-r--r--src/isdn/libosmoisdn.map3
4 files changed, 118 insertions, 14 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE
index b67161dd..1d56d45c 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -9,3 +9,4 @@
#library what description / commit summary line
core ADD osmo_sock_multiaddr_{add,del}_local_addr()
core ADD gsmtap_inst_fd2() core, DEPRECATE gsmtap_inst_fd()
+isdn ABI change add states and flags for external T200 handling
diff --git a/include/osmocom/isdn/lapd_core.h b/include/osmocom/isdn/lapd_core.h
index e4e8b469..776d4f41 100644
--- a/include/osmocom/isdn/lapd_core.h
+++ b/include/osmocom/isdn/lapd_core.h
@@ -84,6 +84,16 @@ enum lapd_state {
LAPD_STATE_TIMER_RECOV,
};
+/*! lapd_flags */
+#define LAPD_F_RTS 0x0001
+
+/*! LAPD T200 state in RTS mode */
+enum lapd_t200_rts {
+ LAPD_T200_RTS_OFF = 0,
+ LAPD_T200_RTS_PENDING,
+ LAPD_T200_RTS_RUNNING,
+};
+
/*! LAPD message format (I / S / U) */
enum lapd_format {
LAPD_FORM_UKN = 0,
@@ -133,6 +143,7 @@ struct lapd_datalink {
struct lapd_cr_ent rem2loc;
} cr;
enum lapd_mode mode; /*!< current mode of link */
+ unsigned int lapd_flags; /*!< \ref lapd_flags to change processing */
int use_sabme; /*!< use SABME instead of SABM */
int reestablish; /*!< enable reestablish support */
int n200, n200_est_rel; /*!< number of retranmissions */
@@ -149,6 +160,7 @@ struct lapd_datalink {
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) */
+ enum lapd_t200_rts t200_rts; /*!< state of T200 in RTS mode */
struct osmo_timer_list t200; /*!< T200 timer */
struct osmo_timer_list t203; /*!< T203 timer */
uint8_t retrans_ctr; /*!< re-transmission counter */
@@ -169,8 +181,11 @@ void lapd_dl_init2(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int max
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_dl_set_flags(struct lapd_datalink *dl, unsigned int flags);
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_ph_rts_ind(struct lapd_msg_ctx *lctx);
int lapd_recv_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
+int lapd_t200_timeout(struct lapd_datalink *dl);
/*! @} */
diff --git a/src/isdn/lapd_core.c b/src/isdn/lapd_core.c
index 57a02252..34748a49 100644
--- a/src/isdn/lapd_core.c
+++ b/src/isdn/lapd_core.c
@@ -204,11 +204,35 @@ static inline const char *lapd_state_name(enum lapd_state state)
static void lapd_start_t200(struct lapd_datalink *dl)
{
- if (osmo_timer_pending(&dl->t200))
- return;
- LOGDL(dl, LOGL_INFO, "start T200 (timeout=%d.%06ds)\n",
- dl->t200_sec, dl->t200_usec);
- osmo_timer_schedule(&dl->t200, dl->t200_sec, dl->t200_usec);
+ if ((dl->lapd_flags & LAPD_F_RTS)) {
+ if (dl->t200_rts != LAPD_T200_RTS_OFF)
+ return;
+ LOGDL(dl, LOGL_INFO, "Start T200. (pending until triggered by RTS)\n");
+ dl->t200_rts = LAPD_T200_RTS_PENDING;
+ } else {
+ if (osmo_timer_pending(&dl->t200))
+ return;
+ LOGDL(dl, LOGL_INFO, "Start T200 (timeout=%d.%06ds).\n", dl->t200_sec, dl->t200_usec);
+ osmo_timer_schedule(&dl->t200, dl->t200_sec, dl->t200_usec);
+ }
+}
+
+/*! Handle timeout condition of T200 in RTS mode.
+ * The caller (LAPDm code) implements the T200 timer and must detect timeout condition.
+ * The function gets called by LAPDm code when it detects a timeout of T200.
+ * \param[in] dl caller-allocated datalink structure */
+int lapd_t200_timeout(struct lapd_datalink *dl)
+{
+ OSMO_ASSERT((dl->lapd_flags & LAPD_F_RTS));
+
+ if (dl->t200_rts != LAPD_T200_RTS_RUNNING)
+ return -EINVAL;
+
+ dl->t200_rts = LAPD_T200_RTS_OFF;
+
+ lapd_t200_cb(dl);
+
+ return 0;
}
static void lapd_start_t203(struct lapd_datalink *dl)
@@ -221,10 +245,24 @@ static void lapd_start_t203(struct lapd_datalink *dl)
static void lapd_stop_t200(struct lapd_datalink *dl)
{
- if (!osmo_timer_pending(&dl->t200))
- return;
+ if ((dl->lapd_flags & LAPD_F_RTS)) {
+ if (dl->t200_rts == LAPD_T200_RTS_OFF)
+ return;
+ dl->t200_rts = LAPD_T200_RTS_OFF;
+ } else {
+ if (!osmo_timer_pending(&dl->t200))
+ return;
+ osmo_timer_del(&dl->t200);
+ }
LOGDL(dl, LOGL_INFO, "stop T200\n");
- osmo_timer_del(&dl->t200);
+}
+
+static bool lapd_is_t200_started(struct lapd_datalink *dl)
+{
+ if ((dl->lapd_flags & LAPD_F_RTS))
+ return (dl->t200_rts != LAPD_T200_RTS_OFF);
+ else
+ return osmo_timer_pending(&dl->t200);
}
static void lapd_stop_t203(struct lapd_datalink *dl)
@@ -359,6 +397,21 @@ void lapd_dl_reset(struct lapd_datalink *dl)
lapd_dl_newstate(dl, LAPD_STATE_IDLE);
}
+/*! Set lapd_flags to change behaviour
+ * \param[in] dl \ref lapd_datalink instance
+ * \param[in] flags \ref lapd_flags */
+int lapd_dl_set_flags(struct lapd_datalink *dl, unsigned int flags)
+{
+ if (lapd_is_t200_started(dl) && (flags & LAPD_F_RTS) != (dl->lapd_flags & LAPD_F_RTS)) {
+ LOGDL(dl, LOGL_ERROR, "Changing RTS flag not allowed while T200 is running.\n");
+ return -EINVAL;
+ }
+
+ dl->lapd_flags = flags;
+
+ return 0;
+}
+
/* reset and de-allocate history buffer */
void lapd_dl_exit(struct lapd_datalink *dl)
{
@@ -806,11 +859,8 @@ static void lapd_acknowledge(struct lapd_msg_ctx *lctx)
/* Stop T203, if running */
lapd_stop_t203(dl);
/* Start T203, if T200 is not running in MF EST state, if enabled */
- if (!osmo_timer_pending(&dl->t200)
- && (dl->t203_sec || dl->t203_usec)
- && (dl->state == LAPD_STATE_MF_EST)) {
+ if (!lapd_is_t200_started(dl) && (dl->t203_sec || dl->t203_usec) && (dl->state == LAPD_STATE_MF_EST))
lapd_start_t203(dl);
- }
}
/* L1 -> L2 */
@@ -1732,6 +1782,31 @@ int lapd_ph_data_ind(struct msgb *msg, struct lapd_msg_ctx *lctx)
return rc;
}
+/*! Enqueue next LAPD frame and run pending T200. (Must be called when frame is ready to send.)
+ * The caller (LAPDm code) calls this function before it sends the next frame.
+ * If there is no frame in the TX queue, LAPD will enqueue next I-frame, if possible.
+ * If the T200 is pending, it is changed to running state.
+ * \param[in] lctx LAPD context
+ * \param[out] rc set to 1, if timer T200 state changed to running, set to 0, if not. */
+int lapd_ph_rts_ind(struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+
+ /* If there is no pending frame, try to enqueue next I frame. */
+ if (llist_empty(&dl->tx_queue) && (dl->state == LAPD_STATE_MF_EST || dl->state == LAPD_STATE_TIMER_RECOV)) {
+ /* Send an I frame, if there are pending outgoing messages. */
+ lapd_send_i(dl, __LINE__, true);
+ }
+
+ /* Run T200 at RTS, if pending. Tell caller that is has been started. (rc = 1) */
+ if (dl->t200_rts == LAPD_T200_RTS_PENDING) {
+ dl->t200_rts = LAPD_T200_RTS_RUNNING;
+ return 1;
+ }
+
+ return 0;
+}
+
/* L3 -> L2 */
/* send unit data */
@@ -1861,6 +1936,12 @@ static int lapd_send_i(struct lapd_datalink *dl, int line, bool rts)
if (!rts)
LOGDL(dl, LOGL_INFO, "%s() called from line %d\n", __func__, line);
+ if ((dl->lapd_flags & LAPD_F_RTS) && !llist_empty(&dl->tx_queue)) {
+ if (!rts)
+ LOGDL(dl, LOGL_INFO, "There is a frame in the TX queue, not checking for sending I frame.\n");
+ return rc;
+ }
+
next_frame:
if (dl->peer_busy) {
@@ -1978,7 +2059,7 @@ static int lapd_send_i(struct lapd_datalink *dl, int line, bool rts)
/* If timer T200 is not running at the time right before transmitting a
* frame, when the PH-READY-TO-SEND primitive is received from the
* physical layer., it shall be set. */
- if (!osmo_timer_pending(&dl->t200)) {
+ if (!lapd_is_t200_started(dl)) {
/* stop Timer T203, if running */
lapd_stop_t203(dl);
/* start Timer T200 */
@@ -1987,7 +2068,11 @@ static int lapd_send_i(struct lapd_datalink *dl, int line, bool rts)
dl->send_ph_data_req(&nctx, msg);
- rc = 0; /* we sent something */
+ /* When using RTS, we send only one frame. */
+ if ((dl->lapd_flags & LAPD_F_RTS))
+ return 0;
+
+ rc = 0; /* We sent an I frame, so sending RR frame is not required. */
goto next_frame;
}
diff --git a/src/isdn/libosmoisdn.map b/src/isdn/libosmoisdn.map
index 3269771c..c29240ba 100644
--- a/src/isdn/libosmoisdn.map
+++ b/src/isdn/libosmoisdn.map
@@ -7,11 +7,14 @@ lapd_dl_init;
lapd_dl_init2;
lapd_dl_set_name;
lapd_dl_reset;
+lapd_dl_set_flags;
lapd_msgb_alloc;
lapd_ph_data_ind;
+lapd_ph_rts_ind;
lapd_recv_dlsap;
lapd_set_mode;
lapd_state_names;
+lapd_t200_timeout;
osmo_i460_demux_in;
osmo_i460_mux_enqueue;