aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Yanitskiy <vyanitskiy@sysmocom.de>2021-05-27 18:26:29 +0200
committerVadim Yanitskiy <vyanitskiy@sysmocom.de>2021-06-05 00:34:36 +0200
commit0686ae612834c329546c2f65d04283685ec790ad (patch)
tree9d6d6b9268ebad97407768b0efc55ff08178bc32
parentd9daa3fd9ea2744de371190632b05b149feb4773 (diff)
[VAMOS] Implement the concept of 'shadow' timeslots
-rw-r--r--include/osmo-bts/bts_trx.h1
-rw-r--r--include/osmo-bts/gsm_data.h13
-rw-r--r--include/osmo-bts/l1sap.h9
-rw-r--r--src/common/bts_trx.c101
-rw-r--r--src/common/gsm_data.c63
-rw-r--r--src/common/l1sap.c25
-rw-r--r--src/common/oml.c12
-rw-r--r--src/common/scheduler.c41
-rw-r--r--src/common/vty.c21
9 files changed, 218 insertions, 68 deletions
diff --git a/include/osmo-bts/bts_trx.h b/include/osmo-bts/bts_trx.h
index d4c3f390..f033573f 100644
--- a/include/osmo-bts/bts_trx.h
+++ b/include/osmo-bts/bts_trx.h
@@ -48,6 +48,7 @@ static inline struct gsm_bts_trx *gsm_bts_bb_trx_get_trx(struct gsm_bts_bb_trx *
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx);
char *gsm_trx_name(const struct gsm_bts_trx *trx);
const char *gsm_trx_unit_id(struct gsm_bts_trx *trx);
diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h
index 93eb2f06..6ce5c3b7 100644
--- a/include/osmo-bts/gsm_data.h
+++ b/include/osmo-bts/gsm_data.h
@@ -463,6 +463,13 @@ struct gsm_bts_trx_ts {
/* Implementation specific structure(s) */
void *priv;
+ /* VAMOS specific fields */
+ struct {
+ /* NULL if BTS_FEAT_VAMOS is not set */
+ struct gsm_bts_trx_ts *peer;
+ bool is_shadow;
+ } vamos;
+
struct gsm_lchan lchan[TS_MAX_LCHAN];
};
@@ -515,6 +522,12 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts);
void gsm_lchan_name_update(struct gsm_lchan *lchan);
const char *gsm_lchans_name(enum gsm_lchan_state s);
+#define GSM_TS_NAME_FMT \
+ "bts=%u,trx=%u,ts=%u" "%s"
+#define GSM_TS_NAME_ARGS(ts) \
+ (ts)->trx->bts->nr, (ts)->trx->nr, (ts)->nr, \
+ (ts)->vamos.is_shadow ? ",shadow" : ""
+
static inline char *gsm_lchan_name(const struct gsm_lchan *lchan)
{
return lchan->name;
diff --git a/include/osmo-bts/l1sap.h b/include/osmo-bts/l1sap.h
index fe774312..f78d1143 100644
--- a/include/osmo-bts/l1sap.h
+++ b/include/osmo-bts/l1sap.h
@@ -19,9 +19,11 @@
#define L1SAP_IS_LINK_SACCH(link_id) \
((link_id & 0xC0) == LID_SACCH)
#define L1SAP_IS_CHAN_TCHF(chan_nr) \
- ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs)
+ ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs || \
+ (chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs)
#define L1SAP_IS_CHAN_TCHH(chan_nr) \
- ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs)
+ ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs || \
+ (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)
#define L1SAP_IS_CHAN_SDCCH4(chan_nr) \
((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH)
#define L1SAP_IS_CHAN_SDCCH8(chan_nr) \
@@ -37,6 +39,9 @@
#define L1SAP_IS_CHAN_CBCH(chan_nr) \
((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH4) \
|| ((chan_nr & 0xf8) == RSL_CHAN_OSMO_CBCH8)
+#define L1SAP_IS_CHAN_VAMOS(chan_nr) \
+ ((chan_nr & 0xf8) == RSL_CHAN_OSMO_VAMOS_Bm_ACCHs || \
+ (chan_nr & 0xf0) == RSL_CHAN_OSMO_VAMOS_Lm_ACCHs)
/* rach type from ra */
#define L1SAP_IS_PACKET_RACH(ra) ((ra & 0xf0) == 0x70 && (ra & 0x0f) != 0x0f)
diff --git a/src/common/bts_trx.c b/src/common/bts_trx.c
index 3d295e58..a5d7ed3d 100644
--- a/src/common/bts_trx.c
+++ b/src/common/bts_trx.c
@@ -1,5 +1,5 @@
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -52,10 +52,76 @@ static int gsm_bts_trx_talloc_destructor(struct gsm_bts_trx *trx)
return 0;
}
+/* Initialize all logical channels of the given timeslot */
+static void gsm_bts_trx_ts_init_lchan(struct gsm_bts_trx_ts *ts)
+{
+ unsigned int ln;
+
+ for (ln = 0; ln < ARRAY_SIZE(ts->lchan); ln++) {
+ struct gsm_lchan *lchan = &ts->lchan[ln];
+
+ lchan->ts = ts;
+ lchan->nr = ln;
+ lchan->type = GSM_LCHAN_NONE;
+ gsm_lchan_name_update(lchan);
+
+ INIT_LLIST_HEAD(&lchan->sapi_cmds);
+ INIT_LLIST_HEAD(&lchan->dl_tch_queue);
+ }
+}
+
+/* Initialize primary timeslots of the given transceiver */
+static void gsm_bts_trx_init_ts(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+
+ ts->trx = trx;
+ ts->nr = tn;
+
+ ts->mo.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,
+ LOGL_INFO, NULL);
+ osmo_fsm_inst_update_id_f(ts->mo.fi, "%s-ts%u",
+ trx->bb_transc.mo.fi->id, ts->nr);
+ gsm_mo_init(&ts->mo, trx->bts, NM_OC_CHANNEL,
+ trx->bts->nr, trx->nr, ts->nr);
+
+ gsm_bts_trx_ts_init_lchan(ts);
+ }
+}
+
+/* Initialize shadow timeslots of the given transceiver */
+void gsm_bts_trx_init_shadow_ts(struct gsm_bts_trx *trx)
+{
+ unsigned int tn;
+
+ for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) {
+ struct gsm_bts_trx_ts *ts;
+
+ ts = talloc_zero(trx, struct gsm_bts_trx_ts);
+ OSMO_ASSERT(ts != NULL);
+
+ ts->trx = trx;
+ ts->nr = tn;
+
+ /* Link both primary and shadow */
+ trx->ts[tn].vamos.peer = ts;
+ ts->vamos.peer = &trx->ts[tn];
+ ts->vamos.is_shadow = true;
+
+ /* Shadow timeslot uses the primary's NM FSM */
+ OSMO_ASSERT(trx->ts[tn].mo.fi != NULL);
+ ts->mo.fi = trx->ts[tn].mo.fi;
+
+ gsm_bts_trx_ts_init_lchan(ts);
+ }
+}
+
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);
- int k;
if (!trx)
return NULL;
@@ -77,36 +143,7 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
gsm_mo_init(&trx->bb_transc.mo, bts, NM_OC_BASEB_TRANSC,
bts->nr, trx->nr, 0xff);
- for (k = 0; k < TRX_NR_TS; k++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[k];
- int l;
-
- ts->trx = trx;
- ts->nr = k;
- ts->pchan = GSM_PCHAN_NONE;
- ts->dyn.pchan_is = GSM_PCHAN_NONE;
- ts->dyn.pchan_want = GSM_PCHAN_NONE;
-
- ts->mo.fi = osmo_fsm_inst_alloc(&nm_chan_fsm, trx, ts,
- LOGL_INFO, NULL);
- osmo_fsm_inst_update_id_f(ts->mo.fi, "bts%d-trx%d-ts%d",
- bts->nr, trx->nr, ts->nr);
- gsm_mo_init(&ts->mo, bts, NM_OC_CHANNEL,
- bts->nr, trx->nr, ts->nr);
-
- for (l = 0; l < TS_MAX_LCHAN; l++) {
- struct gsm_lchan *lchan;
- lchan = &ts->lchan[l];
-
- lchan->ts = ts;
- lchan->nr = l;
- lchan->type = GSM_LCHAN_NONE;
- gsm_lchan_name_update(lchan);
-
- INIT_LLIST_HEAD(&lchan->sapi_cmds);
- INIT_LLIST_HEAD(&lchan->dl_tch_queue);
- }
- }
+ gsm_bts_trx_init_ts(trx);
if (trx->nr != 0)
trx->nominal_power = bts->c0->nominal_power;
diff --git a/src/common/gsm_data.c b/src/common/gsm_data.c
index 63287837..09664e24 100644
--- a/src/common/gsm_data.c
+++ b/src/common/gsm_data.c
@@ -107,11 +107,11 @@ const char *gsm_lchans_name(enum gsm_lchan_state s)
static char ts2str[255];
-
char *gsm_ts_name(const struct gsm_bts_trx_ts *ts)
{
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr);
+ snprintf(ts2str, sizeof(ts2str),
+ "(" GSM_TS_NAME_FMT ")",
+ GSM_TS_NAME_ARGS(ts));
return ts2str;
}
@@ -123,15 +123,14 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
case GSM_PCHAN_TCH_F_TCH_H_PDCH:
if (ts->dyn.pchan_is == ts->dyn.pchan_want)
snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",
+ GSM_TS_NAME_ARGS(ts),
gsm_pchan_name(ts->pchan),
gsm_pchan_name(ts->dyn.pchan_is));
else
snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s"
- " switching %s -> %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",
+ GSM_TS_NAME_ARGS(ts),
gsm_pchan_name(ts->pchan),
gsm_pchan_name(ts->dyn.pchan_is),
gsm_pchan_name(ts->dyn.pchan_want));
@@ -139,16 +138,15 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
case GSM_PCHAN_TCH_F_PDCH:
if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)
snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s as %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ "(" GSM_TS_NAME_FMT ",pchan=%s as %s)",
+ GSM_TS_NAME_ARGS(ts),
gsm_pchan_name(ts->pchan),
(ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
: "TCH/F");
else
snprintf(ts2str, sizeof(ts2str),
- "(bts=%d,trx=%d,ts=%d,pchan=%s"
- " switching %s -> %s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
+ "(" GSM_TS_NAME_FMT ",pchan=%s switching %s -> %s)",
+ GSM_TS_NAME_ARGS(ts),
gsm_pchan_name(ts->pchan),
(ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
: "TCH/F",
@@ -156,9 +154,8 @@ char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts)
: "TCH/F");
break;
default:
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d,pchan=%s)",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan));
+ snprintf(ts2str, sizeof(ts2str), "(" GSM_TS_NAME_FMT ",pchan=%s)",
+ GSM_TS_NAME_ARGS(ts), gsm_pchan_name(ts->pchan));
break;
}
@@ -171,8 +168,8 @@ void gsm_lchan_name_update(struct gsm_lchan *lchan)
const struct gsm_bts_trx *trx = ts->trx;
char *name;
- name = talloc_asprintf(trx, "(bts=%u,trx=%u,ts=%u,ss=%u)",
- trx->bts->nr, trx->nr, ts->nr, lchan->nr);
+ name = talloc_asprintf(trx, "(" GSM_TS_NAME_FMT ",ss=%u)",
+ GSM_TS_NAME_ARGS(ts), lchan->nr);
if (lchan->name != NULL)
talloc_free(lchan->name);
lchan->name = name;
@@ -248,19 +245,30 @@ static uint8_t gsm_pchan2chan_nr(enum gsm_phys_chan_config pchan,
uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan)
{
+ uint8_t chan_nr;
+
switch (lchan->ts->pchan) {
case GSM_PCHAN_TCH_F_TCH_H_PDCH:
/* Return chan_nr reflecting the current TS pchan, either a standard TCH kind, or the
* nonstandard value reflecting PDCH for Osmocom style dyn TS. */
- return gsm_lchan_as_pchan2chan_nr(lchan,
- lchan->ts->dyn.pchan_is);
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, lchan->ts->dyn.pchan_is);
+ break;
case GSM_PCHAN_TCH_F_PDCH:
/* For ip.access style dyn TS, we always want to use the chan_nr as if it was TCH/F.
* We're using custom PDCH ACT and DEACT messages that use the usual chan_nr values. */
- return gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ chan_nr = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_TCH_F);
+ break;
default:
- return gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
+ chan_nr = gsm_pchan2chan_nr(lchan->ts->pchan, lchan->ts->nr, lchan->nr);
+ break;
}
+
+ /* VAMOS: if this lchan belongs to a shadow timeslot, we must reflect
+ * this in the channel number. Convert it to Osmocom specific value. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
+ return chan_nr;
}
uint8_t gsm_lchan_as_pchan2chan_nr(const struct gsm_lchan *lchan,
@@ -286,6 +294,11 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
*rc = -EINVAL;
switch (cbits) {
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Bm_ACCHs:
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ /* fall-through */
case ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs:
lch_idx = 0; /* TCH/F */
if (ts->pchan != GSM_PCHAN_TCH_F &&
@@ -294,6 +307,12 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
ok = false;
break;
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(0):
+ case ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(1):
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ /* fall-through */
case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(0):
case ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(1):
lch_idx = cbits & 0x1; /* TCH/H */
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index b0cffe5c..b17bf011 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -95,18 +95,25 @@ unsigned int l1sap_fn2ccch_block(uint32_t fn)
struct gsm_lchan *get_lchan_by_chan_nr(struct gsm_bts_trx *trx,
unsigned int chan_nr)
{
+ struct gsm_bts_trx_ts *ts;
unsigned int tn, ss;
tn = L1SAP_CHAN2TS(chan_nr);
- OSMO_ASSERT(tn < ARRAY_SIZE(trx->ts));
+ ts = &trx->ts[tn];
+
+ if (L1SAP_IS_CHAN_VAMOS(chan_nr)) {
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ }
if (L1SAP_IS_CHAN_CBCH(chan_nr))
ss = 2; /* CBCH is always on sub-slot 2 */
else
ss = l1sap_chan2ss(chan_nr);
- OSMO_ASSERT(ss < ARRAY_SIZE(trx->ts[tn].lchan));
+ OSMO_ASSERT(ss < ARRAY_SIZE(ts->lchan));
- return &trx->ts[tn].lchan[ss];
+ return &ts->lchan[ss];
}
static struct gsm_lchan *
@@ -1986,18 +1993,22 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *
/* Init DTX DL FSM if necessary */
if (trx->bts->dtxd && lchan->type != GSM_LCHAN_SDCCH) {
- char name[32];
- snprintf(name, sizeof(name), "bts%u-trx%u-ts%u-ss%u",
- trx->bts->nr, trx->nr, lchan->ts->nr, lchan->nr);
lchan->tch.dtx.dl_amr_fsm = osmo_fsm_inst_alloc(&dtx_dl_amr_fsm,
tall_bts_ctx,
lchan,
LOGL_DEBUG,
- name);
+ NULL);
if (!lchan->tch.dtx.dl_amr_fsm) {
l1sap_chan_act_dact_modify(trx, chan_nr, PRIM_INFO_DEACTIVATE, 0);
return -RSL_ERR_EQUIPMENT_FAIL;
}
+
+ rc = osmo_fsm_inst_update_id_f(lchan->tch.dtx.dl_amr_fsm,
+ "bts%u-trx%u-ts%u-ss%u%s",
+ trx->bts->nr, trx->nr,
+ lchan->ts->nr, lchan->nr,
+ lchan->ts->vamos.is_shadow ? "-shadow" : "");
+ OSMO_ASSERT(rc == 0);
}
return 0;
}
diff --git a/src/common/oml.c b/src/common/oml.c
index aba88473..0e7fbd56 100644
--- a/src/common/oml.c
+++ b/src/common/oml.c
@@ -837,9 +837,17 @@ int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
ts->lchan[CCCH_LCHAN].type = GSM_LCHAN_CBCH;
break;
case GSM_PCHAN_TCH_F:
+ if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_F, 1);
+ ts->vamos.peer->pchan = GSM_PCHAN_TCH_F;
+ }
lchans_type_set(ts, GSM_LCHAN_TCH_F, 1);
break;
case GSM_PCHAN_TCH_H:
+ if (ts->vamos.peer != NULL) { /* VAMOS: enable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_TCH_H, 2);
+ ts->vamos.peer->pchan = GSM_PCHAN_TCH_H;
+ }
lchans_type_set(ts, GSM_LCHAN_TCH_H, 2);
break;
case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
@@ -849,6 +857,10 @@ int conf_lchans_as_pchan(struct gsm_bts_trx_ts *ts,
ts->lchan[2].type = GSM_LCHAN_CBCH;
break;
case GSM_PCHAN_PDCH:
+ if (ts->vamos.peer != NULL) { /* VAMOS: disable shadow lchans */
+ lchans_type_set(ts->vamos.peer, GSM_LCHAN_NONE, 1);
+ ts->vamos.peer->pchan = GSM_PCHAN_NONE;
+ }
lchans_type_set(ts, GSM_LCHAN_PDTCH, 1);
break;
default:
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index 6472e894..eb0aecdc 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -744,6 +744,10 @@ int _sched_compose_ph_data_ind(struct l1sched_ts *l1ts, uint32_t fn,
struct osmo_phsap_prim *l1sap;
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
/* compose primitive */
msg = l1sap_msgb_alloc(l2_len);
l1sap = msgb_l1sap_prim(msg);
@@ -780,6 +784,10 @@ int _sched_compose_tch_ind(struct l1sched_ts *l1ts, uint32_t fn,
uint8_t chan_nr = trx_chan_desc[chan].chan_nr | l1ts->ts->nr;
struct gsm_lchan *lchan = &l1ts->ts->lchan[l1sap_chan2ss(chan_nr)];
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
/* compose primitive */
msg = l1sap_msgb_alloc(tch_len);
l1sap = msgb_l1sap_prim(msg);
@@ -831,6 +839,10 @@ int trx_sched_ph_data_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap
return 0;
}
+ /* VAMOS: convert Osmocom specific channel number to a generic one */
+ if (trx->ts[tn].vamos.is_shadow)
+ l1sap->u.data.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
@@ -853,6 +865,10 @@ int trx_sched_tch_req(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
return 0;
}
+ /* VAMOS: convert Osmocom specific channel number to a generic one */
+ if (trx->ts[tn].vamos.is_shadow)
+ l1sap->u.tch.chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg);
return 0;
@@ -874,6 +890,11 @@ static int rts_data_fn(const struct l1sched_ts *l1ts, const struct trx_dl_burst_
chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
link_id = trx_chan_desc[br->chan].link_id;
+
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
/* For handover detection, there are cases where the SACCH should remain inactive until the first RACH
* indicating the TA is received. */
if (L1SAP_IS_LINK_SACCH(link_id)
@@ -909,6 +930,11 @@ static int rts_tch_common(const struct l1sched_ts *l1ts,
chan_nr = trx_chan_desc[br->chan].chan_nr | br->tn;
link_id = trx_chan_desc[br->chan].link_id;
+
+ /* VAMOS: use Osmocom specific channel number */
+ if (l1ts->ts->vamos.is_shadow)
+ chan_nr |= RSL_CHAN_OSMO_VAMOS_MASK;
+
LOGL1SB(DL1P, LOGL_DEBUG, l1ts, br, "TCH RTS.ind: chan_nr=0x%02x\n", chan_nr);
/* only send, if FACCH is selected */
@@ -1018,6 +1044,11 @@ int trx_sched_set_lchan(struct gsm_lchan *lchan, uint8_t chan_nr, uint8_t link_i
bool found = false;
int i;
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
struct l1sched_chan_state *chan_state = &l1ts->chan_state[i];
@@ -1081,6 +1112,11 @@ int trx_sched_set_mode(struct gsm_bts_trx_ts *ts, uint8_t chan_nr, uint8_t rsl_c
if (ts->pchan == GSM_PCHAN_PDCH)
return 0;
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
/* look for all matching chan_nr/link_id */
for (i = 0; i < _TRX_CHAN_MAX; i++) {
if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)
@@ -1133,6 +1169,11 @@ int trx_sched_set_cipher(struct gsm_lchan *lchan, uint8_t chan_nr, bool downlink
if (lchan->ts->pchan == GSM_PCHAN_PDCH)
return 0;
+ /* VAMOS: convert Osmocom specific channel number to a generic one,
+ * otherwise we won't match anything in trx_chan_desc[]. */
+ if (lchan->ts->vamos.is_shadow)
+ chan_nr &= ~RSL_CHAN_OSMO_VAMOS_MASK;
+
/* no algorithm given means a5/0 */
if (algo <= 0)
algo = 0;
diff --git a/src/common/vty.c b/src/common/vty.c
index ccc63e66..8a1bafc4 100644
--- a/src/common/vty.c
+++ b/src/common/vty.c
@@ -1642,8 +1642,9 @@ static void lchan_dump_full_vty(struct vty *vty, const struct gsm_lchan *lchan)
{
struct in_addr ia;
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u: Type %s%s",
+ vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s), Lchan %u: Type %s%s",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
+ lchan->ts->vamos.is_shadow ? "shadow" : "primary",
lchan->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE);
/* show dyn TS details, if applicable */
switch (lchan->ts->pchan) {
@@ -1718,8 +1719,9 @@ static void lchan_dump_short_vty(struct vty *vty, const struct gsm_lchan *lchan)
{
const struct gsm_meas_rep_unidir *mru = &lchan->meas.ul_res;
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u %s",
+ vty_out(vty, "BTS %u, TRX %u, Timeslot %u (%s) %s",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
+ lchan->ts->vamos.is_shadow ? "shadow" : "primary",
gsm_pchan_name(lchan->ts->pchan));
vty_out_dyn_ts_status(vty, lchan->ts);
vty_out(vty, ", Lchan %u, Type %s, State %s - "
@@ -1760,6 +1762,8 @@ static int dump_lchan_trx(const struct gsm_bts_trx *trx, struct vty *vty,
for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
const struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
dump_lchan_trx_ts(ts, vty, dump_cb);
+ if (ts->vamos.peer != NULL) /* VAMOS: shadow timeslot */
+ dump_lchan_trx_ts(ts->vamos.peer, vty, dump_cb);
}
return CMD_SUCCESS;
@@ -1870,7 +1874,8 @@ static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
int bts_nr = atoi(argv[idx+0]);
int trx_nr = atoi(argv[idx+1]);
int ts_nr = atoi(argv[idx+2]);
- int lchan_nr = atoi(argv[idx+3]);
+ bool shadow = argv[idx+3][0] == 's';
+ int lchan_nr = atoi(argv[idx+4]);
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
@@ -1886,6 +1891,11 @@ static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
if (ts_nr >= ARRAY_SIZE(trx->ts))
return NULL;
ts = &trx->ts[ts_nr];
+ if (shadow) { /* VAMOS shadow */
+ if (ts->vamos.peer == NULL)
+ return NULL;
+ ts = ts->vamos.peer;
+ }
if (lchan_nr >= ARRAY_SIZE(ts->lchan))
return NULL;
@@ -1894,7 +1904,7 @@ static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
}
#define BTS_T_T_L_CMD \
- "bts <0-0> trx <0-255> ts <0-7> lchan <0-7>"
+ "bts <0-0> trx <0-255> ts <0-7> (lchan|shadow-lchan) <0-7>"
#define BTS_T_T_L_STR \
"BTS related commands\n" \
"BTS number\n" \
@@ -1902,7 +1912,8 @@ static struct gsm_lchan *resolve_lchan(const struct gsm_network *net,
"TRX number\n" \
"timeslot related commands\n" \
"timeslot number\n" \
- "logical channel commands\n" \
+ "Primary logical channel commands\n" \
+ "Shadow logical channel commands\n" \
"logical channel number\n"
DEFUN(cfg_bts_gsmtap_remote_host,