laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmocore/+/34985?usp=email )

Change subject: LAPD: Add support for RTS based polling and T200
......................................................................

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
---
M TODO-RELEASE
M include/osmocom/isdn/lapd_core.h
M src/isdn/lapd_core.c
M src/isdn/libosmoisdn.map
4 files changed, 135 insertions(+), 14 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified
  daniel: Looks good to me, but someone else must approve




diff --git a/TODO-RELEASE b/TODO-RELEASE
index b67161d..1d56d45 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 e4e8b46..776d4f4 100644
--- a/include/osmocom/isdn/lapd_core.h
+++ b/include/osmocom/isdn/lapd_core.h
@@ -84,6 +84,16 @@
        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_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 @@
        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_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 57a0225..34748a4 100644
--- a/src/isdn/lapd_core.c
+++ b/src/isdn/lapd_core.c
@@ -204,11 +204,35 @@

 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_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 @@
        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 @@
        /* 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 @@
        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 @@
        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 @@
        /* 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 @@

        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 3269771..c29240b 100644
--- a/src/isdn/libosmoisdn.map
+++ b/src/isdn/libosmoisdn.map
@@ -7,11 +7,14 @@
 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;

--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/34985?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ib961b5a44911b99b0487641533301749c0286995
Gerrit-Change-Number: 34985
Gerrit-PatchSet: 10
Gerrit-Owner: jolly <andr...@eversberg.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillm...@sysmocom.de>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: neels <nhofm...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to