<p>neels <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/23943">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  neels: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">lchan and assignment FSMs: make Channel Mode Modify more sane<br><br>The Channel Mode Modify procedure is currently implemented for changing<br>a TCH lchan from signalling to voice mode. For that, however, it is<br>re-using (abusing) the channel activation structs and state transitions,<br>and thus always implies activating a voice stream when the mode<br>modification is done.<br><br>I will add a Channel Mode Modify to enable VAMOS mode soon, so I require<br>separate structs and state transitions which also work on an lchan that<br>already has a voice stream established: a struct lchan_modify_info and<br>LCHAN_EV_REQUEST_MODE_MODIFY, and dedicated assignment FSM state<br>ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED.<br><br>For the part where a Channel Mode Modify enables a voice stream after<br>switching from signalling to speech mode, still use the channel<br>activation code path, but only once the mode modification is done.<br><br>General improvements:<br>- To ask for a mode modification, emit an FSM event that ensures a mode<br>  modify only happens when the lchan state allows it.<br>- The new lchan_modify_info struct reflects only those parts that have<br>  an effect during a mode modification (before the lchan_activate_info<br>  was fully populated, many values not having an effect).<br>- More accurate logging, indicating "Mode Modify" instead of "Channel<br>  Activation"<br><br>A TTCN3 test for the Channel Mode Modify procedure is added in<br>Idf4efaed986de0bbd2b663313e837352cc139f0f, and the test passes both<br>before and after this patch is applied.<br><br>Related: SYS#4895<br>Change-Id: I4986844f839b1c9672c61d916eb3d33d0042d747<br>---<br>M doc/assignment-fsm.dot<br>M include/osmocom/bsc/assignment_fsm.h<br>M include/osmocom/bsc/gsm_data.h<br>M include/osmocom/bsc/lchan_fsm.h<br>M src/osmo-bsc/assignment_fsm.c<br>M src/osmo-bsc/gsm_data.c<br>M src/osmo-bsc/lchan_fsm.c<br>7 files changed, 224 insertions(+), 70 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/doc/assignment-fsm.dot b/doc/assignment-fsm.dot</span><br><span>index c218153..4eb8d98 100644</span><br><span>--- a/doc/assignment-fsm.dot</span><br><span>+++ b/doc/assignment-fsm.dot</span><br><span>@@ -12,6 +12,7 @@</span><br><span>         gscon2 [label="conn FSM",shape=box3d]</span><br><span>      lchan [label="lchan FSM\n(new lchan)",shape=box3d]</span><br><span>         old_lchan [label="old lchan",shape=box3d]</span><br><span style="color: hsl(120, 100%, 40%);">+   lchan2 [label="lchan FSM",shape=box3d]</span><br><span> </span><br><span>         bssap [label="osmo_bsc_bssap.c",shape=box]</span><br><span> </span><br><span>@@ -22,8 +23,7 @@</span><br><span>         bssap -> gscon [label="GSCON_EV_ASSIGNMENT_START\ndata=struct assignment_request",style=dotted]</span><br><span> </span><br><span>     gscon -> WAIT_LCHAN_ACTIVE [label="assignment_fsm_start()",style=dotted]</span><br><span style="color: hsl(0, 100%, 40%);">-   gscon -> WAIT_LCHAN_ESTABLISHED [label="assignment_fsm_start()\n(mode modify)",style=dotted]</span><br><span style="color: hsl(0, 100%, 40%);">-        WAIT_LCHAN_ACTIVE -> lchan [label="lchan_activate()\nFOR_ASSIGNMENT",style=dotted]</span><br><span style="color: hsl(120, 100%, 40%);">+      WAIT_LCHAN_ACTIVE -> lchan [label="lchan_activate()\nFOR_ASSIGNMENT",style=dotted]</span><br><span>      lchan -> WAIT_LCHAN_ACTIVE [label="ASSIGNMENT_EV_\nLCHAN_\nACTIVE,ERROR",style=dotted]</span><br><span>  lchan -> WAIT_LCHAN_ESTABLISHED [label="ASSIGNMENT_EV_\nLCHAN_\nESTABLISHED,ERROR",style=dotted]</span><br><span> </span><br><span>@@ -40,4 +40,10 @@</span><br><span>       WAIT_MGW_ENDPOINT_TO_MSC -> gscon2 [label="gscon_connect_\nmgw_to_msc()",style=dotted]</span><br><span>  gscon2 -> WAIT_MGW_ENDPOINT_TO_MSC [label="ASSIGNMENT_EV_\nMSC_MGW_OK",style=dotted]</span><br><span>    terminate -> gscon2 [label="GSCON_EV_\nASSIGNMENT_END",style=dotted]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   WAIT_LCHAN_ACTIVE -> WAIT_LCHAN_MODIFIED [label="assignment_fsm_start()\n(mode modify)"]</span><br><span style="color: hsl(120, 100%, 40%);">+ WAIT_LCHAN_MODIFIED -> lchan2 [label="lchan_mode_modify()\nMODIFY_FOR_ASSIGNMENT",style=dotted]</span><br><span style="color: hsl(120, 100%, 40%);">+  lchan2 -> WAIT_LCHAN_MODIFIED [label="ASSIGNMENT_EV_\nLCHAN_\nMODIFIED,ERROR",style=dotted]</span><br><span style="color: hsl(120, 100%, 40%);">+      WAIT_LCHAN_MODIFIED -> WAIT_MGW_ENDPOINT_TO_MSC [label="needs\nvoice\nstream"]</span><br><span style="color: hsl(120, 100%, 40%);">+   WAIT_LCHAN_MODIFIED -> terminate [label="no change\nin voice\nstream"]</span><br><span> }</span><br><span>diff --git a/include/osmocom/bsc/assignment_fsm.h b/include/osmocom/bsc/assignment_fsm.h</span><br><span>index 156da42..b4af335 100644</span><br><span>--- a/include/osmocom/bsc/assignment_fsm.h</span><br><span>+++ b/include/osmocom/bsc/assignment_fsm.h</span><br><span>@@ -24,11 +24,13 @@</span><br><span>  ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE,</span><br><span>  ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED,</span><br><span>        ASSIGNMENT_ST_WAIT_MGW_ENDPOINT_TO_MSC,</span><br><span style="color: hsl(120, 100%, 40%);">+       ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED,</span><br><span> };</span><br><span> </span><br><span> enum assignment_fsm_event {</span><br><span>  ASSIGNMENT_EV_LCHAN_ACTIVE,</span><br><span>  ASSIGNMENT_EV_LCHAN_ESTABLISHED,</span><br><span style="color: hsl(120, 100%, 40%);">+      ASSIGNMENT_EV_LCHAN_MODIFIED,</span><br><span>        ASSIGNMENT_EV_LCHAN_ERROR,</span><br><span>   ASSIGNMENT_EV_MSC_MGW_OK,</span><br><span>    ASSIGNMENT_EV_MSC_MGW_FAIL,</span><br><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index bd83ea0..5a202bf 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -564,6 +564,7 @@</span><br><span>       ACTIVATE_FOR_ASSIGNMENT,</span><br><span>     ACTIVATE_FOR_HANDOVER,</span><br><span>       ACTIVATE_FOR_VTY,</span><br><span style="color: hsl(120, 100%, 40%);">+     ACTIVATE_FOR_MODE_MODIFY_RTP,</span><br><span> };</span><br><span> </span><br><span> extern const struct value_string lchan_activate_mode_names[];</span><br><span>@@ -589,6 +590,25 @@</span><br><span>      uint8_t ta;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum lchan_modify_for {</span><br><span style="color: hsl(120, 100%, 40%);">+        MODIFY_FOR_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+      MODIFY_FOR_ASSIGNMENT,</span><br><span style="color: hsl(120, 100%, 40%);">+        MODIFY_FOR_VTY,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string lchan_modify_for_names[];</span><br><span style="color: hsl(120, 100%, 40%);">+static inline const char *lchan_modify_for_name(enum lchan_modify_for modify_for)</span><br><span style="color: hsl(120, 100%, 40%);">+{ return get_value_string(lchan_modify_for_names, modify_for); }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct lchan_modify_info {</span><br><span style="color: hsl(120, 100%, 40%);">+  enum lchan_modify_for modify_for;</span><br><span style="color: hsl(120, 100%, 40%);">+     enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool requires_voice_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t msc_assigned_cic;</span><br><span style="color: hsl(120, 100%, 40%);">+    /* AMR config */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gsm_lchan {</span><br><span>         /* The TS that we're part of */</span><br><span>  struct gsm_bts_trx_ts *ts;</span><br><span>@@ -614,6 +634,11 @@</span><br><span>    } activate;</span><br><span> </span><br><span>      struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct lchan_modify_info info;</span><br><span style="color: hsl(120, 100%, 40%);">+                bool concluded;</span><br><span style="color: hsl(120, 100%, 40%);">+       } modify;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span>             /* If an event to release the lchan comes in while still waiting for responses, just mark this</span><br><span>                * flag, so that the lchan will gracefully release at the next sensible junction. */</span><br><span>                 bool requested;</span><br><span>diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h</span><br><span>index 99964a4..74e2a96 100644</span><br><span>--- a/include/osmocom/bsc/lchan_fsm.h</span><br><span>+++ b/include/osmocom/bsc/lchan_fsm.h</span><br><span>@@ -65,6 +65,7 @@</span><br><span> </span><br><span> void lchan_activate(struct gsm_lchan *lchan, struct lchan_activate_info *info);</span><br><span> void lchan_ready_to_switch_rtp(struct gsm_lchan *lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+void lchan_mode_modify(struct gsm_lchan *lchan, struct lchan_modify_info *info);</span><br><span> </span><br><span> static inline const char *lchan_state_name(struct gsm_lchan *lchan)</span><br><span> {</span><br><span>diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c</span><br><span>index 3a17396..228cb1f 100644</span><br><span>--- a/src/osmo-bsc/assignment_fsm.c</span><br><span>+++ b/src/osmo-bsc/assignment_fsm.c</span><br><span>@@ -241,20 +241,23 @@</span><br><span> static void assignment_success(struct gsm_subscriber_connection *conn)</span><br><span> {</span><br><span>    struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool lchan_changed = (conn->assignment.new_lchan != NULL);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       /* Take on the new lchan */</span><br><span style="color: hsl(0, 100%, 40%);">-     gscon_change_primary_lchan(conn, conn->assignment.new_lchan);</span><br><span style="color: hsl(0, 100%, 40%);">-        conn->assignment.new_lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Take on the new lchan. If there only was a Channel Mode Modify, then there is no new lchan to take on. */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (lchan_changed) {</span><br><span style="color: hsl(120, 100%, 40%);">+          gscon_change_primary_lchan(conn, conn->assignment.new_lchan);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT((bts = conn_get_bts(conn)) != NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (is_siemens_bts(bts) && ts_is_tch(conn->lchan->ts)) {</span><br><span style="color: hsl(0, 100%, 40%);">-          /* HACK: store the actual Classmark 2 LV from the subscriber and use it here! */</span><br><span style="color: hsl(0, 100%, 40%);">-                uint8_t cm2_lv[] = { 0x02, 0x00, 0x00 };</span><br><span style="color: hsl(0, 100%, 40%);">-                send_siemens_mrpci(conn->lchan, cm2_lv);</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT((bts = conn_get_bts(conn)) != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (is_siemens_bts(bts) && ts_is_tch(conn->lchan->ts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        /* HACK: store the actual Classmark 2 LV from the subscriber and use it here! */</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint8_t cm2_lv[] = { 0x02, 0x00, 0x00 };</span><br><span style="color: hsl(120, 100%, 40%);">+                      send_siemens_mrpci(conn->lchan, cm2_lv);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* apply LCLS configuration (if any) */</span><br><span style="color: hsl(120, 100%, 40%);">+               lcls_apply_config(conn);</span><br><span>     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* apply LCLS configuration (if any) */</span><br><span style="color: hsl(0, 100%, 40%);">- lcls_apply_config(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+      conn->assignment.new_lchan = NULL;</span><br><span> </span><br><span>    send_assignment_complete(conn);</span><br><span>      /* If something went wrong during send_assignment_complete(), the fi will be gone from</span><br><span>@@ -267,15 +270,17 @@</span><br><span>               return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Rembered this only for error handling: should assignment fail, assignment_reset() will release</span><br><span style="color: hsl(0, 100%, 40%);">-        * the MGW endpoint right away. If successful, the conn continues to use the endpoint. */</span><br><span style="color: hsl(0, 100%, 40%);">-       conn->assignment.created_ci_for_msc = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lchan_changed) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Rembered this only for error handling: should assignment fail, assignment_reset() will release</span><br><span style="color: hsl(120, 100%, 40%);">+              * the MGW endpoint right away. If successful, the conn continues to use the endpoint. */</span><br><span style="color: hsl(120, 100%, 40%);">+             conn->assignment.created_ci_for_msc = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* New RTP information is now accepted */</span><br><span style="color: hsl(0, 100%, 40%);">-       conn->user_plane.msc_assigned_cic = conn->assignment.req.msc_assigned_cic;</span><br><span style="color: hsl(0, 100%, 40%);">-        osmo_strlcpy(conn->user_plane.msc_assigned_rtp_addr, conn->assignment.req.msc_rtp_addr,</span><br><span style="color: hsl(0, 100%, 40%);">-                sizeof(conn->user_plane.msc_assigned_rtp_addr));</span><br><span style="color: hsl(0, 100%, 40%);">-        conn->user_plane.msc_assigned_rtp_port = conn->assignment.req.msc_rtp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* New RTP information is now accepted */</span><br><span style="color: hsl(120, 100%, 40%);">+             conn->user_plane.msc_assigned_cic = conn->assignment.req.msc_assigned_cic;</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_strlcpy(conn->user_plane.msc_assigned_rtp_addr, conn->assignment.req.msc_rtp_addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                      sizeof(conn->user_plane.msc_assigned_rtp_addr));</span><br><span style="color: hsl(120, 100%, 40%);">+              conn->user_plane.msc_assigned_rtp_port = conn->assignment.req.msc_rtp_port;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        LOG_ASSIGNMENT(conn, LOGL_DEBUG, "Assignment successful\n");</span><br><span>       osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);</span><br><span>@@ -285,7 +290,9 @@</span><br><span> </span><br><span> static void assignment_fsm_update_id(struct gsm_subscriber_connection *conn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsm_lchan *new_lchan = conn->assignment.new_lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Assignment can do a new channel activation, in which case new_lchan points at the new lchan.</span><br><span style="color: hsl(120, 100%, 40%);">+        * Or assignment can Channel Mode Modify the already used lchan, in which case new_lchan == NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_lchan *new_lchan = (conn->assignment.new_lchan ? : conn->lchan);</span><br><span>    if (!new_lchan) {</span><br><span>            osmo_fsm_inst_update_id(conn->assignment.fi, conn->fi->id);</span><br><span>                 return;</span><br><span>@@ -435,7 +442,8 @@</span><br><span>                [CH_RATE_FULL] = "FR",</span><br><span>     };</span><br><span>   struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct lchan_activate_info info;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct lchan_activate_info activ_info;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct lchan_modify_info modif_info;</span><br><span>         int i;</span><br><span> </span><br><span>   OSMO_ASSERT(conn);</span><br><span>@@ -465,6 +473,8 @@</span><br><span>      * LCHAN_EV_REQUEST_MODE_MODIFY in lchan_fsm.c. To not break the lchan, do not even attempt to re-use an lchan</span><br><span>        * that already has an RTP stream set up, rather establish a new lchan (that transition is well implemented). */</span><br><span>     if (reuse_existing_lchan(conn) && !conn->lchan->fi_rtp) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* The new lchan is the old lchan, keep new_lchan == NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+         conn->assignment.new_lchan = NULL;</span><br><span> </span><br><span>            /* If the requested mode and the current TCH mode matches up, just send the</span><br><span>           * assignment complete directly and be done with the assignment procedure. */</span><br><span>@@ -494,28 +504,17 @@</span><br><span>                               gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),</span><br><span>                             gsm_lchan_name(conn->lchan));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-             info = (struct lchan_activate_info){</span><br><span style="color: hsl(0, 100%, 40%);">-                    .activ_for = ACTIVATE_FOR_ASSIGNMENT,</span><br><span style="color: hsl(0, 100%, 40%);">-                   .for_conn = conn,</span><br><span style="color: hsl(120, 100%, 40%);">+             modif_info = (struct lchan_modify_info){</span><br><span style="color: hsl(120, 100%, 40%);">+                      .modify_for = MODIFY_FOR_ASSIGNMENT,</span><br><span>                         .chan_mode = conn->lchan->ch_mode_rate.chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">-                 .encr = conn->lchan->encr,</span><br><span style="color: hsl(0, 100%, 40%);">-                        .s15_s0 = conn->lchan->ch_mode_rate.s15_s0,</span><br><span>                    .requires_voice_stream = conn->assignment.requires_voice_stream,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .s15_s0 = conn->lchan->ch_mode_rate.s15_s0,</span><br><span>                    .msc_assigned_cic = req->msc_assigned_cic,</span><br><span style="color: hsl(0, 100%, 40%);">-                   .re_use_mgw_endpoint_from_lchan = conn->lchan,</span><br><span style="color: hsl(0, 100%, 40%);">-                       .ta = conn->lchan->last_ta,</span><br><span style="color: hsl(0, 100%, 40%);">-                       .ta_known = true,</span><br><span>            };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_fsm_inst_dispatch(conn->lchan->fi, LCHAN_EV_REQUEST_MODE_MODIFY, &info);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Since we opted not to allocate a new lchan, the new lchan is still the old lchan. */</span><br><span style="color: hsl(0, 100%, 40%);">-         conn->assignment.new_lchan = conn->lchan;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Also we need to skip the RR assignment, so we jump forward and wait for the lchan_fsm until it</span><br><span style="color: hsl(0, 100%, 40%);">-                * reaches the established state again. */</span><br><span style="color: hsl(0, 100%, 40%);">-              assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+               if (assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED))</span><br><span style="color: hsl(120, 100%, 40%);">+                      return;</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan_mode_modify(conn->lchan, &modif_info);</span><br><span>          return;</span><br><span>      }</span><br><span> </span><br><span>@@ -571,7 +570,7 @@</span><br><span>                 req->use_osmux ? "yes" : "no");</span><br><span> </span><br><span>    assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);</span><br><span style="color: hsl(0, 100%, 40%);">-      info = (struct lchan_activate_info){</span><br><span style="color: hsl(120, 100%, 40%);">+  activ_info = (struct lchan_activate_info){</span><br><span>           .activ_for = ACTIVATE_FOR_ASSIGNMENT,</span><br><span>                .for_conn = conn,</span><br><span>            .chan_mode = conn->lchan->ch_mode_rate.chan_mode,</span><br><span>@@ -583,7 +582,7 @@</span><br><span>                .ta = conn->lchan->last_ta,</span><br><span>            .ta_known = true,</span><br><span>    };</span><br><span style="color: hsl(0, 100%, 40%);">-      lchan_activate(conn->assignment.new_lchan, &info);</span><br><span style="color: hsl(120, 100%, 40%);">+     lchan_activate(conn->assignment.new_lchan, &activ_info);</span><br><span> }</span><br><span> </span><br><span> static void assignment_fsm_wait_lchan(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -695,8 +694,10 @@</span><br><span>                      conn->assignment.req.msc_rtp_addr,</span><br><span>                        conn->assignment.req.msc_rtp_port);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     /* Assignment can do a new channel activation, in which case new_lchan points at the new lchan.</span><br><span style="color: hsl(120, 100%, 40%);">+        * Or assignment can Channel Mode Modify the already used lchan, in which case new_lchan == NULL. */</span><br><span>         if (!gscon_connect_mgw_to_msc(conn,</span><br><span style="color: hsl(0, 100%, 40%);">-                                   conn->assignment.new_lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                                conn->assignment.new_lchan ? : conn->lchan,</span><br><span>                                    conn->assignment.req.msc_rtp_addr,</span><br><span>                                conn->assignment.req.msc_rtp_port,</span><br><span>                                fi,</span><br><span>@@ -742,6 +743,19 @@</span><br><span>     }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void assignment_fsm_wait_lchan_modified(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    case ASSIGNMENT_EV_LCHAN_MODIFIED:</span><br><span style="color: hsl(120, 100%, 40%);">+            assignment_fsm_post_lchan_established(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define S(x)  (1 << (x))</span><br><span> </span><br><span> static const struct osmo_fsm_state assignment_fsm_states[] = {</span><br><span>@@ -754,7 +768,7 @@</span><br><span>                 .out_state_mask = 0</span><br><span>                  | S(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE)</span><br><span>                         | S(ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE)</span><br><span style="color: hsl(0, 100%, 40%);">-                 | S(ASSIGNMENT_ST_WAIT_LCHAN_ESTABLISHED) /* MODE MODIFY */</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED)</span><br><span>                       ,</span><br><span>    },</span><br><span>   [ASSIGNMENT_ST_WAIT_RR_ASS_COMPLETE] = {</span><br><span>@@ -790,11 +804,22 @@</span><br><span>                     | S(ASSIGNMENT_EV_MSC_MGW_FAIL)</span><br><span>                      ,</span><br><span>    },</span><br><span style="color: hsl(120, 100%, 40%);">+    [ASSIGNMENT_ST_WAIT_LCHAN_MODIFIED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .name = "WAIT_LCHAN_MODIFIED",</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = assignment_fsm_wait_lchan_modified,</span><br><span style="color: hsl(120, 100%, 40%);">+         .in_event_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                    | S(ASSIGNMENT_EV_LCHAN_MODIFIED)</span><br><span style="color: hsl(120, 100%, 40%);">+                     ,</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(ASSIGNMENT_ST_WAIT_MGW_ENDPOINT_TO_MSC)</span><br><span style="color: hsl(120, 100%, 40%);">+                   ,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span> };</span><br><span> </span><br><span> static const struct value_string assignment_fsm_event_names[] = {</span><br><span>    OSMO_VALUE_STRING(ASSIGNMENT_EV_LCHAN_ACTIVE),</span><br><span>       OSMO_VALUE_STRING(ASSIGNMENT_EV_LCHAN_ESTABLISHED),</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(ASSIGNMENT_EV_LCHAN_MODIFIED),</span><br><span>     OSMO_VALUE_STRING(ASSIGNMENT_EV_LCHAN_ERROR),</span><br><span>        OSMO_VALUE_STRING(ASSIGNMENT_EV_MSC_MGW_OK),</span><br><span>         OSMO_VALUE_STRING(ASSIGNMENT_EV_MSC_MGW_FAIL),</span><br><span>@@ -807,6 +832,11 @@</span><br><span> void assignment_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span>      struct gsm_subscriber_connection *conn = assignment_fi_conn(fi);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Assignment can do a new channel activation, in which case new_lchan points at the new lchan.</span><br><span style="color: hsl(120, 100%, 40%);">+        * Or assignment can Channel Mode Modify the already used lchan, in which case new_lchan == NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_lchan *new_lchan = conn->assignment.new_lchan ? : conn->lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    switch (event) {</span><br><span> </span><br><span>         case ASSIGNMENT_EV_CONN_RELEASING:</span><br><span>@@ -815,10 +845,11 @@</span><br><span>           return;</span><br><span> </span><br><span>  case ASSIGNMENT_EV_LCHAN_ERROR:</span><br><span style="color: hsl(0, 100%, 40%);">-         if (data != conn->assignment.new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+            if (data != new_lchan)</span><br><span>                       return;</span><br><span style="color: hsl(0, 100%, 40%);">-         assignment_fail(conn->assignment.new_lchan->activate.gsm0808_error_cause,</span><br><span style="color: hsl(0, 100%, 40%);">-                         "Failed to activate lchan %s",</span><br><span style="color: hsl(120, 100%, 40%);">+              assignment_fail(new_lchan->activate.gsm0808_error_cause,</span><br><span style="color: hsl(120, 100%, 40%);">+                           "Failed to %s lchan %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                            conn->assignment.new_lchan ? "activate" : "modify",</span><br><span>                           gsm_lchan_name(conn->assignment.new_lchan));</span><br><span>              return;</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c</span><br><span>index d5a9d6b..6c08229 100644</span><br><span>--- a/src/osmo-bsc/gsm_data.c</span><br><span>+++ b/src/osmo-bsc/gsm_data.c</span><br><span>@@ -916,6 +916,13 @@</span><br><span>  {}</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string lchan_modify_for_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_VALUE_STRING(MODIFY_FOR_NONE),</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(MODIFY_FOR_ASSIGNMENT),</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(MODIFY_FOR_VTY),</span><br><span style="color: hsl(120, 100%, 40%);">+    {}</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* This may be specific to RR Channel Release, and the mappings were chosen by pure naive guessing without a proper</span><br><span>  * specification available. */</span><br><span> enum gsm48_rr_cause bsc_gsm48_rr_cause_from_gsm0808_cause(enum gsm0808_cause c)</span><br><span>diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c</span><br><span>index 83524e0..1735346 100644</span><br><span>--- a/src/osmo-bsc/lchan_fsm.c</span><br><span>+++ b/src/osmo-bsc/lchan_fsm.c</span><br><span>@@ -66,6 +66,53 @@</span><br><span>       }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void lchan_on_mode_modify_success(struct gsm_lchan *lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      lchan->modify.concluded = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (lchan->modify.info.modify_for) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case MODIFY_FOR_ASSIGNMENT:</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(lchan->conn->assignment.fi, ASSIGNMENT_EV_LCHAN_MODIFIED, lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define lchan_on_mode_modify_failure(lchan, modify_for, for_conn) \</span><br><span style="color: hsl(120, 100%, 40%);">+   _lchan_on_mode_modify_failure(lchan, modify_for, for_conn, \</span><br><span style="color: hsl(120, 100%, 40%);">+                               __FILE__, __LINE__)</span><br><span style="color: hsl(120, 100%, 40%);">+static void _lchan_on_mode_modify_failure(struct gsm_lchan *lchan, enum lchan_modify_for modify_for,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          struct gsm_subscriber_connection *for_conn,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   const char *file, int line)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      if (lchan->modify.concluded)</span><br><span style="color: hsl(120, 100%, 40%);">+               return;</span><br><span style="color: hsl(120, 100%, 40%);">+       lchan->modify.concluded = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (modify_for) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       case MODIFY_FOR_ASSIGNMENT:</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_LCHAN(lchan, LOGL_NOTICE, "Signalling Assignment FSM of error (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan->last_error ? : "unknown error");</span><br><span style="color: hsl(120, 100%, 40%);">+                _osmo_fsm_inst_dispatch(for_conn->assignment.fi, ASSIGNMENT_EV_LCHAN_ERROR, lchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 file, line);</span><br><span style="color: hsl(120, 100%, 40%);">+          return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     case MODIFY_FOR_VTY:</span><br><span style="color: hsl(120, 100%, 40%);">+          LOG_LCHAN(lchan, LOGL_ERROR, "VTY user invoked lchan Channel Mode Modify failed (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan->last_error ? : "unknown error");</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOG_LCHAN(lchan, LOGL_ERROR, "lchan Channel Mode Modify failed (%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       lchan->last_error ? : "unknown error");</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* The idea here is that we must not require to change any lchan state in order to deny a request. */</span><br><span> #define lchan_on_activation_failure(lchan, for_conn, activ_for) \</span><br><span>         _lchan_on_activation_failure(lchan, for_conn, activ_for, \</span><br><span>@@ -122,6 +169,10 @@</span><br><span>                      lchan->last_error ? : "unknown error");</span><br><span>               break;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    case ACTIVATE_FOR_MODE_MODIFY_RTP:</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan_on_mode_modify_failure(lchan, lchan->modify.info.modify_for, for_conn);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     default:</span><br><span>             LOG_LCHAN(lchan, LOGL_ERROR, "lchan activation failed (%s)\n",</span><br><span>                       lchan->last_error ? : "unknown error");</span><br><span>@@ -183,6 +234,10 @@</span><br><span>                 * we will try to roll back a modified RTP connection. */</span><br><span>            break;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    case ACTIVATE_FOR_MODE_MODIFY_RTP:</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan_on_mode_modify_success(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     default:</span><br><span>             LOG_LCHAN(lchan, LOGL_NOTICE, "lchan %s fully established\n",</span><br><span>                        lchan_activate_mode_name(lchan->activate.info.activ_for));</span><br><span>@@ -323,6 +378,18 @@</span><br><span>       /* Remain in state UNUSED */</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void lchan_mode_modify(struct gsm_lchan *lchan, struct lchan_modify_info *info)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(lchan && info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* To make sure that the lchan is actually allowed to initiate Mode Modify, feed through an FSM event. */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (osmo_fsm_inst_dispatch(lchan->fi, LCHAN_EV_REQUEST_MODE_MODIFY, info)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_LCHAN(lchan, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Channel Mode Modify requested, but cannot dispatch LCHAN_EV_REQUEST_MODE_MODIFY event\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan_on_mode_modify_failure(lchan, info->modify_for, lchan->conn);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void lchan_fsm_update_id(struct gsm_lchan *lchan)</span><br><span> {</span><br><span>      osmo_fsm_inst_update_id_f(lchan->fi, "%u-%u-%u-%s-%u",</span><br><span>@@ -881,7 +948,7 @@</span><br><span> static void lchan_fsm_wait_rr_chan_mode_modify_ack_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span>  struct gsm_lchan *lchan = lchan_fi_lchan(fi);</span><br><span style="color: hsl(0, 100%, 40%);">-   gsm48_lchan_modify(lchan, lchan->activate.info.chan_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+ gsm48_lchan_modify(lchan, lchan->modify.info.chan_mode);</span><br><span> }</span><br><span> </span><br><span> static void lchan_fsm_wait_rr_chan_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -921,10 +988,27 @@</span><br><span>     switch (event) {</span><br><span> </span><br><span>         case LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK:</span><br><span style="color: hsl(0, 100%, 40%);">-         if (lchan->activate.info.requires_voice_stream)</span><br><span style="color: hsl(120, 100%, 40%);">+            /* The Channel Mode Modify was ACKed, now the requested values become the accepted and used values. */</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->tch_mode = lchan->modify.info.chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+         lchan->s15_s0 = lchan->modify.info.s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if (lchan->modify.info.requires_voice_stream</span><br><span style="color: hsl(120, 100%, 40%);">+                   && !lchan->fi_rtp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* Continue with RTP stream establishing as done in lchan_activate(). Place the requested values in</span><br><span style="color: hsl(120, 100%, 40%);">+                    * lchan->activate.info and continue with voice stream setup. */</span><br><span style="color: hsl(120, 100%, 40%);">+                   lchan->activate.info = (struct lchan_activate_info){</span><br><span style="color: hsl(120, 100%, 40%);">+                               .activ_for = ACTIVATE_FOR_MODE_MODIFY_RTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                            .for_conn = lchan->conn,</span><br><span style="color: hsl(120, 100%, 40%);">+                           .s15_s0 = lchan->modify.info.s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+                               .requires_voice_stream = true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                .msc_assigned_cic = lchan->modify.info.msc_assigned_cic,</span><br><span style="color: hsl(120, 100%, 40%);">+                   };</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan->activate.concluded = false;</span><br><span>                        lchan_fsm_state_chg(LCHAN_ST_WAIT_RLL_RTP_ESTABLISH);</span><br><span style="color: hsl(0, 100%, 40%);">-           else</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span>                     lchan_fsm_state_chg(LCHAN_ST_ESTABLISHED);</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan_on_mode_modify_success(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>            return;</span><br><span> </span><br><span>  case LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK:</span><br><span>@@ -1014,7 +1098,7 @@</span><br><span> static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span>     struct gsm_lchan *lchan = lchan_fi_lchan(fi);</span><br><span style="color: hsl(0, 100%, 40%);">-   struct lchan_activate_info *info;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct lchan_modify_info *modif_info;</span><br><span>        struct osmo_mgcpc_ep_ci *use_mgwep_ci;</span><br><span> </span><br><span>   switch (event) {</span><br><span>@@ -1052,35 +1136,29 @@</span><br><span>                   return;</span><br><span>              }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           info = data;</span><br><span style="color: hsl(0, 100%, 40%);">-            lchan->activate.info = *info;</span><br><span style="color: hsl(120, 100%, 40%);">+              modif_info = data;</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->modify.info = *modif_info;</span><br><span style="color: hsl(120, 100%, 40%);">+          lchan->modify.concluded = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                if (info->chan_mode == GSM48_CMODE_SPEECH_AMR) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (lchan_mr_config(lchan, info->s15_s0) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (modif_info->chan_mode == GSM48_CMODE_SPEECH_AMR) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (lchan_mr_config(lchan, modif_info->s15_s0) < 0) {</span><br><span>                          lchan_fail("Can not generate multirate configuration IE\n");</span><br><span>                               return;</span><br><span>                      }</span><br><span>            }</span><br><span> </span><br><span>                LOG_LCHAN(lchan, LOGL_INFO,</span><br><span style="color: hsl(0, 100%, 40%);">-                       "Modification requested: %s voice=%s MGW-ci=%s type=%s tch-mode=%s encr-alg=A5/%u ck=%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   lchan_activate_mode_name(lchan->activate.info.activ_for),</span><br><span style="color: hsl(0, 100%, 40%);">-                    lchan->activate.info.requires_voice_stream ? "yes" : "no",</span><br><span style="color: hsl(0, 100%, 40%);">-                       lchan->activate.info.requires_voice_stream ?</span><br><span style="color: hsl(120, 100%, 40%);">+                       "Modification requested: %s voice=%s MGW-ci=%s type=%s tch-mode=%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan_modify_for_name(lchan->modify.info.modify_for),</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan->modify.info.requires_voice_stream ? "yes" : "no",</span><br><span style="color: hsl(120, 100%, 40%);">+                       lchan->modify.info.requires_voice_stream ?</span><br><span>                        (use_mgwep_ci ? osmo_mgcpc_ep_ci_name(use_mgwep_ci) : "new")</span><br><span>                       : "none",</span><br><span>                          gsm_lchant_name(lchan->type),</span><br><span style="color: hsl(0, 100%, 40%);">-                        gsm48_chan_mode_name(lchan->tch_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                       (lchan->activate.info.encr.alg_id ? : 1) - 1,</span><br><span style="color: hsl(0, 100%, 40%);">-                        lchan->activate.info.encr.key_len ? osmo_hexdump_nospc(lchan->activate.info.encr.key,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                                            lchan->activate.info.encr.key_len) : "none");</span><br><span style="color: hsl(120, 100%, 40%);">+                     gsm48_chan_mode_name(lchan->tch_mode));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                /* While the mode is changed the lchan is virtually "not activated", at least</span><br><span style="color: hsl(0, 100%, 40%);">-          * from the FSM implementations perspective */</span><br><span style="color: hsl(0, 100%, 40%);">-          lchan->activate.concluded = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           /* Initiate mode modification, start with the MS side (RR) */</span><br><span>                lchan_fsm_state_chg(LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK);</span><br><span>          return;</span><br><span> </span><br><span>@@ -1389,8 +1467,9 @@</span><br><span>                  | S(LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR)</span><br><span>                      ,</span><br><span>            .out_state_mask = 0</span><br><span style="color: hsl(0, 100%, 40%);">-                     | S(LCHAN_ST_BORKEN)</span><br><span>                         | S(LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK)</span><br><span style="color: hsl(120, 100%, 40%);">+                   | S(LCHAN_ST_WAIT_RF_RELEASE_ACK)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCHAN_ST_BORKEN)</span><br><span>                         ,</span><br><span>    },</span><br><span>   [LCHAN_ST_WAIT_RSL_CHAN_MODE_MODIFY_ACK] = {</span><br><span>@@ -1402,8 +1481,10 @@</span><br><span>                        | S(LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK)</span><br><span>                      ,</span><br><span>            .out_state_mask = 0</span><br><span style="color: hsl(0, 100%, 40%);">-                     | S(LCHAN_ST_BORKEN)</span><br><span style="color: hsl(120, 100%, 40%);">+                  | S(LCHAN_ST_ESTABLISHED)</span><br><span>                    | S(LCHAN_ST_WAIT_RLL_RTP_ESTABLISH)</span><br><span style="color: hsl(120, 100%, 40%);">+                  | S(LCHAN_ST_WAIT_RF_RELEASE_ACK)</span><br><span style="color: hsl(120, 100%, 40%);">+                     | S(LCHAN_ST_BORKEN)</span><br><span>                         ,</span><br><span>    },</span><br><span>   [LCHAN_ST_ESTABLISHED] = {</span><br><span>@@ -1514,6 +1595,7 @@</span><br><span>   OSMO_VALUE_STRING(LCHAN_EV_RR_CHAN_MODE_MODIFY_ERROR),</span><br><span>       OSMO_VALUE_STRING(LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK),</span><br><span>        OSMO_VALUE_STRING(LCHAN_EV_RSL_CHAN_MODE_MODIFY_NACK),</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(LCHAN_EV_REQUEST_MODE_MODIFY),</span><br><span>     {}</span><br><span> };</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/23943">change 23943</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/23943"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I4986844f839b1c9672c61d916eb3d33d0042d747 </div>
<div style="display:none"> Gerrit-Change-Number: 23943 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>