<p>fixeria <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bts/+/24153">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved
  pespin: Looks good to me, but someone else must approve

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">[VAMOS] Implement the concept of 'shadow' timeslots<br><br>Change-Id: I48b44b4df9ffb1cca105aebbd868c29b21f3b1d6<br>Depends: Ia0bd8695a3f12331b696fe69117189cdd48b584d<br>Related: SYS#4895, OS#4941<br>---<br>M include/osmo-bts/bts_trx.h<br>M include/osmo-bts/gsm_data.h<br>M include/osmo-bts/l1sap.h<br>M src/common/bts_trx.c<br>M src/common/gsm_data.c<br>M src/common/l1sap.c<br>M src/common/oml.c<br>M src/common/scheduler.c<br>M src/common/vty.c<br>9 files changed, 218 insertions(+), 68 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmo-bts/bts_trx.h b/include/osmo-bts/bts_trx.h</span><br><span>index d4c3f39..f033573 100644</span><br><span>--- a/include/osmo-bts/bts_trx.h</span><br><span>+++ b/include/osmo-bts/bts_trx.h</span><br><span>@@ -48,6 +48,7 @@</span><br><span> </span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);</span><br><span> struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);</span><br><span style="color: hsl(120, 100%, 40%);">+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx);</span><br><span> char *gsm_trx_name(const struct gsm_bts_trx *trx);</span><br><span> const char *gsm_trx_unit_id(struct gsm_bts_trx *trx);</span><br><span> </span><br><span>diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h</span><br><span>index 93eb2f0..6ce5c3b 100644</span><br><span>--- a/include/osmo-bts/gsm_data.h</span><br><span>+++ b/include/osmo-bts/gsm_data.h</span><br><span>@@ -463,6 +463,13 @@</span><br><span>       /* Implementation specific structure(s) */</span><br><span>   void *priv;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       /* VAMOS specific fields */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* NULL if BTS_FEAT_VAMOS is not set */</span><br><span style="color: hsl(120, 100%, 40%);">+               struct gsm_bts_trx_ts *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+          bool is_shadow;</span><br><span style="color: hsl(120, 100%, 40%);">+       } vamos;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   struct gsm_lchan lchan[TS_MAX_LCHAN];</span><br><span> };</span><br><span> </span><br><span>@@ -515,6 +522,12 @@</span><br><span> void gsm_lchan_name_update(struct gsm_lchan *lchan);</span><br><span> const char *gsm_lchans_name(enum gsm_lchan_state s);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define GSM_TS_NAME_FMT \</span><br><span style="color: hsl(120, 100%, 40%);">+ "bts=%u,trx=%u,ts=%u" "%s"</span><br><span style="color: hsl(120, 100%, 40%);">+#define GSM_TS_NAME_ARGS(ts) \</span><br><span style="color: hsl(120, 100%, 40%);">+        (ts)->trx->bts->nr, (ts)->trx->nr, (ts)->nr, \</span><br><span style="color: hsl(120, 100%, 40%);">+      (ts)->vamos.is_shadow ? ",shadow" : ""</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)</span><br><span> {</span><br><span>    return lchan->name;</span><br><span>diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h</span><br><span>index fe77431..f78d114 100644</span><br><span>--- a/include/osmo-bts/l1sap.h</span><br><span>+++ b/include/osmo-bts/l1sap.h</span><br><span>@@ -19,9 +19,11 @@</span><br><span> #define L1SAP_IS_LINK_SACCH(link_id) \</span><br><span>   ((link_id & 0xC0) == LID_SACCH)</span><br><span> #define L1SAP_IS_CHAN_TCHF(chan_nr) \</span><br><span style="color: hsl(0, 100%, 40%);">-    ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs)</span><br><span style="color: hsl(120, 100%, 40%);">+   ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs || \</span><br><span style="color: hsl(120, 100%, 40%);">+        (chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs)</span><br><span> #define L1SAP_IS_CHAN_TCHH(chan_nr) \</span><br><span style="color: hsl(0, 100%, 40%);">- ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs)</span><br><span style="color: hsl(120, 100%, 40%);">+   ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs || \</span><br><span style="color: hsl(120, 100%, 40%);">+        (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)</span><br><span> #define L1SAP_IS_CHAN_SDCCH4(chan_nr) \</span><br><span>    ((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH)</span><br><span> #define L1SAP_IS_CHAN_SDCCH8(chan_nr) \</span><br><span>@@ -37,6 +39,9 @@</span><br><span> #define L1SAP_IS_CHAN_CBCH(chan_nr) \</span><br><span>       ((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH4) \</span><br><span>      || ((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH8)</span><br><span style="color: hsl(120, 100%, 40%);">+#define L1SAP_IS_CHAN_VAMOS(chan_nr) \</span><br><span style="color: hsl(120, 100%, 40%);">+      ((chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs || \</span><br><span style="color: hsl(120, 100%, 40%);">+     (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)</span><br><span> </span><br><span> /* rach type from ra */</span><br><span> #define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70 && (ra & 0x0f) != 0x0f)</span><br><span>diff --git a/src/common/bts_trx.c b/src/common/bts_trx.c</span><br><span>index 3d295e5..a5d7ed3 100644</span><br><span>--- a/src/common/bts_trx.c</span><br><span>+++ b/src/common/bts_trx.c</span><br><span>@@ -1,5 +1,5 @@</span><br><span> /* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(0, 100%, 40%);">- * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span>  * All Rights Reserved</span><br><span>  *</span><br><span>  * This program is free software; you can redistribute it and/or modify</span><br><span>@@ -52,10 +52,76 @@</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Initialize all logical channels of the given timeslot */</span><br><span style="color: hsl(120, 100%, 40%);">+static void gsm_bts_trx_ts_init_lchan(struct gsm_bts_trx_ts *ts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int ln;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct gsm_lchan *lchan = &ts->lchan[ln];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->ts = ts;</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->nr = ln;</span><br><span style="color: hsl(120, 100%, 40%);">+            lchan->type = GSM_LCHAN_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+              gsm_lchan_name_update(lchan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               INIT_LLIST_HEAD(&lchan->sapi_cmds);</span><br><span style="color: hsl(120, 100%, 40%);">+            INIT_LLIST_HEAD(&lchan->dl_tch_queue);</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%);">+/* Initialize primary timeslots of the given transceiver */</span><br><span style="color: hsl(120, 100%, 40%);">+static void gsm_bts_trx_init_ts(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int tn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct gsm_bts_trx_ts *ts = &trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ts->trx = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+             ts->nr = tn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             ts->mo.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->mo.fi, "%s-ts%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                                    trx->bb_transc.mo.fi->id, ts->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+         gsm_mo_init(&ts->mo, trx->bts, NM_OC_CHANNEL,</span><br><span style="color: hsl(120, 100%, 40%);">+                           trx->bts->nr, trx->nr, ts->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             gsm_bts_trx_ts_init_lchan(ts);</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%);">+/* Initialize shadow timeslots of the given transceiver */</span><br><span style="color: hsl(120, 100%, 40%);">+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       unsigned int tn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct gsm_bts_trx_ts *ts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          ts = talloc_zero(trx, struct gsm_bts_trx_ts);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ts != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ts->trx = trx;</span><br><span style="color: hsl(120, 100%, 40%);">+             ts->nr = tn;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Link both primary and shadow */</span><br><span style="color: hsl(120, 100%, 40%);">+            trx->ts[tn].vamos.peer = ts;</span><br><span style="color: hsl(120, 100%, 40%);">+               ts->vamos.peer = &trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+              ts->vamos.is_shadow = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              /* Shadow timeslot uses the primary's NM FSM */</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(trx->ts[tn].mo.fi != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+            ts->mo.fi = trx->ts[tn].mo.fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                gsm_bts_trx_ts_init_lchan(ts);</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> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)</span><br><span> {</span><br><span>    struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);</span><br><span style="color: hsl(0, 100%, 40%);">- int k;</span><br><span> </span><br><span>   if (!trx)</span><br><span>            return NULL;</span><br><span>@@ -77,36 +143,7 @@</span><br><span>   gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,</span><br><span>                  bts->nr, trx->nr, 0xff);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  for (k = 0; k < TRX_NR_TS; k++) {</span><br><span style="color: hsl(0, 100%, 40%);">-            struct gsm_bts_trx_ts *ts = &trx->ts[k];</span><br><span style="color: hsl(0, 100%, 40%);">-         int l;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          ts->trx = trx;</span><br><span style="color: hsl(0, 100%, 40%);">-               ts->nr = k;</span><br><span style="color: hsl(0, 100%, 40%);">-          ts->pchan = GSM_PCHAN_NONE;</span><br><span style="color: hsl(0, 100%, 40%);">-          ts->dyn.pchan_is = GSM_PCHAN_NONE;</span><br><span style="color: hsl(0, 100%, 40%);">-           ts->dyn.pchan_want = GSM_PCHAN_NONE;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         ts->mo.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                LOGL_INFO, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_fsm_inst_update_id_f(ts->mo.fi, "bts%d-trx%d-ts%d",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     bts->nr, trx->nr, ts->nr);</span><br><span style="color: hsl(0, 100%, 40%);">-           gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,</span><br><span style="color: hsl(0, 100%, 40%);">-                     bts->nr, trx->nr, ts->nr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         for (l = 0; l < TS_MAX_LCHAN; l++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 struct gsm_lchan *lchan;</span><br><span style="color: hsl(0, 100%, 40%);">-                        lchan = &ts->lchan[l];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   lchan->ts = ts;</span><br><span style="color: hsl(0, 100%, 40%);">-                      lchan->nr = l;</span><br><span style="color: hsl(0, 100%, 40%);">-                       lchan->type = GSM_LCHAN_NONE;</span><br><span style="color: hsl(0, 100%, 40%);">-                        gsm_lchan_name_update(lchan);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                   INIT_LLIST_HEAD(&lchan->sapi_cmds);</span><br><span style="color: hsl(0, 100%, 40%);">-                      INIT_LLIST_HEAD(&lchan->dl_tch_queue);</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(120, 100%, 40%);">+     gsm_bts_trx_init_ts(trx);</span><br><span> </span><br><span>        if (trx->nr != 0)</span><br><span>                 trx->nominal_power = bts->c0->nominal_power;</span><br><span>diff --git a/src/common/gsm_data.c b/src/common/gsm_data.c</span><br><span>index 6328783..09664e2 100644</span><br><span>--- a/src/common/gsm_data.c</span><br><span>+++ b/src/common/gsm_data.c</span><br><span>@@ -107,11 +107,11 @@</span><br><span> </span><br><span> static char ts2str[255];</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",</span><br><span style="color: hsl(0, 100%, 40%);">-              ts->trx->bts->nr, ts->trx->nr, ts->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+    snprintf(ts2str, sizeof(ts2str),</span><br><span style="color: hsl(120, 100%, 40%);">+               "(" GSM_TS_NAME_FMT ")",</span><br><span style="color: hsl(120, 100%, 40%);">+          GSM_TS_NAME_ARGS(ts));</span><br><span> </span><br><span>  return ts2str;</span><br><span> }</span><br><span>@@ -123,15 +123,14 @@</span><br><span>  case GSM_PCHAN_TCH_F_TCH_H_PDCH:</span><br><span>             if (ts->dyn.pchan_is == ts->dyn.pchan_want)</span><br><span>                    snprintf(ts2str, sizeof(ts2str),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",</span><br><span style="color: hsl(0, 100%, 40%);">-                               ts->trx->bts->nr, ts->trx->nr, ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",</span><br><span style="color: hsl(120, 100%, 40%);">+                           GSM_TS_NAME_ARGS(ts),</span><br><span>                                gsm_pchan_name(ts->pchan),</span><br><span>                                gsm_pchan_name(ts->dyn.pchan_is));</span><br><span>               else</span><br><span>                         snprintf(ts2str, sizeof(ts2str),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "(bts=%d,trx=%d,ts=%d,pchan=%s"</span><br><span style="color: hsl(0, 100%, 40%);">-                               " switching %s -> %s)",</span><br><span style="color: hsl(0, 100%, 40%);">-                            ts->trx->bts->nr, ts->trx->nr, ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",</span><br><span style="color: hsl(120, 100%, 40%);">+                           GSM_TS_NAME_ARGS(ts),</span><br><span>                                gsm_pchan_name(ts->pchan),</span><br><span>                                gsm_pchan_name(ts->dyn.pchan_is),</span><br><span>                                 gsm_pchan_name(ts->dyn.pchan_want));</span><br><span>@@ -139,16 +138,15 @@</span><br><span>     case GSM_PCHAN_TCH_F_PDCH:</span><br><span>           if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)</span><br><span>                        snprintf(ts2str, sizeof(ts2str),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",</span><br><span style="color: hsl(0, 100%, 40%);">-                               ts->trx->bts->nr, ts->trx->nr, ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",</span><br><span style="color: hsl(120, 100%, 40%);">+                           GSM_TS_NAME_ARGS(ts),</span><br><span>                                gsm_pchan_name(ts->pchan),</span><br><span>                                (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"</span><br><span>                                                            : "TCH/F");</span><br><span>                 else</span><br><span>                         snprintf(ts2str, sizeof(ts2str),</span><br><span style="color: hsl(0, 100%, 40%);">-                                 "(bts=%d,trx=%d,ts=%d,pchan=%s"</span><br><span style="color: hsl(0, 100%, 40%);">-                               " switching %s -> %s)",</span><br><span style="color: hsl(0, 100%, 40%);">-                            ts->trx->bts->nr, ts->trx->nr, ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",</span><br><span style="color: hsl(120, 100%, 40%);">+                           GSM_TS_NAME_ARGS(ts),</span><br><span>                                gsm_pchan_name(ts->pchan),</span><br><span>                                (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"</span><br><span>                                                            : "TCH/F",</span><br><span>@@ -156,9 +154,8 @@</span><br><span>                                                                : "TCH/F");</span><br><span>            break;</span><br><span>       default:</span><br><span style="color: hsl(0, 100%, 40%);">-                snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,pchan=%s)",</span><br><span style="color: hsl(0, 100%, 40%);">-                     ts->trx->bts->nr, ts->trx->nr, ts->nr,</span><br><span style="color: hsl(0, 100%, 40%);">-                        gsm_pchan_name(ts->pchan));</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(ts2str, sizeof(ts2str), "(" GSM_TS_NAME_FMT ",pchan=%s)",</span><br><span style="color: hsl(120, 100%, 40%);">+                         GSM_TS_NAME_ARGS(ts), gsm_pchan_name(ts->pchan));</span><br><span>                break;</span><br><span>       }</span><br><span> </span><br><span>@@ -171,8 +168,8 @@</span><br><span>  const struct gsm_bts_trx *trx = ts->trx;</span><br><span>  char *name;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- name = talloc_asprintf(trx, "(bts=%u,trx=%u,ts=%u,ss=%u)",</span><br><span style="color: hsl(0, 100%, 40%);">-                           trx->bts->nr, trx->nr, ts->nr, lchan->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+      name = talloc_asprintf(trx, "(" GSM_TS_NAME_FMT ",ss=%u)",</span><br><span style="color: hsl(120, 100%, 40%);">+                               GSM_TS_NAME_ARGS(ts), lchan->nr);</span><br><span>  if (lchan->name != NULL)</span><br><span>          talloc_free(lchan->name);</span><br><span>         lchan->name = name;</span><br><span>@@ -248,19 +245,30 @@</span><br><span> </span><br><span> uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t chan_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>   switch (lchan->ts->pchan) {</span><br><span>    case GSM_PCHAN_TCH_F_TCH_H_PDCH:</span><br><span>             /* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the</span><br><span>                 * nonstandard value reflecting PDCH for Osmocom style dyn TS. */</span><br><span style="color: hsl(0, 100%, 40%);">-               return gsm_lchan_as_pchan2chan_nr(lchan,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                  lchan->ts->dyn.pchan_is);</span><br><span style="color: hsl(120, 100%, 40%);">+             chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, lchan->ts->dyn.pchan_is);</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span>       case GSM_PCHAN_TCH_F_PDCH:</span><br><span>           /* For ip.access style dyn TS, we always want to use the chan_nr as if it was TCH/F.</span><br><span>                  * We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */</span><br><span style="color: hsl(0, 100%, 40%);">-             return gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+            chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span>       default:</span><br><span style="color: hsl(0, 100%, 40%);">-                return gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* VAMOS: if this lchan belongs to a shadow timeslot, we must reflect</span><br><span style="color: hsl(120, 100%, 40%);">+  * this in the channel number.  Convert it to Osmocom specific value. */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (lchan->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return chan_nr;</span><br><span> }</span><br><span> </span><br><span> uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,</span><br><span>@@ -286,6 +294,11 @@</span><br><span>                 *rc = -EINVAL;</span><br><span> </span><br><span>   switch (cbits) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Bm_ACCHs:</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ts->vamos.peer == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          ts = ts->vamos.peer;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* fall-through */</span><br><span>   case ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs:</span><br><span>                lch_idx = 0;    /* TCH/F */</span><br><span>          if (ts->pchan != GSM_PCHAN_TCH_F &&</span><br><span>@@ -294,6 +307,12 @@</span><br><span>                    ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)</span><br><span>                      ok = false;</span><br><span>          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(0):</span><br><span style="color: hsl(120, 100%, 40%);">+   case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(1):</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ts->vamos.peer == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          ts = ts->vamos.peer;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* fall-through */</span><br><span>   case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(0):</span><br><span>     case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(1):</span><br><span>             lch_idx = cbits & 0x1;      /* TCH/H */</span><br><span>diff --git a/src/common/l1sap.c b/src/common/l1sap.c</span><br><span>index b0cffe5..b17bf01 100644</span><br><span>--- a/src/common/l1sap.c</span><br><span>+++ b/src/common/l1sap.c</span><br><span>@@ -95,18 +95,25 @@</span><br><span> struct gsm_lchan *get_lchan_by_chan_nr(struct gsm_bts_trx *trx,</span><br><span>                                   unsigned int chan_nr)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts_trx_ts *ts;</span><br><span>   unsigned int tn, ss;</span><br><span> </span><br><span>     tn = L1SAP_CHAN2TS(chan_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(tn < ARRAY_SIZE(trx->ts));</span><br><span style="color: hsl(120, 100%, 40%);">+  ts = &trx->ts[tn];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (L1SAP_IS_CHAN_VAMOS(chan_nr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ts->vamos.peer == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          ts = ts->vamos.peer;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        if (L1SAP_IS_CHAN_CBCH(chan_nr))</span><br><span>             ss = 2; /* CBCH is always on sub-slot 2 */</span><br><span>   else</span><br><span>                 ss = l1sap_chan2ss(chan_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-    OSMO_ASSERT(ss < ARRAY_SIZE(trx->ts[tn].lchan));</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ss < ARRAY_SIZE(ts->lchan));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      return &trx->ts[tn].lchan[ss];</span><br><span style="color: hsl(120, 100%, 40%);">+ return &ts->lchan[ss];</span><br><span> }</span><br><span> </span><br><span> static struct gsm_lchan *</span><br><span>@@ -1986,18 +1993,22 @@</span><br><span> </span><br><span>    /* Init DTX DL FSM if necessary */</span><br><span>   if (trx->bts->dtxd && lchan->type != GSM_LCHAN_SDCCH) {</span><br><span style="color: hsl(0, 100%, 40%);">-                char name[32];</span><br><span style="color: hsl(0, 100%, 40%);">-          snprintf(name, sizeof(name), "bts%u-trx%u-ts%u-ss%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                  trx->bts->nr, trx->nr, lchan->ts->nr, lchan->nr);</span><br><span>                 lchan->tch.dtx.dl_amr_fsm = osmo_fsm_inst_alloc(&dtx_dl_amr_fsm,</span><br><span>                                                              tall_bts_ctx,</span><br><span>                                                                lchan,</span><br><span>                                                               LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                             name);</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                NULL);</span><br><span>               if (!lchan->tch.dtx.dl_amr_fsm) {</span><br><span>                         l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0);</span><br><span>                   return -RSL_ERR_EQUIPMENT_FAIL;</span><br><span>              }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = osmo_fsm_inst_update_id_f(lchan->tch.dtx.dl_amr_fsm,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         "bts%u-trx%u-ts%u-ss%u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          trx->bts->nr, trx->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               lchan->ts->nr, lchan->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            lchan->ts->vamos.is_shadow ? "-shadow" : "");</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(rc == 0);</span><br><span>        }</span><br><span>    return 0;</span><br><span> }</span><br><span>diff --git a/src/common/oml.c b/src/common/oml.c</span><br><span>index aba8847..0e7fbd5 100644</span><br><span>--- a/src/common/oml.c</span><br><span>+++ b/src/common/oml.c</span><br><span>@@ -837,9 +837,17 @@</span><br><span>           ts->lchan[CCCH_LCHAN].type = GSM_LCHAN_CBCH;</span><br><span>              break;</span><br><span>       case GSM_PCHAN_TCH_F:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_F, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ts->vamos.peer->pchan = GSM_PCHAN_TCH_F;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span>            lchans_type_set(ts, GSM_LCHAN_TCH_F, 1);</span><br><span>             break;</span><br><span>       case GSM_PCHAN_TCH_H:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */</span><br><span style="color: hsl(120, 100%, 40%);">+                    lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_H, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+                       ts->vamos.peer->pchan = GSM_PCHAN_TCH_H;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span>            lchans_type_set(ts, GSM_LCHAN_TCH_H, 2);</span><br><span>             break;</span><br><span>       case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:</span><br><span>@@ -849,6 +857,10 @@</span><br><span>                   ts->lchan[2].type = GSM_LCHAN_CBCH;</span><br><span>               break;</span><br><span>       case GSM_PCHAN_PDCH:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ts->vamos.peer != NULL) { /* VAMOS: disable shadow lchans */</span><br><span style="color: hsl(120, 100%, 40%);">+                   lchans_type_set(ts->vamos.peer, GSM_LCHAN_NONE, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ts->vamos.peer->pchan = GSM_PCHAN_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span>            lchans_type_set(ts, GSM_LCHAN_PDTCH, 1);</span><br><span>             break;</span><br><span>       default:</span><br><span>diff --git a/src/common/scheduler.c b/src/common/scheduler.c</span><br><span>index 6472e89..eb0aecd 100644</span><br><span>--- a/src/common/scheduler.c</span><br><span>+++ b/src/common/scheduler.c</span><br><span>@@ -744,6 +744,10 @@</span><br><span>         struct osmo_phsap_prim *l1sap;</span><br><span>       uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       /* VAMOS: use Osmocom specific channel number */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (l1ts->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       /* compose primitive */</span><br><span>      msg = l1sap_msgb_alloc(l2_len);</span><br><span>      l1sap = msgb_l1sap_prim(msg);</span><br><span>@@ -780,6 +784,10 @@</span><br><span>         uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;</span><br><span>  struct gsm_lchan *lchan = &l1ts->ts->lchan[l1sap_chan2ss(chan_nr)];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     /* VAMOS: use Osmocom specific channel number */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (l1ts->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       /* compose primitive */</span><br><span>      msg = l1sap_msgb_alloc(tch_len);</span><br><span>     l1sap = msgb_l1sap_prim(msg);</span><br><span>@@ -831,6 +839,10 @@</span><br><span>                 return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* VAMOS: convert Osmocom specific channel number to a generic one */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (trx->ts[tn].vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+           l1sap->u.data.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);</span><br><span> </span><br><span>         return 0;</span><br><span>@@ -853,6 +865,10 @@</span><br><span>             return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* VAMOS: convert Osmocom specific channel number to a generic one */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (trx->ts[tn].vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+           l1sap->u.tch.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);</span><br><span> </span><br><span>         return 0;</span><br><span>@@ -874,6 +890,11 @@</span><br><span>     chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;</span><br><span>    link_id = trx_chan_desc[br->chan].link_id;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* VAMOS: use Osmocom specific channel number */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (l1ts->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       /* For handover detection, there are cases where the SACCH should remain inactive until the first RACH</span><br><span>        * indicating the TA is received. */</span><br><span>         if (L1SAP_IS_LINK_SACCH(link_id)</span><br><span>@@ -909,6 +930,11 @@</span><br><span>      chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;</span><br><span>    link_id = trx_chan_desc[br->chan].link_id;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* VAMOS: use Osmocom specific channel number */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (l1ts->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+          chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);</span><br><span> </span><br><span>         /* only send, if FACCH is selected */</span><br><span>@@ -1018,6 +1044,11 @@</span><br><span>       bool found = false;</span><br><span>  int i;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+    /* VAMOS: convert Osmocom specific channel number to a generic one,</span><br><span style="color: hsl(120, 100%, 40%);">+    * otherwise we won't match anything in trx_chan_desc[]. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (lchan->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* look for all matching chan_nr/link_id */</span><br><span>  for (i = 0; i < _TRX_CHAN_MAX; i++) {</span><br><span>             struct l1sched_chan_state *chan_state = &l1ts->chan_state[i];</span><br><span>@@ -1081,6 +1112,11 @@</span><br><span>        if (ts->pchan == GSM_PCHAN_PDCH)</span><br><span>          return 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* VAMOS: convert Osmocom specific channel number to a generic one,</span><br><span style="color: hsl(120, 100%, 40%);">+    * otherwise we won't match anything in trx_chan_desc[]. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+           chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* look for all matching chan_nr/link_id */</span><br><span>  for (i = 0; i < _TRX_CHAN_MAX; i++) {</span><br><span>             if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)</span><br><span>@@ -1133,6 +1169,11 @@</span><br><span>        if (lchan->ts->pchan == GSM_PCHAN_PDCH)</span><br><span>                return 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* VAMOS: convert Osmocom specific channel number to a generic one,</span><br><span style="color: hsl(120, 100%, 40%);">+    * otherwise we won't match anything in trx_chan_desc[]. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (lchan->ts->vamos.is_shadow)</span><br><span style="color: hsl(120, 100%, 40%);">+         chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* no algorithm given means a5/0 */</span><br><span>  if (algo <= 0)</span><br><span>            algo = 0;</span><br><span>diff --git a/src/common/vty.c b/src/common/vty.c</span><br><span>index ccc63e6..8a1bafc 100644</span><br><span>--- a/src/common/vty.c</span><br><span>+++ b/src/common/vty.c</span><br><span>@@ -1642,8 +1642,9 @@</span><br><span> {</span><br><span>  struct in_addr ia;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u: Type %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+    vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s), Lchan %u: Type %s%s",</span><br><span>              lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->ts->vamos.is_shadow ? "shadow" : "primary",</span><br><span>                 lchan->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE);</span><br><span>         /* show dyn TS details, if applicable */</span><br><span>     switch (lchan->ts->pchan) {</span><br><span>@@ -1718,8 +1719,9 @@</span><br><span> {</span><br><span>       const struct gsm_meas_rep_unidir *mru = &lchan->meas.ul_res;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- vty_out(vty, "BTS %u, TRX %u, Timeslot %u %s",</span><br><span style="color: hsl(120, 100%, 40%);">+      vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s) %s",</span><br><span>                lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                lchan->ts->vamos.is_shadow ? "shadow" : "primary",</span><br><span>                 gsm_pchan_name(lchan->ts->pchan));</span><br><span>     vty_out_dyn_ts_status(vty, lchan->ts);</span><br><span>    vty_out(vty, ", Lchan %u, Type %s, State %s - "</span><br><span>@@ -1760,6 +1762,8 @@</span><br><span>    for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {</span><br><span>             const struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];</span><br><span>            dump_lchan_trx_ts(ts, vty, dump_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ts->vamos.peer != NULL) /* VAMOS: shadow timeslot */</span><br><span style="color: hsl(120, 100%, 40%);">+                   dump_lchan_trx_ts(ts->vamos.peer, vty, dump_cb);</span><br><span>  }</span><br><span> </span><br><span>        return CMD_SUCCESS;</span><br><span>@@ -1870,7 +1874,8 @@</span><br><span>  int bts_nr = atoi(argv[idx+0]);</span><br><span>      int trx_nr = atoi(argv[idx+1]);</span><br><span>      int ts_nr = atoi(argv[idx+2]);</span><br><span style="color: hsl(0, 100%, 40%);">-  int lchan_nr = atoi(argv[idx+3]);</span><br><span style="color: hsl(120, 100%, 40%);">+     bool shadow = argv[idx+3][0] == 's';</span><br><span style="color: hsl(120, 100%, 40%);">+  int lchan_nr = atoi(argv[idx+4]);</span><br><span>    struct gsm_bts *bts;</span><br><span>         struct gsm_bts_trx *trx;</span><br><span>     struct gsm_bts_trx_ts *ts;</span><br><span>@@ -1886,6 +1891,11 @@</span><br><span>  if (ts_nr >= ARRAY_SIZE(trx->ts))</span><br><span>              return NULL;</span><br><span>         ts = &trx->ts[ts_nr];</span><br><span style="color: hsl(120, 100%, 40%);">+  if (shadow) { /* VAMOS shadow */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ts->vamos.peer == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          ts = ts->vamos.peer;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span>        if (lchan_nr >= ARRAY_SIZE(ts->lchan))</span><br><span>                 return NULL;</span><br><span>@@ -1894,7 +1904,7 @@</span><br><span> }</span><br><span> </span><br><span> #define BTS_T_T_L_CMD \</span><br><span style="color: hsl(0, 100%, 40%);">-        "bts <0-0> trx <0-255> ts <0-7> lchan <0-7>"</span><br><span style="color: hsl(120, 100%, 40%);">+        "bts <0-0> trx <0-255> ts <0-7> (lchan|shadow-lchan) <0-7>"</span><br><span> #define BTS_T_T_L_STR                  \</span><br><span>    "BTS related commands\n"      \</span><br><span>    "BTS number\n"                        \</span><br><span>@@ -1902,7 +1912,8 @@</span><br><span>    "TRX number\n"                        \</span><br><span>    "timeslot related commands\n" \</span><br><span>    "timeslot number\n"           \</span><br><span style="color: hsl(0, 100%, 40%);">-       "logical channel commands\n"  \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Primary logical channel commands\n"  \</span><br><span style="color: hsl(120, 100%, 40%);">+     "Shadow logical channel commands\n"   \</span><br><span>    "logical channel number\n"</span><br><span> </span><br><span> DEFUN(cfg_bts_gsmtap_remote_host,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bts/+/24153">change 24153</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/+/24153"/><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: I48b44b4df9ffb1cca105aebbd868c29b21f3b1d6 </div>
<div style="display:none"> Gerrit-Change-Number: 24153 </div>
<div style="display:none"> Gerrit-PatchSet: 13 </div>
<div style="display:none"> Gerrit-Owner: fixeria <vyanitskiy@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>