diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2021-05-27 18:26:29 +0200 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2021-06-05 00:34:36 +0200 |
commit | 0686ae612834c329546c2f65d04283685ec790ad (patch) | |
tree | 9d6d6b9268ebad97407768b0efc55ff08178bc32 | |
parent | d9daa3fd9ea2744de371190632b05b149feb4773 (diff) |
[VAMOS] Implement the concept of 'shadow' timeslots
Change-Id: I48b44b4df9ffb1cca105aebbd868c29b21f3b1d6
Depends: Ia0bd8695a3f12331b696fe69117189cdd48b584d
Related: SYS#4895, OS#4941
-rw-r--r-- | include/osmo-bts/bts_trx.h | 1 | ||||
-rw-r--r-- | include/osmo-bts/gsm_data.h | 13 | ||||
-rw-r--r-- | include/osmo-bts/l1sap.h | 9 | ||||
-rw-r--r-- | src/common/bts_trx.c | 101 | ||||
-rw-r--r-- | src/common/gsm_data.c | 63 | ||||
-rw-r--r-- | src/common/l1sap.c | 25 | ||||
-rw-r--r-- | src/common/oml.c | 12 | ||||
-rw-r--r-- | src/common/scheduler.c | 41 | ||||
-rw-r--r-- | src/common/vty.c | 21 |
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, |