[VAMOS] Implement the concept of 'shadow' timeslots

Change-Id: I48b44b4df9ffb1cca105aebbd868c29b21f3b1d6
Depends: Ia0bd8695a3f12331b696fe69117189cdd48b584d
Related: SYS#4895, OS#4941
This commit is contained in:
Vadim Yanitskiy 2021-05-27 18:26:29 +02:00
parent d9daa3fd9e
commit 0686ae6128
9 changed files with 218 additions and 68 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

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

View File

@ -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;
}

View File

@ -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:

View File

@ -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;

View File

@ -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,