<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bts/+/20311">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: Introduce NM Channel FSM<br><br>Change-Id: I288cbfb4730b25a334ef1c3d6b9679d6f1d4cfc5<br>---<br>M include/osmo-bts/Makefile.am<br>M include/osmo-bts/gsm_data.h<br>A include/osmo-bts/nm_channel_fsm.h<br>M src/common/Makefile.am<br>M src/common/bts.c<br>M src/common/bts_trx.c<br>M src/common/nm_bb_transc_fsm.c<br>A src/common/nm_channel_fsm.c<br>M src/common/oml.c<br>M src/common/pcu_sock.c<br>M src/common/vty.c<br>M src/osmo-bts-litecell15/oml.c<br>M src/osmo-bts-oc2g/oml.c<br>M src/osmo-bts-octphy/l1_if.c<br>M src/osmo-bts-octphy/l1_oml.c<br>M src/osmo-bts-omldummy/bts_model.c<br>M src/osmo-bts-sysmo/l1_if.c<br>M src/osmo-bts-sysmo/oml.c<br>M src/osmo-bts-trx/l1_if.c<br>M src/osmo-bts-virtual/bts_model.c<br>20 files changed, 450 insertions(+), 147 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/11/20311/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am</span><br><span>index 4593f7a..45961e0 100644</span><br><span>--- a/include/osmo-bts/Makefile.am</span><br><span>+++ b/include/osmo-bts/Makefile.am</span><br><span>@@ -28,5 +28,6 @@</span><br><span>    dtx_dl_amr_fsm.h \</span><br><span>   ta_control.h \</span><br><span>       nm_bb_transc_fsm.h \</span><br><span style="color: hsl(120, 100%, 40%);">+  nm_channel_fsm.h \</span><br><span>   nm_radio_carrier_fsm.h \</span><br><span>     $(NULL)</span><br><span>diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h</span><br><span>index 3d01d55..98fb481 100644</span><br><span>--- a/include/osmo-bts/gsm_data.h</span><br><span>+++ b/include/osmo-bts/gsm_data.h</span><br><span>@@ -306,6 +306,13 @@</span><br><span>                      TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING */</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct nm_chan {</span><br><span style="color: hsl(120, 100%, 40%);">+        /* NM Channel FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool opstart_success; /* OPSTART went OK in lower layers and was acked */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_abis_mo mo;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* One Timeslot in a TRX */</span><br><span> struct gsm_bts_trx_ts {</span><br><span>       struct gsm_bts_trx *trx;</span><br><span>@@ -321,7 +328,7 @@</span><br><span>       } dyn;</span><br><span> </span><br><span>   unsigned int flags;</span><br><span style="color: hsl(0, 100%, 40%);">-     struct gsm_abis_mo mo;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct nm_chan nm_chan;</span><br><span>      int tsc;                /* -1 == use BTS TSC */</span><br><span> </span><br><span>  /* Frequency hopping parameters (configured via OML) */</span><br><span>diff --git a/include/osmo-bts/nm_channel_fsm.h b/include/osmo-bts/nm_channel_fsm.h</span><br><span>new file mode 100644</span><br><span>index 0000000..4f76db6</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmo-bts/nm_channel_fsm.h</span><br><span>@@ -0,0 +1,44 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* NM Channel FSM. Following 3GPP TS 12.21 Figure 2/GSM 12.21:</span><br><span style="color: hsl(120, 100%, 40%);">+  GSM 12.21 Objects' Operational state and availability status behaviour during initialization */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum nm_chan_op_fsm_states {</span><br><span style="color: hsl(120, 100%, 40%);">+    NM_CHAN_ST_OP_DISABLED_NOTINSTALLED,</span><br><span style="color: hsl(120, 100%, 40%);">+  NM_CHAN_ST_OP_DISABLED_DEPENDENCY,</span><br><span style="color: hsl(120, 100%, 40%);">+    NM_CHAN_ST_OP_DISABLED_OFFLINE,</span><br><span style="color: hsl(120, 100%, 40%);">+       NM_CHAN_ST_OP_ENABLED,</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%);">+enum nm_chan_op_fsm_events {</span><br><span style="color: hsl(120, 100%, 40%);">+    NM_CHAN_EV_BBTRANSC_INSTALLED,</span><br><span style="color: hsl(120, 100%, 40%);">+        NM_CHAN_EV_BBTRANSC_ENABLED,</span><br><span style="color: hsl(120, 100%, 40%);">+  NM_CHAN_EV_BBTRANSC_DISABLED,</span><br><span style="color: hsl(120, 100%, 40%);">+ NM_CHAN_EV_OPSTART_ACK,</span><br><span style="color: hsl(120, 100%, 40%);">+       NM_CHAN_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+      NM_CHAN_EV_DISABLE,</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 struct osmo_fsm nm_chan_fsm;</span><br><span>diff --git a/src/common/Makefile.am b/src/common/Makefile.am</span><br><span>index fe8de46..f5ec188 100644</span><br><span>--- a/src/common/Makefile.am</span><br><span>+++ b/src/common/Makefile.am</span><br><span>@@ -38,6 +38,7 @@</span><br><span>      scheduler_mframe.c \</span><br><span>         ta_control.c \</span><br><span>       nm_bb_transc_fsm.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  nm_channel_fsm.c \</span><br><span>   nm_radio_carrier_fsm.c \</span><br><span>     $(NULL)</span><br><span> </span><br><span>diff --git a/src/common/bts.c b/src/common/bts.c</span><br><span>index 4d8445c..0ba3ce0 100644</span><br><span>--- a/src/common/bts.c</span><br><span>+++ b/src/common/bts.c</span><br><span>@@ -410,7 +410,7 @@</span><br><span>               for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {</span><br><span>                    struct gsm_bts_trx_ts *ts = &trx->ts[j];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                     oml_tx_state_changed(&ts->mo);</span><br><span style="color: hsl(120, 100%, 40%);">+                 oml_tx_state_changed(&ts->nm_chan.mo);</span><br><span>                }</span><br><span>    }</span><br><span> </span><br><span>diff --git a/src/common/bts_trx.c b/src/common/bts_trx.c</span><br><span>index 6ffae9e..9551b73 100644</span><br><span>--- a/src/common/bts_trx.c</span><br><span>+++ b/src/common/bts_trx.c</span><br><span>@@ -30,6 +30,7 @@</span><br><span> #include <osmo-bts/phy_link.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)</span><br><span> {</span><br><span>@@ -65,7 +66,11 @@</span><br><span>           ts->dyn.pchan_want = GSM_PCHAN_NONE;</span><br><span>              ts->tsc = -1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,</span><br><span style="color: hsl(120, 100%, 40%);">+               ts->nm_chan.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 LOGL_INFO, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_fsm_inst_update_id_f(ts->nm_chan.fi, "bts%d-trx%d-ts%d",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      bts->nr, trx->nr, ts->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+         gsm_mo_init(&ts->nm_chan.mo, bts, NM_OC_CHANNEL,</span><br><span>                          bts->nr, trx->nr, ts->nr);</span><br><span> </span><br><span>          for (l = 0; l < TS_MAX_LCHAN; l++) {</span><br><span>diff --git a/src/common/nm_bb_transc_fsm.c b/src/common/nm_bb_transc_fsm.c</span><br><span>index 6dfb2b3..57d5557 100644</span><br><span>--- a/src/common/nm_bb_transc_fsm.c</span><br><span>+++ b/src/common/nm_bb_transc_fsm.c</span><br><span>@@ -34,6 +34,7 @@</span><br><span> #include <osmo-bts/bts.h></span><br><span> #include <osmo-bts/rsl.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> #include <osmo-bts/phy_link.h></span><br><span> </span><br><span> #define X(s) (1 << (s))</span><br><span>@@ -55,11 +56,16 @@</span><br><span> static void st_op_disabled_notinstalled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span> {</span><br><span>      struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span> </span><br><span>   switch (event) {</span><br><span>     case NM_BBTRANSC_EV_SW_ACT:</span><br><span>          oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);</span><br><span>             nm_bb_transc_fsm_state_chg(fi, NM_BBTRANSC_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           for (i = 0; i < TRX_NR_TS; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct gsm_bts_trx_ts *ts = &trx->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_BBTRANSC_INSTALLED, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span>            return;</span><br><span>      case NM_BBTRANSC_EV_RSL_UP:</span><br><span>          return;</span><br><span>@@ -79,8 +85,17 @@</span><br><span> static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span>      struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     trx->bb_transc.opstart_success = false;</span><br><span>   oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (prev_state == NM_BBTRANSC_ST_OP_ENABLED) {</span><br><span style="color: hsl(120, 100%, 40%);">+                for (i = 0; i < TRX_NR_TS; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct gsm_bts_trx_ts *ts = &trx->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_BBTRANSC_DISABLED, NULL);</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 void st_op_disabled_offline(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>@@ -127,7 +142,13 @@</span><br><span> static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span> {</span><br><span>      struct gsm_bts_trx *trx = (struct gsm_bts_trx *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+  int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < TRX_NR_TS; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct gsm_bts_trx_ts *ts = &trx->ts[i];</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_BBTRANSC_ENABLED, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> }</span><br><span> </span><br><span> static void st_op_enabled(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span>diff --git a/src/common/nm_channel_fsm.c b/src/common/nm_channel_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f2cdfb4</span><br><span>--- /dev/null</span><br><span>+++ b/src/common/nm_channel_fsm.c</span><br><span>@@ -0,0 +1,220 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* NM Radio Carrier FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Pau Espin Pedrol <pespin@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/tdef.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/protocol/gsm_12_21.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts_model.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/bts.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/rsl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define X(s) (1 << (s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define nm_chan_fsm_state_chg(fi, NEXT_STATE) \</span><br><span style="color: hsl(120, 100%, 40%);">+       osmo_fsm_inst_state_chg(fi, NEXT_STATE, 0, 0)</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%);">+// FSM STATE ACTIONS</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%);">+static void st_op_disabled_notinstalled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     ts->nm_chan.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+       oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED);</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%);">+static void st_op_disabled_notinstalled(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%);">+       struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</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%);">+      case NM_CHAN_EV_BBTRANSC_INSTALLED:</span><br><span style="color: hsl(120, 100%, 40%);">+           oml_mo_tx_sw_act_rep(&ts->nm_chan.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ts->trx->bb_transc.mo.nm_state.operational == NM_OPSTATE_ENABLED)</span><br><span style="color: hsl(120, 100%, 40%);">+                   nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_DEPENDENCY);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</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%);">+static void st_op_disabled_dependency_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     ts->nm_chan.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+       oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</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%);">+static void st_op_disabled_dependency(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%);">+    struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</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%);">+      case NM_CHAN_EV_OPSTART_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPFSML(fi, LOGL_NOTICE, "BSC trying to activate TS while still in avail=dependency. "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Allowing it to stay backward-compatible with older osmo-bts versions, but BSC is wrong.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             ts->nm_chan.opstart_success = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                oml_mo_opstart_ack(&ts->nm_chan.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+           nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_CHAN_EV_OPSTART_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+         ts->nm_chan.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+               oml_mo_opstart_nack(&ts->nm_chan.mo, (int)(intptr_t)data);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_CHAN_EV_BBTRANSC_ENABLED:</span><br><span style="color: hsl(120, 100%, 40%);">+             oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</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%);">+static void st_op_disabled_offline_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     ts->nm_chan.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+       oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE);</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%);">+static void st_op_disabled_offline(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%);">+ struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</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%);">+      case NM_CHAN_EV_OPSTART_ACK:</span><br><span style="color: hsl(120, 100%, 40%);">+          ts->nm_chan.opstart_success = true;</span><br><span style="color: hsl(120, 100%, 40%);">+                oml_mo_opstart_ack(&ts->nm_chan.mo);</span><br><span style="color: hsl(120, 100%, 40%);">+           nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_ENABLED);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_CHAN_EV_OPSTART_NACK:</span><br><span style="color: hsl(120, 100%, 40%);">+         ts->nm_chan.opstart_success = false;</span><br><span style="color: hsl(120, 100%, 40%);">+               oml_mo_opstart_nack(&ts->nm_chan.mo, (int)(intptr_t)data);</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_CHAN_EV_BBTRANSC_DISABLED:</span><br><span style="color: hsl(120, 100%, 40%);">+            oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</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%);">+static void st_op_enabled_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_trx_ts *ts = (struct gsm_bts_trx_ts *)fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+     oml_mo_state_chg(&ts->nm_chan.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</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%);">+static void st_op_enabled(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%);">+      case NM_CHAN_EV_BBTRANSC_DISABLED:</span><br><span style="color: hsl(120, 100%, 40%);">+            nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_DEPENDENCY);</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_CHAN_EV_DISABLE:</span><br><span style="color: hsl(120, 100%, 40%);">+              nm_chan_fsm_state_chg(fi, NM_CHAN_ST_OP_DISABLED_OFFLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return;</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</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%);">+static struct osmo_fsm_state nm_chan_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [NM_CHAN_ST_OP_DISABLED_NOTINSTALLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_CHAN_EV_BBTRANSC_INSTALLED),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "DISABLED_NOTINSTALLED",</span><br><span style="color: hsl(120, 100%, 40%);">+            .onenter = st_op_disabled_notinstalled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = st_op_disabled_notinstalled,</span><br><span style="color: hsl(120, 100%, 40%);">+        },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_CHAN_ST_OP_DISABLED_DEPENDENCY] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_CHAN_EV_OPSTART_ACK) |  /* backward compatibility, buggy BSC */</span><br><span style="color: hsl(120, 100%, 40%);">+                  X(NM_CHAN_EV_OPSTART_NACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                  X(NM_CHAN_EV_BBTRANSC_ENABLED),</span><br><span style="color: hsl(120, 100%, 40%);">+               .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_CHAN_ST_OP_ENABLED), /* backward compatibility, buggy BSC */</span><br><span style="color: hsl(120, 100%, 40%);">+             .name = "DISABLED_DEPENDENCY",</span><br><span style="color: hsl(120, 100%, 40%);">+              .onenter = st_op_disabled_dependency_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = st_op_disabled_dependency,</span><br><span style="color: hsl(120, 100%, 40%);">+  },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_CHAN_ST_OP_DISABLED_OFFLINE] = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_CHAN_EV_OPSTART_ACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_CHAN_EV_OPSTART_NACK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                  X(NM_CHAN_EV_BBTRANSC_DISABLED),</span><br><span style="color: hsl(120, 100%, 40%);">+              .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_CHAN_ST_OP_ENABLED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                    X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "DISABLED_OFFLINE",</span><br><span style="color: hsl(120, 100%, 40%);">+         .onenter = st_op_disabled_offline_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+           .action = st_op_disabled_offline,</span><br><span style="color: hsl(120, 100%, 40%);">+     },</span><br><span style="color: hsl(120, 100%, 40%);">+    [NM_CHAN_ST_OP_ENABLED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .in_event_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                      X(NM_CHAN_EV_BBTRANSC_DISABLED) |</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_CHAN_EV_DISABLE),</span><br><span style="color: hsl(120, 100%, 40%);">+                .out_state_mask =</span><br><span style="color: hsl(120, 100%, 40%);">+                     X(NM_CHAN_ST_OP_DISABLED_OFFLINE) |</span><br><span style="color: hsl(120, 100%, 40%);">+                   X(NM_CHAN_ST_OP_DISABLED_DEPENDENCY),</span><br><span style="color: hsl(120, 100%, 40%);">+         .name = "ENABLED",</span><br><span style="color: hsl(120, 100%, 40%);">+          .onenter = st_op_enabled_on_enter,</span><br><span style="color: hsl(120, 100%, 40%);">+            .action = st_op_enabled,</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%);">+const struct value_string nm_chan_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+     { NM_CHAN_EV_BBTRANSC_INSTALLED, "BBTRANSC_INSTALLED" },</span><br><span style="color: hsl(120, 100%, 40%);">+    { NM_CHAN_EV_BBTRANSC_ENABLED, "BBTRANSC_ENABLED" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { NM_CHAN_EV_BBTRANSC_DISABLED, "BBTRANSC_DISABLED" },</span><br><span style="color: hsl(120, 100%, 40%);">+      { NM_CHAN_EV_OPSTART_ACK, "OPSTART_ACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { NM_CHAN_EV_OPSTART_NACK, "OPSTART_NACK" },</span><br><span style="color: hsl(120, 100%, 40%);">+        { NM_CHAN_EV_DISABLE, "DISABLE" },</span><br><span style="color: hsl(120, 100%, 40%);">+  { 0, NULL }</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%);">+struct osmo_fsm nm_chan_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .name = "NM_CHAN_OP",</span><br><span style="color: hsl(120, 100%, 40%);">+       .states = nm_chan_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+ .num_states = ARRAY_SIZE(nm_chan_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+ .event_names = nm_chan_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+       .log_subsys = DOML,</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%);">+static __attribute__((constructor)) void nm_chan_fsm_init(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(osmo_fsm_register(&nm_chan_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/common/oml.c b/src/common/oml.c</span><br><span>index 19559b8..370cf2d 100644</span><br><span>--- a/src/common/oml.c</span><br><span>+++ b/src/common/oml.c</span><br><span>@@ -880,7 +880,7 @@</span><br><span> </span><br><span>     rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));</span><br><span>   if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                oml_tx_failure_event_rep(&ts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UNSUP_ATTR,</span><br><span style="color: hsl(120, 100%, 40%);">+             oml_tx_failure_event_rep(&ts->nm_chan.mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UNSUP_ATTR,</span><br><span>                                     "New value for Set Channel Attribute not supported");</span><br><span>             return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);</span><br><span>         }</span><br><span>@@ -927,11 +927,11 @@</span><br><span>    }</span><br><span> </span><br><span>        /* merge existing BTS attributes with new attributes */</span><br><span style="color: hsl(0, 100%, 40%);">- tp_merged = osmo_tlvp_copy(ts->mo.nm_attr, bts);</span><br><span style="color: hsl(120, 100%, 40%);">+   tp_merged = osmo_tlvp_copy(ts->nm_chan.mo.nm_attr, bts);</span><br><span>  osmo_tlvp_merge(tp_merged, &tp);</span><br><span> </span><br><span>     /* Call into BTS driver to check attribute values */</span><br><span style="color: hsl(0, 100%, 40%);">-    rc = bts_model_check_oml(bts, foh->msg_type, ts->mo.nm_attr, tp_merged, ts);</span><br><span style="color: hsl(120, 100%, 40%);">+    rc = bts_model_check_oml(bts, foh->msg_type, ts->nm_chan.mo.nm_attr, tp_merged, ts);</span><br><span>   if (rc < 0) {</span><br><span>             LOGPFOH(DOML, LOGL_ERROR, foh, "SET CHAN ATTR: invalid attribute value, rc=%d\n", rc);</span><br><span>             talloc_free(tp_merged);</span><br><span>@@ -940,8 +940,8 @@</span><br><span>        }</span><br><span> </span><br><span>        /* Success: replace old BTS attributes with new */</span><br><span style="color: hsl(0, 100%, 40%);">-      talloc_free(ts->mo.nm_attr);</span><br><span style="color: hsl(0, 100%, 40%);">- ts->mo.nm_attr = tp_merged;</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(ts->nm_chan.mo.nm_attr);</span><br><span style="color: hsl(120, 100%, 40%);">+       ts->nm_chan.mo.nm_attr = tp_merged;</span><br><span> </span><br><span>   /* 9.4.13 Channel Combination */</span><br><span>     if (TLVP_PRES_LEN(&tp, NM_ATT_CHAN_COMB, 1)) {</span><br><span>@@ -1551,7 +1551,7 @@</span><br><span>           trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);</span><br><span>             if (obj_inst->ts_nr >= TRX_NR_TS)</span><br><span>                      return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-            mo = &trx->ts[obj_inst->ts_nr].mo;</span><br><span style="color: hsl(120, 100%, 40%);">+          mo = &trx->ts[obj_inst->ts_nr].nm_chan.mo;</span><br><span>                 break;</span><br><span>       case NM_OC_SITE_MANAGER:</span><br><span>             mo = &bts->site_mgr.mo;</span><br><span>diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c</span><br><span>index 45047ba..0ecc526 100644</span><br><span>--- a/src/common/pcu_sock.c</span><br><span>+++ b/src/common/pcu_sock.c</span><br><span>@@ -211,7 +211,7 @@</span><br><span>        for (tn = 0; tn < 8; tn++) {</span><br><span>              const struct gsm_bts_trx_ts *ts = &trx->ts[tn];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-              if (ts->mo.nm_state.operational != NM_OPSTATE_ENABLED)</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ts->nm_chan.mo.nm_state.operational != NM_OPSTATE_ENABLED)</span><br><span>                    continue;</span><br><span>            if (!ts_should_be_pdch(ts))</span><br><span>                  continue;</span><br><span>@@ -907,7 +907,7 @@</span><br><span>                      break;</span><br><span>               for (j = 0; j < 8; j++) {</span><br><span>                         ts = &trx->ts[j];</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (ts->mo.nm_state.operational == NM_OPSTATE_ENABLED</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (ts->nm_chan.mo.nm_state.operational == NM_OPSTATE_ENABLED</span><br><span>                      && ts->pchan == GSM_PCHAN_PDCH) {</span><br><span>                                ts->lchan[0].rel_act_kind = LCHAN_REL_ACT_PCU;</span><br><span>                            l1sap_chan_rel(trx,</span><br><span>diff --git a/src/common/vty.c b/src/common/vty.c</span><br><span>index b442f83..b7132a9 100644</span><br><span>--- a/src/common/vty.c</span><br><span>+++ b/src/common/vty.c</span><br><span>@@ -1045,7 +1045,7 @@</span><br><span>                     ts->flags & TS_F_PDCH_ACTIVE ? "PDCH" : "TCH/F");</span><br><span>         vty_out(vty, "%s", VTY_NEWLINE);</span><br><span>   vty_out(vty, "  NM State: ");</span><br><span style="color: hsl(0, 100%, 40%);">- net_dump_nmstate(vty, &ts->mo.nm_state);</span><br><span style="color: hsl(120, 100%, 40%);">+       net_dump_nmstate(vty, &ts->nm_chan.mo.nm_state);</span><br><span> }</span><br><span> </span><br><span> DEFUN(show_ts,</span><br><span>diff --git a/src/osmo-bts-litecell15/oml.c b/src/osmo-bts-litecell15/oml.c</span><br><span>index a01df68..e10f818 100644</span><br><span>--- a/src/osmo-bts-litecell15/oml.c</span><br><span>+++ b/src/osmo-bts-litecell15/oml.c</span><br><span>@@ -45,6 +45,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "lc15bts.h"</span><br><span>@@ -278,38 +279,41 @@</span><br><span>                   get_value_string(lc15bts_l1prim_names, l1p->id),</span><br><span>                  get_value_string(lc15bts_l1status_names, status));</span><br><span>           msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case NM_OC_RADIO_CARRIER:</span><br><span>                    return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_NACK,</span><br><span>                                                  (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-           else</span><br><span style="color: hsl(0, 100%, 40%);">-                    return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(0, 100%, 40%);">-            return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Set to Operational State: Enabled */</span><br><span style="color: hsl(0, 100%, 40%);">- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(0, 100%, 40%);">-     mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-          DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(0, 100%, 40%);">-                    LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-              lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (cbch) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan_activate(cbch);</span><br><span style="color: hsl(120, 100%, 40%);">+         case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi, NM_CHAN_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(0);</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Send OPSTART ack */</span><br><span style="color: hsl(0, 100%, 40%);">-  return oml_mo_opstart_ack(mo);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_free(l1_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                        DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(120, 100%, 40%);">+                          LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (cbch) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                            lchan_activate(cbch);</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%);">+             return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> }</span><br><span> </span><br><span> static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,</span><br><span>@@ -319,7 +323,7 @@</span><br><span>        GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);</span><br><span>     GsmL1_MphConnectCnf_t *cnf = &l1p->u.mphConnectCnf;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  mo = &trx->ts[cnf->u8Tn].mo;</span><br><span style="color: hsl(120, 100%, 40%);">+        mo = &trx->ts[cnf->u8Tn].nm_chan.mo;</span><br><span>       return opstart_compl(mo, l1_msg);</span><br><span> }</span><br><span> </span><br><span>@@ -1886,6 +1890,7 @@</span><br><span>                 void *obj)</span><br><span> {</span><br><span>        struct gsm_bts_trx *trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span>   int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1898,7 +1903,8 @@</span><br><span>          rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(0, 100%, 40%);">-             rc = ts_opstart(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+         ts = (struct gsm_bts_trx_ts*) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ts_opstart(ts);</span><br><span>                 break;</span><br><span>       case NM_OC_BTS:</span><br><span>      case NM_OC_SITE_MANAGER:</span><br><span>diff --git a/src/osmo-bts-oc2g/oml.c b/src/osmo-bts-oc2g/oml.c</span><br><span>index 2f2730e..0464225 100644</span><br><span>--- a/src/osmo-bts-oc2g/oml.c</span><br><span>+++ b/src/osmo-bts-oc2g/oml.c</span><br><span>@@ -278,38 +278,41 @@</span><br><span>                    get_value_string(oc2gbts_l1prim_names, l1p->id),</span><br><span>                  get_value_string(oc2gbts_l1status_names, status));</span><br><span>           msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case NM_OC_RADIO_CARRIER:</span><br><span>                    return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_NACK,</span><br><span>                                                  (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-           else</span><br><span style="color: hsl(0, 100%, 40%);">-                    return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(0, 100%, 40%);">-            return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Set to Operational State: Enabled */</span><br><span style="color: hsl(0, 100%, 40%);">- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(0, 100%, 40%);">-     mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-          DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(0, 100%, 40%);">-                    LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-              lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (cbch) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan_activate(cbch);</span><br><span style="color: hsl(120, 100%, 40%);">+         case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi, NM_CHAN_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(0);</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Send OPSTART ack */</span><br><span style="color: hsl(0, 100%, 40%);">-  return oml_mo_opstart_ack(mo);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_free(l1_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                        DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(120, 100%, 40%);">+                          LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (cbch) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                            lchan_activate(cbch);</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%);">+             return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> }</span><br><span> </span><br><span> static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,</span><br><span>@@ -1894,6 +1897,7 @@</span><br><span>                    void *obj)</span><br><span> {</span><br><span>        struct gsm_bts_trx* trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span>   int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1906,6 +1910,7 @@</span><br><span>          rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           ts = (struct gsm_bts_trx_ts*) obj;</span><br><span>           rc = ts_opstart(obj);</span><br><span>                break;</span><br><span>       case NM_OC_BTS:</span><br><span>diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c</span><br><span>index 37a3e65..15353d0 100644</span><br><span>--- a/src/osmo-bts-octphy/l1_if.c</span><br><span>+++ b/src/osmo-bts-octphy/l1_if.c</span><br><span>@@ -311,15 +311,10 @@</span><br><span> /* For OctPHY, this only about sending state changes to BSC */</span><br><span> int l1if_activate_rf(struct gsm_bts_trx *trx, int on)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        int i;</span><br><span>       if (on) {</span><br><span>            /* signal availability */</span><br><span>            osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_SW_ACT, NULL);</span><br><span>          osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_SW_ACT, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span style="color: hsl(0, 100%, 40%);">-                 oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     NM_AVSTATE_DEPENDENCY);</span><br><span>     } else {</span><br><span>             osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_DISABLE, NULL);</span><br><span>                 osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_DISABLE, NULL);</span><br><span>diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c</span><br><span>index 50116b5..f1d873d 100644</span><br><span>--- a/src/osmo-bts-octphy/l1_oml.c</span><br><span>+++ b/src/osmo-bts-octphy/l1_oml.c</span><br><span>@@ -41,6 +41,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "l1_oml.h"</span><br><span>@@ -191,28 +192,28 @@</span><br><span>       /* TODO: Send NACK in case of error! */</span><br><span>      struct gsm_bts_trx *trx = gsm_bts_trx_num(mo->bts, mo->obj_inst.trx_nr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case NM_OC_RADIO_CARRIER:</span><br><span>            return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Set to Operational State: Enabled */</span><br><span style="color: hsl(0, 100%, 40%);">- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(0, 100%, 40%);">-     mo->obj_inst.ts_nr == 7) {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-          mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(0, 100%, 40%);">-                    LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-              lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (cbch) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan_activate(cbch);</span><br><span style="color: hsl(120, 100%, 40%);">+ case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                        DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(120, 100%, 40%);">+                          LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (cbch) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                            lchan_activate(cbch);</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span>            }</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span>      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Send OPSTART ack */</span><br><span style="color: hsl(0, 100%, 40%);">-  return oml_mo_opstart_ack(mo);</span><br><span> }</span><br><span> </span><br><span> static</span><br><span>@@ -1502,7 +1503,7 @@</span><br><span>    }</span><br><span> </span><br><span>        trx = ts->trx;</span><br><span style="color: hsl(0, 100%, 40%);">-       mo = &trx->ts[ar->PchId.byTimeslotNb].mo;</span><br><span style="color: hsl(120, 100%, 40%);">+   mo = &trx->ts[ar->PchId.byTimeslotNb].nm_chan.mo;</span><br><span> </span><br><span>      msgb_free(resp);</span><br><span> </span><br><span>diff --git a/src/osmo-bts-omldummy/bts_model.c b/src/osmo-bts-omldummy/bts_model.c</span><br><span>index 11b71bd..f55b881 100644</span><br><span>--- a/src/osmo-bts-omldummy/bts_model.c</span><br><span>+++ b/src/osmo-bts-omldummy/bts_model.c</span><br><span>@@ -37,6 +37,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> /* TODO: check if dummy method is sufficient, else implement */</span><br><span> int bts_model_lchan_deactivate(struct gsm_lchan *lchan)</span><br><span>@@ -77,13 +78,8 @@</span><br><span> static uint8_t vbts_set_bts(struct gsm_bts *bts)</span><br><span> {</span><br><span>       struct gsm_bts_trx *trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t tn;</span><br><span> </span><br><span>      llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span style="color: hsl(0, 100%, 40%);">-                   oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>                /* report availability of trx to the bts. this will trigger the rsl connection */</span><br><span>            osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_SW_ACT, NULL);</span><br><span>          osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_SW_ACT, NULL);</span><br><span>@@ -127,6 +123,7 @@</span><br><span> {</span><br><span>        int rc;</span><br><span>      struct gsm_bts_trx* trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts* ts;</span><br><span> </span><br><span>       switch (mo->obj_class) {</span><br><span>  case NM_OC_RADIO_CARRIER:</span><br><span>@@ -138,6 +135,9 @@</span><br><span>              rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           ts = (struct gsm_bts_trx_ts *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span>       case NM_OC_SITE_MANAGER:</span><br><span>     case NM_OC_BTS:</span><br><span>      case NM_OC_GPRS_NSE:</span><br><span>diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c</span><br><span>index e766cea..99b17e8 100644</span><br><span>--- a/src/osmo-bts-sysmo/l1_if.c</span><br><span>+++ b/src/osmo-bts-sysmo/l1_if.c</span><br><span>@@ -1219,7 +1219,6 @@</span><br><span>    SuperFemto_Prim_t *sysp = msgb_sysprim(resp);</span><br><span>        GsmL1_Status_t status;</span><br><span>       int on = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     unsigned int i;</span><br><span> </span><br><span>  if (sysp->id == SuperFemto_PrimId_ActivateRfCnf)</span><br><span>          on = 1;</span><br><span>@@ -1244,9 +1243,6 @@</span><br><span>              /* signal availability */</span><br><span>            osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_SW_ACT, NULL);</span><br><span>          osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_SW_ACT, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              for (i = 0; i < ARRAY_SIZE(trx->ts); i++)</span><br><span style="color: hsl(0, 100%, 40%);">-                 oml_mo_state_chg(&trx->ts[i].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span>         } else {</span><br><span>             bts_update_status(BTS_STATUS_RF_ACTIVE, 0);</span><br><span>          osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_DISABLE, NULL);</span><br><span>diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c</span><br><span>index e14bea3..0a5fd0a 100644</span><br><span>--- a/src/osmo-bts-sysmo/oml.c</span><br><span>+++ b/src/osmo-bts-sysmo/oml.c</span><br><span>@@ -42,6 +42,8 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "femtobts.h"</span><br><span>@@ -277,38 +279,41 @@</span><br><span>                        get_value_string(femtobts_l1prim_names, l1p->id),</span><br><span>                         get_value_string(femtobts_l1status_names, status));</span><br><span>          msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case NM_OC_RADIO_CARRIER:</span><br><span>                    return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_NACK,</span><br><span>                                                  (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-           else</span><br><span style="color: hsl(0, 100%, 40%);">-                    return oml_mo_opstart_nack(mo, NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_free(l1_msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* We already have a FSM for Radio Carrier, handle it there */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (mo->obj_class == NM_OC_RADIO_CARRIER)</span><br><span style="color: hsl(0, 100%, 40%);">-            return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Set to Operational State: Enabled */</span><br><span style="color: hsl(0, 100%, 40%);">- oml_mo_state_chg(mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (mo->obj_class == NM_OC_CHANNEL && mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(0, 100%, 40%);">-     mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(0, 100%, 40%);">-          DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(0, 100%, 40%);">-         mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(0, 100%, 40%);">-                    LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-              lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (cbch) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan_activate(cbch);</span><br><span style="color: hsl(120, 100%, 40%);">+         case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi, NM_CHAN_EV_OPSTART_NACK,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                (void*)(intptr_t)NM_NACK_CANT_PERFORM);</span><br><span style="color: hsl(120, 100%, 40%);">+         default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      OSMO_ASSERT(0);</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Send OPSTART ack */</span><br><span style="color: hsl(0, 100%, 40%);">-  return oml_mo_opstart_ack(mo);</span><br><span style="color: hsl(120, 100%, 40%);">+        msgb_free(l1_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+    switch (mo->obj_class) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case NM_OC_RADIO_CARRIER:</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* ugly hack to auto-activate all SAPIs for the BCCH/CCCH on TS0 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (mo->obj_inst.trx_nr == 0 &&</span><br><span style="color: hsl(120, 100%, 40%);">+                mo->obj_inst.ts_nr == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gsm_lchan *cbch = gsm_bts_get_cbch(mo->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                        DEBUGP(DL1C, "====> trying to activate lchans of BCCH\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                       mo->bts->c0->ts[0].lchan[CCCH_LCHAN].rel_act_kind =</span><br><span style="color: hsl(120, 100%, 40%);">+                          LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchan_activate(&mo->bts->c0->ts[0].lchan[CCCH_LCHAN]);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (cbch) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           cbch->rel_act_kind = LCHAN_REL_ACT_OML;</span><br><span style="color: hsl(120, 100%, 40%);">+                            lchan_activate(cbch);</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%);">+             return osmo_fsm_inst_dispatch(trx->ts[mo->obj_inst.ts_nr].nm_chan.fi,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> }</span><br><span> </span><br><span> static int opstart_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg,</span><br><span>@@ -318,7 +323,7 @@</span><br><span>        GsmL1_Prim_t *l1p = msgb_l1prim(l1_msg);</span><br><span>     GsmL1_MphConnectCnf_t *cnf = &l1p->u.mphConnectCnf;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  mo = &trx->ts[cnf->u8Tn].mo;</span><br><span style="color: hsl(120, 100%, 40%);">+        mo = &trx->ts[cnf->u8Tn].nm_chan.mo;</span><br><span>       return opstart_compl(mo, l1_msg);</span><br><span> }</span><br><span> </span><br><span>@@ -1772,6 +1777,7 @@</span><br><span>                 void *obj)</span><br><span> {</span><br><span>        struct gsm_bts_trx* trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span>   int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -1784,7 +1790,8 @@</span><br><span>          rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(0, 100%, 40%);">-             rc = ts_opstart(obj);</span><br><span style="color: hsl(120, 100%, 40%);">+         ts = (struct gsm_bts_trx_ts*) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = ts_opstart(ts);</span><br><span>                 break;</span><br><span>       case NM_OC_BTS:</span><br><span>      case NM_OC_SITE_MANAGER:</span><br><span>diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c</span><br><span>index 9797188..72aa74e 100644</span><br><span>--- a/src/osmo-bts-trx/l1_if.c</span><br><span>+++ b/src/osmo-bts-trx/l1_if.c</span><br><span>@@ -46,6 +46,7 @@</span><br><span> #include <osmo-bts/pcu_if.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> #include "l1_if.h"</span><br><span> #include "trx_if.h"</span><br><span>@@ -92,7 +93,6 @@</span><br><span> {</span><br><span>        struct phy_instance *pinst = l1h->phy_inst;</span><br><span>       struct gsm_bts_trx *trx = pinst->trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t tn;</span><br><span> </span><br><span>      /* HACK, we should change state when we receive first clock from</span><br><span>      * transceiver */</span><br><span>@@ -103,19 +103,9 @@</span><br><span>                     osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_SW_ACT, NULL);</span><br><span>                   pinst->u.osmotrx.sw_act_reported = true;</span><br><span>          }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span style="color: hsl(0, 100%, 40%);">-                   oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                           (l1h->config.slotmask & (1 << tn)) ?</span><br><span style="color: hsl(0, 100%, 40%);">-                                       NM_AVSTATE_DEPENDENCY :</span><br><span style="color: hsl(0, 100%, 40%);">-                                 NM_AVSTATE_NOT_INSTALLED);</span><br><span>   } else {</span><br><span>             osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_DISABLE, NULL);</span><br><span>                 osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_DISABLE, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span style="color: hsl(0, 100%, 40%);">-                   oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED,</span><br><span style="color: hsl(0, 100%, 40%);">-                           NM_AVSTATE_OFF_LINE);</span><br><span>        }</span><br><span> }</span><br><span> </span><br><span>@@ -604,6 +594,7 @@</span><br><span>                   void *obj)</span><br><span> {</span><br><span>        struct gsm_bts_trx *trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span>   int rc;</span><br><span> </span><br><span>  switch (mo->obj_class) {</span><br><span>@@ -617,6 +608,9 @@</span><br><span>            rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           ts = (struct gsm_bts_trx_ts *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span>       case NM_OC_BTS:</span><br><span>      case NM_OC_SITE_MANAGER:</span><br><span>     case NM_OC_GPRS_NSE:</span><br><span>diff --git a/src/osmo-bts-virtual/bts_model.c b/src/osmo-bts-virtual/bts_model.c</span><br><span>index 218697b..b89013b 100644</span><br><span>--- a/src/osmo-bts-virtual/bts_model.c</span><br><span>+++ b/src/osmo-bts-virtual/bts_model.c</span><br><span>@@ -37,6 +37,7 @@</span><br><span> #include <osmo-bts/l1sap.h></span><br><span> #include <osmo-bts/nm_radio_carrier_fsm.h></span><br><span> #include <osmo-bts/nm_bb_transc_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmo-bts/nm_channel_fsm.h></span><br><span> </span><br><span> #include "virtual_um.h"</span><br><span> </span><br><span>@@ -84,13 +85,8 @@</span><br><span> static uint8_t vbts_set_bts(struct gsm_bts *bts)</span><br><span> {</span><br><span>        struct gsm_bts_trx *trx;</span><br><span style="color: hsl(0, 100%, 40%);">-        uint8_t tn;</span><br><span> </span><br><span>      llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                for (tn = 0; tn < TRX_NR_TS; tn++)</span><br><span style="color: hsl(0, 100%, 40%);">-                   oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>                /* report availability of trx to the bts. this will trigger the rsl connection */</span><br><span>            osmo_fsm_inst_dispatch(trx->rc.fi, NM_RCARRIER_EV_SW_ACT, NULL);</span><br><span>          osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_SW_ACT, NULL);</span><br><span>@@ -141,6 +137,7 @@</span><br><span> {</span><br><span>        int rc;</span><br><span>      struct gsm_bts_trx* trx;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_trx_ts *ts;</span><br><span> </span><br><span>       switch (mo->obj_class) {</span><br><span>  case NM_OC_RADIO_CARRIER:</span><br><span>@@ -152,6 +149,9 @@</span><br><span>              rc = osmo_fsm_inst_dispatch(trx->bb_transc.fi, NM_BBTRANSC_EV_OPSTART_ACK, NULL);</span><br><span>                 break;</span><br><span>       case NM_OC_CHANNEL:</span><br><span style="color: hsl(120, 100%, 40%);">+           ts = (struct gsm_bts_trx_ts *) obj;</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = osmo_fsm_inst_dispatch(ts->nm_chan.fi, NM_CHAN_EV_OPSTART_ACK, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span>       case NM_OC_SITE_MANAGER:</span><br><span>     case NM_OC_BTS:</span><br><span>      case NM_OC_GPRS_NSE:</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/20311">change 20311</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-bts/+/20311"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bts </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I288cbfb4730b25a334ef1c3d6b9679d6f1d4cfc5 </div>
<div style="display:none"> Gerrit-Change-Number: 20311 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>