[VAMOS] Implement the concept of 'shadow' timeslots
Change-Id: I48b44b4df9ffb1cca105aebbd868c29b21f3b1d6 Depends: Ia0bd8695a3f12331b696fe69117189cdd48b584d Related: SYS#4895, OS#4941
This commit is contained in:
parent
d9daa3fd9e
commit
0686ae6128
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue