From holger at freyther.de Mon Feb 1 06:33:49 2016 From: holger at freyther.de (Holger Freyther) Date: Mon, 1 Feb 2016 07:33:49 +0100 Subject: LCR segfault on SIP invite In-Reply-To: References: <20160118152936.GL17432@nataraja> Message-ID: <44436924-E3C4-40AC-85BA-3C981866553B@freyther.de> > On 31 Jan 2016, at 23:09, OMAR RAMADAN wrote: > > So it turns out gcc 4.8 optimizes too aggressively when compiling sofia-sip for LCR. > Another symptom of this is that message payloads are missing. > > Solution is to compile with "-fno-aggressive-loop-optimizations" Apparently undefined behavior in the sofia-sip code, debian and now our meta-telephony Yocto layer carry a patch for one routine but in our case there was a silent failure and no segfault. Do you have a backtrace of LCR? holger From laforge at gnumonks.org Mon Feb 1 09:56:20 2016 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 1 Feb 2016 10:56:20 +0100 Subject: cscn copyright question In-Reply-To: <20160128120843.GB1755@dub6> References: <20160128120843.GB1755@dub6> Message-ID: <20160201095620.GD14265@nataraja> Hi Neels, On Thu, Jan 28, 2016 at 01:08:43PM +0100, Neels Hofmeyr wrote: > Is this a proper way to copyright OsmoCSCN? I'm trying to mention both the > facts that it's something new as well as that it is based on a copy-paste of > OsmoNITB: your proposal looks fine. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From suraev at alumni.ntnu.no Mon Feb 1 14:04:13 2016 From: suraev at alumni.ntnu.no (=?UTF-8?B?TWF4ICjimK0p?=) Date: Mon, 1 Feb 2016 15:04:13 +0100 Subject: [PATCH 1/3] Cleanup build In-Reply-To: References: <1453832833-15763-1-git-send-email-suraev@alumni.ntnu.no> <1453832833-15763-2-git-send-email-suraev@alumni.ntnu.no> Message-ID: <56AF65DD.3070001@alumni.ntnu.no> 30.01.2016 10:01, Holger Freyther ?????: >> On 26 Jan 2016, at 19:27, suraev at alumni.ntnu.no wrote: >> >> >> libtool >> +arm*linux*libtool > *libtool then? Yes, that would work too. > > >> -AM_INIT_AUTOMAKE([dist-bzip2]) >> +AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects]) > have you tried make distcheck? > Tried it - got "archives ready for distribution" message. Is there some particular result I should be looking for after running "make distcheck"? cheers, Max. From suraev at alumni.ntnu.no Mon Feb 1 15:09:08 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Mon, 1 Feb 2016 16:09:08 +0100 Subject: [PATCH 1/4] Cleanup build In-Reply-To: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> References: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454339351-1765-2-git-send-email-suraev@alumni.ntnu.no> From: Max Ignore cross-compilation bild byproducts. Enable subdir-objects to increase compatibility with newer automake. --- .gitignore | 3 ++- configure.ac | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 6cc9aa5..df344ec 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,8 @@ configure depcomp install-sh missing -libtool +*libtool +compile ltmain.sh core diff --git a/configure.ac b/configure.ac index 5274022..7a97954 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_INIT([osmo-pcu], m4_esyscmd([./git-version-gen .tarball-version]), [osmocom-net-gprs at lists.osmocom.org]) -AM_INIT_AUTOMAKE([dist-bzip2]) +AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects]) AC_CONFIG_TESTDIR(tests) dnl kernel style compile messages -- 2.5.0 From suraev at alumni.ntnu.no Mon Feb 1 15:09:10 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Mon, 1 Feb 2016 16:09:10 +0100 Subject: [PATCH 3/4] Restructure sources In-Reply-To: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> References: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454339351-1765-4-git-send-email-suraev@alumni.ntnu.no> From: Max Move hardware-spicefic files into subdirectory similar to the way it's done in OsmoBTS to make adding new hardware support easier. --- src/Makefile.am | 49 +++++++++++++++++++-------------- src/{ => osmo-bts-sysmo}/femtobts.c | 0 src/{ => osmo-bts-sysmo}/femtobts.h | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_fwd.c | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_hw.c | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_if.c | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_if.h | 0 7 files changed, 29 insertions(+), 20 deletions(-) rename src/{ => osmo-bts-sysmo}/femtobts.c (100%) rename src/{ => osmo-bts-sysmo}/femtobts.h (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_fwd.c (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_hw.c (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_if.c (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_if.h (100%) diff --git a/src/Makefile.am b/src/Makefile.am index 832c3b0..3049744 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,11 +64,6 @@ bin_PROGRAMS = \ noinst_PROGRAMS = -if ENABLE_SYSMODSP -noinst_PROGRAMS += \ - osmo-pcu-remote -endif - noinst_HEADERS = \ gprs_debug.h \ csn1.h \ @@ -83,8 +78,6 @@ noinst_HEADERS = \ bitvector.h \ pcu_vty.h \ pcu_vty_functions.h \ - sysmo_l1_if.h \ - femtobts.h \ tbf.h \ bts.h \ poll_controller.h \ @@ -101,30 +94,46 @@ noinst_HEADERS = \ osmo_pcu_SOURCES = pcu_main.cpp if ENABLE_SYSMODSP -osmo_pcu_SOURCES += sysmo_l1_if.c \ - sysmo_l1_hw.c \ - femtobts.c - -osmo_pcu_remote_SOURCES = pcu_main.cpp \ - sysmo_l1_if.c \ - sysmo_l1_fwd.c \ - femtobts.c -endif +AM_CPPFLAGS += -I$(srcdir)/osmo-bts-sysmo -osmo_pcu_LDADD = \ +EXTRA_DIST = \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_if.h \ + osmo-bts-sysmo/sysmo_l1_hw.c \ + osmo-bts-sysmo/femtobts.c \ + osmo-bts-sysmo/femtobts.h + +noinst_HEADERS += \ + osmo-bts-sysmo/sysmo_l1_if.h \ + osmo-bts-sysmo/femtobts.h + +noinst_PROGRAMS += \ + osmo-pcu-remote + +osmo_pcu_SOURCES += \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_hw.c \ + osmo-bts-sysmo/femtobts.c + +osmo_pcu_remote_SOURCES = \ + pcu_main.cpp \ + osmo-bts-sysmo/sysmo_l1_if.c \ + osmo-bts-sysmo/sysmo_l1_fwd.c \ + osmo-bts-sysmo/femtobts.c + +osmo_pcu_remote_LDADD = \ libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(COMMON_LA) +endif -if ENABLE_SYSMODSP -osmo_pcu_remote_LDADD = \ +osmo_pcu_LDADD = \ libgprs.la \ $(LIBOSMOGB_LIBS) \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ $(COMMON_LA) -endif #MOSTLYCLEANFILES += testSource testDestination diff --git a/src/femtobts.c b/src/osmo-bts-sysmo/femtobts.c similarity index 100% rename from src/femtobts.c rename to src/osmo-bts-sysmo/femtobts.c diff --git a/src/femtobts.h b/src/osmo-bts-sysmo/femtobts.h similarity index 100% rename from src/femtobts.h rename to src/osmo-bts-sysmo/femtobts.h diff --git a/src/sysmo_l1_fwd.c b/src/osmo-bts-sysmo/sysmo_l1_fwd.c similarity index 100% rename from src/sysmo_l1_fwd.c rename to src/osmo-bts-sysmo/sysmo_l1_fwd.c diff --git a/src/sysmo_l1_hw.c b/src/osmo-bts-sysmo/sysmo_l1_hw.c similarity index 100% rename from src/sysmo_l1_hw.c rename to src/osmo-bts-sysmo/sysmo_l1_hw.c diff --git a/src/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c similarity index 100% rename from src/sysmo_l1_if.c rename to src/osmo-bts-sysmo/sysmo_l1_if.c diff --git a/src/sysmo_l1_if.h b/src/osmo-bts-sysmo/sysmo_l1_if.h similarity index 100% rename from src/sysmo_l1_if.h rename to src/osmo-bts-sysmo/sysmo_l1_if.h -- 2.5.0 From suraev at alumni.ntnu.no Mon Feb 1 15:09:09 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Mon, 1 Feb 2016 16:09:09 +0100 Subject: [PATCH 2/4] Rename define for direct hw access In-Reply-To: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> References: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454339351-1765-3-git-send-email-suraev@alumni.ntnu.no> From: Max --- src/Makefile.am | 2 +- src/osmobts_sock.cpp | 2 +- src/pcu_l1_if.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 6428bef..832c3b0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) if ENABLE_SYSMODSP -AM_CPPFLAGS += -DENABLE_SYSMODSP +AM_CPPFLAGS += -DENABLE_DIRECT_PHY endif AM_CXXFLAGS = -Wall -ldl -pthread diff --git a/src/osmobts_sock.cpp b/src/osmobts_sock.cpp index b42f042..21a404f 100644 --- a/src/osmobts_sock.cpp +++ b/src/osmobts_sock.cpp @@ -100,7 +100,7 @@ static void pcu_sock_close(struct pcu_sock_state *state, int lost) /* disable all slots, kick all TBFs */ for (trx = 0; trx < 8; trx++) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if (bts->trx[trx].fl1h) { l1if_close_pdch(bts->trx[trx].fl1h); bts->trx[trx].fl1h = NULL; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 9d7dbee..06cf234 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -124,7 +124,7 @@ static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY struct gprs_rlcmac_bts *bts = bts_main_data(); if (bts->trx[trx].fl1h) @@ -140,7 +140,7 @@ void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY struct gprs_rlcmac_bts *bts = bts_main_data(); if (bts->trx[trx].fl1h) @@ -430,7 +430,7 @@ bssgp_failed: bts->trx[trx].arfcn = info_ind->trx[trx].arfcn; if ((info_ind->flags & PCU_IF_FLAG_SYSMO) && info_ind->trx[trx].hlayer1) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY LOGP(DL1IF, LOGL_DEBUG, " TRX %d hlayer1=%x\n", trx, info_ind->trx[trx].hlayer1); if (!bts->trx[trx].fl1h) @@ -455,7 +455,7 @@ bssgp_failed: if ((info_ind->trx[trx].pdch_mask & (1 << ts))) { /* FIXME: activate dynamically at RLCMAC */ if (!pdch->is_enabled()) { -#ifdef ENABLE_SYSMODSP +#ifdef ENABLE_DIRECT_PHY if ((info_ind->flags & PCU_IF_FLAG_SYSMO)) l1if_connect_pdch( -- 2.5.0 From suraev at alumni.ntnu.no Mon Feb 1 15:09:07 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Mon, 1 Feb 2016 16:09:07 +0100 Subject: [PATCH 0/4] Cleanup and restructure Message-ID: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> From: Max This is v2 of patchset to simplify new hardware support by restructuring sources, simplifying internal API and cleaining up various bits and pieces. Max (4): Cleanup build Rename define for direct hw access Restructure sources Change internal API for consistency .gitignore | 3 +- configure.ac | 2 +- src/Makefile.am | 51 +++++++++++++++++++-------------- src/{ => osmo-bts-sysmo}/femtobts.c | 0 src/{ => osmo-bts-sysmo}/femtobts.h | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_fwd.c | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_hw.c | 0 src/{ => osmo-bts-sysmo}/sysmo_l1_if.c | 8 +++--- src/{ => osmo-bts-sysmo}/sysmo_l1_if.h | 2 +- src/osmobts_sock.cpp | 2 +- src/pcu_l1_if.cpp | 17 ++++++----- 11 files changed, 47 insertions(+), 38 deletions(-) rename src/{ => osmo-bts-sysmo}/femtobts.c (100%) rename src/{ => osmo-bts-sysmo}/femtobts.h (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_fwd.c (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_hw.c (100%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_if.c (98%) rename src/{ => osmo-bts-sysmo}/sysmo_l1_if.h (98%) -- 2.5.0 From suraev at alumni.ntnu.no Mon Feb 1 15:09:11 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Mon, 1 Feb 2016 16:09:11 +0100 Subject: [PATCH 4/4] Change internal API for consistency In-Reply-To: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> References: <1454339351-1765-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454339351-1765-5-git-send-email-suraev@alumni.ntnu.no> From: Max Use uint8_t for TRX numbering everywhere (we don't expect hardware with more than 256 transceivers in the near future). This change helps to avoid unnecessary casts and make API much clearer. --- src/osmo-bts-sysmo/sysmo_l1_if.c | 8 ++++---- src/osmo-bts-sysmo/sysmo_l1_if.h | 2 +- src/pcu_l1_if.cpp | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.c b/src/osmo-bts-sysmo/sysmo_l1_if.c index 8572786..8ecbcfb 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.c +++ b/src/osmo-bts-sysmo/sysmo_l1_if.c @@ -155,7 +155,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h, switch (rts_ind->sapi) { case GsmL1_Sapi_Pdtch: case GsmL1_Sapi_Pacch: - rc = pcu_rx_rts_req_pdtch((long)fl1h->priv, rts_ind->u8Tn, + rc = pcu_rx_rts_req_pdtch(fl1h->trx, rts_ind->u8Tn, rts_ind->u16Arfcn, rts_ind->u32Fn, rts_ind->u8BlockNbr); case GsmL1_Sapi_Ptcch: // FIXME @@ -215,7 +215,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h, != GsmL1_PdtchPlType_Full) break; /* PDTCH / PACCH frame handling */ - pcu_rx_data_ind_pdtch((long)fl1h->priv, data_ind->u8Tn, + pcu_rx_data_ind_pdtch(fl1h->trx, data_ind->u8Tn, data_ind->msgUnitParam.u8Buffer + 1, data_ind->msgUnitParam.u8Size - 1, data_ind->u32Fn, @@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, return 0; } -void *l1if_open_pdch(void *priv, uint32_t hlayer1) +void *l1if_open_pdch(uint8_t trx, uint32_t hlayer1) { struct femtol1_hdl *fl1h; int rc; @@ -367,7 +367,7 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1) return NULL; fl1h->hLayer1 = hlayer1; - fl1h->priv = priv; + fl1h->trx = trx; fl1h->clk_cal = 0; /* default clock source: OCXO */ fl1h->clk_src = SuperFemto_ClkSrcId_Ocxo; diff --git a/src/osmo-bts-sysmo/sysmo_l1_if.h b/src/osmo-bts-sysmo/sysmo_l1_if.h index 6b50d4e..83ca481 100644 --- a/src/osmo-bts-sysmo/sysmo_l1_if.h +++ b/src/osmo-bts-sysmo/sysmo_l1_if.h @@ -38,7 +38,7 @@ struct femtol1_hdl { struct gsmtap_inst *gsmtap; uint32_t gsmtap_sapi_mask; - void *priv; /* user reference */ + uint8_t trx; struct osmo_timer_list alive_timer; unsigned int alive_prim_cnt; diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 06cf234..b938acf 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -42,7 +42,7 @@ extern "C" { // FIXME: move this, when changed from c++ to c. extern "C" { -void *l1if_open_pdch(void *priv, uint32_t hlayer1); +void *l1if_open_pdch(uint8_t trx, uint32_t hlayer1); int l1if_connect_pdch(void *obj, uint8_t ts); int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); @@ -315,9 +315,8 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) struct gprs_bssgp_pcu *pcu; struct gprs_rlcmac_pdch *pdch; struct in_addr ia; - int rc = 0; - int trx, ts; - int i; + int rc = 0, ts, i; + uint8_t trx; if (info_ind->version != PCU_IF_VERSION) { fprintf(stderr, "PCU interface version number of BTS (%d) is " @@ -435,7 +434,7 @@ bssgp_failed: info_ind->trx[trx].hlayer1); if (!bts->trx[trx].fl1h) bts->trx[trx].fl1h = l1if_open_pdch( - (void *)trx, + trx, info_ind->trx[trx].hlayer1); if (!bts->trx[trx].fl1h) { LOGP(DL1IF, LOGL_FATAL, "Failed to open direct " -- 2.5.0 From suraev at alumni.ntnu.no Tue Feb 2 11:19:32 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Tue, 2 Feb 2016 12:19:32 +0100 Subject: [PATCH 1/2] Expand bitvec interface Message-ID: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> From: Max Add bit filling, shifting and other functions necessary for bit compression implementation. Add corresponding tests. --- include/osmocom/core/bitvec.h | 9 +++ src/bitvec.c | 132 ++++++++++++++++++++++++++++++++++++-- tests/bitvec/bitvec_test.c | 143 +++++++++++++++++++++++++++++++++++++++++- tests/bitvec/bitvec_test.ok | 119 +++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 7 deletions(-) diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h index a7e6fc4..5314cf2 100644 --- a/include/osmocom/core/bitvec.h +++ b/include/osmocom/core/bitvec.h @@ -4,6 +4,7 @@ /* (C) 2009 by Harald Welte * (C) 2012 Ivan Klyuchnikov + * (C) 2015 Sysmocom s.f.m.c. GmbH * * All Rights Reserved * @@ -41,6 +42,7 @@ #include #include +#include /*! \brief A single GSM bit * @@ -82,5 +84,12 @@ unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer); unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer); uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len); int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len); +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill); +char bit_value_to_char(enum bit_value v); +void bitvec_to_string_r(const struct bitvec *bv, char *str); +void bitvec_zero(struct bitvec *bv); +unsigned bitvec_rl(const struct bitvec *bv, bool b); +void bitvec_shiftl(struct bitvec *bv, unsigned int n); +int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits); /*! @} */ diff --git a/src/bitvec.c b/src/bitvec.c index b5d2c24..fc016a6 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -34,7 +34,9 @@ #include #include #include +#include +#include #include #define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit) @@ -224,6 +226,20 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits) return 0; } +/*! \brief get multiple bits (num_bits) from beginning of vector (MSB side) */ +int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits) +{ + uint8_t tmp[2]; + if (num_bits > 15 || bv->cur_bit < num_bits) + return -EINVAL; + + if (num_bits < 9) + return bv->data[0] >> (8 - num_bits); + + memcpy(tmp, bv->data, 2); + return osmo_load16be(tmp) >> (16 - num_bits); +} + /*! \brief get multiple bits (based on numeric value) from current pos */ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits) { @@ -242,15 +258,27 @@ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits) return ui; } +/*! \brief fill num_bits with \fill starting from the current position + * returns 0 on success, negative otherwise (out of vector boundary) + */ +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill) +{ + unsigned i, stop = bv->cur_bit + num_bits; + for (i = bv->cur_bit; i < stop; i++) + if (bitvec_set_bit(bv, fill) < 0) + return -EINVAL; + + return 0; +} + /*! \brief pad all remaining bits up to num_bits */ int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) { - unsigned int i; - - for (i = bv->cur_bit; i <= up_to_bit; i++) - bitvec_set_bit(bv, L); + int n = up_to_bit - bv->cur_bit + 1; + if (n < 1) + return 0; - return 0; + return bitvec_fill(bv, n, L); } /*! \brief find first bit set in bit vector */ @@ -446,4 +474,98 @@ int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t va return 0; } +/*! \brief convert enum to corresponding character */ +char bit_value_to_char(enum bit_value v) +{ + switch (v) { + case ZERO: return '0'; + case ONE: return '1'; + case L: return 'L'; + case H: return 'H'; + } + /* make compiler happy - "avoid control reaches end of non-void function" warning: */ + return '?'; +} + +/*! \brief prints bit vector to provided string + * It's caller's responcibility to ensure that we won't shoot him in the foot. + */ +void bitvec_to_string_r(const struct bitvec *bv, char *str) +{ + unsigned i, pos = 0; + char *cur = str; + for (i = 0; i < bv->cur_bit; i++) { + if (0 == i % 8) + *cur++ = ' '; + *cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i)); + pos++; + } + *cur = 0; +} + +/* we assume that x have at least 1 non-b bit */ +static inline unsigned _leading_bits(uint8_t x, bool b) +{ + if (b) { + if (x < 0x80) return 0; + if (x < 0xC0) return 1; + if (x < 0xE0) return 2; + if (x < 0xF0) return 3; + if (x < 0xF8) return 4; + if (x < 0xFC) return 5; + if (x < 0xFE) return 6; + } else { + if (x > 0x7F) return 0; + if (x > 0x3F) return 1; + if (x > 0x1F) return 2; + if (x > 0xF) return 3; + if (x > 7) return 4; + if (x > 3) return 5; + if (x > 1) return 6; + } + return 7; +} +/*! \brief force bit vector to all 0 and current bit to the beginnig of the vector */ +void bitvec_zero(struct bitvec *bv) +{ + bv->cur_bit = 0; + memset(bv->data, 0, bv->data_len); +} + +/*! \brief Return number (bits) of uninterrupted run of \b in \bv starting from the MSB */ +unsigned bitvec_rl(const struct bitvec *bv, bool b) +{ + unsigned i; + for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) { + if ( (b ? 0xFF : 0) != bv->data[i]) + return i * 8 + _leading_bits(bv->data[i], b); + } + + return bv->cur_bit; +} + +/*! \brief Shifts bitvec to the left, n MSB bits lost */ +void bitvec_shiftl(struct bitvec *bv, unsigned n) +{ + if (0 == n) + return; + if (n >= bv->cur_bit) { + bitvec_zero(bv); + return; + } + + memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8); + + uint8_t tmp[2]; + unsigned i; + for (i = 0; i < bv->data_len - 2; i++) { + uint16_t t = osmo_load16be(bv->data + i); + osmo_store16be(t << (n % 8), &tmp); + bv->data[i] = tmp[0]; + } + + bv->data[bv->data_len - 1] <<= (n % 8); + bv->cur_bit -= n; +} + /*! @} */ diff --git a/tests/bitvec/bitvec_test.c b/tests/bitvec/bitvec_test.c index 7d131e0..4fc9db3 100644 --- a/tests/bitvec/bitvec_test.c +++ b/tests/bitvec/bitvec_test.c @@ -3,9 +3,82 @@ #include #include #include +#include +#include +#include #include #include +#include + +#define BIN_PATTERN "%d%d%d%d%d%d%d%d" +#define BIN(byte) \ + (byte & 0x80 ? 1 : 0), \ + (byte & 0x40 ? 1 : 0), \ + (byte & 0x20 ? 1 : 0), \ + (byte & 0x10 ? 1 : 0), \ + (byte & 0x08 ? 1 : 0), \ + (byte & 0x04 ? 1 : 0), \ + (byte & 0x02 ? 1 : 0), \ + (byte & 0x01 ? 1 : 0) + +static char lol[1024]; // we pollute this with printed vectors +static inline void test_rl(const struct bitvec *bv) +{ + bitvec_to_string_r(bv, lol); + printf("%s [%d] RL0=%d, RL1=%d\n", lol, bv->cur_bit, bitvec_rl(bv, false), bitvec_rl(bv, true)); +} + +static inline void test_shift(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + printf("%s << %d:\n", lol, n); + bitvec_shiftl(bv, n); + bitvec_to_string_r(bv, lol); + printf("%s\n", lol); +} + +static inline void test_get(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + printf("%s [%d]", lol, bv->cur_bit); + int16_t x = bitvec_get_int16_msb(bv, n); + uint8_t tmp[2]; + osmo_store16be(x, &tmp); + printf(" -> %d (%u bit) ["BIN_PATTERN" "BIN_PATTERN"]:\n", x, n, BIN(tmp[0]), BIN(tmp[1])); + bitvec_to_string_r(bv, lol); + printf("%s [%d]\n", lol, bv->cur_bit); +} + +static inline void test_fill(struct bitvec *bv, unsigned n, enum bit_value val) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int fi = bitvec_fill(bv, n, val); + printf("%c> FILL %s [%d] -%d-> [%d]:\n", bit_value_to_char(val), lol, bvlen, n, fi); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} + +static inline void test_spare(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int sp = bitvec_spare_padding(bv, n); + printf("%c> SPARE %s [%d] -%d-> [%d]:\n", bit_value_to_char(L), lol, bvlen, n, sp); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} + +static inline void test_set(struct bitvec *bv, enum bit_value bit) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int set = bitvec_set_bit(bv, bit); + printf("%c> SET %s [%d] ++> [%d]:\n", bit_value_to_char(bit), lol, bvlen, set); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} static void test_byte_ops() { @@ -33,7 +106,7 @@ static void test_byte_ops() rc = bitvec_set_uint(&bv, 0x7e, 8); OSMO_ASSERT(rc >= 0); - fprintf(stderr, "bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len)); + printf("bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len)); /* Read from bitvec */ memset(out, 0xff, sizeof(out)); @@ -45,7 +118,7 @@ static void test_byte_ops() rc = bitvec_get_uint(&bv, 8); OSMO_ASSERT(rc == 0x7e); - fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out))); + printf("out: %s\n", osmo_hexdump(out, sizeof(out))); OSMO_ASSERT(out[0] == 0xff); OSMO_ASSERT(out[in_size+1] == 0xff); @@ -72,11 +145,77 @@ static void test_unhex(const char *hex) int main(int argc, char **argv) { + srand(time(NULL)); + + struct bitvec bv; + uint8_t i = 8, test[i]; + + memset(test, 0, i); + bv.data_len = i; + bv.data = test; + bv.cur_bit = 0; + + printf("test shifting...\n"); + + bitvec_set_uint(&bv, 0x0E, 7); + test_shift(&bv, 3); + test_shift(&bv, 17); + bitvec_set_uint(&bv, 0, 32); + bitvec_set_uint(&bv, 0x0A, 7); + test_shift(&bv, 24); + + printf("checking RL functions...\n"); + + bitvec_zero(&bv); + test_rl(&bv); + bitvec_set_uint(&bv, 0x000F, 32); + test_rl(&bv); + bitvec_shiftl(&bv, 18); + test_rl(&bv); + bitvec_set_uint(&bv, 0x0F, 8); + test_rl(&bv); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xFF, 8); + test_rl(&bv); + bitvec_set_uint(&bv, 0xFE, 7); + test_rl(&bv); + bitvec_set_uint(&bv, 0, 17); + test_rl(&bv); + bitvec_shiftl(&bv, 18); + test_rl(&bv); + + printf("probing bit access...\n"); + + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0x3747817, 32); + bitvec_shiftl(&bv, 10); + + test_get(&bv, 2); + test_get(&bv, 7); + test_get(&bv, 9); + test_get(&bv, 13); + test_get(&bv, 16); + test_get(&bv, 42); + + printf("feeling bit fills...\n"); + + test_set(&bv, ONE); + test_fill(&bv, 3, ZERO); + test_spare(&bv, 38); + test_spare(&bv, 43); + test_spare(&bv, 1); + test_spare(&bv, 7); + test_fill(&bv, 5, ONE); + test_fill(&bv, 3, L); + + printf("byte me...\n"); + test_byte_ops(); test_unhex("48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("47240c00400000000000000079eb2ac9402b2b2b2b2b2b"); test_unhex("47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("DEADFACE000000000000000000000000000000BEEFFEED"); test_unhex("FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + return 0; } diff --git a/tests/bitvec/bitvec_test.ok b/tests/bitvec/bitvec_test.ok index 83328b2..1c993d3 100644 --- a/tests/bitvec/bitvec_test.ok +++ b/tests/bitvec/bitvec_test.ok @@ -1,4 +1,123 @@ +test shifting... + 0001110 << 3: + 1110 + 1110 << 17: + + 00000000 00000000 00000000 00000000 0001010 << 24: + 00000000 0001010 +checking RL functions... + [0] RL0=0, RL1=0 + 00000000 00000000 00000000 00001111 [32] RL0=28, RL1=0 + 00000000 001111 [14] RL0=10, RL1=0 + 00000000 00111100 001111 [22] RL0=10, RL1=0 + 11111111 [8] RL0=0, RL1=8 + 11111111 1111110 [15] RL0=0, RL1=14 + 11111111 11111100 00000000 00000000 [32] RL0=0, RL1=14 + 00000000 000000 [14] RL0=14, RL1=0 +probing bit access... + 11010001 11100000 010111 [22] -> 3 (2 bit) [00000000 00000011]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 104 (7 bit) [00000000 01101000]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 419 (9 bit) [00000001 10100011]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 6716 (13 bit) [00011010 00111100]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> -22 (16 bit) [11111111 11101010]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> -22 (42 bit) [11111111 11101010]: + 11010001 11100000 010111 [22] +feeling bit fills... +1> SET 11010001 11100000 010111 [22] ++> [0]: + 11010001 11100000 0101111 [23] + +0> FILL 11010001 11100000 0101111 [23] -3-> [0]: + 11010001 11100000 01011110 00 [26] + +L> SPARE 11010001 11100000 01011110 00 [26] -38-> [0]: + 11010001 11100000 01011110 00101011 0010101 [39] + +L> SPARE 11010001 11100000 01011110 00101011 0010101 [39] -43-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -1-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -7-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +1> FILL 11010001 11100000 01011110 00101011 00101011 0010 [44] -5-> [0]: + 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] + +L> FILL 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] -3-> [0]: + 11010001 11100000 01011110 00101011 00101011 00101111 1010 [52] + +byte me... === start test_byte_ops === +bitvec: 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff === end test_byte_ops === 1 -=> cur_bit=184 48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000 -- 2.5.0 From suraev at alumni.ntnu.no Tue Feb 2 11:19:33 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Tue, 2 Feb 2016 12:19:33 +0100 Subject: [PATCH 2/2] Add T4 bit map compression routines In-Reply-To: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> References: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454411973-30799-2-git-send-email-suraev@alumni.ntnu.no> From: Max Add bit map encoder and decoder functions: decoder is fully functional while encoder is good enough for testing - no backtracking to find the best possible compression is implemented. If somebody is willing to implement MS side of EDGE than this has to be expanded. Add corresponding tests. N. B: the encoding is implemented according to ETSI TS 44.060 which is slightly different from T4 used for fax according to CCITT G31D (RFC 804). Ticket: OW#2407 Sponsored-by: On-Waves ehf --- .gitignore | 1 + include/Makefile.am | 1 + include/osmocom/core/bitcomp.h | 42 ++++ src/Makefile.am | 2 +- src/bitcomp.c | 477 +++++++++++++++++++++++++++++++++++++++++ tests/Makefile.am | 7 +- tests/bits/bitcomp_test.c | 66 ++++++ tests/bits/bitcomp_test.ok | 29 +++ tests/testsuite.at | 6 + 9 files changed, 628 insertions(+), 3 deletions(-) create mode 100644 include/osmocom/core/bitcomp.h create mode 100644 src/bitcomp.c create mode 100644 tests/bits/bitcomp_test.c create mode 100644 tests/bits/bitcomp_test.ok diff --git a/.gitignore b/.gitignore index 955634e..8904938 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ tests/vty/vty_test tests/gb/gprs_bssgp_test tests/smscb/gsm0341_test tests/bitvec/bitvec_test +tests/bits/bitcomp_test tests/gprs/gprs_test tests/msgb/msgb_test diff --git a/include/Makefile.am b/include/Makefile.am index 07d6c00..a965fb9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -7,6 +7,7 @@ nobase_include_HEADERS = \ osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ + osmocom/core/bitcomp.h \ osmocom/core/conv.h \ osmocom/core/crc16.h \ osmocom/core/crc16gen.h \ diff --git a/include/osmocom/core/bitcomp.h b/include/osmocom/core/bitcomp.h new file mode 100644 index 0000000..89eccbc --- /dev/null +++ b/include/osmocom/core/bitcomp.h @@ -0,0 +1,42 @@ +#pragma once + +/* bit compression routines */ + +/* (C) 2016 sysmocom s.f.m.c. GmbH by Max Suraev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \defgroup bitcomp Bit compression + * @{ + */ + +/*! \file bitcomp.h + * \brief Osmocom bit compression routines + */ + +#include +#include + +#include + + +int osmo_t4_encode(struct bitvec *bv); +int osmo_t4_decode(const struct bitvec *in, bool cc, struct bitvec *out); + +/*! @} */ diff --git a/src/Makefile.am b/src/Makefile.am index c46cddf..45a77e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ lib_LTLIBRARIES = libosmocore.la libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS) libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ - bitvec.c statistics.c \ + bitvec.c bitcomp.c statistics.c \ write_queue.c utils.c socket.c \ logging.c logging_syslog.c rate_ctr.c \ gsmtap_util.c crc16.c panic.c backtrace.c \ diff --git a/src/bitcomp.c b/src/bitcomp.c new file mode 100644 index 0000000..b0aa6de --- /dev/null +++ b/src/bitcomp.c @@ -0,0 +1,477 @@ +/* bit compression routines */ + +/* (C) 2016 sysmocom s.f.m.c. GmbH by Max Suraev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \defgroup bitcomp Bit compression + * @{ + */ + +/*! \file bitcomp.c + * \brief Osmocom bit compression routines + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Terminating codes for uninterrupted sequences of 0 and 1 up to 64 bit length + * according to TS 44.060 9.1.10 + */ +unsigned _term[2][64] = { + { + 0b0000110111, + 0b10, + 0b11, + 0b010, + 0b011, + 0b0011, + 0b0010, + 0b00011, + 0b000101, + 0b000100, + 0b0000100, + 0b0000101, + 0b0000111, + 0b00000100, + 0b00000111, + 0b000011000, + 0b0000010111, + 0b0000011000, + 0b0000001000, + 0b00001100111, + 0b00001101000, + 0b00001101100, + 0b00000110111, + 0b00000101000, + 0b00000010111, + 0b00000011000, + 0b000011001010, + 0b000011001011, + 0b000011001100, + 0b000011001101, + 0b000001101000, + 0b000001101001, + 0b000001101010, + 0b000001101011, + 0b000011010010, + 0b000011010011, + 0b000011010100, + 0b000011010101, + 0b000011010110, + 0b000011010111, + 0b000001101100, + 0b000001101101, + 0b000011011010, + 0b000011011011, + 0b000001010100, + 0b000001010101, + 0b000001010110, + 0b000001010111, + 0b000001100100, + 0b000001100101, + 0b000001010010, + 0b000001010011, + 0b000000100100, + 0b000000110111, + 0b000000111000, + 0b000000100111, + 0b000000101000, + 0b000001011000, + 0b000001011001, + 0b000000101011, + 0b000000101100, + 0b000001011010, + 0b000001100110, + 0b000001100111 + }, + { + 0b00110101, + 0b000111, + 0b0111, + 0b1000, + 0b1011, + 0b1100, + 0b1110, + 0b1111, + 0b10011, + 0b10100, + 0b00111, + 0b01000, + 0b001000, + 0b000011, + 0b110100, + 0b110101, + 0b101010, + 0b101011, + 0b0100111, + 0b0001100, + 0b0001000, + 0b0010111, + 0b0000011, + 0b0000100, + 0b0101000, + 0b0101011, + 0b0010011, + 0b0100100, + 0b0011000, + 0b00000010, + 0b00000011, + 0b00011010, + 0b00011011, + 0b00010010, + 0b00010011, + 0b00010100, + 0b00010101, + 0b00010110, + 0b00010111, + 0b00101000, + 0b00101001, + 0b00101010, + 0b00101011, + 0b00101100, + 0b00101101, + 0b00000100, + 0b00000101, + 0b00001010, + 0b00001011, + 0b01010010, + 0b01010011, + 0b01010100, + 0b01010101, + 0b00100100, + 0b00100101, + 0b01011000, + 0b01011001, + 0b01011010, + 0b01011011, + 0b01001010, + 0b01001011, + 0b00110010, + 0b00110011, + 0b00110100 + } +}; + +unsigned _term_length[2][64] = { + {10, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, + {8, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8} +}; + +unsigned _min_term_length[] = {2, 4}; +unsigned _min_make_up_length[] = {10, 5}; + +unsigned _max_term_length[] = {12, 8}; +unsigned _max_make_up_length[] = {13, 9}; + +unsigned _make_up_length[2][15] = { + {10, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13}, + {5, 5, 6, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9} +}; + +unsigned _make_up_ind[15] = {64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960}; + +unsigned _make_up[2][15] = { + { + 0b0000001111, + 0b000011001000, + 0b000011001001, + 0b000001011011, + 0b000000110011, + 0b000000110100, + 0b000000110101, + 0b0000001101100, + 0b0000001101101, + 0b0000001001010, + 0b0000001001011, + 0b0000001001100, + 0b0000001001101, + 0b0000001110010, + 0b0000001110011 + }, + { + 0b11011, + 0b10010, + 0b010111, + 0b0110111, + 0b00110110, + 0b00110111, + 0b01100100, + 0b01100101, + 0b01101000, + 0b01100111, + 0b011001100, + 0b011001101, + 0b011010010, + 0b011010011, + 0b011010100 + } +}; + +/*! \brief Attempt to decode compressed bit vector + * + * Return length of RLE according to modified ITU-T T.4 from TS 44.060 Table 9.1.10.2 + * or -1 if no applicable RLE found + * N. B: we need explicit bit length to make decoding unambiguous +*/ +static inline int _rle_term(unsigned w, bool b, unsigned bits) +{ + unsigned i; + for (i = 0; i < 64; i++) + if (w == _term[b][i] && bits == _term_length[b][i]) + return i; + return -1; +} + +static inline int _rle_makeup(unsigned w, bool b, unsigned bits) +{ + unsigned i; + for (i = 0; i < 15; i++) + if (w == _make_up[b][i] && bits == _make_up_length[b][i]) + return _make_up_ind[i]; + return -1; +} + +/*! \brief Make-up codes for a given length + * + * Return proper make-up code word for an uninterrupted sequence of b bits + * of length len according to modified ITU-T T.4 from TS 44.060 Table 9.1.10.2 */ +static inline int _rle(struct bitvec *bv, unsigned len, bool b) +{ + if (len >= 960) { + bitvec_set_uint(bv, _make_up[b][14], _make_up_length[b][14]); + return bitvec_set_uint(bv, _term[b][len - 960], _term_length[b][len - 960]); + } + + if (len >= 896) { + bitvec_set_uint(bv, _make_up[b][13], _make_up_length[b][13]); + return bitvec_set_uint(bv, _term[b][len - 896], _term_length[b][len - 896]); + } + + if (len >= 832) { + bitvec_set_uint(bv, _make_up[b][12], _make_up_length[b][12]); + return bitvec_set_uint(bv, _term[b][len - 832], _term_length[b][len - 832]); + } + + if (len >= 768) { + bitvec_set_uint(bv, _make_up[b][11], _make_up_length[b][11]); + return bitvec_set_uint(bv, _term[b][len - 768], _term_length[b][len - 768]); + } + + if (len >= 704) { + bitvec_set_uint(bv, _make_up[b][10], _make_up_length[b][10]); + return bitvec_set_uint(bv, _term[b][len - 704], _term_length[b][len - 704]); + } + + if (len >= 640) { + bitvec_set_uint(bv, _make_up[b][9], _make_up_length[b][9]); + return bitvec_set_uint(bv, _term[b][len - 640], _term_length[b][len - 640]); + } + + if (len >= 576) { + bitvec_set_uint(bv, _make_up[b][8], _make_up_length[b][8]); + return bitvec_set_uint(bv, _term[b][len - 576], _term_length[b][len - 576]); + } + + if (len >= 512) { + bitvec_set_uint(bv, _make_up[b][7], _make_up_length[b][7]); + return bitvec_set_uint(bv, _term[b][len - 512], _term_length[b][len - 512]); + } + + if (len >= 448) { + bitvec_set_uint(bv, _make_up[b][6], _make_up_length[b][6]); + return bitvec_set_uint(bv, _term[b][len - 448], _term_length[b][len - 448]); + } + + if (len >= 384) { + bitvec_set_uint(bv, _make_up[b][5], _make_up_length[b][5]); + return bitvec_set_uint(bv, _term[b][len - 384], _term_length[b][len - 384]); + } + + if (len >= 320) { + bitvec_set_uint(bv, _make_up[b][4], _make_up_length[b][4]); + return bitvec_set_uint(bv, _term[b][len - 320], _term_length[b][len - 320]); + } + + if (len >= 256) { + bitvec_set_uint(bv, _make_up[b][3], _make_up_length[b][3]); + return bitvec_set_uint(bv, _term[b][len - 256], _term_length[b][len - 256]); + } + + if (len >= 192) { + bitvec_set_uint(bv, _make_up[b][2], _make_up_length[b][2]); + return bitvec_set_uint(bv, _term[b][len - 192], _term_length[b][len - 192]); + } + + if (len >= 128) { + bitvec_set_uint(bv, _make_up[b][1], _make_up_length[b][1]); + return bitvec_set_uint(bv, _term[b][len - 128], _term_length[b][len - 128]); + } + + if (len >= 64) { + bitvec_set_uint(bv, _make_up[b][0], _make_up_length[b][0]); + return bitvec_set_uint(bv, _term[b][len - 64], _term_length[b][len - 64]); + } + + return bitvec_set_uint(bv, _term[b][len], _term_length[b][len]); +} + +enum dec_state { + EXPECT_TERM, // only TERM is expected, keep parsing with the same color code + TOO_LONG, // that's what she said + NEED_MORE_BITS, // parsing failed, retry with bigger code word + CORRUPT, // kaboom! how the hell did you made that happen?! + OK // move along, nothing to see here +}; + +static inline enum dec_state _t4_step(struct bitvec *v, uint16_t w, bool b, unsigned bits, bool term_only) +{ + if (bits > _max_make_up_length[b]) + return TOO_LONG; + if (bits < _min_term_length[b]) + return NEED_MORE_BITS; + + if (term_only) { + if (bits > _max_term_length[b]) + return CORRUPT; + int t = _rle_term(w, b, bits); + if (-1 != t) { + bitvec_fill(v, t, b ? ONE : ZERO); + return OK; + } + return NEED_MORE_BITS; + } + + int m = _rle_makeup(w, b, bits); + if (-1 != m) { + bitvec_fill(v, m, b ? ONE : ZERO); + return EXPECT_TERM; + } + + m = _rle_term(w, b, bits); + if (-1 != m) { + bitvec_fill(v, m, b ? ONE : ZERO); + return OK; + } + + return NEED_MORE_BITS; +} + +/*! \brief decode T4-encoded bit vector + * Assumes MSB first encoding. + * \param[in] in bit vector with encoded data + * \param[in] cc color code (whether decoding should start with 1 or 0) + * \param[out] out the bit vector to store result into + * returns 0 on success, negative value otherwise + */ +int osmo_t4_decode(const struct bitvec *in, bool cc, struct bitvec *out) +{ + uint8_t orig[in->data_len]; + struct bitvec vec; + vec.data = orig; + vec.data_len = in->data_len; + bitvec_zero(&vec); + memcpy(vec.data, in->data, in->data_len); + vec.cur_bit = in->cur_bit; + + // init decoder: + unsigned bits = _min_term_length[cc]; + enum dec_state d; + int16_t w = bitvec_get_int16_msb(&vec, bits); + bool b = cc; + bool term_only = false; + + while (vec.cur_bit > 0) { + d = _t4_step(out, w, b, bits, term_only); + + switch (d) { + case EXPECT_TERM: + bitvec_shiftl(&vec, bits); + bits = _min_term_length[b]; + w = bitvec_get_int16_msb(&vec, bits); + term_only = true; + break; + case OK: + bitvec_shiftl(&vec, bits); + bits = _min_term_length[!b]; + w = bitvec_get_int16_msb(&vec, bits); + b = !b; + term_only = false; + break; + case NEED_MORE_BITS: + bits++; + w = bitvec_get_int16_msb(&vec, bits); + break; + case TOO_LONG: + return -EINVAL; + case CORRUPT: + return -EINVAL; + } + } + + return 0; +} + +/*! \brief encode bit vector in-place using T4 encoding + * Assumes MSB first encoding. + * \param[in] bv bit vector to be encoded + * returns color code (if the encoding started with 0 or 1) or -1 on failure (encoded is bigger than original) + */ +int osmo_t4_encode(struct bitvec *bv) +{ + unsigned rl0 = bitvec_rl(bv, false), rl1 = bitvec_rl(bv, true); + int r = (rl0 > rl1) ? 0 : 1; + uint8_t orig[bv->data_len], tmp[bv->data_len * 2]; // FIXME: better estimate max possible encoding overhead + struct bitvec comp, vec; + comp.data = tmp; + comp.data_len = bv->data_len * 2; + bitvec_zero(&comp); + vec.data = orig; + vec.data_len = bv->data_len; + bitvec_zero(&vec); + memcpy(vec.data, bv->data, bv->data_len); + vec.cur_bit = bv->cur_bit; + + while (vec.cur_bit > 0) { + if (rl0 > rl1) { + bitvec_shiftl(&vec, rl0); + _rle(&comp, rl0, false); + } else { + bitvec_shiftl(&vec, rl1); + _rle(&comp, rl1, true); + } +// printf(" -> [%d/%d]", comp.cur_bit + vec.cur_bit, bv->cur_bit); // TODO: implement backtracking + rl0 = bitvec_rl(&vec, false); + rl1 = bitvec_rl(&vec, true); + } + if (comp.cur_bit < bv->cur_bit) { + memcpy(bv->data, tmp, bv->data_len); + bv->cur_bit = comp.cur_bit; + return r; + } + return -1; +} + + diff --git a/tests/Makefile.am b/tests/Makefile.am index a4a6b2e..571e87b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,7 +12,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test \ smscb/gsm0341_test stats/stats_test \ - bitvec/bitvec_test msgb/msgb_test + bitvec/bitvec_test msgb/msgb_test bits/bitcomp_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test @@ -42,6 +42,9 @@ bits_bitrev_test_LDADD = $(top_builddir)/src/libosmocore.la bitvec_bitvec_test_SOURCES = bitvec/bitvec_test.c bitvec_bitvec_test_LDADD = $(top_builddir)/src/libosmocore.la +bits_bitcomp_test_SOURCES = bits/bitcomp_test.c +bits_bitcomp_test_LDADD = $(top_builddir)/src/libosmocore.la + conv_conv_test_SOURCES = conv/conv_test.c conv_conv_test_LDADD = $(top_builddir)/src/libosmocore.la @@ -136,7 +139,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ loggingrb/logging_test.err strrb/strrb_test.ok \ vty/vty_test.ok comp128/comp128_test.ok \ utils/utils_test.ok stats/stats_test.ok \ - bitvec/bitvec_test.ok msgb/msgb_test.ok + bitvec/bitvec_test.ok msgb/msgb_test.ok bits/bitcomp_test.ok DISTCLEANFILES = atconfig diff --git a/tests/bits/bitcomp_test.c b/tests/bits/bitcomp_test.c new file mode 100644 index 0000000..f6895cf --- /dev/null +++ b/tests/bits/bitcomp_test.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static char lol[1024]; // for pretty-printing + +int main(int argc, char **argv) +{ + srand(time(NULL)); + + struct bitvec bv, out; + uint8_t i = 20, test[i], data[i]; + + bv.data_len = i; + bv.data = test; + out.data_len = i; + out.data = data; + bitvec_zero(&bv); + bitvec_zero(&out); + + printf("\nrunning static tests...\n"); + + printf("\nTEST1:\n 00110111 01000111 10000001 1111\n"); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0x374781F, 28); bitvec_to_string_r(&bv, lol); printf("%s", lol); + + printf("\nEncoded:\n%d", osmo_t4_encode(&bv)); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf(" [%d]\nExpected:\n0 11011110 10001000 01110101 01100101 100 [35]\n", bv.cur_bit); + + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xDE887565, 32); + bitvec_set_uint(&bv, 4, 3); + bitvec_to_string_r(&bv, lol); + printf(" %s [%d]\n", lol, bv.cur_bit); + int d = osmo_t4_decode(&bv, 0, &out); + printf("\nDecoded:\n%d", d); + bitvec_to_string_r(&out, lol); + printf("%s [%d]\n", lol, out.cur_bit); + printf("Expected:\n 00110111 01000111 10000001 1111 \n"); + + printf("\nTEST2:\n 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00\n"); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xFFFFFFFF, 32); + bitvec_set_uint(&bv, 0xFFFFFFFF, 32); + bitvec_set_uint(&bv, 0xFFFFFC00, 26); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf("\nEncoded:\n%d", osmo_t4_encode(&bv)); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf(" [%d]\nExpected:\n1 11011101 01000001 00 [18]\n", bv.cur_bit); + + bitvec_zero(&out); + d = osmo_t4_decode(&bv, 1, &out); + printf("\nDecoded:\n%d", d); + bitvec_to_string_r(&out, lol); + printf("%s [%d]\n", lol, out.cur_bit); + printf("Expected:\n 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00\n"); + + return 0; +} diff --git a/tests/bits/bitcomp_test.ok b/tests/bits/bitcomp_test.ok new file mode 100644 index 0000000..238f3c4 --- /dev/null +++ b/tests/bits/bitcomp_test.ok @@ -0,0 +1,29 @@ + +running static tests... + +TEST1: + 00110111 01000111 10000001 1111 + 00110111 01000111 10000001 1111 +Encoded: +-1 00110111 01000111 10000001 1111 [28] +Expected: +0 11011110 10001000 01110101 01100101 100 [35] + 11011110 10001000 01110101 01100101 100 [35] + +Decoded: +0 00110111 01000111 10000001 1111 [28] +Expected: + 00110111 01000111 10000001 1111 + +TEST2: + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 +Encoded: +1 11011101 01000001 00 [18] +Expected: +1 11011101 01000001 00 [18] + +Decoded: +0 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 [90] +Expected: + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 diff --git a/tests/testsuite.at b/tests/testsuite.at index 9cda1de..3d4d526 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,12 @@ cat $abs_srcdir/bitvec/bitvec_test.ok > expout AT_CHECK([$abs_top_builddir/tests/bitvec/bitvec_test], [0], [expout], [ignore]) AT_CLEANUP +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bits/bitcomp_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/bits/bitcomp_test], [0], [expout]) +AT_CLEANUP + AT_SETUP([conv]) AT_KEYWORDS([conv]) cat $abs_srcdir/conv/conv_test.ok > expout -- 2.5.0 From dwilllmann at sysmocom.de Wed Feb 3 17:53:29 2016 From: dwilllmann at sysmocom.de (Daniel Willmann) Date: Wed, 3 Feb 2016 18:53:29 +0100 Subject: [PATCH 1/3] gtp: Pass pdp along when calling gtp_req() in gtp_update_context() In-Reply-To: References: Message-ID: From: Daniel Willmann With no pdp parameter gtp_req() will send the packet to TEID 0 which is not what we want. When trying to modify an established pdp context the correct TEID of that context must be used. --- gtp/gtp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtp/gtp.c b/gtp/gtp.c index a3772ff..7cc2328 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -1871,7 +1871,7 @@ int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, pdp->omcid.l, pdp->omcid.v); - gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp); + gtp_req(gsn, pdp->version, pdp, &packet, length, inetaddr, cbp); return 0; } -- 2.1.4 From dwilllmann at sysmocom.de Wed Feb 3 17:53:28 2016 From: dwilllmann at sysmocom.de (Daniel Willmann) Date: Wed, 3 Feb 2016 18:53:28 +0100 Subject: [PATCH 0/3] Fix handling PDP update messages Message-ID: From: Daniel Willmann Hello, it seems PDP context updates was never really used/tested to an Update PDP context would not go through. The following patches fix that (at least for gtpv1). Regards Daniel Daniel Willmann (3): gtp: Pass pdp along when calling gtp_req() in gtp_update_context() gtp: Make gtp_update_pdp_conf() work for gtp0 and gtp1 connections gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly gtp/gtp.c | 162 +++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 118 insertions(+), 44 deletions(-) -- 2.1.4 -- - Daniel Willmann http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From dwilllmann at sysmocom.de Wed Feb 3 17:53:30 2016 From: dwilllmann at sysmocom.de (Daniel Willmann) Date: Wed, 3 Feb 2016 18:53:30 +0100 Subject: [PATCH 2/3] gtp: Make gtp_update_pdp_conf() work for gtp0 and gtp1 connections In-Reply-To: References: Message-ID: <2d3c22115fa4fc0e742b159a28951e83bdcad6fd.1454521570.git.daniel@totalueberwachung.de> From: Daniel Willmann pdp_getgtp1(&pdp, get_tei(pack)) works like pdp_getgtp0 for gtp0 connections. Using get_hlen() for gtpie_decaps is used in other places to decode ies for both version 0 and 1. --- gtp/gtp.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/gtp/gtp.c b/gtp/gtp.c index 7cc2328..772ab08 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -2175,33 +2175,27 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, uint8_t cause, recovery; void *cbp = NULL; uint8_t type = 0; + int hlen = get_hlen(pack); /* Remove packet from queue */ if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF; - /* TODO This function is called from gtp_decaps1c() (for GTP v1) but - * uses gtp0.h.flow (GTP v0 data element) - */ /* Find the context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet *)pack)->gtp0.h.flow))) { + if (pdp_getgtp1(&pdp, get_tei(pack))) { gsn->err_unknownpdp++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, - "Unknown PDP context\n"); + "Unknown PDP context: %u\n", get_tei(pack)); if (gsn->cb_conf) - gsn->cb_conf(type, cause, NULL, cbp); + gsn->cb_conf(type, EOF, NULL, cbp); return EOF; } /* Register that we have received a valid teic from GGSN */ pdp->teic_confirmed = 1; - /* TODO This function is called from gtp_decaps1c() (for GTP v1) but - * explicitly passes version 0 and GTP0_HEADER_SIZE to gtpie_decaps() - */ /* Decode information elements */ - if (gtpie_decaps - (ie, 0, pack + GTP0_HEADER_SIZE, len - GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack + hlen, len - hlen)) { gsn->invalid++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Invalid message format\n"); -- 2.1.4 From dwilllmann at sysmocom.de Wed Feb 3 17:53:31 2016 From: dwilllmann at sysmocom.de (Daniel Willmann) Date: Wed, 3 Feb 2016 18:53:31 +0100 Subject: [PATCH 3/3] gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly In-Reply-To: References: Message-ID: <31daf439e34a6f4b1b6a323ab84e437371f972d5.1454521570.git.daniel@totalueberwachung.de> From: Daniel Willmann libgtp cannot understand its own update pdp request (in gtp v1) Only require the conditional and mandatory fields for gtpv1 and not others. Refer to 3GPP TS 29.060 Ch. 7.3.4 --- gtp/gtp.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 32 deletions(-) diff --git a/gtp/gtp.c b/gtp/gtp.c index 772ab08..0ef4a54 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -2225,22 +2225,87 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, } /* Check all conditional information elements */ - if (GTPCAUSE_ACC_REQ != cause) { - if (gsn->cb_conf) - gsn->cb_conf(type, cause, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return 0; - } else { - /* Check for missing conditionary information elements */ - if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) && - gtpie_exist(ie, GTPIE_REORDER, 0) && - gtpie_exist(ie, GTPIE_FL_DI, 0) && - gtpie_exist(ie, GTPIE_FL_C, 0) && - gtpie_exist(ie, GTPIE_CHARGING_ID, 0) && - gtpie_exist(ie, GTPIE_EUA, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) { + /* TODO: This does not handle GGSN-initiated update responses */ + if (GTPCAUSE_ACC_REQ == cause) { + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + &pdp->qos_neg0, + sizeof(pdp->qos_neg0))) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } + + if (version == 1) { + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } + + if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, + len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + } + + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { gsn->missing++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, @@ -2252,24 +2317,39 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, return EOF; } - /* Update pdp with new values */ - gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_neg0, sizeof(pdp->qos_neg0)); - gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder); - gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru); - gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc); - gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid); - gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v)); + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, + len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } - if (gsn->cb_conf) - gsn->cb_conf(type, cause, pdp, cbp); - return 0; /* Succes */ + if (version == 1) { + if (gtpie_gettlv + (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l, + &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) { + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, + pack, len, + "Missing conditional information field\n"); + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); + pdp_freepdp(pdp); */ + return EOF; + } + } } + + if (gsn->cb_conf) + gsn->cb_conf(type, cause, pdp, cbp); + return 0; /* Succes */ } /* API: Send Delete PDP Context Request */ -- 2.1.4 From laforge at gnumonks.org Wed Feb 3 18:12:53 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 3 Feb 2016 19:12:53 +0100 Subject: [PATCH 3/3] gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly In-Reply-To: <31daf439e34a6f4b1b6a323ab84e437371f972d5.1454521570.git.daniel@totalueberwachung.de> References: <31daf439e34a6f4b1b6a323ab84e437371f972d5.1454521570.git.daniel@totalueberwachung.de> Message-ID: <20160203181253.GB2572@nataraja> Hi Daniel, On Wed, Feb 03, 2016 at 06:53:31PM +0100, Daniel Willmann wrote: > + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, > + &pdp->qos_neg0, > + sizeof(pdp->qos_neg0))) { > + gsn->missing++; > + GTP_LOGPKG(LOGL_ERROR, peer, > + pack, len, > + "Missing conditional information field\n"); > + if (gsn->cb_conf) > + gsn->cb_conf(type, EOF, pdp, cbp); > + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); > + pdp_freepdp(pdp); */ > + return EOF; > + } > + > + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { > + gsn->missing++; > + GTP_LOGPKG(LOGL_ERROR, peer, > + pack, len, > + "Missing conditional information field\n"); > + if (gsn->cb_conf) > + gsn->cb_conf(type, EOF, pdp, cbp); > + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); > + pdp_freepdp(pdp); */ > + return EOF; > + } This looks like a bit too much of copy+paste to me. Can't we put that into a separate function, or if not, at least a macro that hides all the verbosity and the copy+paste? Also, why is ther a commented-out section about cb_delete_context involved? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Wed Feb 3 18:24:03 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:03 +0100 Subject: [PATCH 4/7] TRX: scheduler: don't access l1h->config from scheduler In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-4-git-send-email-laforge@gnumonks.org> From: Harald Welte --- src/osmo-bts-trx/scheduler.c | 2 +- src/osmo-bts-trx/trx_if.c | 4 ++++ src/osmo-bts-trx/trx_if.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index 33f4f7f..d4af2b7 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -1660,7 +1660,7 @@ static int trx_sched_fn(uint32_t fn) struct l1sched_trx *l1t = trx_l1sched_hdl(trx); /* we don't schedule, if power is off */ - if (!l1h->config.poweron) + if (!trx_if_powered(l1h)) continue; /* process every TS of TRX */ diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index fef2064..16c9fc7 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -558,3 +558,7 @@ void trx_if_close(struct trx_l1h *l1h) trx_udp_close(&l1h->trx_ofd_data); } +int trx_if_powered(struct trx_l1h *l1h) +{ + return l1h->config.poweron; +} diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index ac0ee42..3862e2b 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -31,5 +31,6 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr, int trx_if_open(struct trx_l1h *l1h); void trx_if_flush(struct trx_l1h *l1h); void trx_if_close(struct trx_l1h *l1h); +int trx_if_powered(struct trx_l1h *l1h); #endif /* TRX_IF_H */ -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:02 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:02 +0100 Subject: [PATCH 3/7] TRX: call trx_loop_sacch_clock from TRX scheduler backend In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-3-git-send-email-laforge@gnumonks.org> From: Harald Welte this removes the dependency of scheduler.c on loops.h --- src/osmo-bts-trx/scheduler.c | 6 ------ src/osmo-bts-trx/scheduler_trx.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index c904e62..33f4f7f 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -40,7 +40,6 @@ #include "scheduler.h" #include "scheduler_backend.h" #include "trx_if.h" -#include "loops.h" extern void *tall_bts_ctx; @@ -404,7 +403,6 @@ static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, uint8_t chan_nr, link_id; struct msgb *msg; struct osmo_phsap_prim *l1sap; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); /* get data for RTS indication */ chan_nr = trx_chan_desc[chan].chan_nr | tn; @@ -420,10 +418,6 @@ static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, chan_nr, link_id, fn, tn, l1t->trx->nr); - /* send clock information to loops process */ - if (L1SAP_IS_LINK_SACCH(link_id)) - trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]); - /* generate prim */ msg = l1sap_msgb_alloc(200); if (!msg) diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index ec53fbf..a77f5a5 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -127,6 +127,8 @@ ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + uint8_t link_id = trx_chan_desc[chan].link_id; + uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn; struct msgb *msg = NULL; /* make GCC happy */ ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; static ubit_t bits[148]; @@ -138,6 +140,10 @@ ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, goto send_burst; } + /* send clock information to loops process */ + if (L1SAP_IS_LINK_SACCH(link_id)) + trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]); + /* get mac block from queue */ msg = _sched_dequeue_prim(l1t, tn, fn, chan); if (msg) -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:06 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:06 +0100 Subject: [PATCH 7/7] TRX: Move scheduler to src/common In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-7-git-send-email-laforge@gnumonks.org> From: Harald Welte This is the final step to make the L1 scheduler generally available to other BTS models than OsmoTRX. --- include/osmo-bts/Makefile.am | 2 +- include/osmo-bts/scheduler.h | 175 ++++ include/osmo-bts/scheduler_backend.h | 82 ++ src/common/Makefile.am | 4 +- src/common/scheduler.c | 1621 +++++++++++++++++++++++++++++++++ src/osmo-bts-trx/Makefile.am | 6 +- src/osmo-bts-trx/l1_if.c | 2 +- src/osmo-bts-trx/l1_if.h | 2 +- src/osmo-bts-trx/main.c | 2 +- src/osmo-bts-trx/scheduler.c | 1622 ---------------------------------- src/osmo-bts-trx/scheduler.h | 175 ---- src/osmo-bts-trx/scheduler_backend.h | 82 -- src/osmo-bts-trx/scheduler_trx.c | 4 +- src/osmo-bts-trx/trx_if.c | 2 +- src/osmo-bts-trx/trx_vty.c | 2 +- 15 files changed, 1892 insertions(+), 1891 deletions(-) create mode 100644 include/osmo-bts/scheduler.h create mode 100644 include/osmo-bts/scheduler_backend.h create mode 100644 src/common/scheduler.c delete mode 100644 src/osmo-bts-trx/scheduler.c delete mode 100644 src/osmo-bts-trx/scheduler.h delete mode 100644 src/osmo-bts-trx/scheduler_backend.h diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index bf037ae..af88a1a 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,4 +1,4 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \ - power_control.h + power_control.h scheduler.h scheduler_backend.h diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h new file mode 100644 index 0000000..13ef051 --- /dev/null +++ b/include/osmo-bts/scheduler.h @@ -0,0 +1,175 @@ +#ifndef TRX_SCHEDULER_H +#define TRX_SCHEDULER_H + +/* These types define the different channels on a multiframe. + * Each channel has queues and can be activated individually. + */ +enum trx_chan_type { + TRXC_IDLE = 0, + TRXC_FCCH, + TRXC_SCH, + TRXC_BCCH, + TRXC_RACH, + TRXC_CCCH, + TRXC_TCHF, + TRXC_TCHH_0, + TRXC_TCHH_1, + TRXC_SDCCH4_0, + TRXC_SDCCH4_1, + TRXC_SDCCH4_2, + TRXC_SDCCH4_3, + TRXC_SDCCH8_0, + TRXC_SDCCH8_1, + TRXC_SDCCH8_2, + TRXC_SDCCH8_3, + TRXC_SDCCH8_4, + TRXC_SDCCH8_5, + TRXC_SDCCH8_6, + TRXC_SDCCH8_7, + TRXC_SACCHTF, + TRXC_SACCHTH_0, + TRXC_SACCHTH_1, + TRXC_SACCH4_0, + TRXC_SACCH4_1, + TRXC_SACCH4_2, + TRXC_SACCH4_3, + TRXC_SACCH8_0, + TRXC_SACCH8_1, + TRXC_SACCH8_2, + TRXC_SACCH8_3, + TRXC_SACCH8_4, + TRXC_SACCH8_5, + TRXC_SACCH8_6, + TRXC_SACCH8_7, + TRXC_PDTCH, + TRXC_PTCCH, + _TRX_CHAN_MAX +}; + +/* States each channel on a multiframe */ +struct l1sched_chan_state { + /* scheduler */ + uint8_t active; /* Channel is active */ + ubit_t *dl_bursts; /* burst buffer for TX */ + sbit_t *ul_bursts; /* burst buffer for RX */ + uint32_t ul_first_fn; /* fn of first burst */ + uint8_t ul_mask; /* mask of received bursts */ + + /* RSSI / TOA */ + uint8_t rssi_num; /* number of RSSI values */ + float rssi_sum; /* sum of RSSI values */ + uint8_t toa_num; /* number of TOA values */ + float toa_sum; /* sum of TOA values */ + + /* loss detection */ + uint8_t lost; /* (SACCH) loss detection */ + + /* mode */ + uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */ + + /* AMR */ + uint8_t codec[4]; /* 4 possible codecs for amr */ + int codecs; /* number of possible codecs */ + float ber_sum; /* sum of bit error rates */ + int ber_num; /* number of bit error rates */ + uint8_t ul_ft; /* current uplink FT index */ + uint8_t dl_ft; /* current downlink FT index */ + uint8_t ul_cmr; /* current uplink CMR index */ + uint8_t dl_cmr; /* current downlink CMR index */ + uint8_t amr_loop; /* if AMR loop is enabled */ + + /* TCH/H */ + uint8_t dl_ongoing_facch; /* FACCH/H on downlink */ + uint8_t ul_ongoing_facch; /* FACCH/H on uplink */ + + /* encryption */ + int ul_encr_algo; /* A5/x encry algo downlink */ + int dl_encr_algo; /* A5/x encry algo uplink */ + int ul_encr_key_len; + int dl_encr_key_len; + uint8_t ul_encr_key[MAX_A5_KEY_LEN]; + uint8_t dl_encr_key[MAX_A5_KEY_LEN]; + + /* measurements */ + struct { + uint8_t clock; /* cyclic clock counter */ + int8_t rssi[32]; /* last RSSI values */ + int rssi_count; /* received RSSI values */ + int rssi_valid_count; /* number of stored value */ + int rssi_got_burst; /* any burst received so far */ + float toa_sum; /* sum of TOA values */ + int toa_num; /* number of TOA value */ + } meas; + + /* handover */ + uint8_t ho_rach_detect; /* if rach detection is on */ +}; + +struct l1sched_ts { + uint8_t mf_index; /* selected multiframe index */ + uint32_t mf_last_fn; /* last received frame number */ + uint8_t mf_period; /* period of multiframe */ + const struct trx_sched_frame *mf_frames; /* pointer to frame layout */ + + struct llist_head dl_prims; /* Queue primitves for TX */ + + /* Channel states for all logical channels */ + struct l1sched_chan_state chan_state[_TRX_CHAN_MAX]; +}; + +struct l1sched_trx { + struct gsm_bts_trx *trx; + struct l1sched_ts ts[TRX_NR_TS]; +}; + +struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn); + +/*! \brief how many frame numbers in advance we should send bursts to PHY */ +extern uint32_t trx_clock_advance; +/*! \brief advance RTS.ind to L2 by that many clocks */ +extern uint32_t trx_rts_advance; +/*! \brief last frame number as received from PHY */ +extern uint32_t transceiver_last_fn; + + +/*! \brief Initialize the scheudler data structures */ +int trx_sched_init(struct l1sched_trx *l1t); + +/*! \brief De-initialize the scheudler data structures */ +void trx_sched_exit(struct l1sched_trx *l1t); + +/*! \brief Handle a PH-DATA.req from L2 down to L1 */ +int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); + +/*! \brief Handle a PH-TCH.req from L2 down to L1 */ +int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); + +/*! \brief PHY informs us of new (current) GSM freme nunmber */ +int trx_sched_clock(struct gsm_bts *bts, uint32_t fn); + +/*! \brief handle an UL burst received by PHY */ +int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + sbit_t *bits, int8_t rssi, float toa); + +/*! \brief set multiframe scheduler to given physical channel config */ +int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, + enum gsm_phys_chan_config pchan); + +/*! \brief set all matching logical channels active/inactive */ +int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, + int active); + +/*! \brief set mode of all matching logical channels to given mode(s) */ +int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, + uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, + uint8_t codec2, uint8_t codec3, uint8_t initial_codec, + uint8_t handover); + +/*! \brief set ciphering on given logical channels */ +int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, + int algo, uint8_t *key, int key_len); + +/* \brief close all logical channels and reset timeslots */ +void trx_sched_reset(struct l1sched_trx *l1t); + +#endif /* TRX_SCHEDULER_H */ diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h new file mode 100644 index 0000000..9f663cd --- /dev/null +++ b/include/osmo-bts/scheduler_backend.h @@ -0,0 +1,82 @@ +#pragma once + +typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan); + +typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan, + uint8_t bid); + +typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan, + uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); + +struct trx_chan_desc { + /*! \brief Is this on a PDCH (PS) ? */ + int pdch; + /*! \brief TRX Channel Type */ + enum trx_chan_type chan; + /*! \brief Channel Number (like in RSL) */ + uint8_t chan_nr; + /*! \brief Link ID (like in RSL) */ + uint8_t link_id; + /*! \brief Human-readable name */ + const char *name; + /*! \brief function to call when we want to generate RTS.req to L2 */ + trx_sched_rts_func *rts_fn; + /*! \brief function to call when DATA.req received from L2 */ + trx_sched_dl_func *dl_fn; + /*! \brief function to call when burst received from PHY */ + trx_sched_ul_func *ul_fn; + /*! \breif is this channel automatically active at start? */ + int auto_active; +}; +extern const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX]; + +extern const ubit_t _sched_tsc[8][26]; +const ubit_t _sched_fcch_burst[148]; +const ubit_t _sched_sch_train[64]; + +struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, + enum trx_chan_type chan); + +int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi); + +int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); + +ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); + +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); +int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); +void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index e577eba..fea205c 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -2,10 +2,12 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOTRAU_CFLAGS) LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) -noinst_LIBRARIES = libbts.a +noinst_LIBRARIES = libbts.a libl1sched.a libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ l1sap.c cbch.c power_control.c main.c + +libl1sched_a_SOURCES = scheduler.c diff --git a/src/common/scheduler.c b/src/common/scheduler.c new file mode 100644 index 0000000..64d89ac --- /dev/null +++ b/src/common/scheduler.c @@ -0,0 +1,1621 @@ +/* Scheduler for OsmoBTS-TRX */ + +/* (C) 2013 by Andreas Eversberg + * (C) 2015 by Alexander Chemeris + * (C) 2015 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void *tall_bts_ctx; + +static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan); +static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan); +static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan); +/*! \brief Dummy Burst (TS 05.02 Chapter 5.2.6) */ +static const ubit_t dummy_burst[148] = { + 0,0,0, + 1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,1,1,0, + 0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,0, + 0,1,0,1,1,1,0,0,0,1,0,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0, + 0,0,1,1,0,0,1,1,0,0,1,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1, + 0,0,1,0,1,1,1,1,1,0,1,0,1,0, + 0,0,0, +}; + +/*! \brief FCCH Burst (TS 05.02 Chapter 5.2.4) */ +const ubit_t _sched_fcch_burst[148] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +/*! \brief Training Sequences (TS 05.02 Chapter 5.2.3) */ +const ubit_t _sched_tsc[8][26] = { + { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1, }, + { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1, }, + { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0, }, + { 0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,0, }, + { 0,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1, }, + { 0,1,0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,0, }, + { 1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,1,1,1, }, + { 1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0, }, +}; + +/*! \brief SCH trainign sequence (TS 05.02 Chapter 5.2.5) */ +const ubit_t _sched_sch_train[64] = { + 1,0,1,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1, + 0,0,1,0,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,1,1,0,1,1, +}; + +/* + * subchannel description structure + */ + +const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { + { 0, TRXC_IDLE, 0, 0, "IDLE", NULL, tx_idle_fn, NULL, 1 }, + { 0, TRXC_FCCH, 0, 0, "FCCH", NULL, tx_fcch_fn, NULL, 1 }, + { 0, TRXC_SCH, 0, 0, "SCH", NULL, tx_sch_fn, NULL, 1 }, + { 0, TRXC_BCCH, 0x80, 0x00, "BCCH", rts_data_fn, tx_data_fn, NULL, 1 }, + { 0, TRXC_RACH, 0x88, 0x00, "RACH", NULL, NULL, rx_rach_fn, 1 }, + { 0, TRXC_CCCH, 0x90, 0x00, "CCCH", rts_data_fn, tx_data_fn, NULL, 1 }, + { 0, TRXC_TCHF, 0x08, 0x00, "TCH/F", rts_tchf_fn, tx_tchf_fn, rx_tchf_fn, 0 }, + { 0, TRXC_TCHH_0, 0x10, 0x00, "TCH/H(0)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, + { 0, TRXC_TCHH_1, 0x18, 0x00, "TCH/H(1)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, + { 0, TRXC_SDCCH4_0, 0x20, 0x00, "SDCCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_1, 0x28, 0x00, "SDCCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_2, 0x30, 0x00, "SDCCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH4_3, 0x38, 0x00, "SDCCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_0, 0x40, 0x00, "SDCCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_1, 0x48, 0x00, "SDCCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_2, 0x50, 0x00, "SDCCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_3, 0x58, 0x00, "SDCCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_4, 0x60, 0x00, "SDCCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_5, 0x68, 0x00, "SDCCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_6, 0x70, 0x00, "SDCCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SDCCH8_7, 0x78, 0x00, "SDCCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTF, 0x08, 0x40, "SACCH/TF", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTH_0, 0x10, 0x40, "SACCH/TH(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCHTH_1, 0x18, 0x40, "SACCH/TH(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_0, 0x20, 0x40, "SACCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_1, 0x28, 0x40, "SACCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_2, 0x30, 0x40, "SACCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH4_3, 0x38, 0x40, "SACCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_0, 0x40, 0x40, "SACCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_1, 0x48, 0x40, "SACCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_2, 0x50, 0x40, "SACCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_3, 0x58, 0x40, "SACCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_4, 0x60, 0x40, "SACCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_5, 0x68, 0x40, "SACCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_6, 0x70, 0x40, "SACCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 0, TRXC_SACCH8_7, 0x78, 0x40, "SACCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, + { 1, TRXC_PDTCH, 0x08, 0x00, "PDTCH", rts_data_fn, tx_pdtch_fn, rx_pdtch_fn, 0 }, + { 1, TRXC_PTCCH, 0x08, 0x00, "PTCCH", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, +}; + + +/* + * init / exit + */ + +int trx_sched_init(struct l1sched_trx *l1t) +{ + uint8_t tn; + int i; + + LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); + + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + l1ts->mf_index = 0; + l1ts->mf_last_fn = 0; + INIT_LLIST_HEAD(&l1ts->dl_prims); + for (i = 0; i < ARRAY_SIZE(&l1ts->chan_state); i++) { + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; + chan_state->active = 0; + } + } + + return 0; +} + +void trx_sched_exit(struct l1sched_trx *l1t) +{ + struct gsm_bts_trx_ts *ts; + uint8_t tn; + int i; + + LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr); + + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + msgb_queue_flush(&l1ts->dl_prims); + for (i = 0; i < _TRX_CHAN_MAX; i++) { + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; + if (chan_state->dl_bursts) { + talloc_free(chan_state->dl_bursts); + chan_state->dl_bursts = NULL; + } + if (chan_state->ul_bursts) { + talloc_free(chan_state->ul_bursts); + chan_state->ul_bursts = NULL; + } + } + /* clear lchan channel states */ + ts = &l1t->trx->ts[tn]; + for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) + lchan_set_state(&ts->lchan[i], LCHAN_S_NONE); + } +} + +/* close all logical channels and reset timeslots */ +void trx_sched_reset(struct l1sched_trx *l1t) +{ + trx_sched_exit(l1t); + trx_sched_init(l1t); +} + +struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, + enum trx_chan_type chan) +{ + struct msgb *msg, *msg2; + struct osmo_phsap_prim *l1sap; + uint32_t prim_fn; + uint8_t chan_nr, link_id; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + /* get prim of current fn from queue */ + llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) { + l1sap = msgb_l1sap_prim(msg); + if (l1sap->oph.operation != PRIM_OP_REQUEST) { +wrong_type: + LOGP(DL1C, LOGL_ERROR, "Prim for ts=%u at fn=%u has " + "wrong type.\n", tn, fn); +free_msg: + /* unlink and free message */ + llist_del(&msg->list); + msgb_free(msg); + return NULL; + } + switch (l1sap->oph.primitive) { + case PRIM_PH_DATA: + chan_nr = l1sap->u.data.chan_nr; + link_id = l1sap->u.data.link_id; + prim_fn = ((l1sap->u.data.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME); + break; + case PRIM_TCH: + chan_nr = l1sap->u.tch.chan_nr; + link_id = 0; + prim_fn = ((l1sap->u.tch.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME); + break; + default: + goto wrong_type; + } + if (prim_fn > 100) { + LOGP(DL1C, LOGL_NOTICE, "Prim for trx=%u ts=%u at fn=%u " + "is out of range, or channel already disabled. " + "If this happens in conjunction with PCU, " + "increase 'rts-advance' by 5. (current fn=%u)\n", + l1t->trx->nr, tn, l1sap->u.data.fn, fn); + /* unlink and free message */ + llist_del(&msg->list); + msgb_free(msg); + continue; + } + if (prim_fn > 0) + continue; + + goto found_msg; + } + + return NULL; + +found_msg: + if ((chan_nr ^ (trx_chan_desc[chan].chan_nr | tn)) + || ((link_id & 0xc0) ^ trx_chan_desc[chan].link_id)) { + LOGP(DL1C, LOGL_ERROR, "Prim for ts=%u at fn=%u has wrong " + "chan_nr=%02x link_id=%02x, expecting chan_nr=%02x " + "link_id=%02x.\n", tn, fn, chan_nr, link_id, + trx_chan_desc[chan].chan_nr | tn, + trx_chan_desc[chan].link_id); + goto free_msg; + } + + /* unlink and return message */ + llist_del(&msg->list); + return msg; +} + +int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) +{ + struct msgb *msg; + struct osmo_phsap_prim *l1sap; + uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + /* compose primitive */ + msg = l1sap_msgb_alloc(l2_len); + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, + PRIM_OP_INDICATION, msg); + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.link_id = trx_chan_desc[chan].link_id; + l1sap->u.data.fn = fn; + l1sap->u.data.rssi = (int8_t) (rssi); + msg->l2h = msgb_put(msg, l2_len); + if (l2_len) + memcpy(msg->l2h, l2, l2_len); + + if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) + l1ts->chan_state[chan].lost = 0; + + /* forward primitive */ + l1sap_up(l1t->trx, l1sap); + + return 0; +} + +int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len) +{ + struct msgb *msg; + struct osmo_phsap_prim *l1sap; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + /* compose primitive */ + msg = l1sap_msgb_alloc(tch_len); + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH, + PRIM_OP_INDICATION, msg); + l1sap->u.tch.chan_nr = trx_chan_desc[chan].chan_nr | tn; + l1sap->u.tch.fn = fn; + msg->l2h = msgb_put(msg, tch_len); + if (tch_len) + memcpy(msg->l2h, tch, tch_len); + + if (l1ts->chan_state[chan].lost) + l1ts->chan_state[chan].lost--; + + /* forward primitive */ + l1sap_up(l1t->trx, l1sap); + + return 0; +} + + + +/* + * data request (from upper layer) + */ + +int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) +{ + uint8_t tn = l1sap->u.data.chan_nr & 7; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x " + "fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr, + l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr); + + if (!l1sap->oph.msg) + abort(); + + /* ignore empty frame */ + if (!msgb_l2len(l1sap->oph.msg)) { + msgb_free(l1sap->oph.msg); + return 0; + } + + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); + + return 0; +} + +int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) +{ + uint8_t tn = l1sap->u.tch.chan_nr & 7; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + + LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x " + "fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr, + l1sap->u.tch.fn, tn, l1t->trx->nr); + + if (!l1sap->oph.msg) + abort(); + + /* ignore empty frame */ + if (!msgb_l2len(l1sap->oph.msg)) { + msgb_free(l1sap->oph.msg); + return 0; + } + + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); + + return 0; +} + + +/* + * ready-to-send indication (to upper layer) + */ + +/* RTS for data frame */ +static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) +{ + uint8_t chan_nr, link_id; + struct msgb *msg; + struct osmo_phsap_prim *l1sap; + + /* get data for RTS indication */ + chan_nr = trx_chan_desc[chan].chan_nr | tn; + link_id = trx_chan_desc[chan].link_id; + + if (!chan_nr) { + LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " + "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); + return -ENODEV; + } + + LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x " + "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, + chan_nr, link_id, fn, tn, l1t->trx->nr); + + /* generate prim */ + msg = l1sap_msgb_alloc(200); + if (!msg) + return -ENOMEM; + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.link_id = link_id; + l1sap->u.data.fn = fn; + + return l1sap_up(l1t->trx, l1sap); +} + +static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, int facch) +{ + uint8_t chan_nr, link_id; + struct msgb *msg; + struct osmo_phsap_prim *l1sap; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + int rc = 0; + + /* get data for RTS indication */ + chan_nr = trx_chan_desc[chan].chan_nr | tn; + link_id = trx_chan_desc[chan].link_id; + + if (!chan_nr) { + LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " + "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); + return -ENODEV; + } + + LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x " + "fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, + chan_nr, fn, tn, l1t->trx->nr); + + /* only send, if FACCH is selected */ + if (facch) { + /* generate prim */ + msg = l1sap_msgb_alloc(200); + if (!msg) + return -ENOMEM; + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.link_id = link_id; + l1sap->u.data.fn = fn; + + rc = l1sap_up(l1t->trx, l1sap); + } + + /* dont send, if TCH is in signalling only mode */ + if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { + /* generate prim */ + msg = l1sap_msgb_alloc(200); + if (!msg) + return -ENOMEM; + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.tch.chan_nr = chan_nr; + l1sap->u.tch.fn = fn; + + return l1sap_up(l1t->trx, l1sap); + } + + return rc; +} + +/* RTS for full rate traffic frame */ +static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) +{ + /* TCH/F may include FACCH on every 4th burst */ + return rts_tch_common(l1t, tn, fn, chan, 1); +} + + +/* RTS for half rate traffic frame */ +static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) +{ + /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */ + return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1); +} + +/* + * multiframe structure + */ + +/* frame structures */ +struct trx_sched_frame { + /*! \brief downlink TRX channel type */ + enum trx_chan_type dl_chan; + /*! \brief downlink block ID */ + uint8_t dl_bid; + /*! \breff uplink TRX channel type */ + enum trx_chan_type ul_chan; + /*! \brief uplink block ID */ + uint8_t ul_bid; +}; + +static const struct trx_sched_frame frame_bcch[51] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_BCCH, 0, TRXC_RACH, 0 }, { TRXC_BCCH, 1, TRXC_RACH, 0 }, { TRXC_BCCH, 2, TRXC_RACH, 0 }, { TRXC_BCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_IDLE, 0, TRXC_RACH, 0 }, +}; + +static const struct trx_sched_frame frame_bcch_sdcch4[102] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_FCCH, 0, TRXC_SDCCH4_3, 0 }, + { TRXC_SCH, 0, TRXC_SDCCH4_3, 1 }, + { TRXC_BCCH, 0, TRXC_SDCCH4_3, 2 }, + { TRXC_BCCH, 1, TRXC_SDCCH4_3, 3 }, + { TRXC_BCCH, 2, TRXC_RACH, 0 }, + { TRXC_BCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_SACCH4_2, 0 }, + { TRXC_CCCH, 1, TRXC_SACCH4_2, 1 }, + { TRXC_CCCH, 2, TRXC_SACCH4_2, 2 }, + { TRXC_CCCH, 3, TRXC_SACCH4_2, 3 }, + { TRXC_FCCH, 0, TRXC_SACCH4_3, 0 }, + { TRXC_SCH, 0, TRXC_SACCH4_3, 1 }, + { TRXC_CCCH, 0, TRXC_SACCH4_3, 2 }, + { TRXC_CCCH, 1, TRXC_SACCH4_3, 3 }, + { TRXC_CCCH, 2, TRXC_RACH, 0 }, + { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 1, TRXC_RACH, 0 }, + { TRXC_CCCH, 2, TRXC_RACH, 0 }, + { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 3, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 3, TRXC_RACH, 0 }, + { TRXC_SDCCH4_3, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_3, 1, TRXC_SDCCH4_0, 0 }, + { TRXC_SDCCH4_3, 2, TRXC_SDCCH4_0, 1 }, + { TRXC_SDCCH4_3, 3, TRXC_SDCCH4_0, 2 }, + { TRXC_FCCH, 0, TRXC_SDCCH4_0, 3 }, + { TRXC_SCH, 0, TRXC_SDCCH4_1, 0 }, + { TRXC_SACCH4_0, 0, TRXC_SDCCH4_1, 1 }, + { TRXC_SACCH4_0, 1, TRXC_SDCCH4_1, 2 }, + { TRXC_SACCH4_0, 2, TRXC_SDCCH4_1, 3 }, + { TRXC_SACCH4_0, 3, TRXC_RACH, 0 }, + { TRXC_SACCH4_1, 0, TRXC_RACH, 0 }, + { TRXC_SACCH4_1, 1, TRXC_SDCCH4_2, 0 }, + { TRXC_SACCH4_1, 2, TRXC_SDCCH4_2, 1 }, + { TRXC_SACCH4_1, 3, TRXC_SDCCH4_2, 2 }, + { TRXC_IDLE, 0, TRXC_SDCCH4_2, 3 }, + + { TRXC_FCCH, 0, TRXC_SDCCH4_3, 0 }, + { TRXC_SCH, 0, TRXC_SDCCH4_3, 1 }, + { TRXC_BCCH, 0, TRXC_SDCCH4_3, 2 }, + { TRXC_BCCH, 1, TRXC_SDCCH4_3, 3 }, + { TRXC_BCCH, 2, TRXC_RACH, 0 }, + { TRXC_BCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_SACCH4_0, 0 }, + { TRXC_CCCH, 1, TRXC_SACCH4_0, 1 }, + { TRXC_CCCH, 2, TRXC_SACCH4_0, 2 }, + { TRXC_CCCH, 3, TRXC_SACCH4_0, 3 }, + { TRXC_FCCH, 0, TRXC_SACCH4_1, 0 }, + { TRXC_SCH, 0, TRXC_SACCH4_1, 1 }, + { TRXC_CCCH, 0, TRXC_SACCH4_1, 2 }, + { TRXC_CCCH, 1, TRXC_SACCH4_1, 3 }, + { TRXC_CCCH, 2, TRXC_RACH, 0 }, + { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_CCCH, 0, TRXC_RACH, 0 }, + { TRXC_CCCH, 1, TRXC_RACH, 0 }, + { TRXC_CCCH, 2, TRXC_RACH, 0 }, + { TRXC_CCCH, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_0, 3, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_1, 3, TRXC_RACH, 0 }, + { TRXC_FCCH, 0, TRXC_RACH, 0 }, + { TRXC_SCH, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 1, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 2, TRXC_RACH, 0 }, + { TRXC_SDCCH4_2, 3, TRXC_RACH, 0 }, + { TRXC_SDCCH4_3, 0, TRXC_RACH, 0 }, + { TRXC_SDCCH4_3, 1, TRXC_SDCCH4_0, 0 }, + { TRXC_SDCCH4_3, 2, TRXC_SDCCH4_0, 1 }, + { TRXC_SDCCH4_3, 3, TRXC_SDCCH4_0, 2 }, + { TRXC_FCCH, 0, TRXC_SDCCH4_0, 3 }, + { TRXC_SCH, 0, TRXC_SDCCH4_1, 0 }, + { TRXC_SACCH4_2, 0, TRXC_SDCCH4_1, 1 }, + { TRXC_SACCH4_2, 1, TRXC_SDCCH4_1, 2 }, + { TRXC_SACCH4_2, 2, TRXC_SDCCH4_1, 3 }, + { TRXC_SACCH4_2, 3, TRXC_RACH, 0 }, + { TRXC_SACCH4_3, 0, TRXC_RACH, 0 }, + { TRXC_SACCH4_3, 1, TRXC_SDCCH4_2, 0 }, + { TRXC_SACCH4_3, 2, TRXC_SDCCH4_2, 1 }, + { TRXC_SACCH4_3, 3, TRXC_SDCCH4_2, 2 }, + { TRXC_IDLE, 0, TRXC_SDCCH4_2, 3 }, +}; + +static const struct trx_sched_frame frame_sdcch8[102] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_SDCCH8_0, 0, TRXC_SACCH8_5, 0 }, + { TRXC_SDCCH8_0, 1, TRXC_SACCH8_5, 1 }, + { TRXC_SDCCH8_0, 2, TRXC_SACCH8_5, 2 }, + { TRXC_SDCCH8_0, 3, TRXC_SACCH8_5, 3 }, + { TRXC_SDCCH8_1, 0, TRXC_SACCH8_6, 0 }, + { TRXC_SDCCH8_1, 1, TRXC_SACCH8_6, 1 }, + { TRXC_SDCCH8_1, 2, TRXC_SACCH8_6, 2 }, + { TRXC_SDCCH8_1, 3, TRXC_SACCH8_6, 3 }, + { TRXC_SDCCH8_2, 0, TRXC_SACCH8_7, 0 }, + { TRXC_SDCCH8_2, 1, TRXC_SACCH8_7, 1 }, + { TRXC_SDCCH8_2, 2, TRXC_SACCH8_7, 2 }, + { TRXC_SDCCH8_2, 3, TRXC_SACCH8_7, 3 }, + { TRXC_SDCCH8_3, 0, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 1, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 2, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 3, TRXC_SDCCH8_0, 0 }, + { TRXC_SDCCH8_4, 0, TRXC_SDCCH8_0, 1 }, + { TRXC_SDCCH8_4, 1, TRXC_SDCCH8_0, 2 }, + { TRXC_SDCCH8_4, 2, TRXC_SDCCH8_0, 3 }, + { TRXC_SDCCH8_4, 3, TRXC_SDCCH8_1, 0 }, + { TRXC_SDCCH8_5, 0, TRXC_SDCCH8_1, 1 }, + { TRXC_SDCCH8_5, 1, TRXC_SDCCH8_1, 2 }, + { TRXC_SDCCH8_5, 2, TRXC_SDCCH8_1, 3 }, + { TRXC_SDCCH8_5, 3, TRXC_SDCCH8_2, 0 }, + { TRXC_SDCCH8_6, 0, TRXC_SDCCH8_2, 1 }, + { TRXC_SDCCH8_6, 1, TRXC_SDCCH8_2, 2 }, + { TRXC_SDCCH8_6, 2, TRXC_SDCCH8_2, 3 }, + { TRXC_SDCCH8_6, 3, TRXC_SDCCH8_3, 0 }, + { TRXC_SDCCH8_7, 0, TRXC_SDCCH8_3, 1 }, + { TRXC_SDCCH8_7, 1, TRXC_SDCCH8_3, 2 }, + { TRXC_SDCCH8_7, 2, TRXC_SDCCH8_3, 3 }, + { TRXC_SDCCH8_7, 3, TRXC_SDCCH8_4, 0 }, + { TRXC_SACCH8_0, 0, TRXC_SDCCH8_4, 1 }, + { TRXC_SACCH8_0, 1, TRXC_SDCCH8_4, 2 }, + { TRXC_SACCH8_0, 2, TRXC_SDCCH8_4, 3 }, + { TRXC_SACCH8_0, 3, TRXC_SDCCH8_5, 0 }, + { TRXC_SACCH8_1, 0, TRXC_SDCCH8_5, 1 }, + { TRXC_SACCH8_1, 1, TRXC_SDCCH8_5, 2 }, + { TRXC_SACCH8_1, 2, TRXC_SDCCH8_5, 3 }, + { TRXC_SACCH8_1, 3, TRXC_SDCCH8_6, 0 }, + { TRXC_SACCH8_2, 0, TRXC_SDCCH8_6, 1 }, + { TRXC_SACCH8_2, 1, TRXC_SDCCH8_6, 2 }, + { TRXC_SACCH8_2, 2, TRXC_SDCCH8_6, 3 }, + { TRXC_SACCH8_2, 3, TRXC_SDCCH8_7, 0 }, + { TRXC_SACCH8_3, 0, TRXC_SDCCH8_7, 1 }, + { TRXC_SACCH8_3, 1, TRXC_SDCCH8_7, 2 }, + { TRXC_SACCH8_3, 2, TRXC_SDCCH8_7, 3 }, + { TRXC_SACCH8_3, 3, TRXC_SACCH8_0, 0 }, + { TRXC_IDLE, 0, TRXC_SACCH8_0, 1 }, + { TRXC_IDLE, 0, TRXC_SACCH8_0, 2 }, + { TRXC_IDLE, 0, TRXC_SACCH8_0, 3 }, + + { TRXC_SDCCH8_0, 0, TRXC_SACCH8_1, 0 }, + { TRXC_SDCCH8_0, 1, TRXC_SACCH8_1, 1 }, + { TRXC_SDCCH8_0, 2, TRXC_SACCH8_1, 2 }, + { TRXC_SDCCH8_0, 3, TRXC_SACCH8_1, 3 }, + { TRXC_SDCCH8_1, 0, TRXC_SACCH8_2, 0 }, + { TRXC_SDCCH8_1, 1, TRXC_SACCH8_2, 1 }, + { TRXC_SDCCH8_1, 2, TRXC_SACCH8_2, 2 }, + { TRXC_SDCCH8_1, 3, TRXC_SACCH8_2, 3 }, + { TRXC_SDCCH8_2, 0, TRXC_SACCH8_3, 0 }, + { TRXC_SDCCH8_2, 1, TRXC_SACCH8_3, 1 }, + { TRXC_SDCCH8_2, 2, TRXC_SACCH8_3, 2 }, + { TRXC_SDCCH8_2, 3, TRXC_SACCH8_3, 3 }, + { TRXC_SDCCH8_3, 0, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 1, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 2, TRXC_IDLE, 0 }, + { TRXC_SDCCH8_3, 3, TRXC_SDCCH8_0, 0 }, + { TRXC_SDCCH8_4, 0, TRXC_SDCCH8_0, 1 }, + { TRXC_SDCCH8_4, 1, TRXC_SDCCH8_0, 2 }, + { TRXC_SDCCH8_4, 2, TRXC_SDCCH8_0, 3 }, + { TRXC_SDCCH8_4, 3, TRXC_SDCCH8_1, 0 }, + { TRXC_SDCCH8_5, 0, TRXC_SDCCH8_1, 1 }, + { TRXC_SDCCH8_5, 1, TRXC_SDCCH8_1, 2 }, + { TRXC_SDCCH8_5, 2, TRXC_SDCCH8_1, 3 }, + { TRXC_SDCCH8_5, 3, TRXC_SDCCH8_2, 0 }, + { TRXC_SDCCH8_6, 0, TRXC_SDCCH8_2, 1 }, + { TRXC_SDCCH8_6, 1, TRXC_SDCCH8_2, 2 }, + { TRXC_SDCCH8_6, 2, TRXC_SDCCH8_2, 3 }, + { TRXC_SDCCH8_6, 3, TRXC_SDCCH8_3, 0 }, + { TRXC_SDCCH8_7, 0, TRXC_SDCCH8_3, 1 }, + { TRXC_SDCCH8_7, 1, TRXC_SDCCH8_3, 2 }, + { TRXC_SDCCH8_7, 2, TRXC_SDCCH8_3, 3 }, + { TRXC_SDCCH8_7, 3, TRXC_SDCCH8_4, 0 }, + { TRXC_SACCH8_4, 0, TRXC_SDCCH8_4, 1 }, + { TRXC_SACCH8_4, 1, TRXC_SDCCH8_4, 2 }, + { TRXC_SACCH8_4, 2, TRXC_SDCCH8_4, 3 }, + { TRXC_SACCH8_4, 3, TRXC_SDCCH8_5, 0 }, + { TRXC_SACCH8_5, 0, TRXC_SDCCH8_5, 1 }, + { TRXC_SACCH8_5, 1, TRXC_SDCCH8_5, 2 }, + { TRXC_SACCH8_5, 2, TRXC_SDCCH8_5, 3 }, + { TRXC_SACCH8_5, 3, TRXC_SDCCH8_6, 0 }, + { TRXC_SACCH8_6, 0, TRXC_SDCCH8_6, 1 }, + { TRXC_SACCH8_6, 1, TRXC_SDCCH8_6, 2 }, + { TRXC_SACCH8_6, 2, TRXC_SDCCH8_6, 3 }, + { TRXC_SACCH8_6, 3, TRXC_SDCCH8_7, 0 }, + { TRXC_SACCH8_7, 0, TRXC_SDCCH8_7, 1 }, + { TRXC_SACCH8_7, 1, TRXC_SDCCH8_7, 2 }, + { TRXC_SACCH8_7, 2, TRXC_SDCCH8_7, 3 }, + { TRXC_SACCH8_7, 3, TRXC_SACCH8_4, 0 }, + { TRXC_IDLE, 0, TRXC_SACCH8_4, 1 }, + { TRXC_IDLE, 0, TRXC_SACCH8_4, 2 }, + { TRXC_IDLE, 0, TRXC_SACCH8_4, 3 }, +}; + +static const struct trx_sched_frame frame_tchf_ts0[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, +}; + +static const struct trx_sched_frame frame_tchf_ts1[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, +}; + +static const struct trx_sched_frame frame_tchf_ts2[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, +}; + +static const struct trx_sched_frame frame_tchf_ts3[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, +}; + +static const struct trx_sched_frame frame_tchf_ts4[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, +}; + +static const struct trx_sched_frame frame_tchf_ts5[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, +}; + +static const struct trx_sched_frame frame_tchf_ts6[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, +}; + +static const struct trx_sched_frame frame_tchf_ts7[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, + { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, +}; + +static const struct trx_sched_frame frame_tchh_ts01[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, +}; + +static const struct trx_sched_frame frame_tchh_ts23[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, +}; + +static const struct trx_sched_frame frame_tchh_ts45[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, +}; + +static const struct trx_sched_frame frame_tchh_ts67[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, + { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, +}; + +static const struct trx_sched_frame frame_pdch[104] = { +/* dl_chan dl_bid ul_chan ul_bid */ + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PTCCH, 0, TRXC_PTCCH, 0 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PTCCH, 1, TRXC_PTCCH, 1 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PTCCH, 2, TRXC_PTCCH, 2 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PTCCH, 3, TRXC_PTCCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, + { TRXC_IDLE, 0, TRXC_IDLE, 0 }, +}; + +/* multiframe structure */ +struct trx_sched_multiframe { + /*! \brief physical channel config (channel combination) */ + enum gsm_phys_chan_config pchan; + /*! \brief applies to which timeslots? */ + uint8_t slotmask; + /*! \brief repeats how many frames */ + uint8_t period; + /*! \brief pointer to scheduling structure */ + const struct trx_sched_frame *frames; + /*! \brife human-readable name */ + const char *name; +}; + +static const struct trx_sched_multiframe trx_sched_multiframes[] = { + { GSM_PCHAN_NONE, 0xff, 0, NULL, "NONE"}, + { GSM_PCHAN_CCCH, 0xff, 51, frame_bcch, "BCCH+CCCH" }, + { GSM_PCHAN_CCCH_SDCCH4, 0xff, 102, frame_bcch_sdcch4, "BCCH+CCCH+SDCCH/4+SACCH/4" }, + { GSM_PCHAN_SDCCH8_SACCH8C, 0xff, 102, frame_sdcch8, "SDCCH/8+SACCH/8" }, + { GSM_PCHAN_TCH_F, 0x01, 104, frame_tchf_ts0, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x02, 104, frame_tchf_ts1, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x04, 104, frame_tchf_ts2, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x08, 104, frame_tchf_ts3, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x10, 104, frame_tchf_ts4, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x20, 104, frame_tchf_ts5, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x40, 104, frame_tchf_ts6, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_F, 0x80, 104, frame_tchf_ts7, "TCH/F+SACCH" }, + { GSM_PCHAN_TCH_H, 0x03, 104, frame_tchh_ts01, "TCH/H+SACCH" }, + { GSM_PCHAN_TCH_H, 0x0c, 104, frame_tchh_ts23, "TCH/H+SACCH" }, + { GSM_PCHAN_TCH_H, 0x30, 104, frame_tchh_ts45, "TCH/H+SACCH" }, + { GSM_PCHAN_TCH_H, 0xc0, 104, frame_tchh_ts67, "TCH/H+SACCH" }, + { GSM_PCHAN_PDCH, 0xff, 104, frame_pdch, "PDCH" }, +}; + + +/* + * scheduler functions + */ + +/* set multiframe scheduler to given pchan */ +int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, + enum gsm_phys_chan_config pchan) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + int i; + + for (i = 0; i < ARRAY_SIZE(trx_sched_multiframes); i++) { + if (trx_sched_multiframes[i].pchan == pchan + && (trx_sched_multiframes[i].slotmask & (1 << tn))) { + l1ts->mf_index = i; + l1ts->mf_period = trx_sched_multiframes[i].period; + l1ts->mf_frames = trx_sched_multiframes[i].frames; + LOGP(DL1C, LOGL_NOTICE, "Configuring multiframe with " + "%s trx=%d ts=%d\n", + trx_sched_multiframes[i].name, + l1t->trx->nr, tn); + return 0; + } + } + + LOGP(DL1C, LOGL_NOTICE, "Failed to configuring multiframe " + "trx=%d ts=%d\n", l1t->trx->nr, tn); + + return -ENOTSUP; +} + +/* setting all logical channels given attributes to active/inactive */ +int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, + int active) +{ + uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + uint8_t ss = l1sap_chan2ss(chan_nr); + int i; + int rc = -EINVAL; + + /* look for all matching chan_nr/link_id */ + for (i = 0; i < _TRX_CHAN_MAX; i++) { + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; + /* skip if pchan type does not match pdch flag */ + if ((trx_sched_multiframes[l1ts->mf_index].pchan + == GSM_PCHAN_PDCH) + != trx_chan_desc[i].pdch) + continue; + if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8) + && trx_chan_desc[i].link_id == link_id) { + rc = 0; + if (chan_state->active == active) + continue; + LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n", + (active) ? "Activating" : "Deactivating", + trx_chan_desc[i].name, l1t->trx->nr, tn); + if (active) + memset(chan_state, 0, sizeof(*chan_state)); + chan_state->active = active; + /* free burst memory, to cleanly start with burst 0 */ + if (chan_state->dl_bursts) { + talloc_free(chan_state->dl_bursts); + chan_state->dl_bursts = NULL; + } + if (chan_state->ul_bursts) { + talloc_free(chan_state->ul_bursts); + chan_state->ul_bursts = NULL; + } + if (!active) + chan_state->ho_rach_detect = 0; + } + } + + /* disable handover detection (on deactivation) */ + if (!active) + _sched_act_rach_det(l1t, tn, ss, 0); + + return rc; +} + +/* setting all logical channels given attributes to active/inactive */ +int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, + uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, + uint8_t codec2, uint8_t codec3, uint8_t initial_id, uint8_t handover) +{ + uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + uint8_t ss = l1sap_chan2ss(chan_nr); + int i; + int rc = -EINVAL; + struct l1sched_chan_state *chan_state; + + /* no mode for PDCH */ + if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) + return 0; + + /* 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) + && trx_chan_desc[i].link_id == 0x00) { + chan_state = &l1ts->chan_state[i]; + LOGP(DL1C, LOGL_NOTICE, "Set mode %u, %u, handover %u " + "on %s of trx=%d ts=%d\n", rsl_cmode, tch_mode, + handover, trx_chan_desc[i].name, l1t->trx->nr, + tn); + chan_state->rsl_cmode = rsl_cmode; + chan_state->tch_mode = tch_mode; + chan_state->ho_rach_detect = handover; + if (rsl_cmode == RSL_CMOD_SPD_SPEECH + && tch_mode == GSM48_CMODE_SPEECH_AMR) { + chan_state->codecs = codecs; + chan_state->codec[0] = codec0; + chan_state->codec[1] = codec1; + chan_state->codec[2] = codec2; + chan_state->codec[3] = codec3; + chan_state->ul_ft = initial_id; + chan_state->dl_ft = initial_id; + chan_state->ul_cmr = initial_id; + chan_state->dl_cmr = initial_id; + chan_state->ber_sum = 0; + chan_state->ber_num = 0; + } + rc = 0; + } + } + + /* command rach detection + * always enable handover, even if state is still set (due to loss + * of transceiver link). + * disable handover, if state is still set, since we might not know + * the actual state of transceiver (due to loss of link) */ + _sched_act_rach_det(l1t, tn, ss, handover); + + return rc; +} + +/* setting cipher on logical channels */ +int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, + int algo, uint8_t *key, int key_len) +{ + uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + int i; + int rc = -EINVAL; + struct l1sched_chan_state *chan_state; + + /* no cipher for PDCH */ + if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) + return 0; + + /* no algorithm given means a5/0 */ + if (algo <= 0) + algo = 0; + else if (key_len != 8) { + LOGP(DL1C, LOGL_ERROR, "Algo A5/%d not supported with given " + "key len=%d\n", algo, key_len); + return -ENOTSUP; + } + + /* look for all matching chan_nr */ + for (i = 0; i < _TRX_CHAN_MAX; i++) { + /* skip if pchan type */ + if (trx_chan_desc[i].pdch) + continue; + if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)) { + chan_state = &l1ts->chan_state[i]; + LOGP(DL1C, LOGL_NOTICE, "Set a5/%d %s for %s on trx=%d " + "ts=%d\n", algo, + (downlink) ? "downlink" : "uplink", + trx_chan_desc[i].name, l1t->trx->nr, tn); + if (downlink) { + chan_state->dl_encr_algo = algo; + memcpy(chan_state->dl_encr_key, key, key_len); + chan_state->dl_encr_key_len = key_len; + } else { + chan_state->ul_encr_algo = algo; + memcpy(chan_state->ul_encr_key, key, key_len); + chan_state->ul_encr_key_len = key_len; + } + rc = 0; + } + } + + return rc; +} + +/* process ready-to-send */ +int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + const struct trx_sched_frame *frame; + uint8_t offset, period, bid; + trx_sched_rts_func *func; + enum trx_chan_type chan; + + /* no multiframe set */ + if (!l1ts->mf_index) + return 0; + + /* get frame from multiframe */ + period = l1ts->mf_period; + offset = fn % period; + frame = l1ts->mf_frames + offset; + + chan = frame->dl_chan; + bid = frame->dl_bid; + func = trx_chan_desc[frame->dl_chan].rts_fn; + + /* only on bid == 0 */ + if (bid != 0) + return 0; + + /* no RTS function */ + if (!func) + return 0; + + /* check if channel is active */ + if (!trx_chan_desc[chan].auto_active + && !l1ts->chan_state[chan].active) + return -EINVAL; + + return func(l1t, tn, fn, frame->dl_chan); +} + +/* process downlink burst */ +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *l1cs; + const struct trx_sched_frame *frame; + uint8_t offset, period, bid; + trx_sched_dl_func *func; + enum trx_chan_type chan; + ubit_t *bits = NULL; + + if (!l1ts->mf_index) + goto no_data; + + /* get frame from multiframe */ + period = l1ts->mf_period; + offset = fn % period; + frame = l1ts->mf_frames + offset; + + chan = frame->dl_chan; + bid = frame->dl_bid; + func = trx_chan_desc[chan].dl_fn; + + l1cs = &l1ts->chan_state[chan]; + + /* check if channel is active */ + if (!trx_chan_desc[chan].auto_active && !l1cs->active) + goto no_data; + + /* get burst from function */ + bits = func(l1t, tn, fn, chan, bid); + + /* encrypt */ + if (bits && l1cs->dl_encr_algo) { + ubit_t ks[114]; + int i; + + osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL); + for (i = 0; i < 57; i++) { + bits[i + 3] ^= ks[i]; + bits[i + 88] ^= ks[i + 57]; + } + } + +no_data: + /* in case of C0, we need a dummy burst to maintain RF power */ + if (bits == NULL && l1t->trx == l1t->trx->bts->c0) { +if (0) if (chan != TRXC_IDLE) // hack + LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u " + "burst=%d on C0, so filling with dummy burst\n", + trx_chan_desc[chan].name, fn, tn, bid); + bits = (ubit_t *) dummy_burst; + } + + return bits; +} + +/* process uplink burst */ +int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn, + sbit_t *bits, int8_t rssi, float toa) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *l1cs; + const struct trx_sched_frame *frame; + uint8_t offset, period, bid; + trx_sched_ul_func *func; + enum trx_chan_type chan; + uint32_t fn, elapsed; + + if (!l1ts->mf_index) + return -EINVAL; + + /* calculate how many frames have been elapsed */ + elapsed = (current_fn + GSM_HYPERFRAME - l1ts->mf_last_fn) % GSM_HYPERFRAME; + + /* start counting from last fn + 1, but only if not too many fn have + * been elapsed */ + if (elapsed < 10) + fn = (l1ts->mf_last_fn + 1) % GSM_HYPERFRAME; + else + fn = current_fn; + + while (42) { + /* get frame from multiframe */ + period = l1ts->mf_period; + offset = fn % period; + frame = l1ts->mf_frames + offset; + + chan = frame->ul_chan; + bid = frame->ul_bid; + func = trx_chan_desc[chan].ul_fn; + + l1cs = &l1ts->chan_state[chan]; + + /* check if channel is active */ + if (!trx_chan_desc[chan].auto_active && !l1cs->active) + goto next_frame; + + /* omit bursts which have no handler, like IDLE bursts */ + if (!func) + goto next_frame; + + /* put burst to function */ + if (fn == current_fn) { + /* decrypt */ + if (bits && l1cs->ul_encr_algo) { + ubit_t ks[114]; + int i; + + osmo_a5(l1cs->ul_encr_algo, + l1cs->ul_encr_key, + fn, NULL, ks); + for (i = 0; i < 57; i++) { + if (ks[i]) + bits[i + 3] = - bits[i + 3]; + if (ks[i + 57]) + bits[i + 88] = - bits[i + 88]; + } + } + + func(l1t, tn, fn, chan, bid, bits, rssi, toa); + } else if (chan != TRXC_RACH && !l1cs->ho_rach_detect) { + sbit_t spare[148]; + + memset(spare, 0, 148); + func(l1t, tn, fn, chan, bid, spare, -128, 0); + } + +next_frame: + /* reached current fn */ + if (fn == current_fn) + break; + + fn = (fn + 1) % GSM_HYPERFRAME; + } + + l1ts->mf_last_fn = fn; + + return 0; +} + +struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn) +{ + OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts)); + return &l1t->ts[tn]; +} diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am index 1644af6..0c0d281 100644 --- a/src/osmo-bts-trx/Makefile.am +++ b/src/osmo-bts-trx/Makefile.am @@ -2,10 +2,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(ORTP_CFLAGS) LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS) -EXTRA_DIST = trx_if.h l1_if.h scheduler.h scheduler_backend.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h loops.h amr.h +EXTRA_DIST = trx_if.h l1_if.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h loops.h amr.h bin_PROGRAMS = osmobts-trx -osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler.c scheduler_trx.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c loops.c amr.c -osmobts_trx_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) +osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler_trx.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c loops.c amr.c +osmobts_trx_LDADD = $(top_builddir)/src/common/libbts.a $(top_builddir)/src/common/libl1sched.a $(LDADD) diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index 70a5c59..edd4b7b 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -36,10 +36,10 @@ #include #include #include +#include #include "l1_if.h" #include "trx_if.h" -#include "scheduler.h" static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = { diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index 6dec273..f492687 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -1,7 +1,7 @@ #ifndef L1_IF_H_TRX #define L1_IF_H_TRX -#include "scheduler.h" +#include struct trx_config { uint8_t poweron; /* poweron(1) or poweroff(0) */ diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index 6c2dabf..aa6987c 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -53,10 +53,10 @@ #include #include #include +#include #include "l1_if.h" #include "trx_if.h" -#include "scheduler.h" int bts_model_init(struct gsm_bts *bts) { diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c deleted file mode 100644 index dee46ed..0000000 --- a/src/osmo-bts-trx/scheduler.c +++ /dev/null @@ -1,1622 +0,0 @@ -/* Scheduler for OsmoBTS-TRX */ - -/* (C) 2013 by Andreas Eversberg - * (C) 2015 by Alexander Chemeris - * (C) 2015 by Harald Welte - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scheduler.h" -#include "scheduler_backend.h" - -extern void *tall_bts_ctx; - -static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan); -static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan); -static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan); -/*! \brief Dummy Burst (TS 05.02 Chapter 5.2.6) */ -static const ubit_t dummy_burst[148] = { - 0,0,0, - 1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,0,1,1,1,0, - 0,0,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,0, - 0,1,0,1,1,1,0,0,0,1,0,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1,0,0,1,0,1,0, - 0,0,1,1,0,0,1,1,0,0,1,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,1, - 0,0,1,0,1,1,1,1,1,0,1,0,1,0, - 0,0,0, -}; - -/*! \brief FCCH Burst (TS 05.02 Chapter 5.2.4) */ -const ubit_t _sched_fcch_burst[148] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; - -/*! \brief Training Sequences (TS 05.02 Chapter 5.2.3) */ -const ubit_t _sched_tsc[8][26] = { - { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1, }, - { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1, }, - { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0, }, - { 0,1,0,0,0,1,1,1,1,0,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1,0, }, - { 0,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,1, }, - { 0,1,0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,1,0, }, - { 1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,1,1,1, }, - { 1,1,1,0,1,1,1,1,0,0,0,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0, }, -}; - -/*! \brief SCH trainign sequence (TS 05.02 Chapter 5.2.5) */ -const ubit_t _sched_sch_train[64] = { - 1,0,1,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1, - 0,0,1,0,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,1,1,0,1,1, -}; - -/* - * subchannel description structure - */ - -const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { - { 0, TRXC_IDLE, 0, 0, "IDLE", NULL, tx_idle_fn, NULL, 1 }, - { 0, TRXC_FCCH, 0, 0, "FCCH", NULL, tx_fcch_fn, NULL, 1 }, - { 0, TRXC_SCH, 0, 0, "SCH", NULL, tx_sch_fn, NULL, 1 }, - { 0, TRXC_BCCH, 0x80, 0x00, "BCCH", rts_data_fn, tx_data_fn, NULL, 1 }, - { 0, TRXC_RACH, 0x88, 0x00, "RACH", NULL, NULL, rx_rach_fn, 1 }, - { 0, TRXC_CCCH, 0x90, 0x00, "CCCH", rts_data_fn, tx_data_fn, NULL, 1 }, - { 0, TRXC_TCHF, 0x08, 0x00, "TCH/F", rts_tchf_fn, tx_tchf_fn, rx_tchf_fn, 0 }, - { 0, TRXC_TCHH_0, 0x10, 0x00, "TCH/H(0)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, - { 0, TRXC_TCHH_1, 0x18, 0x00, "TCH/H(1)", rts_tchh_fn, tx_tchh_fn, rx_tchh_fn, 0 }, - { 0, TRXC_SDCCH4_0, 0x20, 0x00, "SDCCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_1, 0x28, 0x00, "SDCCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_2, 0x30, 0x00, "SDCCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH4_3, 0x38, 0x00, "SDCCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_0, 0x40, 0x00, "SDCCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_1, 0x48, 0x00, "SDCCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_2, 0x50, 0x00, "SDCCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_3, 0x58, 0x00, "SDCCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_4, 0x60, 0x00, "SDCCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_5, 0x68, 0x00, "SDCCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_6, 0x70, 0x00, "SDCCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SDCCH8_7, 0x78, 0x00, "SDCCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTF, 0x08, 0x40, "SACCH/TF", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTH_0, 0x10, 0x40, "SACCH/TH(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCHTH_1, 0x18, 0x40, "SACCH/TH(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_0, 0x20, 0x40, "SACCH/4(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_1, 0x28, 0x40, "SACCH/4(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_2, 0x30, 0x40, "SACCH/4(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH4_3, 0x38, 0x40, "SACCH/4(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_0, 0x40, 0x40, "SACCH/8(0)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_1, 0x48, 0x40, "SACCH/8(1)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_2, 0x50, 0x40, "SACCH/8(2)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_3, 0x58, 0x40, "SACCH/8(3)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_4, 0x60, 0x40, "SACCH/8(4)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_5, 0x68, 0x40, "SACCH/8(5)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_6, 0x70, 0x40, "SACCH/8(6)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 0, TRXC_SACCH8_7, 0x78, 0x40, "SACCH/8(7)", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, - { 1, TRXC_PDTCH, 0x08, 0x00, "PDTCH", rts_data_fn, tx_pdtch_fn, rx_pdtch_fn, 0 }, - { 1, TRXC_PTCCH, 0x08, 0x00, "PTCCH", rts_data_fn, tx_data_fn, rx_data_fn, 0 }, -}; - - -/* - * init / exit - */ - -int trx_sched_init(struct l1sched_trx *l1t) -{ - uint8_t tn; - int i; - - LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); - - for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - l1ts->mf_index = 0; - l1ts->mf_last_fn = 0; - INIT_LLIST_HEAD(&l1ts->dl_prims); - for (i = 0; i < ARRAY_SIZE(&l1ts->chan_state); i++) { - struct l1sched_chan_state *chan_state; - chan_state = &l1ts->chan_state[i]; - chan_state->active = 0; - } - } - - return 0; -} - -void trx_sched_exit(struct l1sched_trx *l1t) -{ - struct gsm_bts_trx_ts *ts; - uint8_t tn; - int i; - - LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr); - - for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - msgb_queue_flush(&l1ts->dl_prims); - for (i = 0; i < _TRX_CHAN_MAX; i++) { - struct l1sched_chan_state *chan_state; - chan_state = &l1ts->chan_state[i]; - if (chan_state->dl_bursts) { - talloc_free(chan_state->dl_bursts); - chan_state->dl_bursts = NULL; - } - if (chan_state->ul_bursts) { - talloc_free(chan_state->ul_bursts); - chan_state->ul_bursts = NULL; - } - } - /* clear lchan channel states */ - ts = &l1t->trx->ts[tn]; - for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) - lchan_set_state(&ts->lchan[i], LCHAN_S_NONE); - } -} - -/* close all logical channels and reset timeslots */ -void trx_sched_reset(struct l1sched_trx *l1t) -{ - trx_sched_exit(l1t); - trx_sched_init(l1t); -} - -struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - struct msgb *msg, *msg2; - struct osmo_phsap_prim *l1sap; - uint32_t prim_fn; - uint8_t chan_nr, link_id; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - /* get prim of current fn from queue */ - llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) { - l1sap = msgb_l1sap_prim(msg); - if (l1sap->oph.operation != PRIM_OP_REQUEST) { -wrong_type: - LOGP(DL1C, LOGL_ERROR, "Prim for ts=%u at fn=%u has " - "wrong type.\n", tn, fn); -free_msg: - /* unlink and free message */ - llist_del(&msg->list); - msgb_free(msg); - return NULL; - } - switch (l1sap->oph.primitive) { - case PRIM_PH_DATA: - chan_nr = l1sap->u.data.chan_nr; - link_id = l1sap->u.data.link_id; - prim_fn = ((l1sap->u.data.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME); - break; - case PRIM_TCH: - chan_nr = l1sap->u.tch.chan_nr; - link_id = 0; - prim_fn = ((l1sap->u.tch.fn + GSM_HYPERFRAME - fn) % GSM_HYPERFRAME); - break; - default: - goto wrong_type; - } - if (prim_fn > 100) { - LOGP(DL1C, LOGL_NOTICE, "Prim for trx=%u ts=%u at fn=%u " - "is out of range, or channel already disabled. " - "If this happens in conjunction with PCU, " - "increase 'rts-advance' by 5. (current fn=%u)\n", - l1t->trx->nr, tn, l1sap->u.data.fn, fn); - /* unlink and free message */ - llist_del(&msg->list); - msgb_free(msg); - continue; - } - if (prim_fn > 0) - continue; - - goto found_msg; - } - - return NULL; - -found_msg: - if ((chan_nr ^ (trx_chan_desc[chan].chan_nr | tn)) - || ((link_id & 0xc0) ^ trx_chan_desc[chan].link_id)) { - LOGP(DL1C, LOGL_ERROR, "Prim for ts=%u at fn=%u has wrong " - "chan_nr=%02x link_id=%02x, expecting chan_nr=%02x " - "link_id=%02x.\n", tn, fn, chan_nr, link_id, - trx_chan_desc[chan].chan_nr | tn, - trx_chan_desc[chan].link_id); - goto free_msg; - } - - /* unlink and return message */ - llist_del(&msg->list); - return msg; -} - -int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) -{ - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - /* compose primitive */ - msg = l1sap_msgb_alloc(l2_len); - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_DATA, - PRIM_OP_INDICATION, msg); - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.link_id = trx_chan_desc[chan].link_id; - l1sap->u.data.fn = fn; - l1sap->u.data.rssi = (int8_t) (rssi); - msg->l2h = msgb_put(msg, l2_len); - if (l2_len) - memcpy(msg->l2h, l2, l2_len); - - if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) - l1ts->chan_state[chan].lost = 0; - - /* forward primitive */ - l1sap_up(l1t->trx, l1sap); - - return 0; -} - -int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len) -{ - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - /* compose primitive */ - msg = l1sap_msgb_alloc(tch_len); - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH, - PRIM_OP_INDICATION, msg); - l1sap->u.tch.chan_nr = trx_chan_desc[chan].chan_nr | tn; - l1sap->u.tch.fn = fn; - msg->l2h = msgb_put(msg, tch_len); - if (tch_len) - memcpy(msg->l2h, tch, tch_len); - - if (l1ts->chan_state[chan].lost) - l1ts->chan_state[chan].lost--; - - /* forward primitive */ - l1sap_up(l1t->trx, l1sap); - - return 0; -} - - - -/* - * data request (from upper layer) - */ - -int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) -{ - uint8_t tn = l1sap->u.data.chan_nr & 7; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x " - "fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr, - l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr); - - if (!l1sap->oph.msg) - abort(); - - /* ignore empty frame */ - if (!msgb_l2len(l1sap->oph.msg)) { - msgb_free(l1sap->oph.msg); - return 0; - } - - msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); - - return 0; -} - -int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) -{ - uint8_t tn = l1sap->u.tch.chan_nr & 7; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x " - "fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr, - l1sap->u.tch.fn, tn, l1t->trx->nr); - - if (!l1sap->oph.msg) - abort(); - - /* ignore empty frame */ - if (!msgb_l2len(l1sap->oph.msg)) { - msgb_free(l1sap->oph.msg); - return 0; - } - - msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); - - return 0; -} - - -/* - * ready-to-send indication (to upper layer) - */ - -/* RTS for data frame */ -static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - uint8_t chan_nr, link_id; - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - - /* get data for RTS indication */ - chan_nr = trx_chan_desc[chan].chan_nr | tn; - link_id = trx_chan_desc[chan].link_id; - - if (!chan_nr) { - LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " - "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); - return -ENODEV; - } - - LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x " - "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, link_id, fn, tn, l1t->trx->nr); - - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.link_id = link_id; - l1sap->u.data.fn = fn; - - return l1sap_up(l1t->trx, l1sap); -} - -static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, int facch) -{ - uint8_t chan_nr, link_id; - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - int rc = 0; - - /* get data for RTS indication */ - chan_nr = trx_chan_desc[chan].chan_nr | tn; - link_id = trx_chan_desc[chan].link_id; - - if (!chan_nr) { - LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " - "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); - return -ENODEV; - } - - LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x " - "fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, fn, tn, l1t->trx->nr); - - /* only send, if FACCH is selected */ - if (facch) { - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.link_id = link_id; - l1sap->u.data.fn = fn; - - rc = l1sap_up(l1t->trx, l1sap); - } - - /* dont send, if TCH is in signalling only mode */ - if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.tch.chan_nr = chan_nr; - l1sap->u.tch.fn = fn; - - return l1sap_up(l1t->trx, l1sap); - } - - return rc; -} - -/* RTS for full rate traffic frame */ -static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - /* TCH/F may include FACCH on every 4th burst */ - return rts_tch_common(l1t, tn, fn, chan, 1); -} - - -/* RTS for half rate traffic frame */ -static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */ - return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1); -} - -/* - * multiframe structure - */ - -/* frame structures */ -struct trx_sched_frame { - /*! \brief downlink TRX channel type */ - enum trx_chan_type dl_chan; - /*! \brief downlink block ID */ - uint8_t dl_bid; - /*! \breff uplink TRX channel type */ - enum trx_chan_type ul_chan; - /*! \brief uplink block ID */ - uint8_t ul_bid; -}; - -static const struct trx_sched_frame frame_bcch[51] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_BCCH, 0, TRXC_RACH, 0 }, { TRXC_BCCH, 1, TRXC_RACH, 0 }, { TRXC_BCCH, 2, TRXC_RACH, 0 }, { TRXC_BCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, { TRXC_CCCH, 1, TRXC_RACH, 0 }, { TRXC_CCCH, 2, TRXC_RACH, 0 }, { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_IDLE, 0, TRXC_RACH, 0 }, -}; - -static const struct trx_sched_frame frame_bcch_sdcch4[102] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_FCCH, 0, TRXC_SDCCH4_3, 0 }, - { TRXC_SCH, 0, TRXC_SDCCH4_3, 1 }, - { TRXC_BCCH, 0, TRXC_SDCCH4_3, 2 }, - { TRXC_BCCH, 1, TRXC_SDCCH4_3, 3 }, - { TRXC_BCCH, 2, TRXC_RACH, 0 }, - { TRXC_BCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_SACCH4_2, 0 }, - { TRXC_CCCH, 1, TRXC_SACCH4_2, 1 }, - { TRXC_CCCH, 2, TRXC_SACCH4_2, 2 }, - { TRXC_CCCH, 3, TRXC_SACCH4_2, 3 }, - { TRXC_FCCH, 0, TRXC_SACCH4_3, 0 }, - { TRXC_SCH, 0, TRXC_SACCH4_3, 1 }, - { TRXC_CCCH, 0, TRXC_SACCH4_3, 2 }, - { TRXC_CCCH, 1, TRXC_SACCH4_3, 3 }, - { TRXC_CCCH, 2, TRXC_RACH, 0 }, - { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 1, TRXC_RACH, 0 }, - { TRXC_CCCH, 2, TRXC_RACH, 0 }, - { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 3, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 3, TRXC_RACH, 0 }, - { TRXC_SDCCH4_3, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_3, 1, TRXC_SDCCH4_0, 0 }, - { TRXC_SDCCH4_3, 2, TRXC_SDCCH4_0, 1 }, - { TRXC_SDCCH4_3, 3, TRXC_SDCCH4_0, 2 }, - { TRXC_FCCH, 0, TRXC_SDCCH4_0, 3 }, - { TRXC_SCH, 0, TRXC_SDCCH4_1, 0 }, - { TRXC_SACCH4_0, 0, TRXC_SDCCH4_1, 1 }, - { TRXC_SACCH4_0, 1, TRXC_SDCCH4_1, 2 }, - { TRXC_SACCH4_0, 2, TRXC_SDCCH4_1, 3 }, - { TRXC_SACCH4_0, 3, TRXC_RACH, 0 }, - { TRXC_SACCH4_1, 0, TRXC_RACH, 0 }, - { TRXC_SACCH4_1, 1, TRXC_SDCCH4_2, 0 }, - { TRXC_SACCH4_1, 2, TRXC_SDCCH4_2, 1 }, - { TRXC_SACCH4_1, 3, TRXC_SDCCH4_2, 2 }, - { TRXC_IDLE, 0, TRXC_SDCCH4_2, 3 }, - - { TRXC_FCCH, 0, TRXC_SDCCH4_3, 0 }, - { TRXC_SCH, 0, TRXC_SDCCH4_3, 1 }, - { TRXC_BCCH, 0, TRXC_SDCCH4_3, 2 }, - { TRXC_BCCH, 1, TRXC_SDCCH4_3, 3 }, - { TRXC_BCCH, 2, TRXC_RACH, 0 }, - { TRXC_BCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_SACCH4_0, 0 }, - { TRXC_CCCH, 1, TRXC_SACCH4_0, 1 }, - { TRXC_CCCH, 2, TRXC_SACCH4_0, 2 }, - { TRXC_CCCH, 3, TRXC_SACCH4_0, 3 }, - { TRXC_FCCH, 0, TRXC_SACCH4_1, 0 }, - { TRXC_SCH, 0, TRXC_SACCH4_1, 1 }, - { TRXC_CCCH, 0, TRXC_SACCH4_1, 2 }, - { TRXC_CCCH, 1, TRXC_SACCH4_1, 3 }, - { TRXC_CCCH, 2, TRXC_RACH, 0 }, - { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_CCCH, 0, TRXC_RACH, 0 }, - { TRXC_CCCH, 1, TRXC_RACH, 0 }, - { TRXC_CCCH, 2, TRXC_RACH, 0 }, - { TRXC_CCCH, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_0, 3, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_1, 3, TRXC_RACH, 0 }, - { TRXC_FCCH, 0, TRXC_RACH, 0 }, - { TRXC_SCH, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 1, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 2, TRXC_RACH, 0 }, - { TRXC_SDCCH4_2, 3, TRXC_RACH, 0 }, - { TRXC_SDCCH4_3, 0, TRXC_RACH, 0 }, - { TRXC_SDCCH4_3, 1, TRXC_SDCCH4_0, 0 }, - { TRXC_SDCCH4_3, 2, TRXC_SDCCH4_0, 1 }, - { TRXC_SDCCH4_3, 3, TRXC_SDCCH4_0, 2 }, - { TRXC_FCCH, 0, TRXC_SDCCH4_0, 3 }, - { TRXC_SCH, 0, TRXC_SDCCH4_1, 0 }, - { TRXC_SACCH4_2, 0, TRXC_SDCCH4_1, 1 }, - { TRXC_SACCH4_2, 1, TRXC_SDCCH4_1, 2 }, - { TRXC_SACCH4_2, 2, TRXC_SDCCH4_1, 3 }, - { TRXC_SACCH4_2, 3, TRXC_RACH, 0 }, - { TRXC_SACCH4_3, 0, TRXC_RACH, 0 }, - { TRXC_SACCH4_3, 1, TRXC_SDCCH4_2, 0 }, - { TRXC_SACCH4_3, 2, TRXC_SDCCH4_2, 1 }, - { TRXC_SACCH4_3, 3, TRXC_SDCCH4_2, 2 }, - { TRXC_IDLE, 0, TRXC_SDCCH4_2, 3 }, -}; - -static const struct trx_sched_frame frame_sdcch8[102] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_SDCCH8_0, 0, TRXC_SACCH8_5, 0 }, - { TRXC_SDCCH8_0, 1, TRXC_SACCH8_5, 1 }, - { TRXC_SDCCH8_0, 2, TRXC_SACCH8_5, 2 }, - { TRXC_SDCCH8_0, 3, TRXC_SACCH8_5, 3 }, - { TRXC_SDCCH8_1, 0, TRXC_SACCH8_6, 0 }, - { TRXC_SDCCH8_1, 1, TRXC_SACCH8_6, 1 }, - { TRXC_SDCCH8_1, 2, TRXC_SACCH8_6, 2 }, - { TRXC_SDCCH8_1, 3, TRXC_SACCH8_6, 3 }, - { TRXC_SDCCH8_2, 0, TRXC_SACCH8_7, 0 }, - { TRXC_SDCCH8_2, 1, TRXC_SACCH8_7, 1 }, - { TRXC_SDCCH8_2, 2, TRXC_SACCH8_7, 2 }, - { TRXC_SDCCH8_2, 3, TRXC_SACCH8_7, 3 }, - { TRXC_SDCCH8_3, 0, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 1, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 2, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 3, TRXC_SDCCH8_0, 0 }, - { TRXC_SDCCH8_4, 0, TRXC_SDCCH8_0, 1 }, - { TRXC_SDCCH8_4, 1, TRXC_SDCCH8_0, 2 }, - { TRXC_SDCCH8_4, 2, TRXC_SDCCH8_0, 3 }, - { TRXC_SDCCH8_4, 3, TRXC_SDCCH8_1, 0 }, - { TRXC_SDCCH8_5, 0, TRXC_SDCCH8_1, 1 }, - { TRXC_SDCCH8_5, 1, TRXC_SDCCH8_1, 2 }, - { TRXC_SDCCH8_5, 2, TRXC_SDCCH8_1, 3 }, - { TRXC_SDCCH8_5, 3, TRXC_SDCCH8_2, 0 }, - { TRXC_SDCCH8_6, 0, TRXC_SDCCH8_2, 1 }, - { TRXC_SDCCH8_6, 1, TRXC_SDCCH8_2, 2 }, - { TRXC_SDCCH8_6, 2, TRXC_SDCCH8_2, 3 }, - { TRXC_SDCCH8_6, 3, TRXC_SDCCH8_3, 0 }, - { TRXC_SDCCH8_7, 0, TRXC_SDCCH8_3, 1 }, - { TRXC_SDCCH8_7, 1, TRXC_SDCCH8_3, 2 }, - { TRXC_SDCCH8_7, 2, TRXC_SDCCH8_3, 3 }, - { TRXC_SDCCH8_7, 3, TRXC_SDCCH8_4, 0 }, - { TRXC_SACCH8_0, 0, TRXC_SDCCH8_4, 1 }, - { TRXC_SACCH8_0, 1, TRXC_SDCCH8_4, 2 }, - { TRXC_SACCH8_0, 2, TRXC_SDCCH8_4, 3 }, - { TRXC_SACCH8_0, 3, TRXC_SDCCH8_5, 0 }, - { TRXC_SACCH8_1, 0, TRXC_SDCCH8_5, 1 }, - { TRXC_SACCH8_1, 1, TRXC_SDCCH8_5, 2 }, - { TRXC_SACCH8_1, 2, TRXC_SDCCH8_5, 3 }, - { TRXC_SACCH8_1, 3, TRXC_SDCCH8_6, 0 }, - { TRXC_SACCH8_2, 0, TRXC_SDCCH8_6, 1 }, - { TRXC_SACCH8_2, 1, TRXC_SDCCH8_6, 2 }, - { TRXC_SACCH8_2, 2, TRXC_SDCCH8_6, 3 }, - { TRXC_SACCH8_2, 3, TRXC_SDCCH8_7, 0 }, - { TRXC_SACCH8_3, 0, TRXC_SDCCH8_7, 1 }, - { TRXC_SACCH8_3, 1, TRXC_SDCCH8_7, 2 }, - { TRXC_SACCH8_3, 2, TRXC_SDCCH8_7, 3 }, - { TRXC_SACCH8_3, 3, TRXC_SACCH8_0, 0 }, - { TRXC_IDLE, 0, TRXC_SACCH8_0, 1 }, - { TRXC_IDLE, 0, TRXC_SACCH8_0, 2 }, - { TRXC_IDLE, 0, TRXC_SACCH8_0, 3 }, - - { TRXC_SDCCH8_0, 0, TRXC_SACCH8_1, 0 }, - { TRXC_SDCCH8_0, 1, TRXC_SACCH8_1, 1 }, - { TRXC_SDCCH8_0, 2, TRXC_SACCH8_1, 2 }, - { TRXC_SDCCH8_0, 3, TRXC_SACCH8_1, 3 }, - { TRXC_SDCCH8_1, 0, TRXC_SACCH8_2, 0 }, - { TRXC_SDCCH8_1, 1, TRXC_SACCH8_2, 1 }, - { TRXC_SDCCH8_1, 2, TRXC_SACCH8_2, 2 }, - { TRXC_SDCCH8_1, 3, TRXC_SACCH8_2, 3 }, - { TRXC_SDCCH8_2, 0, TRXC_SACCH8_3, 0 }, - { TRXC_SDCCH8_2, 1, TRXC_SACCH8_3, 1 }, - { TRXC_SDCCH8_2, 2, TRXC_SACCH8_3, 2 }, - { TRXC_SDCCH8_2, 3, TRXC_SACCH8_3, 3 }, - { TRXC_SDCCH8_3, 0, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 1, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 2, TRXC_IDLE, 0 }, - { TRXC_SDCCH8_3, 3, TRXC_SDCCH8_0, 0 }, - { TRXC_SDCCH8_4, 0, TRXC_SDCCH8_0, 1 }, - { TRXC_SDCCH8_4, 1, TRXC_SDCCH8_0, 2 }, - { TRXC_SDCCH8_4, 2, TRXC_SDCCH8_0, 3 }, - { TRXC_SDCCH8_4, 3, TRXC_SDCCH8_1, 0 }, - { TRXC_SDCCH8_5, 0, TRXC_SDCCH8_1, 1 }, - { TRXC_SDCCH8_5, 1, TRXC_SDCCH8_1, 2 }, - { TRXC_SDCCH8_5, 2, TRXC_SDCCH8_1, 3 }, - { TRXC_SDCCH8_5, 3, TRXC_SDCCH8_2, 0 }, - { TRXC_SDCCH8_6, 0, TRXC_SDCCH8_2, 1 }, - { TRXC_SDCCH8_6, 1, TRXC_SDCCH8_2, 2 }, - { TRXC_SDCCH8_6, 2, TRXC_SDCCH8_2, 3 }, - { TRXC_SDCCH8_6, 3, TRXC_SDCCH8_3, 0 }, - { TRXC_SDCCH8_7, 0, TRXC_SDCCH8_3, 1 }, - { TRXC_SDCCH8_7, 1, TRXC_SDCCH8_3, 2 }, - { TRXC_SDCCH8_7, 2, TRXC_SDCCH8_3, 3 }, - { TRXC_SDCCH8_7, 3, TRXC_SDCCH8_4, 0 }, - { TRXC_SACCH8_4, 0, TRXC_SDCCH8_4, 1 }, - { TRXC_SACCH8_4, 1, TRXC_SDCCH8_4, 2 }, - { TRXC_SACCH8_4, 2, TRXC_SDCCH8_4, 3 }, - { TRXC_SACCH8_4, 3, TRXC_SDCCH8_5, 0 }, - { TRXC_SACCH8_5, 0, TRXC_SDCCH8_5, 1 }, - { TRXC_SACCH8_5, 1, TRXC_SDCCH8_5, 2 }, - { TRXC_SACCH8_5, 2, TRXC_SDCCH8_5, 3 }, - { TRXC_SACCH8_5, 3, TRXC_SDCCH8_6, 0 }, - { TRXC_SACCH8_6, 0, TRXC_SDCCH8_6, 1 }, - { TRXC_SACCH8_6, 1, TRXC_SDCCH8_6, 2 }, - { TRXC_SACCH8_6, 2, TRXC_SDCCH8_6, 3 }, - { TRXC_SACCH8_6, 3, TRXC_SDCCH8_7, 0 }, - { TRXC_SACCH8_7, 0, TRXC_SDCCH8_7, 1 }, - { TRXC_SACCH8_7, 1, TRXC_SDCCH8_7, 2 }, - { TRXC_SACCH8_7, 2, TRXC_SDCCH8_7, 3 }, - { TRXC_SACCH8_7, 3, TRXC_SACCH8_4, 0 }, - { TRXC_IDLE, 0, TRXC_SACCH8_4, 1 }, - { TRXC_IDLE, 0, TRXC_SACCH8_4, 2 }, - { TRXC_IDLE, 0, TRXC_SACCH8_4, 3 }, -}; - -static const struct trx_sched_frame frame_tchf_ts0[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, -}; - -static const struct trx_sched_frame frame_tchf_ts1[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, -}; - -static const struct trx_sched_frame frame_tchf_ts2[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, -}; - -static const struct trx_sched_frame frame_tchf_ts3[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, -}; - -static const struct trx_sched_frame frame_tchf_ts4[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, -}; - -static const struct trx_sched_frame frame_tchf_ts5[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, -}; - -static const struct trx_sched_frame frame_tchf_ts6[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, -}; - -static const struct trx_sched_frame frame_tchf_ts7[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 1, TRXC_SACCHTF, 1 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 2, TRXC_SACCHTF, 2 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 3, TRXC_SACCHTF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_TCHF, 0, TRXC_TCHF, 0 }, { TRXC_TCHF, 1, TRXC_TCHF, 1 }, { TRXC_TCHF, 2, TRXC_TCHF, 2 }, { TRXC_TCHF, 3, TRXC_TCHF, 3 }, - { TRXC_SACCHTF, 0, TRXC_SACCHTF, 0 }, -}; - -static const struct trx_sched_frame frame_tchh_ts01[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, -}; - -static const struct trx_sched_frame frame_tchh_ts23[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, -}; - -static const struct trx_sched_frame frame_tchh_ts45[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, -}; - -static const struct trx_sched_frame frame_tchh_ts67[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 1, TRXC_SACCHTH_0, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 1, TRXC_SACCHTH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 2, TRXC_SACCHTH_0, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 2, TRXC_SACCHTH_1, 2 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 3, TRXC_SACCHTH_0, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 3, TRXC_SACCHTH_1, 3 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_0, 0, TRXC_SACCHTH_0, 0 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_TCHH_0, 0, TRXC_TCHH_0, 0 }, { TRXC_TCHH_1, 0, TRXC_TCHH_1, 0 }, { TRXC_TCHH_0, 1, TRXC_TCHH_0, 1 }, { TRXC_TCHH_1, 1, TRXC_TCHH_1, 1 }, - { TRXC_SACCHTH_1, 0, TRXC_SACCHTH_1, 0 }, -}; - -static const struct trx_sched_frame frame_pdch[104] = { -/* dl_chan dl_bid ul_chan ul_bid */ - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PTCCH, 0, TRXC_PTCCH, 0 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PTCCH, 1, TRXC_PTCCH, 1 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PTCCH, 2, TRXC_PTCCH, 2 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PTCCH, 3, TRXC_PTCCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_PDTCH, 0, TRXC_PDTCH, 0 }, { TRXC_PDTCH, 1, TRXC_PDTCH, 1 }, { TRXC_PDTCH, 2, TRXC_PDTCH, 2 }, { TRXC_PDTCH, 3, TRXC_PDTCH, 3 }, - { TRXC_IDLE, 0, TRXC_IDLE, 0 }, -}; - -/* multiframe structure */ -struct trx_sched_multiframe { - /*! \brief physical channel config (channel combination) */ - enum gsm_phys_chan_config pchan; - /*! \brief applies to which timeslots? */ - uint8_t slotmask; - /*! \brief repeats how many frames */ - uint8_t period; - /*! \brief pointer to scheduling structure */ - const struct trx_sched_frame *frames; - /*! \brife human-readable name */ - const char *name; -}; - -static const struct trx_sched_multiframe trx_sched_multiframes[] = { - { GSM_PCHAN_NONE, 0xff, 0, NULL, "NONE"}, - { GSM_PCHAN_CCCH, 0xff, 51, frame_bcch, "BCCH+CCCH" }, - { GSM_PCHAN_CCCH_SDCCH4, 0xff, 102, frame_bcch_sdcch4, "BCCH+CCCH+SDCCH/4+SACCH/4" }, - { GSM_PCHAN_SDCCH8_SACCH8C, 0xff, 102, frame_sdcch8, "SDCCH/8+SACCH/8" }, - { GSM_PCHAN_TCH_F, 0x01, 104, frame_tchf_ts0, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x02, 104, frame_tchf_ts1, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x04, 104, frame_tchf_ts2, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x08, 104, frame_tchf_ts3, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x10, 104, frame_tchf_ts4, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x20, 104, frame_tchf_ts5, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x40, 104, frame_tchf_ts6, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_F, 0x80, 104, frame_tchf_ts7, "TCH/F+SACCH" }, - { GSM_PCHAN_TCH_H, 0x03, 104, frame_tchh_ts01, "TCH/H+SACCH" }, - { GSM_PCHAN_TCH_H, 0x0c, 104, frame_tchh_ts23, "TCH/H+SACCH" }, - { GSM_PCHAN_TCH_H, 0x30, 104, frame_tchh_ts45, "TCH/H+SACCH" }, - { GSM_PCHAN_TCH_H, 0xc0, 104, frame_tchh_ts67, "TCH/H+SACCH" }, - { GSM_PCHAN_PDCH, 0xff, 104, frame_pdch, "PDCH" }, -}; - - -/* - * scheduler functions - */ - -/* set multiframe scheduler to given pchan */ -int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, - enum gsm_phys_chan_config pchan) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - int i; - - for (i = 0; i < ARRAY_SIZE(trx_sched_multiframes); i++) { - if (trx_sched_multiframes[i].pchan == pchan - && (trx_sched_multiframes[i].slotmask & (1 << tn))) { - l1ts->mf_index = i; - l1ts->mf_period = trx_sched_multiframes[i].period; - l1ts->mf_frames = trx_sched_multiframes[i].frames; - LOGP(DL1C, LOGL_NOTICE, "Configuring multiframe with " - "%s trx=%d ts=%d\n", - trx_sched_multiframes[i].name, - l1t->trx->nr, tn); - return 0; - } - } - - LOGP(DL1C, LOGL_NOTICE, "Failed to configuring multiframe " - "trx=%d ts=%d\n", l1t->trx->nr, tn); - - return -ENOTSUP; -} - -/* setting all logical channels given attributes to active/inactive */ -int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, - int active) -{ - uint8_t tn = L1SAP_CHAN2TS(chan_nr); - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - uint8_t ss = l1sap_chan2ss(chan_nr); - int i; - int rc = -EINVAL; - - /* look for all matching chan_nr/link_id */ - for (i = 0; i < _TRX_CHAN_MAX; i++) { - struct l1sched_chan_state *chan_state; - chan_state = &l1ts->chan_state[i]; - /* skip if pchan type does not match pdch flag */ - if ((trx_sched_multiframes[l1ts->mf_index].pchan - == GSM_PCHAN_PDCH) - != trx_chan_desc[i].pdch) - continue; - if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8) - && trx_chan_desc[i].link_id == link_id) { - rc = 0; - if (chan_state->active == active) - continue; - LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n", - (active) ? "Activating" : "Deactivating", - trx_chan_desc[i].name, l1t->trx->nr, tn); - if (active) - memset(chan_state, 0, sizeof(*chan_state)); - chan_state->active = active; - /* free burst memory, to cleanly start with burst 0 */ - if (chan_state->dl_bursts) { - talloc_free(chan_state->dl_bursts); - chan_state->dl_bursts = NULL; - } - if (chan_state->ul_bursts) { - talloc_free(chan_state->ul_bursts); - chan_state->ul_bursts = NULL; - } - if (!active) - chan_state->ho_rach_detect = 0; - } - } - - /* disable handover detection (on deactivation) */ - if (!active) - _sched_act_rach_det(l1t, tn, ss, 0); - - return rc; -} - -/* setting all logical channels given attributes to active/inactive */ -int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, - uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, - uint8_t codec2, uint8_t codec3, uint8_t initial_id, uint8_t handover) -{ - uint8_t tn = L1SAP_CHAN2TS(chan_nr); - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - uint8_t ss = l1sap_chan2ss(chan_nr); - int i; - int rc = -EINVAL; - struct l1sched_chan_state *chan_state; - - /* no mode for PDCH */ - if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) - return 0; - - /* 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) - && trx_chan_desc[i].link_id == 0x00) { - chan_state = &l1ts->chan_state[i]; - LOGP(DL1C, LOGL_NOTICE, "Set mode %u, %u, handover %u " - "on %s of trx=%d ts=%d\n", rsl_cmode, tch_mode, - handover, trx_chan_desc[i].name, l1t->trx->nr, - tn); - chan_state->rsl_cmode = rsl_cmode; - chan_state->tch_mode = tch_mode; - chan_state->ho_rach_detect = handover; - if (rsl_cmode == RSL_CMOD_SPD_SPEECH - && tch_mode == GSM48_CMODE_SPEECH_AMR) { - chan_state->codecs = codecs; - chan_state->codec[0] = codec0; - chan_state->codec[1] = codec1; - chan_state->codec[2] = codec2; - chan_state->codec[3] = codec3; - chan_state->ul_ft = initial_id; - chan_state->dl_ft = initial_id; - chan_state->ul_cmr = initial_id; - chan_state->dl_cmr = initial_id; - chan_state->ber_sum = 0; - chan_state->ber_num = 0; - } - rc = 0; - } - } - - /* command rach detection - * always enable handover, even if state is still set (due to loss - * of transceiver link). - * disable handover, if state is still set, since we might not know - * the actual state of transceiver (due to loss of link) */ - _sched_act_rach_det(l1t, tn, ss, handover); - - return rc; -} - -/* setting cipher on logical channels */ -int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, - int algo, uint8_t *key, int key_len) -{ - uint8_t tn = L1SAP_CHAN2TS(chan_nr); - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - int i; - int rc = -EINVAL; - struct l1sched_chan_state *chan_state; - - /* no cipher for PDCH */ - if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) - return 0; - - /* no algorithm given means a5/0 */ - if (algo <= 0) - algo = 0; - else if (key_len != 8) { - LOGP(DL1C, LOGL_ERROR, "Algo A5/%d not supported with given " - "key len=%d\n", algo, key_len); - return -ENOTSUP; - } - - /* look for all matching chan_nr */ - for (i = 0; i < _TRX_CHAN_MAX; i++) { - /* skip if pchan type */ - if (trx_chan_desc[i].pdch) - continue; - if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)) { - chan_state = &l1ts->chan_state[i]; - LOGP(DL1C, LOGL_NOTICE, "Set a5/%d %s for %s on trx=%d " - "ts=%d\n", algo, - (downlink) ? "downlink" : "uplink", - trx_chan_desc[i].name, l1t->trx->nr, tn); - if (downlink) { - chan_state->dl_encr_algo = algo; - memcpy(chan_state->dl_encr_key, key, key_len); - chan_state->dl_encr_key_len = key_len; - } else { - chan_state->ul_encr_algo = algo; - memcpy(chan_state->ul_encr_key, key, key_len); - chan_state->ul_encr_key_len = key_len; - } - rc = 0; - } - } - - return rc; -} - -/* process ready-to-send */ -int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - const struct trx_sched_frame *frame; - uint8_t offset, period, bid; - trx_sched_rts_func *func; - enum trx_chan_type chan; - - /* no multiframe set */ - if (!l1ts->mf_index) - return 0; - - /* get frame from multiframe */ - period = l1ts->mf_period; - offset = fn % period; - frame = l1ts->mf_frames + offset; - - chan = frame->dl_chan; - bid = frame->dl_bid; - func = trx_chan_desc[frame->dl_chan].rts_fn; - - /* only on bid == 0 */ - if (bid != 0) - return 0; - - /* no RTS function */ - if (!func) - return 0; - - /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active - && !l1ts->chan_state[chan].active) - return -EINVAL; - - return func(l1t, tn, fn, frame->dl_chan); -} - -/* process downlink burst */ -const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *l1cs; - const struct trx_sched_frame *frame; - uint8_t offset, period, bid; - trx_sched_dl_func *func; - enum trx_chan_type chan; - ubit_t *bits = NULL; - - if (!l1ts->mf_index) - goto no_data; - - /* get frame from multiframe */ - period = l1ts->mf_period; - offset = fn % period; - frame = l1ts->mf_frames + offset; - - chan = frame->dl_chan; - bid = frame->dl_bid; - func = trx_chan_desc[chan].dl_fn; - - l1cs = &l1ts->chan_state[chan]; - - /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active && !l1cs->active) - goto no_data; - - /* get burst from function */ - bits = func(l1t, tn, fn, chan, bid); - - /* encrypt */ - if (bits && l1cs->dl_encr_algo) { - ubit_t ks[114]; - int i; - - osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL); - for (i = 0; i < 57; i++) { - bits[i + 3] ^= ks[i]; - bits[i + 88] ^= ks[i + 57]; - } - } - -no_data: - /* in case of C0, we need a dummy burst to maintain RF power */ - if (bits == NULL && l1t->trx == l1t->trx->bts->c0) { -if (0) if (chan != TRXC_IDLE) // hack - LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u " - "burst=%d on C0, so filling with dummy burst\n", - trx_chan_desc[chan].name, fn, tn, bid); - bits = (ubit_t *) dummy_burst; - } - - return bits; -} - -/* process uplink burst */ -int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn, - sbit_t *bits, int8_t rssi, float toa) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *l1cs; - const struct trx_sched_frame *frame; - uint8_t offset, period, bid; - trx_sched_ul_func *func; - enum trx_chan_type chan; - uint32_t fn, elapsed; - - if (!l1ts->mf_index) - return -EINVAL; - - /* calculate how many frames have been elapsed */ - elapsed = (current_fn + GSM_HYPERFRAME - l1ts->mf_last_fn) % GSM_HYPERFRAME; - - /* start counting from last fn + 1, but only if not too many fn have - * been elapsed */ - if (elapsed < 10) - fn = (l1ts->mf_last_fn + 1) % GSM_HYPERFRAME; - else - fn = current_fn; - - while (42) { - /* get frame from multiframe */ - period = l1ts->mf_period; - offset = fn % period; - frame = l1ts->mf_frames + offset; - - chan = frame->ul_chan; - bid = frame->ul_bid; - func = trx_chan_desc[chan].ul_fn; - - l1cs = &l1ts->chan_state[chan]; - - /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active && !l1cs->active) - goto next_frame; - - /* omit bursts which have no handler, like IDLE bursts */ - if (!func) - goto next_frame; - - /* put burst to function */ - if (fn == current_fn) { - /* decrypt */ - if (bits && l1cs->ul_encr_algo) { - ubit_t ks[114]; - int i; - - osmo_a5(l1cs->ul_encr_algo, - l1cs->ul_encr_key, - fn, NULL, ks); - for (i = 0; i < 57; i++) { - if (ks[i]) - bits[i + 3] = - bits[i + 3]; - if (ks[i + 57]) - bits[i + 88] = - bits[i + 88]; - } - } - - func(l1t, tn, fn, chan, bid, bits, rssi, toa); - } else if (chan != TRXC_RACH && !l1cs->ho_rach_detect) { - sbit_t spare[148]; - - memset(spare, 0, 148); - func(l1t, tn, fn, chan, bid, spare, -128, 0); - } - -next_frame: - /* reached current fn */ - if (fn == current_fn) - break; - - fn = (fn + 1) % GSM_HYPERFRAME; - } - - l1ts->mf_last_fn = fn; - - return 0; -} - -struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn) -{ - OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts)); - return &l1t->ts[tn]; -} diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h deleted file mode 100644 index 13ef051..0000000 --- a/src/osmo-bts-trx/scheduler.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef TRX_SCHEDULER_H -#define TRX_SCHEDULER_H - -/* These types define the different channels on a multiframe. - * Each channel has queues and can be activated individually. - */ -enum trx_chan_type { - TRXC_IDLE = 0, - TRXC_FCCH, - TRXC_SCH, - TRXC_BCCH, - TRXC_RACH, - TRXC_CCCH, - TRXC_TCHF, - TRXC_TCHH_0, - TRXC_TCHH_1, - TRXC_SDCCH4_0, - TRXC_SDCCH4_1, - TRXC_SDCCH4_2, - TRXC_SDCCH4_3, - TRXC_SDCCH8_0, - TRXC_SDCCH8_1, - TRXC_SDCCH8_2, - TRXC_SDCCH8_3, - TRXC_SDCCH8_4, - TRXC_SDCCH8_5, - TRXC_SDCCH8_6, - TRXC_SDCCH8_7, - TRXC_SACCHTF, - TRXC_SACCHTH_0, - TRXC_SACCHTH_1, - TRXC_SACCH4_0, - TRXC_SACCH4_1, - TRXC_SACCH4_2, - TRXC_SACCH4_3, - TRXC_SACCH8_0, - TRXC_SACCH8_1, - TRXC_SACCH8_2, - TRXC_SACCH8_3, - TRXC_SACCH8_4, - TRXC_SACCH8_5, - TRXC_SACCH8_6, - TRXC_SACCH8_7, - TRXC_PDTCH, - TRXC_PTCCH, - _TRX_CHAN_MAX -}; - -/* States each channel on a multiframe */ -struct l1sched_chan_state { - /* scheduler */ - uint8_t active; /* Channel is active */ - ubit_t *dl_bursts; /* burst buffer for TX */ - sbit_t *ul_bursts; /* burst buffer for RX */ - uint32_t ul_first_fn; /* fn of first burst */ - uint8_t ul_mask; /* mask of received bursts */ - - /* RSSI / TOA */ - uint8_t rssi_num; /* number of RSSI values */ - float rssi_sum; /* sum of RSSI values */ - uint8_t toa_num; /* number of TOA values */ - float toa_sum; /* sum of TOA values */ - - /* loss detection */ - uint8_t lost; /* (SACCH) loss detection */ - - /* mode */ - uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */ - - /* AMR */ - uint8_t codec[4]; /* 4 possible codecs for amr */ - int codecs; /* number of possible codecs */ - float ber_sum; /* sum of bit error rates */ - int ber_num; /* number of bit error rates */ - uint8_t ul_ft; /* current uplink FT index */ - uint8_t dl_ft; /* current downlink FT index */ - uint8_t ul_cmr; /* current uplink CMR index */ - uint8_t dl_cmr; /* current downlink CMR index */ - uint8_t amr_loop; /* if AMR loop is enabled */ - - /* TCH/H */ - uint8_t dl_ongoing_facch; /* FACCH/H on downlink */ - uint8_t ul_ongoing_facch; /* FACCH/H on uplink */ - - /* encryption */ - int ul_encr_algo; /* A5/x encry algo downlink */ - int dl_encr_algo; /* A5/x encry algo uplink */ - int ul_encr_key_len; - int dl_encr_key_len; - uint8_t ul_encr_key[MAX_A5_KEY_LEN]; - uint8_t dl_encr_key[MAX_A5_KEY_LEN]; - - /* measurements */ - struct { - uint8_t clock; /* cyclic clock counter */ - int8_t rssi[32]; /* last RSSI values */ - int rssi_count; /* received RSSI values */ - int rssi_valid_count; /* number of stored value */ - int rssi_got_burst; /* any burst received so far */ - float toa_sum; /* sum of TOA values */ - int toa_num; /* number of TOA value */ - } meas; - - /* handover */ - uint8_t ho_rach_detect; /* if rach detection is on */ -}; - -struct l1sched_ts { - uint8_t mf_index; /* selected multiframe index */ - uint32_t mf_last_fn; /* last received frame number */ - uint8_t mf_period; /* period of multiframe */ - const struct trx_sched_frame *mf_frames; /* pointer to frame layout */ - - struct llist_head dl_prims; /* Queue primitves for TX */ - - /* Channel states for all logical channels */ - struct l1sched_chan_state chan_state[_TRX_CHAN_MAX]; -}; - -struct l1sched_trx { - struct gsm_bts_trx *trx; - struct l1sched_ts ts[TRX_NR_TS]; -}; - -struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn); - -/*! \brief how many frame numbers in advance we should send bursts to PHY */ -extern uint32_t trx_clock_advance; -/*! \brief advance RTS.ind to L2 by that many clocks */ -extern uint32_t trx_rts_advance; -/*! \brief last frame number as received from PHY */ -extern uint32_t transceiver_last_fn; - - -/*! \brief Initialize the scheudler data structures */ -int trx_sched_init(struct l1sched_trx *l1t); - -/*! \brief De-initialize the scheudler data structures */ -void trx_sched_exit(struct l1sched_trx *l1t); - -/*! \brief Handle a PH-DATA.req from L2 down to L1 */ -int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); - -/*! \brief Handle a PH-TCH.req from L2 down to L1 */ -int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); - -/*! \brief PHY informs us of new (current) GSM freme nunmber */ -int trx_sched_clock(struct gsm_bts *bts, uint32_t fn); - -/*! \brief handle an UL burst received by PHY */ -int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - sbit_t *bits, int8_t rssi, float toa); - -/*! \brief set multiframe scheduler to given physical channel config */ -int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, - enum gsm_phys_chan_config pchan); - -/*! \brief set all matching logical channels active/inactive */ -int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, - int active); - -/*! \brief set mode of all matching logical channels to given mode(s) */ -int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, - uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, - uint8_t codec2, uint8_t codec3, uint8_t initial_codec, - uint8_t handover); - -/*! \brief set ciphering on given logical channels */ -int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, - int algo, uint8_t *key, int key_len); - -/* \brief close all logical channels and reset timeslots */ -void trx_sched_reset(struct l1sched_trx *l1t); - -#endif /* TRX_SCHEDULER_H */ diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h deleted file mode 100644 index 9f663cd..0000000 --- a/src/osmo-bts-trx/scheduler_backend.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn, enum trx_chan_type chan); - -typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn, enum trx_chan_type chan, - uint8_t bid); - -typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn, enum trx_chan_type chan, - uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); - -struct trx_chan_desc { - /*! \brief Is this on a PDCH (PS) ? */ - int pdch; - /*! \brief TRX Channel Type */ - enum trx_chan_type chan; - /*! \brief Channel Number (like in RSL) */ - uint8_t chan_nr; - /*! \brief Link ID (like in RSL) */ - uint8_t link_id; - /*! \brief Human-readable name */ - const char *name; - /*! \brief function to call when we want to generate RTS.req to L2 */ - trx_sched_rts_func *rts_fn; - /*! \brief function to call when DATA.req received from L2 */ - trx_sched_dl_func *dl_fn; - /*! \brief function to call when burst received from PHY */ - trx_sched_ul_func *ul_fn; - /*! \breif is this channel automatically active at start? */ - int auto_active; -}; -extern const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX]; - -extern const ubit_t _sched_tsc[8][26]; -const ubit_t _sched_fcch_burst[148]; -const ubit_t _sched_sch_train[64]; - -struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, - enum trx_chan_type chan); - -int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi); - -int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); - -ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); - -const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); -int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); -void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 5629a64..ac9212b 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -38,10 +38,10 @@ #include #include #include +#include +#include #include "l1_if.h" -#include "scheduler.h" -#include "scheduler_backend.h" #include "gsm0503_coding.h" #include "trx_if.h" #include "loops.h" diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index c9cfaef..dbe6f68 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -36,10 +36,10 @@ #include #include +#include #include "l1_if.h" #include "trx_if.h" -#include "scheduler.h" /* enable to print RSSI level graph */ //#define TOA_RSSI_DEBUG diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index 5da0c21..a4a7909 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -39,9 +39,9 @@ #include #include #include +#include #include "l1_if.h" -#include "scheduler.h" #include "trx_if.h" #include "loops.h" -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:00 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:00 +0100 Subject: [PATCH 1/7] TRX: factor out the scheduler from remaining code Message-ID: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> From: Harald Welte The L1 scheduler is a generally useful component that is unfortunately tied quite a bit into the OsmoTRX support. Let's try to separate it out by having separate per-trx/per-ts/per-chan data structures pre-fixed with l1sched_ Using this patch it should be one step easier to use the scheduler for other BTS models, such as the intended upcoming virtual BTS. --- src/osmo-bts-trx/l1_if.c | 35 ++-- src/osmo-bts-trx/l1_if.h | 121 +---------- src/osmo-bts-trx/loops.c | 83 ++++---- src/osmo-bts-trx/loops.h | 14 +- src/osmo-bts-trx/scheduler.c | 486 +++++++++++++++++++++++-------------------- src/osmo-bts-trx/scheduler.h | 143 ++++++++++++- src/osmo-bts-trx/trx_if.c | 2 +- 7 files changed, 473 insertions(+), 411 deletions(-) diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index a45ba05..70a5c59 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -68,9 +68,10 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) if (!l1h) return NULL; l1h->trx = trx; + l1h->l1s.trx = trx; trx->role_bts.l1h = l1h; - trx_sched_init(l1h); + trx_sched_init(&l1h->l1s); rc = trx_if_open(l1h); if (rc < 0) { @@ -89,7 +90,7 @@ err: void l1if_close(struct trx_l1h *l1h) { trx_if_close(l1h); - trx_sched_exit(l1h); + trx_sched_exit(&l1h->l1s); talloc_free(l1h); } @@ -267,7 +268,7 @@ int bts_model_trx_close(struct gsm_bts_trx *trx) enum gsm_phys_chan_config pchan = trx->ts[0].pchan; /* close all logical channels and reset timeslots */ - trx_sched_reset(l1h); + trx_sched_reset(&l1h->l1s); /* deactivate lchan for CCCH */ if (pchan == GSM_PCHAN_CCCH || pchan == GSM_PCHAN_CCCH_SDCCH4) { @@ -374,8 +375,12 @@ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) l1if_provision_transceiver_trx(l1h); } + /* ignore disabled slots */ + if (!(l1h->config.slotmask & (1 << tn))) + return NM_NACK_RES_NOTAVAIL; + /* set physical channel */ - rc = trx_sched_set_pchan(l1h, tn, pchan); + rc = trx_sched_set_pchan(&l1h->l1s, tn, pchan); if (rc) return NM_NACK_RES_NOTAVAIL; @@ -413,17 +418,17 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan, if (!downlink) { /* set uplink */ - trx_sched_set_cipher(l1h, chan_nr, 0, lchan->encr.alg_id - 1, + trx_sched_set_cipher(&l1h->l1s, chan_nr, 0, lchan->encr.alg_id - 1, lchan->encr.key, lchan->encr.key_len); lchan->ciph_state = LCHAN_CIPH_RX_CONF; } else { /* set downlink and also set uplink, if not already */ if (lchan->ciph_state != LCHAN_CIPH_RX_CONF) { - trx_sched_set_cipher(l1h, chan_nr, 0, + trx_sched_set_cipher(&l1h->l1s, chan_nr, 0, lchan->encr.alg_id - 1, lchan->encr.key, lchan->encr.key_len); } - trx_sched_set_cipher(l1h, chan_nr, 1, lchan->encr.alg_id - 1, + trx_sched_set_cipher(&l1h->l1s, chan_nr, 1, lchan->encr.alg_id - 1, lchan->encr.key, lchan->encr.key_len); lchan->ciph_state = LCHAN_CIPH_RXTX_CONF; } @@ -510,12 +515,12 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) if (!msg) break; /* put data into scheduler's queue */ - return trx_sched_ph_data_req(l1h, l1sap); + return trx_sched_ph_data_req(&l1h->l1s, l1sap); case OSMO_PRIM(PRIM_TCH, PRIM_OP_REQUEST): if (!msg) break; /* put data into scheduler's queue */ - return trx_sched_tch_req(l1h, l1sap); + return trx_sched_tch_req(&l1h->l1s, l1sap); case OSMO_PRIM(PRIM_MPH_INFO, PRIM_OP_REQUEST): switch (l1sap->u.info.type) { case PRIM_INFO_ACT_CIPH: @@ -542,11 +547,11 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) break; } /* activate dedicated channel */ - trx_sched_set_lchan(l1h, chan_nr, 0x00, 1); + trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 1); /* activate associated channel */ - trx_sched_set_lchan(l1h, chan_nr, 0x40, 1); + trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 1); /* set mode */ - trx_sched_set_mode(l1h, chan_nr, + trx_sched_set_mode(&l1h->l1s, chan_nr, lchan->rsl_cmode, lchan->tch_mode, lchan->tch.amr_mr.num_modes, lchan->tch.amr_mr.bts_mode[0].mode, @@ -574,7 +579,7 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) } if (l1sap->u.info.type == PRIM_INFO_MODIFY) { /* change mode */ - trx_sched_set_mode(l1h, chan_nr, + trx_sched_set_mode(&l1h->l1s, chan_nr, lchan->rsl_cmode, lchan->tch_mode, lchan->tch.amr_mr.num_modes, lchan->tch.amr_mr.bts_mode[0].mode, @@ -591,12 +596,12 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) break; } /* deactivate associated channel */ - trx_sched_set_lchan(l1h, chan_nr, 0x40, 0); + trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x40, 0); if (!l1sap->u.info.u.act_req.sacch_only) { /* set lchan inactive */ lchan_set_state(lchan, LCHAN_S_NONE); /* deactivate dedicated channel */ - trx_sched_set_lchan(l1h, chan_nr, 0x00, 0); + trx_sched_set_lchan(&l1h->l1s, chan_nr, 0x00, 0); /* confirm only on dedicated channel */ mph_info_chan_confirm(l1h, chan_nr, PRIM_INFO_DEACTIVATE, 0); diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index 2c672cb..6dec273 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -1,109 +1,7 @@ #ifndef L1_IF_H_TRX #define L1_IF_H_TRX -/* These types define the different channels on a multiframe. - * Each channel has queues and can be activated individually. - */ -enum trx_chan_type { - TRXC_IDLE = 0, - TRXC_FCCH, - TRXC_SCH, - TRXC_BCCH, - TRXC_RACH, - TRXC_CCCH, - TRXC_TCHF, - TRXC_TCHH_0, - TRXC_TCHH_1, - TRXC_SDCCH4_0, - TRXC_SDCCH4_1, - TRXC_SDCCH4_2, - TRXC_SDCCH4_3, - TRXC_SDCCH8_0, - TRXC_SDCCH8_1, - TRXC_SDCCH8_2, - TRXC_SDCCH8_3, - TRXC_SDCCH8_4, - TRXC_SDCCH8_5, - TRXC_SDCCH8_6, - TRXC_SDCCH8_7, - TRXC_SACCHTF, - TRXC_SACCHTH_0, - TRXC_SACCHTH_1, - TRXC_SACCH4_0, - TRXC_SACCH4_1, - TRXC_SACCH4_2, - TRXC_SACCH4_3, - TRXC_SACCH8_0, - TRXC_SACCH8_1, - TRXC_SACCH8_2, - TRXC_SACCH8_3, - TRXC_SACCH8_4, - TRXC_SACCH8_5, - TRXC_SACCH8_6, - TRXC_SACCH8_7, - TRXC_PDTCH, - TRXC_PTCCH, - _TRX_CHAN_MAX -}; - -/* States each channel on a multiframe */ -struct trx_chan_state { - /* scheduler */ - uint8_t active; /* Channel is active */ - ubit_t *dl_bursts; /* burst buffer for TX */ - sbit_t *ul_bursts; /* burst buffer for RX */ - uint32_t ul_first_fn; /* fn of first burst */ - uint8_t ul_mask; /* mask of received bursts */ - - /* RSSI / TOA */ - uint8_t rssi_num; /* number of RSSI values */ - float rssi_sum; /* sum of RSSI values */ - uint8_t toa_num; /* number of TOA values */ - float toa_sum; /* sum of TOA values */ - - /* loss detection */ - uint8_t lost; /* (SACCH) loss detection */ - - /* mode */ - uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */ - - /* AMR */ - uint8_t codec[4]; /* 4 possible codecs for amr */ - int codecs; /* number of possible codecs */ - float ber_sum; /* sum of bit error rates */ - int ber_num; /* number of bit error rates */ - uint8_t ul_ft; /* current uplink FT index */ - uint8_t dl_ft; /* current downlink FT index */ - uint8_t ul_cmr; /* current uplink CMR index */ - uint8_t dl_cmr; /* current downlink CMR index */ - uint8_t amr_loop; /* if AMR loop is enabled */ - - /* TCH/H */ - uint8_t dl_ongoing_facch; /* FACCH/H on downlink */ - uint8_t ul_ongoing_facch; /* FACCH/H on uplink */ - - /* encryption */ - int ul_encr_algo; /* A5/x encry algo downlink */ - int dl_encr_algo; /* A5/x encry algo uplink */ - int ul_encr_key_len; - int dl_encr_key_len; - uint8_t ul_encr_key[MAX_A5_KEY_LEN]; - uint8_t dl_encr_key[MAX_A5_KEY_LEN]; - - /* measurements */ - struct { - uint8_t clock; /* cyclic clock counter */ - int8_t rssi[32]; /* last RSSI values */ - int rssi_count; /* received RSSI values */ - int rssi_valid_count; /* number of stored value */ - int rssi_got_burst; /* any burst received so far */ - float toa_sum; /* sum of TOA values */ - int toa_num; /* number of TOA value */ - } meas; - - /* handover */ - uint8_t ho_rach_detect; /* if rach detection is on */ -}; +#include "scheduler.h" struct trx_config { uint8_t poweron; /* poweron(1) or poweroff(0) */ @@ -152,16 +50,9 @@ struct trx_l1h { /* transceiver config */ struct trx_config config; - - uint8_t mf_index[TRX_NR_TS]; /* selected multiframe index */ - uint32_t mf_last_fn[TRX_NR_TS]; /* last received frame */ - uint8_t mf_period[TRX_NR_TS]; /* period of multiframe */ - const struct trx_sched_frame *mf_frames[TRX_NR_TS]; /* pointer to frame layout */ - - /* Channel states for all channels on all timeslots */ - struct trx_chan_state chan_states[TRX_NR_TS][_TRX_CHAN_MAX]; - struct llist_head dl_prims[TRX_NR_TS]; /* Queue primitves for TX */ uint8_t ho_rach_detect[TRX_NR_TS][TS_MAX_LCHAN]; + + struct l1sched_trx l1s; }; struct trx_l1h *l1if_open(struct gsm_bts_trx *trx); @@ -176,4 +67,10 @@ void l1if_fill_meas_res(struct osmo_phsap_prim *l1sap, uint8_t chan_nr, float ta int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint8_t chan_nr, int n_errors, int n_bits_total, float rssi, float toa); +static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx) +{ + struct trx_l1h *l1h = trx_l1h_hdl(trx); + return &l1h->l1s; +} + #endif /* L1_IF_H_TRX */ diff --git a/src/osmo-bts-trx/loops.c b/src/osmo-bts-trx/loops.c index 52ac170..8070e80 100644 --- a/src/osmo-bts-trx/loops.c +++ b/src/osmo-bts-trx/loops.c @@ -33,7 +33,7 @@ #include "l1_if.h" #include "loops.h" -#define MS_PWR_DBM(lvl) ms_pwr_dbm(gsm_arfcn2band(l1h->config.arfcn), lvl) +#define MS_PWR_DBM(arfcn, lvl) ms_pwr_dbm(gsm_arfcn2band(arfcn), lvl) /* * MS Power loop @@ -42,11 +42,12 @@ int trx_ms_power_loop = 0; int8_t trx_target_rssi = -10; -static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan, - uint8_t chan_nr, struct trx_chan_state *chan_state, int8_t diff) +static int ms_power_diff(struct gsm_lchan *lchan, uint8_t chan_nr, int8_t diff) { + struct gsm_bts_trx *trx = lchan->ts->trx; + uint16_t arfcn = trx->arfcn; int8_t new_power; - + new_power = lchan->ms_power - (diff >> 1); if (diff == 0) @@ -56,7 +57,7 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan, new_power = 0; // FIXME: to go above 1W, we need to know classmark of MS - if (l1h->config.arfcn >= 512 && l1h->config.arfcn <= 885) { + if (arfcn >= 512 && arfcn <= 885) { if (new_power > 15) new_power = 15; } else { @@ -73,8 +74,8 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan, if (lchan->ms_power == new_power) { LOGP(DLOOP, LOGL_INFO, "Keeping MS new_power of trx=%u " "chan_nr=0x%02x at control level %d (%d dBm)\n", - l1h->trx->nr, chan_nr, new_power, - MS_PWR_DBM(new_power)); + trx->nr, chan_nr, new_power, + MS_PWR_DBM(arfcn, new_power)); return 0; } @@ -82,15 +83,16 @@ static int ms_power_diff(struct trx_l1h *l1h, struct gsm_lchan *lchan, LOGP(DLOOP, LOGL_INFO, "%s MS new_power of trx=%u chan_nr=0x%02x from " "control level %d (%d dBm) to %d (%d dBm)\n", (diff > 0) ? "Raising" : "Lowering", - l1h->trx->nr, chan_nr, lchan->ms_power, - MS_PWR_DBM(lchan->ms_power), new_power, MS_PWR_DBM(new_power)); + trx->nr, chan_nr, lchan->ms_power, + MS_PWR_DBM(arfcn, lchan->ms_power), new_power, + MS_PWR_DBM(arfcn, new_power)); lchan->ms_power = new_power; return 0; } -static int ms_power_val(struct trx_chan_state *chan_state, int8_t rssi) +static int ms_power_val(struct l1sched_chan_state *chan_state, int8_t rssi) { /* ignore inserted dummy frames, treat as lost frames */ if (rssi < -127) @@ -112,9 +114,10 @@ static int ms_power_val(struct trx_chan_state *chan_state, int8_t rssi) return 0; } -static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan, - uint8_t chan_nr, struct trx_chan_state *chan_state) +static int ms_power_clock(struct gsm_lchan *lchan, + uint8_t chan_nr, struct l1sched_chan_state *chan_state) { + struct gsm_bts_trx *trx = lchan->ts->trx; int rssi; int i; @@ -134,9 +137,8 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan, if (chan_state->meas.rssi_count == 0) { LOGP(DLOOP, LOGL_NOTICE, "LOST SACCH frame of trx=%u " "chan_nr=0x%02x, so we raise MS power\n", - l1h->trx->nr, chan_nr); - return ms_power_diff(l1h, lchan, chan_nr, chan_state, - MS_RAISE_MAX); + trx->nr, chan_nr); + return ms_power_diff(lchan, chan_nr, MS_RAISE_MAX); } /* reset total counter */ @@ -157,9 +159,10 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan, /* change RSSI */ LOGP(DLOOP, LOGL_DEBUG, "Lowest RSSI: %d Target RSSI: %d Current " "MS power: %d (%d dBm) of trx=%u chan_nr=0x%02x\n", rssi, - trx_target_rssi, lchan->ms_power, MS_PWR_DBM(lchan->ms_power), - l1h->trx->nr, chan_nr); - ms_power_diff(l1h, lchan, chan_nr, chan_state, trx_target_rssi - rssi); + trx_target_rssi, lchan->ms_power, + MS_PWR_DBM(trx->arfcn, lchan->ms_power), + trx->nr, chan_nr); + ms_power_diff(lchan, chan_nr, trx_target_rssi - rssi); return 0; } @@ -171,9 +174,11 @@ static int ms_power_clock(struct trx_l1h *l1h, struct gsm_lchan *lchan, int trx_ta_loop = 1; -int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr, - struct trx_chan_state *chan_state, float toa) +int ta_val(struct gsm_lchan *lchan, uint8_t chan_nr, + struct l1sched_chan_state *chan_state, float toa) { + struct gsm_bts_trx *trx = lchan->ts->trx; + /* check if the current L1 header acks to the current ordered TA */ if (lchan->meas.l1_info[1] != lchan->rqd_ta) return 0; @@ -190,19 +195,19 @@ int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr, if (toa < -0.9F && lchan->rqd_ta > 0) { LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too " "early (%.2f), now lowering TA from %d to %d\n", - l1h->trx->nr, chan_nr, toa, lchan->rqd_ta, + trx->nr, chan_nr, toa, lchan->rqd_ta, lchan->rqd_ta - 1); lchan->rqd_ta--; } else if (toa > 0.9F && lchan->rqd_ta < 63) { LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is too " "late (%.2f), now raising TA from %d to %d\n", - l1h->trx->nr, chan_nr, toa, lchan->rqd_ta, + trx->nr, chan_nr, toa, lchan->rqd_ta, lchan->rqd_ta + 1); lchan->rqd_ta++; } else LOGP(DLOOP, LOGL_INFO, "TOA of trx=%u chan_nr=0x%02x is " "correct (%.2f), keeping current TA of %d\n", - l1h->trx->nr, chan_nr, toa, lchan->rqd_ta); + trx->nr, chan_nr, toa, lchan->rqd_ta); chan_state->meas.toa_num = 0; chan_state->meas.toa_sum = 0; @@ -210,29 +215,29 @@ int ta_val(struct trx_l1h *l1h, struct gsm_lchan *lchan, uint8_t chan_nr, return 0; } -int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state, int8_t rssi, float toa) +int trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state, int8_t rssi, float toa) { - struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)] + struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)] .lchan[l1sap_chan2ss(chan_nr)]; if (trx_ms_power_loop) ms_power_val(chan_state, rssi); if (trx_ta_loop) - ta_val(l1h, lchan, chan_nr, chan_state, toa); + ta_val(lchan, chan_nr, chan_state, toa); return 0; } -int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state) +int trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state) { - struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)] + struct gsm_lchan *lchan = &l1t->trx->ts[L1SAP_CHAN2TS(chan_nr)] .lchan[l1sap_chan2ss(chan_nr)]; if (trx_ms_power_loop) - ms_power_clock(l1h, lchan, chan_nr, chan_state); + ms_power_clock(lchan, chan_nr, chan_state); /* count the number of SACCH clocks */ chan_state->meas.clock++; @@ -240,10 +245,11 @@ int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr, return 0; } -int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state, float ber) +int trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state, float ber) { - struct gsm_lchan *lchan = &l1h->trx->ts[L1SAP_CHAN2TS(chan_nr)] + struct gsm_bts_trx *trx = l1t->trx; + struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)] .lchan[l1sap_chan2ss(chan_nr)]; int c_i; @@ -280,7 +286,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, LOGP(DLOOP, LOGL_DEBUG, "Current bit error rate (BER) %.6f " "codec id %d of trx=%u chan_nr=0x%02x\n", ber, - chan_state->ul_ft, l1h->trx->nr, chan_nr); + chan_state->ul_ft, trx->nr, chan_nr); /* degrade */ if (chan_state->dl_cmr > 0) { @@ -290,7 +296,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, LOGP(DLOOP, LOGL_DEBUG, "Degrading due to BER %.6f " "from codec id %d to %d of trx=%u " "chan_nr=0x%02x\n", ber, chan_state->dl_cmr, - chan_state->dl_cmr - 1, l1h->trx->nr, chan_nr); + chan_state->dl_cmr - 1, trx->nr, chan_nr); chan_state->dl_cmr--; } @@ -306,7 +312,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, LOGP(DLOOP, LOGL_DEBUG, "Upgrading due to BER %.6f " "from codec id %d to %d of trx=%u " "chan_nr=0x%02x\n", ber, chan_state->dl_cmr, - chan_state->dl_cmr + 1, l1h->trx->nr, chan_nr); + chan_state->dl_cmr + 1, trx->nr, chan_nr); chan_state->dl_cmr++; } @@ -316,7 +322,7 @@ int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, return 0; } -int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop) +int trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop) { if (chan_state->amr_loop && !loop) { chan_state->amr_loop = 0; @@ -336,4 +342,3 @@ int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop) return 0; } - diff --git a/src/osmo-bts-trx/loops.h b/src/osmo-bts-trx/loops.h index 27b0ef2..613d2d0 100644 --- a/src/osmo-bts-trx/loops.h +++ b/src/osmo-bts-trx/loops.h @@ -17,15 +17,15 @@ extern int trx_ms_power_loop; extern int8_t trx_target_rssi; extern int trx_ta_loop; -int trx_loop_sacch_input(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state, int8_t rssi, float toa); +int trx_loop_sacch_input(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state, int8_t rssi, float toa); -int trx_loop_sacch_clock(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state); +int trx_loop_sacch_clock(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state); -int trx_loop_amr_input(struct trx_l1h *l1h, uint8_t chan_nr, - struct trx_chan_state *chan_state, float ber); +int trx_loop_amr_input(struct l1sched_trx *l1t, uint8_t chan_nr, + struct l1sched_chan_state *chan_state, float ber); -int trx_loop_amr_set(struct trx_chan_state *chan_state, int loop); +int trx_loop_amr_set(struct l1sched_chan_state *chan_state, int loop); #endif /* _TRX_LOOPS_H */ diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index 1710b4e..6d0f180 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -2,6 +2,7 @@ /* (C) 2013 by Andreas Eversberg * (C) 2015 by Alexander Chemeris + * (C) 2015 by Harald Welte * * All Rights Reserved * @@ -67,47 +68,47 @@ uint32_t trx_clock_advance = 20; /* advance RTS to give some time for data processing. (especially PCU) */ uint32_t trx_rts_advance = 5; /* about 20ms */ -typedef int trx_sched_rts_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); -typedef ubit_t *trx_sched_dl_func(struct trx_l1h *l1h, uint8_t tn, +typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -typedef int trx_sched_ul_func(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); -static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); -static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); -static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); -static ubit_t *tx_idle_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_fcch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid); -static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); -static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); -static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); -static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); -static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); @@ -219,23 +220,22 @@ static const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { * init / exit */ -int trx_sched_init(struct trx_l1h *l1h) +int trx_sched_init(struct l1sched_trx *l1t) { uint8_t tn; int i; - struct trx_chan_state *chan_state; - LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1h->trx->nr); + LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); - /* hack to get bts */ - bts = l1h->trx->bts; + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - for (tn = 0; tn < TRX_NR_TS; tn++) { - l1h->mf_index[tn] = 0; - l1h->mf_last_fn[tn] = 0; - INIT_LLIST_HEAD(&l1h->dl_prims[tn]); - for (i = 0; i < _TRX_CHAN_MAX; i++) { - chan_state = &l1h->chan_states[tn][i]; + l1ts->mf_index = 0; + l1ts->mf_last_fn = 0; + INIT_LLIST_HEAD(&l1ts->dl_prims); + for (i = 0; i < ARRAY_SIZE(&l1ts->chan_state); i++) { + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; chan_state->active = 0; } } @@ -243,18 +243,20 @@ int trx_sched_init(struct trx_l1h *l1h) return 0; } -void trx_sched_exit(struct trx_l1h *l1h) +void trx_sched_exit(struct l1sched_trx *l1t) { + struct gsm_bts_trx_ts *ts; uint8_t tn; int i; - struct trx_chan_state *chan_state; - LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1h->trx->nr); + LOGP(DL1C, LOGL_NOTICE, "Exit scheduler for trx=%u\n", l1t->trx->nr); - for (tn = 0; tn < TRX_NR_TS; tn++) { - msgb_queue_flush(&l1h->dl_prims[tn]); + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + msgb_queue_flush(&l1ts->dl_prims); for (i = 0; i < _TRX_CHAN_MAX; i++) { - chan_state = &l1h->chan_states[tn][i]; + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; if (chan_state->dl_bursts) { talloc_free(chan_state->dl_bursts); chan_state->dl_bursts = NULL; @@ -265,16 +267,17 @@ void trx_sched_exit(struct trx_l1h *l1h) } } /* clear lchan channel states */ - for (i = 0; i < TRX_NR_TS; i++) - l1h->trx->ts[tn].lchan[i].state = LCHAN_S_NONE; + ts = &l1t->trx->ts[tn]; + for (i = 0; i < ARRAY_SIZE(ts->lchan); i++) + lchan_set_state(&ts->lchan[i], LCHAN_S_NONE); } } /* close all logical channels and reset timeslots */ -void trx_sched_reset(struct trx_l1h *l1h) +void trx_sched_reset(struct l1sched_trx *l1t) { - trx_sched_exit(l1h); - trx_sched_init(l1h); + trx_sched_exit(l1t); + trx_sched_init(l1t); } @@ -282,13 +285,14 @@ void trx_sched_reset(struct trx_l1h *l1h) * data request (from upper layer) */ -int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap) +int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) { uint8_t tn = l1sap->u.data.chan_nr & 7; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x " "fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr, - l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1h->trx->nr); + l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr); if (!l1sap->oph.msg) abort(); @@ -299,18 +303,19 @@ int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap) return 0; } - msgb_enqueue(&l1h->dl_prims[tn], l1sap->oph.msg); + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); return 0; } -int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap) +int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) { uint8_t tn = l1sap->u.tch.chan_nr & 7; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x " "fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr, - l1sap->u.tch.fn, tn, l1h->trx->nr); + l1sap->u.tch.fn, tn, l1t->trx->nr); if (!l1sap->oph.msg) abort(); @@ -321,7 +326,7 @@ int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap) return 0; } - msgb_enqueue(&l1h->dl_prims[tn], l1sap->oph.msg); + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); return 0; } @@ -332,12 +337,13 @@ int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap) */ /* RTS for data frame */ -static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan) { uint8_t chan_nr, link_id; struct msgb *msg; struct osmo_phsap_prim *l1sap; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); /* get data for RTS indication */ chan_nr = trx_chan_desc[chan].chan_nr | tn; @@ -351,11 +357,11 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x " "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, link_id, fn, tn, l1h->trx->nr); + chan_nr, link_id, fn, tn, l1t->trx->nr); /* send clock information to loops process */ if (L1SAP_IS_LINK_SACCH(link_id)) - trx_loop_sacch_clock(l1h, chan_nr, &l1h->chan_states[tn][chan]); + trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]); /* generate prim */ msg = l1sap_msgb_alloc(200); @@ -368,15 +374,16 @@ static int rts_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, l1sap->u.data.link_id = link_id; l1sap->u.data.fn = fn; - return l1sap_up(l1h->trx, l1sap); + return l1sap_up(l1t->trx, l1sap); } -static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, int facch) { uint8_t chan_nr, link_id; struct msgb *msg; struct osmo_phsap_prim *l1sap; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); int rc = 0; /* get data for RTS indication */ @@ -391,7 +398,7 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x " "fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, fn, tn, l1h->trx->nr); + chan_nr, fn, tn, l1t->trx->nr); /* only send, if FACCH is selected */ if (facch) { @@ -406,11 +413,11 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, l1sap->u.data.link_id = link_id; l1sap->u.data.fn = fn; - rc = l1sap_up(l1h->trx, l1sap); + rc = l1sap_up(l1t->trx, l1sap); } /* dont send, if TCH is in signalling only mode */ - if (l1h->chan_states[tn][chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { + if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { /* generate prim */ msg = l1sap_msgb_alloc(200); if (!msg) @@ -421,27 +428,27 @@ static int rts_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, l1sap->u.tch.chan_nr = chan_nr; l1sap->u.tch.fn = fn; - return l1sap_up(l1h->trx, l1sap); + return l1sap_up(l1t->trx, l1sap); } return rc; } /* RTS for full rate traffic frame */ -static int rts_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan) { /* TCH/F may include FACCH on every 4th burst */ - return rts_tch_common(l1h, tn, fn, chan, 1); + return rts_tch_common(l1t, tn, fn, chan, 1); } /* RTS for half rate traffic frame */ -static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan) { /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */ - return rts_tch_common(l1h, tn, fn, chan, ((fn % 26) >> 2) & 1); + return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1); } @@ -450,25 +457,25 @@ static int rts_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, */ /* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */ -static ubit_t *tx_idle_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); return NULL; } -static ubit_t *tx_fcch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); return (ubit_t *) fcch_burst; } -static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { static ubit_t bits[148], burst[78]; @@ -477,12 +484,12 @@ static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t t3p, bsic; LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); /* create SB info from GSM time and BSIC */ gsm_fn2gsmtime(&t, fn); t3p = t.t3 / 10; - bsic = l1h->trx->bts->bsic; + bsic = l1t->trx->bts->bsic; sb_info[0] = ((bsic & 0x3f) << 2) | ((t.t1 & 0x600) >> 9); @@ -508,16 +515,17 @@ static ubit_t *tx_sch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, return bits; } -static struct msgb *dequeue_prim(struct trx_l1h *l1h, int8_t tn,uint32_t fn, +static struct msgb *dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, enum trx_chan_type chan) { struct msgb *msg, *msg2; struct osmo_phsap_prim *l1sap; uint32_t prim_fn; uint8_t chan_nr, link_id; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); /* get prim of current fn from queue */ - llist_for_each_entry_safe(msg, msg2, &l1h->dl_prims[tn], list) { + llist_for_each_entry_safe(msg, msg2, &l1ts->dl_prims, list) { l1sap = msgb_l1sap_prim(msg); if (l1sap->oph.operation != PRIM_OP_REQUEST) { wrong_type: @@ -548,7 +556,7 @@ free_msg: "is out of range, or channel already disabled. " "If this happens in conjunction with PCU, " "increase 'rts-advance' by 5. (current fn=%u)\n", - l1h->trx->nr, tn, l1sap->u.data.fn, fn); + l1t->trx->nr, tn, l1sap->u.data.fn, fn); /* unlink and free message */ llist_del(&msg->list); msgb_free(msg); @@ -578,12 +586,13 @@ found_msg: return msg; } -static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) { struct msgb *msg; struct osmo_phsap_prim *l1sap; uint8_t chan_nr = trx_chan_desc[chan].chan_nr | tn; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); /* compose primitive */ msg = l1sap_msgb_alloc(l2_len); @@ -599,19 +608,20 @@ static int compose_ph_data_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, memcpy(msg->l2h, l2, l2_len); if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) - l1h->chan_states[tn][chan].lost = 0; + l1ts->chan_state[chan].lost = 0; /* forward primitive */ - l1sap_up(l1h->trx, l1sap); + l1sap_up(l1t->trx, l1sap); return 0; } -static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len) { struct msgb *msg; struct osmo_phsap_prim *l1sap; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); /* compose primitive */ msg = l1sap_msgb_alloc(tch_len); @@ -624,20 +634,22 @@ static int compose_tch_ind(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if (tch_len) memcpy(msg->l2h, tch, tch_len); - if (l1h->chan_states[tn][chan].lost) - l1h->chan_states[tn][chan].lost--; + if (l1ts->chan_state[chan].lost) + l1ts->chan_state[chan].lost--; /* forward primitive */ - l1sap_up(l1h->trx, l1sap); + l1sap_up(l1t->trx, l1sap); return 0; } -static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; struct msgb *msg = NULL; /* make GCC happy */ - ubit_t *burst, **bursts_p = &l1h->chan_states[tn][chan].dl_bursts; + ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; static ubit_t bits[148]; /* send burst, if we already got a frame */ @@ -648,13 +660,13 @@ static ubit_t *tx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, } /* get mac block from queue */ - msg = dequeue_prim(l1h, tn, fn, chan); + msg = dequeue_prim(l1t, tn, fn, chan); if (msg) goto got_msg; LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1h->trx->nr, tn, fn); + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); no_msg: /* free burst memory */ @@ -677,15 +689,15 @@ got_msg: /* handle loss detection of sacch */ if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { /* count and send BFI */ - if (++(l1h->chan_states[tn][chan].lost) > 1) { + if (++(l1ts->chan_state[chan].lost) > 1) { /* TODO: Should we pass old TOA here? Otherwise we risk * unnecessary decreasing TA */ /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, 456, 456, -110, 0); - compose_ph_data_ind(l1h, tn, 0, chan, NULL, 0, -110); + compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110); } } @@ -707,21 +719,23 @@ send_burst: burst = *bursts_p + bid * 116; memset(bits, 0, 3); memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[l1h->config.tsc], 26); + memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); memcpy(bits + 87, burst + 58, 58); memset(bits + 145, 0, 3); LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); return bits; } -static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; struct msgb *msg = NULL; /* make GCC happy */ - ubit_t *burst, **bursts_p = &l1h->chan_states[tn][chan].dl_bursts; + ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; static ubit_t bits[148]; int rc; @@ -733,13 +747,13 @@ static ubit_t *tx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, } /* get mac block from queue */ - msg = dequeue_prim(l1h, tn, fn, chan); + msg = dequeue_prim(l1t, tn, fn, chan); if (msg) goto got_msg; LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1h->trx->nr, tn, fn); + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); no_msg: /* free burst memory */ @@ -777,29 +791,30 @@ send_burst: burst = *bursts_p + bid * 116; memset(bits, 0, 3); memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[l1h->config.tsc], 26); + memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); memcpy(bits + 87, burst + 58, 58); memset(bits + 145, 0, 3); LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); return bits; } -static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch, struct msgb **_msg_facch, int codec_mode_request) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; uint8_t rsl_cmode = chan_state->rsl_cmode; uint8_t tch_mode = chan_state->tch_mode; struct osmo_phsap_prim *l1sap; /* handle loss detection of received TCH frames */ if (rsl_cmode == RSL_CMOD_SPD_SPEECH - && ++(l1h->chan_states[tn][chan].lost) > 5) { + && ++(chan_state->lost) > 5) { uint8_t tch_data[GSM_FR_BYTES]; int len; @@ -831,7 +846,7 @@ static void tx_tch_common(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if (len < 2) break; memset(tch_data + 2, 0, len - 2); - compose_tch_ind(l1h, tn, 0, chan, tch_data, len); + compose_tch_ind(l1t, tn, 0, chan, tch_data, len); break; default: inval_mode1: @@ -840,12 +855,12 @@ inval_mode1: len = 0; } if (len) - compose_tch_ind(l1h, tn, 0, chan, tch_data, len); + compose_tch_ind(l1t, tn, 0, chan, tch_data, len); } /* get frame and unlink from queue */ - msg1 = dequeue_prim(l1h, tn, fn, chan); - msg2 = dequeue_prim(l1h, tn, fn, chan); + msg1 = dequeue_prim(l1t, tn, fn, chan); + msg2 = dequeue_prim(l1t, tn, fn, chan); if (msg1) { l1sap = msgb_l1sap_prim(msg1); if (l1sap->oph.primitive == PRIM_TCH) { @@ -898,7 +913,7 @@ inval_mode1: LOGP(DL1C, LOGL_NOTICE, "%s Dropping speech frame, " "because we are not in speech mode trx=%u " "ts=%u at fn=%u.\n", trx_chan_desc[chan].name, - l1h->trx->nr, tn, fn); + l1t->trx->nr, tn, fn); goto free_bad_msg; } @@ -913,7 +928,7 @@ inval_mode1: "HR frame' trx=%u ts=%u at " "fn=%u.\n", trx_chan_desc[chan].name, - l1h->trx->nr, tn, fn); + l1t->trx->nr, tn, fn); goto free_bad_msg; } break; @@ -924,7 +939,7 @@ inval_mode1: LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " "FR frame' trx=%u ts=%u at fn=%u.\n", trx_chan_desc[chan].name, - l1h->trx->nr, tn, fn); + l1t->trx->nr, tn, fn); goto free_bad_msg; } break; @@ -937,7 +952,7 @@ inval_mode1: LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " "EFR frame' trx=%u ts=%u at fn=%u.\n", trx_chan_desc[chan].name, - l1h->trx->nr, tn, fn); + l1t->trx->nr, tn, fn); goto free_bad_msg; } break; @@ -966,7 +981,7 @@ inval_mode1: " of RTP frame not in list. " "trx=%u ts=%u\n", trx_chan_desc[chan].name, ft_codec, - l1h->trx->nr, tn); + l1t->trx->nr, tn); goto free_bad_msg; } if (codec_mode_request && chan_state->dl_ft != ft) { @@ -974,7 +989,7 @@ inval_mode1: " of RTP cannot be changed now, but in " "next frame. trx=%u ts=%u\n", trx_chan_desc[chan].name, ft_codec, - l1h->trx->nr, tn); + l1t->trx->nr, tn); goto free_bad_msg; } chan_state->dl_ft = ft; @@ -982,7 +997,7 @@ inval_mode1: LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " "AMR frame' trx=%u ts=%u at fn=%u.\n", trx_chan_desc[chan].name, - l1h->trx->nr, tn, fn); + l1t->trx->nr, tn, fn); goto free_bad_msg; } break; @@ -1014,11 +1029,13 @@ send_frame: *_msg_facch = msg_facch; } -static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { struct msgb *msg_tch = NULL, *msg_facch = NULL; - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; uint8_t tch_mode = chan_state->tch_mode; ubit_t *burst, **bursts_p = &chan_state->dl_bursts; static ubit_t bits[148]; @@ -1030,7 +1047,7 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, goto send_burst; } - tx_tch_common(l1h, tn, fn, chan, bid, &msg_tch, &msg_facch, + tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, (((fn + 4) % 26) >> 2) & 1); /* alloc burst memory, if not already, @@ -1048,7 +1065,7 @@ static ubit_t *tx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if (!msg_tch && !msg_facch) { LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1h->trx->nr, tn, fn); + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); goto send_burst; } @@ -1079,21 +1096,23 @@ send_burst: burst = *bursts_p + bid * 116; memset(bits, 0, 3); memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[l1h->config.tsc], 26); + memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); memcpy(bits + 87, burst + 58, 58); memset(bits + 145, 0, 3); LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); return bits; } -static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid) { struct msgb *msg_tch = NULL, *msg_facch = NULL; - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; uint8_t tch_mode = chan_state->tch_mode; ubit_t *burst, **bursts_p = &chan_state->dl_bursts; static ubit_t bits[148]; @@ -1106,7 +1125,7 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, } /* get TCH and/or FACCH */ - tx_tch_common(l1h, tn, fn, chan, bid, &msg_tch, &msg_facch, + tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, (((fn + 4) % 26) >> 2) & 1); /* check for FACCH alignment */ @@ -1138,7 +1157,7 @@ static ubit_t *tx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) { LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1h->trx->nr, tn, fn); + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); goto send_burst; } @@ -1171,12 +1190,12 @@ send_burst: burst = *bursts_p + bid * 116; memset(bits, 0, 3); memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[l1h->config.tsc], 26); + memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); memcpy(bits + 87, burst + 58, 58); memset(bits + 145, 0, 3); LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); return bits; } @@ -1186,7 +1205,7 @@ send_burst: * RX on uplink (indication to upper layer) */ -static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa) { @@ -1201,7 +1220,7 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, trx_chan_desc[chan].name, fn, toa); /* decode */ - rc = rach_decode(&ra, bits + 8 + 41, l1h->trx->bts->bsic); + rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic); if (rc) { LOGP(DL1C, LOGL_NOTICE, "Received bad AB frame at fn=%u " "(%u/51)\n", fn, fn % 51); @@ -1223,17 +1242,18 @@ static int rx_rach_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, l1sap.u.rach_ind.fn = fn; /* forward primitive */ - l1sap_up(l1h->trx, &l1sap); + l1sap_up(l1t->trx, &l1sap); return 0; } /*! \brief a single burst was received by the PHY, process it */ -static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa) { - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint32_t *first_fn = &chan_state->ul_first_fn; uint8_t *mask = &chan_state->ul_mask; @@ -1247,10 +1267,10 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* handle rach, if handover rach detection is turned on */ if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa); + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); LOGP(DL1C, LOGL_DEBUG, "Data received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); /* alloc burst memory, if not already */ if (!*bursts_p) { @@ -1284,7 +1304,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* send burst information to loops process */ if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { - trx_loop_sacch_input(l1h, trx_chan_desc[chan].chan_nr | tn, + trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | tn, chan_state, rssi, toa); } @@ -1296,7 +1316,7 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if ((*mask & 0xf) != 0xf) { LOGP(DL1C, LOGL_NOTICE, "Received incomplete data frame at " "fn=%u (%u/%u) for %s\n", *first_fn, - (*first_fn) % l1h->mf_period[tn], l1h->mf_period[tn], + (*first_fn) % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); /* we require first burst to have correct FN */ @@ -1312,24 +1332,25 @@ static int rx_data_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if (rc) { LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u " "(%u/%u) for %s\n", *first_fn, - (*first_fn) % l1h->mf_period[tn], l1h->mf_period[tn], + (*first_fn) % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); l2_len = 0; } else l2_len = GSM_MACBLOCK_LEN; /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); - return compose_ph_data_ind(l1h, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num); + return compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num); } -static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa) { - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint8_t *mask = &chan_state->ul_mask; float *rssi_sum = &chan_state->rssi_sum; @@ -1341,7 +1362,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, int rc; LOGP(DL1C, LOGL_DEBUG, "PDTCH received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); /* alloc burst memory, if not already */ if (!*bursts_p) { @@ -1380,7 +1401,7 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if ((*mask & 0xf) != 0xf) { LOGP(DL1C, LOGL_NOTICE, "Received incomplete PDTCH block " "ending at fn=%u (%u/%u) for %s\n", fn, - fn % l1h->mf_period[tn], l1h->mf_period[tn], + fn % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); } *mask = 0x0; @@ -1389,27 +1410,28 @@ static int rx_pdtch_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total); /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); if (rc <= 0) { LOGP(DL1C, LOGL_NOTICE, "Received bad PDTCH block ending at " - "fn=%u (%u/%u) for %s\n", fn, fn % l1h->mf_period[tn], - l1h->mf_period[tn], trx_chan_desc[chan].name); + "fn=%u (%u/%u) for %s\n", fn, fn % l1ts->mf_period, + l1ts->mf_period, trx_chan_desc[chan].name); return 0; } l2[0] = 7; /* valid frame */ - return compose_ph_data_ind(l1h, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, + return compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, l2, rc + 1, *rssi_sum / *rssi_num); } -static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa) { - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint8_t *mask = &chan_state->ul_mask; uint8_t rsl_cmode = chan_state->rsl_cmode; @@ -1420,10 +1442,10 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* handle rach, if handover rach detection is turned on */ if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa); + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); LOGP(DL1C, LOGL_DEBUG, "TCH/F received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); /* alloc burst memory, if not already */ if (!*bursts_p) { @@ -1454,7 +1476,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if ((*mask & 0xf) != 0xf) { LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " "at fn=%u (%u/%u) for %s\n", fn, - fn % l1h->mf_period[tn], l1h->mf_period[tn], + fn % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); } *mask = 0x0; @@ -1479,7 +1501,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, chan_state->codecs, &chan_state->ul_ft, &chan_state->ul_cmr, &n_errors, &n_bits_total); if (rc) - trx_loop_amr_input(l1h, + trx_loop_amr_input(l1t, trx_chan_desc[chan].chan_nr | tn, chan_state, (float)n_errors/(float)n_bits_total); amr = 2; /* we store tch_data + 2 header bytes */ @@ -1498,7 +1520,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, memcpy(*bursts_p, *bursts_p + 464, 464); /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, n_errors, n_bits_total, rssi, toa); /* Check if the frame is bad */ @@ -1516,7 +1538,7 @@ static int rx_tchf_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { - compose_ph_data_ind(l1h, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, + compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, tch_data + amr, GSM_MACBLOCK_LEN, rssi); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { @@ -1551,15 +1573,16 @@ bfi: return 0; /* TCH or BFI */ - return compose_tch_ind(l1h, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, + return compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, tch_data, rc); } -static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa) { - struct trx_chan_state *chan_state = &l1h->chan_states[tn][chan]; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; sbit_t *burst, **bursts_p = &chan_state->ul_bursts; uint8_t *mask = &chan_state->ul_mask; uint8_t rsl_cmode = chan_state->rsl_cmode; @@ -1570,10 +1593,10 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* handle rach, if handover rach detection is turned on */ if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1h, tn, fn, chan, bid, bits, rssi, toa); + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); LOGP(DL1C, LOGL_DEBUG, "TCH/H received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1h->trx->nr, bid); + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); /* alloc burst memory, if not already */ if (!*bursts_p) { @@ -1604,7 +1627,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, if ((*mask & 0x3) != 0x3) { LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " "at fn=%u (%u/%u) for %s\n", fn, - fn % l1h->mf_period[tn], l1h->mf_period[tn], + fn % l1ts->mf_period, l1ts->mf_period, trx_chan_desc[chan].name); } *mask = 0x0; @@ -1641,7 +1664,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, chan_state->codecs, &chan_state->ul_ft, &chan_state->ul_cmr, &n_errors, &n_bits_total); if (rc) - trx_loop_amr_input(l1h, + trx_loop_amr_input(l1t, trx_chan_desc[chan].chan_nr | tn, chan_state, (float)n_errors/(float)n_bits_total); amr = 2; /* we store tch_data + 2 two */ @@ -1661,7 +1684,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, memcpy(*bursts_p + 232, *bursts_p + 464, 232); /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1h->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, n_errors, n_bits_total, rssi, toa); /* Check if the frame is bad */ @@ -1680,7 +1703,7 @@ static int rx_tchh_fn(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { chan_state->ul_ongoing_facch = 1; - compose_ph_data_ind(l1h, tn, + compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, tch_data + amr, GSM_MACBLOCK_LEN, rssi); bfi: @@ -1718,7 +1741,7 @@ bfi: * with the slot 12, so an extra FN must be substracted to get correct * start of frame. */ - return compose_tch_ind(l1h, tn, + return compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME, chan, tch_data, rc); } @@ -2487,61 +2510,59 @@ static const struct trx_sched_multiframe trx_sched_multiframes[] = { */ /* set multiframe scheduler to given pchan */ -int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn, +int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, enum gsm_phys_chan_config pchan) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); int i; - /* ignore disabled slots */ - if (!(l1h->config.slotmask & (1 << tn))) - return -ENOTSUP; - for (i = 0; i < ARRAY_SIZE(trx_sched_multiframes); i++) { if (trx_sched_multiframes[i].pchan == pchan && (trx_sched_multiframes[i].slotmask & (1 << tn))) { - l1h->mf_index[tn] = i; - l1h->mf_period[tn] = trx_sched_multiframes[i].period; - l1h->mf_frames[tn] = trx_sched_multiframes[i].frames; + l1ts->mf_index = i; + l1ts->mf_period = trx_sched_multiframes[i].period; + l1ts->mf_frames = trx_sched_multiframes[i].frames; LOGP(DL1C, LOGL_NOTICE, "Configuring multiframe with " "%s trx=%d ts=%d\n", trx_sched_multiframes[i].name, - l1h->trx->nr, tn); + l1t->trx->nr, tn); return 0; } } LOGP(DL1C, LOGL_NOTICE, "Failed to configuring multiframe " - "trx=%d ts=%d\n", l1h->trx->nr, tn); + "trx=%d ts=%d\n", l1t->trx->nr, tn); return -ENOTSUP; } /* setting all logical channels given attributes to active/inactive */ -int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id, +int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, int active) { uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); uint8_t ss = l1sap_chan2ss(chan_nr); int i; int rc = -EINVAL; - struct trx_chan_state *chan_state; /* look for all matching chan_nr/link_id */ for (i = 0; i < _TRX_CHAN_MAX; i++) { + struct l1sched_chan_state *chan_state; + chan_state = &l1ts->chan_state[i]; /* skip if pchan type does not match pdch flag */ - if ((trx_sched_multiframes[l1h->mf_index[tn]].pchan + if ((trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) != trx_chan_desc[i].pdch) continue; if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8) && trx_chan_desc[i].link_id == link_id) { - chan_state = &l1h->chan_states[tn][i]; rc = 0; if (chan_state->active == active) continue; LOGP(DL1C, LOGL_NOTICE, "%s %s on trx=%d ts=%d\n", (active) ? "Activating" : "Deactivating", - trx_chan_desc[i].name, l1h->trx->nr, tn); + trx_chan_desc[i].name, l1t->trx->nr, tn); if (active) memset(chan_state, 0, sizeof(*chan_state)); chan_state->active = active; @@ -2554,12 +2575,14 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id, talloc_free(chan_state->ul_bursts); chan_state->ul_bursts = NULL; } + if (!active) + chan_state->ho_rach_detect = 0; } } /* disable handover detection (on deactivation) */ - if (l1h->ho_rach_detect[tn][ss]) { - l1h->ho_rach_detect[tn][ss] = 0; + if (!active) { + struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); trx_if_cmd_nohandover(l1h, tn, ss); } @@ -2567,28 +2590,30 @@ int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id, } /* setting all logical channels given attributes to active/inactive */ -int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode, +int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, uint8_t codec2, uint8_t codec3, uint8_t initial_id, uint8_t handover) { uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); uint8_t ss = l1sap_chan2ss(chan_nr); int i; int rc = -EINVAL; - struct trx_chan_state *chan_state; + struct l1sched_chan_state *chan_state; /* no mode for PDCH */ - if (trx_sched_multiframes[l1h->mf_index[tn]].pchan == GSM_PCHAN_PDCH) + if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) return 0; /* 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) && trx_chan_desc[i].link_id == 0x00) { - chan_state = &l1h->chan_states[tn][i]; + chan_state = &l1ts->chan_state[i]; LOGP(DL1C, LOGL_NOTICE, "Set mode %u, %u, handover %u " "on %s of trx=%d ts=%d\n", rsl_cmode, tch_mode, - handover, trx_chan_desc[i].name, l1h->trx->nr, + handover, trx_chan_desc[i].name, l1t->trx->nr, tn); chan_state->rsl_cmode = rsl_cmode; chan_state->tch_mode = tch_mode; @@ -2617,10 +2642,8 @@ int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode, * disable handover, if state is still set, since we might not know * the actual state of transceiver (due to loss of link) */ if (handover) { - l1h->ho_rach_detect[tn][ss] = 1; trx_if_cmd_handover(l1h, tn, ss); - } else if (l1h->ho_rach_detect[tn][ss]) { - l1h->ho_rach_detect[tn][ss] = 0; + } else { trx_if_cmd_nohandover(l1h, tn, ss); } @@ -2628,16 +2651,17 @@ int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode, } /* setting cipher on logical channels */ -int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink, +int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, int algo, uint8_t *key, int key_len) { uint8_t tn = L1SAP_CHAN2TS(chan_nr); + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); int i; int rc = -EINVAL; - struct trx_chan_state *chan_state; + struct l1sched_chan_state *chan_state; /* no cipher for PDCH */ - if (trx_sched_multiframes[l1h->mf_index[tn]].pchan == GSM_PCHAN_PDCH) + if (trx_sched_multiframes[l1ts->mf_index].pchan == GSM_PCHAN_PDCH) return 0; /* no algorithm given means a5/0 */ @@ -2655,11 +2679,11 @@ int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink, if (trx_chan_desc[i].pdch) continue; if (trx_chan_desc[i].chan_nr == (chan_nr & 0xf8)) { - chan_state = &l1h->chan_states[tn][i]; + chan_state = &l1ts->chan_state[i]; LOGP(DL1C, LOGL_NOTICE, "Set a5/%d %s for %s on trx=%d " "ts=%d\n", algo, (downlink) ? "downlink" : "uplink", - trx_chan_desc[i].name, l1h->trx->nr, tn); + trx_chan_desc[i].name, l1t->trx->nr, tn); if (downlink) { chan_state->dl_encr_algo = algo; memcpy(chan_state->dl_encr_key, key, key_len); @@ -2677,21 +2701,22 @@ int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink, } /* process ready-to-send */ -static int trx_sched_rts(struct trx_l1h *l1h, uint8_t tn, uint32_t fn) +static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); const struct trx_sched_frame *frame; uint8_t offset, period, bid; trx_sched_rts_func *func; enum trx_chan_type chan; /* no multiframe set */ - if (!l1h->mf_index[tn]) + if (!l1ts->mf_index) return 0; /* get frame from multiframe */ - period = l1h->mf_period[tn]; + period = l1ts->mf_period; offset = fn % period; - frame = l1h->mf_frames[tn] + offset; + frame = l1ts->mf_frames + offset; chan = frame->dl_chan; bid = frame->dl_bid; @@ -2707,49 +2732,51 @@ static int trx_sched_rts(struct trx_l1h *l1h, uint8_t tn, uint32_t fn) /* check if channel is active */ if (!trx_chan_desc[chan].auto_active - && !l1h->chan_states[tn][chan].active) + && !l1ts->chan_state[chan].active) return -EINVAL; - return func(l1h, tn, fn, frame->dl_chan); + return func(l1t, tn, fn, frame->dl_chan); } /* process downlink burst */ -static const ubit_t *trx_sched_dl_burst(struct trx_l1h *l1h, uint8_t tn, +static const ubit_t *trx_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *l1cs; const struct trx_sched_frame *frame; uint8_t offset, period, bid; trx_sched_dl_func *func; enum trx_chan_type chan; ubit_t *bits = NULL; - if (!l1h->mf_index[tn]) + if (!l1ts->mf_index) goto no_data; /* get frame from multiframe */ - period = l1h->mf_period[tn]; + period = l1ts->mf_period; offset = fn % period; - frame = l1h->mf_frames[tn] + offset; + frame = l1ts->mf_frames + offset; chan = frame->dl_chan; bid = frame->dl_bid; func = trx_chan_desc[chan].dl_fn; + l1cs = &l1ts->chan_state[chan]; + /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active - && !l1h->chan_states[tn][chan].active) + if (!trx_chan_desc[chan].auto_active && !l1cs->active) goto no_data; /* get burst from function */ - bits = func(l1h, tn, fn, chan, bid); + bits = func(l1t, tn, fn, chan, bid); /* encrypt */ - if (bits && l1h->chan_states[tn][chan].dl_encr_algo) { + if (bits && l1cs->dl_encr_algo) { ubit_t ks[114]; int i; - osmo_a5(l1h->chan_states[tn][chan].dl_encr_algo, - l1h->chan_states[tn][chan].dl_encr_key, fn, ks, NULL); + osmo_a5(l1cs->dl_encr_algo, l1cs->dl_encr_key, fn, ks, NULL); for (i = 0; i < 57; i++) { bits[i + 3] ^= ks[i]; bits[i + 88] ^= ks[i + 57]; @@ -2758,7 +2785,7 @@ static const ubit_t *trx_sched_dl_burst(struct trx_l1h *l1h, uint8_t tn, no_data: /* in case of C0, we need a dummy burst to maintain RF power */ - if (bits == NULL && l1h->trx == l1h->trx->bts->c0) { + if (bits == NULL && l1t->trx == l1t->trx->bts->c0) { if (0) if (chan != TRXC_IDLE) // hack LOGP(DL1C, LOGL_DEBUG, "No burst data for %s fn=%u ts=%u " "burst=%d on C0, so filling with dummy burst\n", @@ -2770,41 +2797,44 @@ if (0) if (chan != TRXC_IDLE) // hack } /* process uplink burst */ -int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn, +int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t current_fn, sbit_t *bits, int8_t rssi, float toa) { + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *l1cs; const struct trx_sched_frame *frame; uint8_t offset, period, bid; trx_sched_ul_func *func; enum trx_chan_type chan; uint32_t fn, elapsed; - if (!l1h->mf_index[tn]) + if (!l1ts->mf_index) return -EINVAL; /* calculate how many frames have been elapsed */ - elapsed = (current_fn + GSM_HYPERFRAME - l1h->mf_last_fn[tn]) % GSM_HYPERFRAME; + elapsed = (current_fn + GSM_HYPERFRAME - l1ts->mf_last_fn) % GSM_HYPERFRAME; /* start counting from last fn + 1, but only if not too many fn have * been elapsed */ if (elapsed < 10) - fn = (l1h->mf_last_fn[tn] + 1) % GSM_HYPERFRAME; + fn = (l1ts->mf_last_fn + 1) % GSM_HYPERFRAME; else fn = current_fn; while (42) { /* get frame from multiframe */ - period = l1h->mf_period[tn]; + period = l1ts->mf_period; offset = fn % period; - frame = l1h->mf_frames[tn] + offset; + frame = l1ts->mf_frames + offset; chan = frame->ul_chan; bid = frame->ul_bid; func = trx_chan_desc[chan].ul_fn; + l1cs = &l1ts->chan_state[chan]; + /* check if channel is active */ - if (!trx_chan_desc[chan].auto_active - && !l1h->chan_states[tn][chan].active) + if (!trx_chan_desc[chan].auto_active && !l1cs->active) goto next_frame; /* omit bursts which have no handler, like IDLE bursts */ @@ -2814,12 +2844,12 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn, /* put burst to function */ if (fn == current_fn) { /* decrypt */ - if (bits && l1h->chan_states[tn][chan].ul_encr_algo) { + if (bits && l1cs->ul_encr_algo) { ubit_t ks[114]; int i; - osmo_a5(l1h->chan_states[tn][chan].ul_encr_algo, - l1h->chan_states[tn][chan].ul_encr_key, + osmo_a5(l1cs->ul_encr_algo, + l1cs->ul_encr_key, fn, NULL, ks); for (i = 0; i < 57; i++) { if (ks[i]) @@ -2829,13 +2859,12 @@ int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t current_fn, } } - func(l1h, tn, fn, chan, bid, bits, rssi, toa); - } else if (chan != TRXC_RACH - && !l1h->chan_states[tn][chan].ho_rach_detect) { + func(l1t, tn, fn, chan, bid, bits, rssi, toa); + } else if (chan != TRXC_RACH && !l1cs->ho_rach_detect) { sbit_t spare[148]; memset(spare, 0, 148); - func(l1h, tn, fn, chan, bid, spare, -128, 0); + func(l1t, tn, fn, chan, bid, spare, -128, 0); } next_frame: @@ -2846,7 +2875,7 @@ next_frame: fn = (fn + 1) % GSM_HYPERFRAME; } - l1h->mf_last_fn[tn] = fn; + l1ts->mf_last_fn = fn; return 0; } @@ -2855,7 +2884,6 @@ next_frame: static int trx_sched_fn(uint32_t fn) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t tn; const ubit_t *bits; uint8_t gain; @@ -2869,22 +2897,20 @@ static int trx_sched_fn(uint32_t fn) /* process every TRX */ llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct l1sched_trx *l1t = trx_l1sched_hdl(trx); /* we don't schedule, if power is off */ if (!l1h->config.poweron) continue; /* process every TS of TRX */ - for (tn = 0; tn < TRX_NR_TS; tn++) { - /* ignore disabled slots */ - if (!(l1h->config.slotmask & (1 << tn))) - continue; + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { /* ready-to-send */ - trx_sched_rts(l1h, tn, + trx_sched_rts(l1t, tn, (fn + trx_rts_advance) % GSM_HYPERFRAME); /* get burst for FN */ - bits = trx_sched_dl_burst(l1h, tn, fn); + bits = trx_sched_dl_burst(l1t, tn, fn); if (!bits) { /* if no bits, send no burst */ continue; @@ -2910,6 +2936,7 @@ extern int quit; /* this timer fires for every FN to be processed */ static void trx_ctrl_timer_cb(void *data) { + struct gsm_bts *bts = data; struct timeval tv_now, *tv_clock = &transceiver_clock_tv; int32_t elapsed; @@ -2926,7 +2953,7 @@ no_clock: /* close all logical channels and reset timeslots */ llist_for_each_entry(trx, &bts->trx_list, list) { trx_if_flush(trx_l1h_hdl(trx)); - trx_sched_reset(trx_l1h_hdl(trx)); + trx_sched_reset(trx_l1sched_hdl(trx)); if (trx->nr == 0) trx_if_cmd_poweroff(trx_l1h_hdl(trx)); } @@ -3061,3 +3088,8 @@ new_clock: return 0; } +struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn) +{ + OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts)); + return &l1t->ts[tn]; +} diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h index 3e30693..c153b9e 100644 --- a/src/osmo-bts-trx/scheduler.h +++ b/src/osmo-bts-trx/scheduler.h @@ -1,6 +1,129 @@ #ifndef TRX_SCHEDULER_H #define TRX_SCHEDULER_H +/* These types define the different channels on a multiframe. + * Each channel has queues and can be activated individually. + */ +enum trx_chan_type { + TRXC_IDLE = 0, + TRXC_FCCH, + TRXC_SCH, + TRXC_BCCH, + TRXC_RACH, + TRXC_CCCH, + TRXC_TCHF, + TRXC_TCHH_0, + TRXC_TCHH_1, + TRXC_SDCCH4_0, + TRXC_SDCCH4_1, + TRXC_SDCCH4_2, + TRXC_SDCCH4_3, + TRXC_SDCCH8_0, + TRXC_SDCCH8_1, + TRXC_SDCCH8_2, + TRXC_SDCCH8_3, + TRXC_SDCCH8_4, + TRXC_SDCCH8_5, + TRXC_SDCCH8_6, + TRXC_SDCCH8_7, + TRXC_SACCHTF, + TRXC_SACCHTH_0, + TRXC_SACCHTH_1, + TRXC_SACCH4_0, + TRXC_SACCH4_1, + TRXC_SACCH4_2, + TRXC_SACCH4_3, + TRXC_SACCH8_0, + TRXC_SACCH8_1, + TRXC_SACCH8_2, + TRXC_SACCH8_3, + TRXC_SACCH8_4, + TRXC_SACCH8_5, + TRXC_SACCH8_6, + TRXC_SACCH8_7, + TRXC_PDTCH, + TRXC_PTCCH, + _TRX_CHAN_MAX +}; + +/* States each channel on a multiframe */ +struct l1sched_chan_state { + /* scheduler */ + uint8_t active; /* Channel is active */ + ubit_t *dl_bursts; /* burst buffer for TX */ + sbit_t *ul_bursts; /* burst buffer for RX */ + uint32_t ul_first_fn; /* fn of first burst */ + uint8_t ul_mask; /* mask of received bursts */ + + /* RSSI / TOA */ + uint8_t rssi_num; /* number of RSSI values */ + float rssi_sum; /* sum of RSSI values */ + uint8_t toa_num; /* number of TOA values */ + float toa_sum; /* sum of TOA values */ + + /* loss detection */ + uint8_t lost; /* (SACCH) loss detection */ + + /* mode */ + uint8_t rsl_cmode, tch_mode; /* mode for TCH channels */ + + /* AMR */ + uint8_t codec[4]; /* 4 possible codecs for amr */ + int codecs; /* number of possible codecs */ + float ber_sum; /* sum of bit error rates */ + int ber_num; /* number of bit error rates */ + uint8_t ul_ft; /* current uplink FT index */ + uint8_t dl_ft; /* current downlink FT index */ + uint8_t ul_cmr; /* current uplink CMR index */ + uint8_t dl_cmr; /* current downlink CMR index */ + uint8_t amr_loop; /* if AMR loop is enabled */ + + /* TCH/H */ + uint8_t dl_ongoing_facch; /* FACCH/H on downlink */ + uint8_t ul_ongoing_facch; /* FACCH/H on uplink */ + + /* encryption */ + int ul_encr_algo; /* A5/x encry algo downlink */ + int dl_encr_algo; /* A5/x encry algo uplink */ + int ul_encr_key_len; + int dl_encr_key_len; + uint8_t ul_encr_key[MAX_A5_KEY_LEN]; + uint8_t dl_encr_key[MAX_A5_KEY_LEN]; + + /* measurements */ + struct { + uint8_t clock; /* cyclic clock counter */ + int8_t rssi[32]; /* last RSSI values */ + int rssi_count; /* received RSSI values */ + int rssi_valid_count; /* number of stored value */ + int rssi_got_burst; /* any burst received so far */ + float toa_sum; /* sum of TOA values */ + int toa_num; /* number of TOA value */ + } meas; + + /* handover */ + uint8_t ho_rach_detect; /* if rach detection is on */ +}; + +struct l1sched_ts { + uint8_t mf_index; /* selected multiframe index */ + uint32_t mf_last_fn; /* last received frame number */ + uint8_t mf_period; /* period of multiframe */ + const struct trx_sched_frame *mf_frames; /* pointer to frame layout */ + + struct llist_head dl_prims; /* Queue primitves for TX */ + + /* Channel states for all logical channels */ + struct l1sched_chan_state chan_state[_TRX_CHAN_MAX]; +}; + +struct l1sched_trx { + struct gsm_bts_trx *trx; + struct l1sched_ts ts[TRX_NR_TS]; +}; + +struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn); + /*! \brief how many frame numbers in advance we should send bursts to PHY */ extern uint32_t trx_clock_advance; /*! \brief advance RTS.ind to L2 by that many clocks */ @@ -10,43 +133,43 @@ extern uint32_t transceiver_last_fn; /*! \brief Initialize the scheudler data structures */ -int trx_sched_init(struct trx_l1h *l1h); +int trx_sched_init(struct l1sched_trx *l1t); /*! \brief De-initialize the scheudler data structures */ -void trx_sched_exit(struct trx_l1h *l1h); +void trx_sched_exit(struct l1sched_trx *l1t); /*! \brief Handle a PH-DATA.req from L2 down to L1 */ -int trx_sched_ph_data_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap); +int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); /*! \brief Handle a PH-TCH.req from L2 down to L1 */ -int trx_sched_tch_req(struct trx_l1h *l1h, struct osmo_phsap_prim *l1sap); +int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); /*! \brief PHY informs us of new (current) GSM freme nunmber */ int trx_sched_clock(uint32_t fn); /*! \brief handle an UL burst received by PHY */ -int trx_sched_ul_burst(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, +int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, sbit_t *bits, int8_t rssi, float toa); /*! \brief set multiframe scheduler to given physical channel config */ -int trx_sched_set_pchan(struct trx_l1h *l1h, uint8_t tn, +int trx_sched_set_pchan(struct l1sched_trx *l1t, uint8_t tn, enum gsm_phys_chan_config pchan); /*! \brief set all matching logical channels active/inactive */ -int trx_sched_set_lchan(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t link_id, +int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_id, int active); /*! \brief set mode of all matching logical channels to given mode(s) */ -int trx_sched_set_mode(struct trx_l1h *l1h, uint8_t chan_nr, uint8_t rsl_cmode, +int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmode, uint8_t tch_mode, int codecs, uint8_t codec0, uint8_t codec1, uint8_t codec2, uint8_t codec3, uint8_t initial_codec, uint8_t handover); /*! \brief set ciphering on given logical channels */ -int trx_sched_set_cipher(struct trx_l1h *l1h, uint8_t chan_nr, int downlink, +int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, int algo, uint8_t *key, int key_len); /* \brief close all logical channels and reset timeslots */ -void trx_sched_reset(struct trx_l1h *l1h); +void trx_sched_reset(struct l1sched_trx *l1t); #endif /* TRX_SCHEDULER_H */ diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index 419fea6..fef2064 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -454,7 +454,7 @@ static int trx_data_read_cb(struct osmo_fd *ofd, unsigned int what) fprintf(stderr, "%s\n", deb); #endif - trx_sched_ul_burst(l1h, tn, fn, bits, rssi, toa); + trx_sched_ul_burst(&l1h->l1s, tn, fn, bits, rssi, toa); return 0; } -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:04 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:04 +0100 Subject: [PATCH 5/7] TRX: scheduler: Move trx_sched_clock() to scheduler_trx.c In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-5-git-send-email-laforge@gnumonks.org> From: Harald Welte This funciton (and associated static functions) are TRX specific, and scheduler.c should only contain generic code. --- src/osmo-bts-trx/scheduler.c | 230 +---------------------------------- src/osmo-bts-trx/scheduler.h | 2 +- src/osmo-bts-trx/scheduler_backend.h | 2 + src/osmo-bts-trx/scheduler_trx.c | 220 +++++++++++++++++++++++++++++++++ src/osmo-bts-trx/trx_if.c | 5 +- 5 files changed, 229 insertions(+), 230 deletions(-) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index d4af2b7..10f8972 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -36,27 +36,12 @@ #include #include -#include "l1_if.h" #include "scheduler.h" #include "scheduler_backend.h" -#include "trx_if.h" +//#include "trx_if.h" extern void *tall_bts_ctx; -static struct gsm_bts *bts; - -/* clock states */ -static uint32_t transceiver_lost; -uint32_t transceiver_last_fn; -static struct timeval transceiver_clock_tv; -static struct osmo_timer_list transceiver_clock_timer; - -/* clock advance for the transceiver */ -uint32_t trx_clock_advance = 20; - -/* advance RTS to give some time for data processing. (especially PCU) */ -uint32_t trx_rts_advance = 5; /* about 20ms */ - static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -1460,7 +1445,7 @@ int trx_sched_set_cipher(struct l1sched_trx *l1t, uint8_t chan_nr, int downlink, } /* process ready-to-send */ -static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) +int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); const struct trx_sched_frame *frame; @@ -1498,8 +1483,7 @@ static int trx_sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) } /* process downlink burst */ -static const ubit_t *trx_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn) +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn) { struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); struct l1sched_chan_state *l1cs; @@ -1639,214 +1623,6 @@ next_frame: return 0; } -/* schedule all frames of all TRX for given FN */ -static int trx_sched_fn(uint32_t fn) -{ - struct gsm_bts_trx *trx; - uint8_t tn; - const ubit_t *bits; - uint8_t gain; - - /* send time indication */ - l1if_mph_time_ind(bts, fn); - - /* advance frame number, so the transceiver has more time until - * it must be transmitted. */ - fn = (fn + trx_clock_advance) % GSM_HYPERFRAME; - - /* process every TRX */ - llist_for_each_entry(trx, &bts->trx_list, list) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); - struct l1sched_trx *l1t = trx_l1sched_hdl(trx); - - /* we don't schedule, if power is off */ - if (!trx_if_powered(l1h)) - continue; - - /* process every TS of TRX */ - for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { - /* ready-to-send */ - trx_sched_rts(l1t, tn, - (fn + trx_rts_advance) % GSM_HYPERFRAME); - /* get burst for FN */ - bits = trx_sched_dl_burst(l1t, tn, fn); - if (!bits) { - /* if no bits, send no burst */ - continue; - } else - gain = 0; - trx_if_data(l1h, tn, fn, gain, bits); - } - } - - return 0; -} - - -/* - * frame clock - */ - -#define FRAME_DURATION_uS 4615 -#define MAX_FN_SKEW 50 -#define TRX_LOSS_FRAMES 400 - -extern int quit; -/* this timer fires for every FN to be processed */ -static void trx_ctrl_timer_cb(void *data) -{ - struct gsm_bts *bts = data; - struct timeval tv_now, *tv_clock = &transceiver_clock_tv; - int32_t elapsed; - - /* check if transceiver is still alive */ - if (transceiver_lost++ == TRX_LOSS_FRAMES) { - struct gsm_bts_trx *trx; - - LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n"); - -no_clock: - transceiver_available = 0; - - /* flush pending messages of transceiver */ - /* close all logical channels and reset timeslots */ - llist_for_each_entry(trx, &bts->trx_list, list) { - trx_if_flush(trx_l1h_hdl(trx)); - trx_sched_reset(trx_l1sched_hdl(trx)); - if (trx->nr == 0) - trx_if_cmd_poweroff(trx_l1h_hdl(trx)); - } - - /* tell BSC */ - check_transceiver_availability(bts, 0); - - return; - } - - gettimeofday(&tv_now, NULL); - - elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 - + (tv_now.tv_usec - tv_clock->tv_usec); - - /* if someone played with clock, or if the process stalled */ - if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) { - LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n", - elapsed); - goto no_clock; - } - - /* schedule next FN clock */ - while (elapsed > FRAME_DURATION_uS / 2) { - tv_clock->tv_usec += FRAME_DURATION_uS; - if (tv_clock->tv_usec >= 1000000) { - tv_clock->tv_sec++; - tv_clock->tv_usec -= 1000000; - } - transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; - trx_sched_fn(transceiver_last_fn); - elapsed -= FRAME_DURATION_uS; - } - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS - elapsed); -} - - -/* receive clock from transceiver */ -int trx_sched_clock(uint32_t fn) -{ - struct timeval tv_now, *tv_clock = &transceiver_clock_tv; - int32_t elapsed; - int32_t elapsed_fn; - - if (quit) - return 0; - - /* reset lost counter */ - transceiver_lost = 0; - - gettimeofday(&tv_now, NULL); - - /* clock becomes valid */ - if (!transceiver_available) { - LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", - fn); - - transceiver_available = 1; - - /* start provisioning transceiver */ - l1if_provision_transceiver(bts); - - /* tell BSC */ - check_transceiver_availability(bts, 1); - -new_clock: - transceiver_last_fn = fn; - trx_sched_fn(transceiver_last_fn); - - /* schedule first FN clock */ - memcpy(tv_clock, &tv_now, sizeof(struct timeval)); - memset(&transceiver_clock_timer, 0, - sizeof(transceiver_clock_timer)); - transceiver_clock_timer.cb = trx_ctrl_timer_cb; - transceiver_clock_timer.data = bts; - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS); - - return 0; - } - - osmo_timer_del(&transceiver_clock_timer); - - /* calculate elapsed time since last_fn */ - elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 - + (tv_now.tv_usec - tv_clock->tv_usec); - - /* how much frames have been elapsed since last fn processed */ - elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME; - if (elapsed_fn >= 135774) - elapsed_fn -= GSM_HYPERFRAME; - - /* check for max clock skew */ - if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) { - LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, " - "new fn=%u\n", transceiver_last_fn, fn); - goto new_clock; - } - - LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n", - elapsed_fn * FRAME_DURATION_uS - elapsed); - - /* too many frames have been processed already */ - if (elapsed_fn < 0) { - /* set clock to the time or last FN should have been - * transmitted. */ - tv_clock->tv_sec = tv_now.tv_sec; - tv_clock->tv_usec = tv_now.tv_usec + - (0 - elapsed_fn) * FRAME_DURATION_uS; - if (tv_clock->tv_usec >= 1000000) { - tv_clock->tv_sec++; - tv_clock->tv_usec -= 1000000; - } - /* set time to the time our next FN has to be transmitted */ - osmo_timer_schedule(&transceiver_clock_timer, 0, - FRAME_DURATION_uS * (1 - elapsed_fn)); - - return 0; - } - - /* transmit what we still need to transmit */ - while (fn != transceiver_last_fn) { - transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; - trx_sched_fn(transceiver_last_fn); - } - - /* schedule next FN to be transmitted */ - memcpy(tv_clock, &tv_now, sizeof(struct timeval)); - osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS); - - return 0; -} - struct l1sched_ts *l1sched_trx_get_ts(struct l1sched_trx *l1t, uint8_t tn) { OSMO_ASSERT(tn < ARRAY_SIZE(l1t->ts)); diff --git a/src/osmo-bts-trx/scheduler.h b/src/osmo-bts-trx/scheduler.h index c153b9e..13ef051 100644 --- a/src/osmo-bts-trx/scheduler.h +++ b/src/osmo-bts-trx/scheduler.h @@ -145,7 +145,7 @@ int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap); /*! \brief PHY informs us of new (current) GSM freme nunmber */ -int trx_sched_clock(uint32_t fn); +int trx_sched_clock(struct gsm_bts *bts, uint32_t fn); /*! \brief handle an UL burst received by PHY */ int trx_sched_ul_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h index ea3e620..b808455 100644 --- a/src/osmo-bts-trx/scheduler_backend.h +++ b/src/osmo-bts-trx/scheduler_backend.h @@ -77,3 +77,5 @@ int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, float toa); +const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); +int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index a77f5a5..0aeb835 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -49,6 +49,18 @@ extern void *tall_bts_ctx; +/* clock states */ +static uint32_t transceiver_lost; +uint32_t transceiver_last_fn; +static struct timeval transceiver_clock_tv; +static struct osmo_timer_list transceiver_clock_timer; + +/* clock advance for the transceiver */ +uint32_t trx_clock_advance = 20; + +/* advance RTS to give some time for data processing. (especially PCU) */ +uint32_t trx_rts_advance = 5; /* about 20ms */ + /* Enable this to multiply TOA of RACH by 10. * This is usefull to check tenth of timing advances with RSSI test tool. * Note that regular phones will not work when using this test! */ @@ -1238,3 +1250,211 @@ bfi: (fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME, chan, tch_data, rc); } + +/* schedule all frames of all TRX for given FN */ +static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) +{ + struct gsm_bts_trx *trx; + uint8_t tn; + const ubit_t *bits; + uint8_t gain; + + /* send time indication */ + l1if_mph_time_ind(bts, fn); + + /* advance frame number, so the transceiver has more time until + * it must be transmitted. */ + fn = (fn + trx_clock_advance) % GSM_HYPERFRAME; + + /* process every TRX */ + llist_for_each_entry(trx, &bts->trx_list, list) { + struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct l1sched_trx *l1t = trx_l1sched_hdl(trx); + + /* we don't schedule, if power is off */ + if (!trx_if_powered(l1h)) + continue; + + /* process every TS of TRX */ + for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { + /* ready-to-send */ + _sched_rts(l1t, tn, + (fn + trx_rts_advance) % GSM_HYPERFRAME); + /* get burst for FN */ + bits = _sched_dl_burst(l1t, tn, fn); + if (!bits) { + /* if no bits, send no burst */ + continue; + } else + gain = 0; + trx_if_data(l1h, tn, fn, gain, bits); + } + } + + return 0; +} + + +/* + * frame clock + */ + +#define FRAME_DURATION_uS 4615 +#define MAX_FN_SKEW 50 +#define TRX_LOSS_FRAMES 400 + +extern int quit; +/* this timer fires for every FN to be processed */ +static void trx_ctrl_timer_cb(void *data) +{ + struct gsm_bts *bts = data; + struct timeval tv_now, *tv_clock = &transceiver_clock_tv; + int32_t elapsed; + + /* check if transceiver is still alive */ + if (transceiver_lost++ == TRX_LOSS_FRAMES) { + struct gsm_bts_trx *trx; + + LOGP(DL1C, LOGL_NOTICE, "No more clock from transceiver\n"); + +no_clock: + transceiver_available = 0; + + /* flush pending messages of transceiver */ + /* close all logical channels and reset timeslots */ + llist_for_each_entry(trx, &bts->trx_list, list) { + trx_if_flush(trx_l1h_hdl(trx)); + trx_sched_reset(trx_l1sched_hdl(trx)); + if (trx->nr == 0) + trx_if_cmd_poweroff(trx_l1h_hdl(trx)); + } + + /* tell BSC */ + check_transceiver_availability(bts, 0); + + return; + } + + gettimeofday(&tv_now, NULL); + + elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 + + (tv_now.tv_usec - tv_clock->tv_usec); + + /* if someone played with clock, or if the process stalled */ + if (elapsed > FRAME_DURATION_uS * MAX_FN_SKEW || elapsed < 0) { + LOGP(DL1C, LOGL_NOTICE, "PC clock skew: elapsed uS %d\n", + elapsed); + goto no_clock; + } + + /* schedule next FN clock */ + while (elapsed > FRAME_DURATION_uS / 2) { + tv_clock->tv_usec += FRAME_DURATION_uS; + if (tv_clock->tv_usec >= 1000000) { + tv_clock->tv_sec++; + tv_clock->tv_usec -= 1000000; + } + transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; + trx_sched_fn(bts, transceiver_last_fn); + elapsed -= FRAME_DURATION_uS; + } + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS - elapsed); +} + + +/* receive clock from transceiver */ +int trx_sched_clock(struct gsm_bts *bts, uint32_t fn) +{ + struct timeval tv_now, *tv_clock = &transceiver_clock_tv; + int32_t elapsed; + int32_t elapsed_fn; + + if (quit) + return 0; + + /* reset lost counter */ + transceiver_lost = 0; + + gettimeofday(&tv_now, NULL); + + /* clock becomes valid */ + if (!transceiver_available) { + LOGP(DL1C, LOGL_NOTICE, "initial GSM clock received: fn=%u\n", + fn); + + transceiver_available = 1; + + /* start provisioning transceiver */ + l1if_provision_transceiver(bts); + + /* tell BSC */ + check_transceiver_availability(bts, 1); + +new_clock: + transceiver_last_fn = fn; + trx_sched_fn(bts, transceiver_last_fn); + + /* schedule first FN clock */ + memcpy(tv_clock, &tv_now, sizeof(struct timeval)); + memset(&transceiver_clock_timer, 0, + sizeof(transceiver_clock_timer)); + transceiver_clock_timer.cb = trx_ctrl_timer_cb; + transceiver_clock_timer.data = bts; + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS); + + return 0; + } + + osmo_timer_del(&transceiver_clock_timer); + + /* calculate elapsed time since last_fn */ + elapsed = (tv_now.tv_sec - tv_clock->tv_sec) * 1000000 + + (tv_now.tv_usec - tv_clock->tv_usec); + + /* how much frames have been elapsed since last fn processed */ + elapsed_fn = (fn + GSM_HYPERFRAME - transceiver_last_fn) % GSM_HYPERFRAME; + if (elapsed_fn >= 135774) + elapsed_fn -= GSM_HYPERFRAME; + + /* check for max clock skew */ + if (elapsed_fn > MAX_FN_SKEW || elapsed_fn < -MAX_FN_SKEW) { + LOGP(DL1C, LOGL_NOTICE, "GSM clock skew: old fn=%u, " + "new fn=%u\n", transceiver_last_fn, fn); + goto new_clock; + } + + LOGP(DL1C, LOGL_INFO, "GSM clock jitter: %d\n", + elapsed_fn * FRAME_DURATION_uS - elapsed); + + /* too many frames have been processed already */ + if (elapsed_fn < 0) { + /* set clock to the time or last FN should have been + * transmitted. */ + tv_clock->tv_sec = tv_now.tv_sec; + tv_clock->tv_usec = tv_now.tv_usec + + (0 - elapsed_fn) * FRAME_DURATION_uS; + if (tv_clock->tv_usec >= 1000000) { + tv_clock->tv_sec++; + tv_clock->tv_usec -= 1000000; + } + /* set time to the time our next FN has to be transmitted */ + osmo_timer_schedule(&transceiver_clock_timer, 0, + FRAME_DURATION_uS * (1 - elapsed_fn)); + + return 0; + } + + /* transmit what we still need to transmit */ + while (fn != transceiver_last_fn) { + transceiver_last_fn = (transceiver_last_fn + 1) % GSM_HYPERFRAME; + trx_sched_fn(bts, transceiver_last_fn); + } + + /* schedule next FN to be transmitted */ + memcpy(tv_clock, &tv_now, sizeof(struct timeval)); + osmo_timer_schedule(&transceiver_clock_timer, 0, FRAME_DURATION_uS); + + return 0; +} diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index 16c9fc7..c9cfaef 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -121,6 +121,7 @@ static struct osmo_fd trx_ofd_clk; /* get clock from clock socket */ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) { + struct trx_l1h *l1h = ofd->data; char buf[1500]; int len; uint32_t fn; @@ -145,7 +146,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) "correctly, correcting to fn=%u\n", fn); } - trx_sched_clock(fn); + trx_sched_clock(l1h->trx->bts, fn); return 0; } @@ -503,7 +504,7 @@ int trx_if_open(struct trx_l1h *l1h) /* open sockets */ if (l1h->trx->nr == 0) { - rc = trx_udp_open(NULL, &trx_ofd_clk, base_port_local, + rc = trx_udp_open(l1h, &trx_ofd_clk, base_port_local, trx_clk_read_cb); if (rc < 0) return rc; -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:01 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:01 +0100 Subject: [PATCH 2/7] TRX: split scheduler in generic part and backend part In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-2-git-send-email-laforge@gnumonks.org> From: Harald Welte the backend is performing the actual encoding and decoding functions, while the generic part constsits of the TDMA structures and generating the RTS.ind --- src/osmo-bts-trx/Makefile.am | 4 +- src/osmo-bts-trx/scheduler.c | 1485 +++------------------------------- src/osmo-bts-trx/scheduler_backend.h | 79 ++ src/osmo-bts-trx/scheduler_trx.c | 1234 ++++++++++++++++++++++++++++ 4 files changed, 1440 insertions(+), 1362 deletions(-) create mode 100644 src/osmo-bts-trx/scheduler_backend.h create mode 100644 src/osmo-bts-trx/scheduler_trx.c diff --git a/src/osmo-bts-trx/Makefile.am b/src/osmo-bts-trx/Makefile.am index 26bc8e2..1644af6 100644 --- a/src/osmo-bts-trx/Makefile.am +++ b/src/osmo-bts-trx/Makefile.am @@ -2,10 +2,10 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(OPENBSC_INCDIR) AM_CFLAGS = -Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODEC_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOTRAU_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(ORTP_CFLAGS) LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOTRAU_LIBS) $(LIBOSMOABIS_LIBS) $(LIBOSMOCTRL_LIBS) $(ORTP_LIBS) -EXTRA_DIST = trx_if.h l1_if.h scheduler.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h loops.h amr.h +EXTRA_DIST = trx_if.h l1_if.h scheduler.h scheduler_backend.h gsm0503_parity.h gsm0503_conv.h gsm0503_interleaving.h gsm0503_mapping.h gsm0503_coding.h gsm0503_tables.h loops.h amr.h bin_PROGRAMS = osmobts-trx -osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c loops.c amr.c +osmobts_trx_SOURCES = main.c trx_if.c l1_if.c scheduler.c scheduler_trx.c trx_vty.c gsm0503_parity.c gsm0503_conv.c gsm0503_interleaving.c gsm0503_mapping.c gsm0503_coding.c gsm0503_tables.c loops.c amr.c osmobts_trx_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index 6d0f180..c904e62 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -31,28 +31,18 @@ #include #include -#include - #include #include #include #include -#include #include "l1_if.h" #include "scheduler.h" -#include "gsm0503_coding.h" +#include "scheduler_backend.h" #include "trx_if.h" #include "loops.h" -#include "amr.h" -#include "loops.h" -/* Enable this to multiply TOA of RACH by 10. - * This is usefull to check tenth of timing advances with RSSI test tool. - * Note that regular phones will not work when using this test! */ -//#define TA_TEST - -void *tall_bts_ctx; +extern void *tall_bts_ctx; static struct gsm_bts *bts; @@ -68,50 +58,12 @@ uint32_t trx_clock_advance = 20; /* advance RTS to give some time for data processing. (especially PCU) */ uint32_t trx_rts_advance = 5; /* about 20ms */ -typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan); -typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn, - uint32_t fn, enum trx_chan_type chan, uint8_t bid); -typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); - static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan); -static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid); -static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); -static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa); - /*! \brief Dummy Burst (TS 05.02 Chapter 5.2.6) */ static const ubit_t dummy_burst[148] = { 0,0,0, @@ -124,7 +76,7 @@ static const ubit_t dummy_burst[148] = { }; /*! \brief FCCH Burst (TS 05.02 Chapter 5.2.4) */ -static const ubit_t fcch_burst[148] = { +const ubit_t _sched_fcch_burst[148] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -133,7 +85,7 @@ static const ubit_t fcch_burst[148] = { }; /*! \brief Training Sequences (TS 05.02 Chapter 5.2.3) */ -static const ubit_t tsc[8][26] = { +const ubit_t _sched_tsc[8][26] = { { 0,0,1,0,0,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,1,0,1,1,1, }, { 0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1, }, { 0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0, }, @@ -145,7 +97,7 @@ static const ubit_t tsc[8][26] = { }; /*! \brief SCH trainign sequence (TS 05.02 Chapter 5.2.5) */ -static const ubit_t sch_train[64] = { +const ubit_t _sched_sch_train[64] = { 1,0,1,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,1, 0,0,1,0,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,1,1,0,1,1, }; @@ -154,27 +106,7 @@ static const ubit_t sch_train[64] = { * subchannel description structure */ -struct trx_chan_desc { - /*! \brief Is this on a PDCH (PS) ? */ - int pdch; - /*! \brief TRX Channel Type */ - enum trx_chan_type chan; - /*! \brief Channel Number (like in RSL) */ - uint8_t chan_nr; - /*! \brief Link ID (like in RSL) */ - uint8_t link_id; - /*! \brief Human-readable name */ - const char *name; - /*! \brief function to call when we want to generate RTS.req to L2 */ - trx_sched_rts_func *rts_fn; - /*! \brief function to call when DATA.req received from L2 */ - trx_sched_dl_func *dl_fn; - /*! \brief function to call when burst received from PHY */ - trx_sched_ul_func *ul_fn; - /*! \breif is this channel automatically active at start? */ - int auto_active; -}; -static const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { +const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { { 0, TRXC_IDLE, 0, 0, "IDLE", NULL, tx_idle_fn, NULL, 1 }, { 0, TRXC_FCCH, 0, 0, "FCCH", NULL, tx_fcch_fn, NULL, 1 }, { 0, TRXC_SCH, 0, 0, "SCH", NULL, tx_sch_fn, NULL, 1 }, @@ -280,243 +212,8 @@ void trx_sched_reset(struct l1sched_trx *l1t) trx_sched_init(l1t); } - -/* - * data request (from upper layer) - */ - -int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) -{ - uint8_t tn = l1sap->u.data.chan_nr & 7; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x " - "fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr, - l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr); - - if (!l1sap->oph.msg) - abort(); - - /* ignore empty frame */ - if (!msgb_l2len(l1sap->oph.msg)) { - msgb_free(l1sap->oph.msg); - return 0; - } - - msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); - - return 0; -} - -int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) -{ - uint8_t tn = l1sap->u.tch.chan_nr & 7; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x " - "fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr, - l1sap->u.tch.fn, tn, l1t->trx->nr); - - if (!l1sap->oph.msg) - abort(); - - /* ignore empty frame */ - if (!msgb_l2len(l1sap->oph.msg)) { - msgb_free(l1sap->oph.msg); - return 0; - } - - msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); - - return 0; -} - - -/* - * ready-to-send indication (to upper layer) - */ - -/* RTS for data frame */ -static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - uint8_t chan_nr, link_id; - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - - /* get data for RTS indication */ - chan_nr = trx_chan_desc[chan].chan_nr | tn; - link_id = trx_chan_desc[chan].link_id; - - if (!chan_nr) { - LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " - "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); - return -ENODEV; - } - - LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x " - "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, link_id, fn, tn, l1t->trx->nr); - - /* send clock information to loops process */ - if (L1SAP_IS_LINK_SACCH(link_id)) - trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]); - - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.link_id = link_id; - l1sap->u.data.fn = fn; - - return l1sap_up(l1t->trx, l1sap); -} - -static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, int facch) -{ - uint8_t chan_nr, link_id; - struct msgb *msg; - struct osmo_phsap_prim *l1sap; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - int rc = 0; - - /* get data for RTS indication */ - chan_nr = trx_chan_desc[chan].chan_nr | tn; - link_id = trx_chan_desc[chan].link_id; - - if (!chan_nr) { - LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " - "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); - return -ENODEV; - } - - LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x " - "fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, - chan_nr, fn, tn, l1t->trx->nr); - - /* only send, if FACCH is selected */ - if (facch) { - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.data.chan_nr = chan_nr; - l1sap->u.data.link_id = link_id; - l1sap->u.data.fn = fn; - - rc = l1sap_up(l1t->trx, l1sap); - } - - /* dont send, if TCH is in signalling only mode */ - if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { - /* generate prim */ - msg = l1sap_msgb_alloc(200); - if (!msg) - return -ENOMEM; - l1sap = msgb_l1sap_prim(msg); - osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, - PRIM_OP_INDICATION, msg); - l1sap->u.tch.chan_nr = chan_nr; - l1sap->u.tch.fn = fn; - - return l1sap_up(l1t->trx, l1sap); - } - - return rc; -} - -/* RTS for full rate traffic frame */ -static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - /* TCH/F may include FACCH on every 4th burst */ - return rts_tch_common(l1t, tn, fn, chan, 1); -} - - -/* RTS for half rate traffic frame */ -static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan) -{ - /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */ - return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1); -} - - -/* - * TX on downlink - */ - -/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */ -static ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) -{ - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); - - return NULL; -} - -static ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) -{ - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); - - return (ubit_t *) fcch_burst; -} - -static ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) -{ - static ubit_t bits[148], burst[78]; - uint8_t sb_info[4]; - struct gsm_time t; - uint8_t t3p, bsic; - - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); - - /* create SB info from GSM time and BSIC */ - gsm_fn2gsmtime(&t, fn); - t3p = t.t3 / 10; - bsic = l1t->trx->bts->bsic; - sb_info[0] = - ((bsic & 0x3f) << 2) | - ((t.t1 & 0x600) >> 9); - sb_info[1] = - ((t.t1 & 0x1fe) >> 1); - sb_info[2] = - ((t.t1 & 0x001) << 7) | - ((t.t2 & 0x1f) << 2) | - ((t3p & 0x6) >> 1); - sb_info[3] = - (t3p & 0x1); - - /* encode bursts */ - sch_encode(burst, sb_info); - - /* compose burst */ - memset(bits, 0, 3); - memcpy(bits + 3, burst, 39); - memcpy(bits + 42, sch_train, 64); - memcpy(bits + 106, burst + 39, 39); - memset(bits + 145, 0, 3); - - return bits; -} - -static struct msgb *dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, - enum trx_chan_type chan) +struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, + enum trx_chan_type chan) { struct msgb *msg, *msg2; struct osmo_phsap_prim *l1sap; @@ -586,8 +283,8 @@ found_msg: return msg; } -static int compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) +int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) { struct msgb *msg; struct osmo_phsap_prim *l1sap; @@ -616,8 +313,8 @@ static int compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, return 0; } -static int compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len) +int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len) { struct msgb *msg; struct osmo_phsap_prim *l1sap; @@ -643,1110 +340,178 @@ static int compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, return 0; } -static ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; - struct msgb *msg = NULL; /* make GCC happy */ - ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; - static ubit_t bits[148]; - - /* send burst, if we already got a frame */ - if (bid > 0) { - if (!*bursts_p) - return NULL; - goto send_burst; - } - - /* get mac block from queue */ - msg = dequeue_prim(l1t, tn, fn, chan); - if (msg) - goto got_msg; - - LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " - "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); - -no_msg: - /* free burst memory */ - if (*bursts_p) { - talloc_free(*bursts_p); - *bursts_p = NULL; - } - return NULL; - -got_msg: - /* check validity of message */ - if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) { - LOGP(DL1C, LOGL_FATAL, "Prim not 23 bytes, please FIX! " - "(len=%d)\n", msgb_l2len(msg)); - /* free message */ - msgb_free(msg); - goto no_msg; - } - - /* handle loss detection of sacch */ - if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { - /* count and send BFI */ - if (++(l1ts->chan_state[chan].lost) > 1) { - /* TODO: Should we pass old TOA here? Otherwise we risk - * unnecessary decreasing TA */ - - /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, - 456, 456, -110, 0); - - compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110); - } - } - - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 464); - if (!*bursts_p) - return NULL; - } - - /* encode bursts */ - xcch_encode(*bursts_p, msg->l2h); - /* free message */ - msgb_free(msg); -send_burst: - /* compose burst */ - burst = *bursts_p + bid * 116; - memset(bits, 0, 3); - memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); - memcpy(bits + 87, burst + 58, 58); - memset(bits + 145, 0, 3); - - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - return bits; -} +/* + * data request (from upper layer) + */ -static ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) +int trx_sched_ph_data_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) { + uint8_t tn = l1sap->u.data.chan_nr & 7; struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; - struct msgb *msg = NULL; /* make GCC happy */ - ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; - static ubit_t bits[148]; - int rc; - - /* send burst, if we already got a frame */ - if (bid > 0) { - if (!*bursts_p) - return NULL; - goto send_burst; - } - - /* get mac block from queue */ - msg = dequeue_prim(l1t, tn, fn, chan); - if (msg) - goto got_msg; - - LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " - "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); - -no_msg: - /* free burst memory */ - if (*bursts_p) { - talloc_free(*bursts_p); - *bursts_p = NULL; - } - return NULL; -got_msg: - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 464); - if (!*bursts_p) - return NULL; - } + LOGP(DL1C, LOGL_INFO, "PH-DATA.req: chan_nr=0x%02x link_id=0x%02x " + "fn=%u ts=%u trx=%u\n", l1sap->u.data.chan_nr, + l1sap->u.data.link_id, l1sap->u.data.fn, tn, l1t->trx->nr); - /* encode bursts */ - rc = pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h); + if (!l1sap->oph.msg) + abort(); - /* check validity of message */ - if (rc) { - LOGP(DL1C, LOGL_FATAL, "Prim invalid length, please FIX! " - "(len=%d)\n", rc); - /* free message */ - msgb_free(msg); - goto no_msg; + /* ignore empty frame */ + if (!msgb_l2len(l1sap->oph.msg)) { + msgb_free(l1sap->oph.msg); + return 0; } - /* free message */ - msgb_free(msg); - -send_burst: - /* compose burst */ - burst = *bursts_p + bid * 116; - memset(bits, 0, 3); - memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); - memcpy(bits + 87, burst + 58, 58); - memset(bits + 145, 0, 3); - - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); - return bits; + return 0; } -static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch, - struct msgb **_msg_facch, int codec_mode_request) +int trx_sched_tch_req(struct l1sched_trx *l1t, struct osmo_phsap_prim *l1sap) { + uint8_t tn = l1sap->u.tch.chan_nr & 7; struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - uint8_t rsl_cmode = chan_state->rsl_cmode; - uint8_t tch_mode = chan_state->tch_mode; - struct osmo_phsap_prim *l1sap; - /* handle loss detection of received TCH frames */ - if (rsl_cmode == RSL_CMOD_SPD_SPEECH - && ++(chan_state->lost) > 5) { - uint8_t tch_data[GSM_FR_BYTES]; - int len; - - LOGP(DL1C, LOGL_NOTICE, "Missing TCH bursts detected, sending " - "BFI for %s\n", trx_chan_desc[chan].name); - - /* indicate bad frame */ - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (chan != TRXC_TCHF) { /* HR */ - tch_data[0] = 0x70; /* F = 0, FT = 111 */ - memset(tch_data + 1, 0, 14); - len = 15; - break; - } - memset(tch_data, 0, GSM_FR_BYTES); - len = GSM_FR_BYTES; - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (chan != TRXC_TCHF) - goto inval_mode1; - memset(tch_data, 0, GSM_EFR_BYTES); - len = GSM_EFR_BYTES; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - len = amr_compose_payload(tch_data, - chan_state->codec[chan_state->dl_cmr], - chan_state->codec[chan_state->dl_ft], 1); - if (len < 2) - break; - memset(tch_data + 2, 0, len - 2); - compose_tch_ind(l1t, tn, 0, chan, tch_data, len); - break; - default: -inval_mode1: - LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please " - "fix!\n"); - len = 0; - } - if (len) - compose_tch_ind(l1t, tn, 0, chan, tch_data, len); - } + LOGP(DL1C, LOGL_INFO, "TCH.req: chan_nr=0x%02x " + "fn=%u ts=%u trx=%u\n", l1sap->u.tch.chan_nr, + l1sap->u.tch.fn, tn, l1t->trx->nr); - /* get frame and unlink from queue */ - msg1 = dequeue_prim(l1t, tn, fn, chan); - msg2 = dequeue_prim(l1t, tn, fn, chan); - if (msg1) { - l1sap = msgb_l1sap_prim(msg1); - if (l1sap->oph.primitive == PRIM_TCH) { - msg_tch = msg1; - if (msg2) { - l1sap = msgb_l1sap_prim(msg2); - if (l1sap->oph.primitive == PRIM_TCH) { - LOGP(DL1C, LOGL_FATAL, "TCH twice, " - "please FIX! "); - msgb_free(msg2); - } else - msg_facch = msg2; - } - } else { - msg_facch = msg1; - if (msg2) { - l1sap = msgb_l1sap_prim(msg2); - if (l1sap->oph.primitive != PRIM_TCH) { - LOGP(DL1C, LOGL_FATAL, "FACCH twice, " - "please FIX! "); - msgb_free(msg2); - } else - msg_tch = msg2; - } - } - } else if (msg2) { - l1sap = msgb_l1sap_prim(msg2); - if (l1sap->oph.primitive == PRIM_TCH) - msg_tch = msg2; - else - msg_facch = msg2; - } + if (!l1sap->oph.msg) + abort(); - /* check validity of message */ - if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) { - LOGP(DL1C, LOGL_FATAL, "Prim not 23 bytes, please FIX! " - "(len=%d)\n", msgb_l2len(msg_facch)); - /* free message */ - msgb_free(msg_facch); - msg_facch = NULL; + /* ignore empty frame */ + if (!msgb_l2len(l1sap->oph.msg)) { + msgb_free(l1sap->oph.msg); + return 0; } - /* check validity of message, get AMR ft and cmr */ - if (!msg_facch && msg_tch) { - int len; - uint8_t bfi, cmr_codec, ft_codec; - int cmr, ft, i; - - if (rsl_cmode != RSL_CMOD_SPD_SPEECH) { - LOGP(DL1C, LOGL_NOTICE, "%s Dropping speech frame, " - "because we are not in speech mode trx=%u " - "ts=%u at fn=%u.\n", trx_chan_desc[chan].name, - l1t->trx->nr, tn, fn); - goto free_bad_msg; - } - - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR / HR */ - if (chan != TRXC_TCHF) { /* HR */ - len = 15; - if (msgb_l2len(msg_tch) >= 1 - && (msg_tch->l2h[0] & 0xf0) != 0x00) { - LOGP(DL1C, LOGL_NOTICE, "%s " - "Transmitting 'bad " - "HR frame' trx=%u ts=%u at " - "fn=%u.\n", - trx_chan_desc[chan].name, - l1t->trx->nr, tn, fn); - goto free_bad_msg; - } - break; - } - len = GSM_FR_BYTES; - if (msgb_l2len(msg_tch) >= 1 - && (msg_tch->l2h[0] >> 4) != 0xd) { - LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " - "FR frame' trx=%u ts=%u at fn=%u.\n", - trx_chan_desc[chan].name, - l1t->trx->nr, tn, fn); - goto free_bad_msg; - } - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - if (chan != TRXC_TCHF) - goto inval_mode2; - len = GSM_EFR_BYTES; - if (msgb_l2len(msg_tch) >= 1 - && (msg_tch->l2h[0] >> 4) != 0xc) { - LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " - "EFR frame' trx=%u ts=%u at fn=%u.\n", - trx_chan_desc[chan].name, - l1t->trx->nr, tn, fn); - goto free_bad_msg; - } - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - len = amr_decompose_payload(msg_tch->l2h, - msgb_l2len(msg_tch), &cmr_codec, &ft_codec, - &bfi); - cmr = -1; - ft = -1; - for (i = 0; i < chan_state->codecs; i++) { - if (chan_state->codec[i] == cmr_codec) - cmr = i; - if (chan_state->codec[i] == ft_codec) - ft = i; - } - if (cmr >= 0) { /* new request */ - chan_state->dl_cmr = cmr; - /* disable AMR loop */ - trx_loop_amr_set(chan_state, 0); - } else { - /* enable AMR loop */ - trx_loop_amr_set(chan_state, 1); - } - if (ft < 0) { - LOGP(DL1C, LOGL_ERROR, "%s Codec (FT = %d) " - " of RTP frame not in list. " - "trx=%u ts=%u\n", - trx_chan_desc[chan].name, ft_codec, - l1t->trx->nr, tn); - goto free_bad_msg; - } - if (codec_mode_request && chan_state->dl_ft != ft) { - LOGP(DL1C, LOGL_NOTICE, "%s Codec (FT = %d) " - " of RTP cannot be changed now, but in " - "next frame. trx=%u ts=%u\n", - trx_chan_desc[chan].name, ft_codec, - l1t->trx->nr, tn); - goto free_bad_msg; - } - chan_state->dl_ft = ft; - if (bfi) { - LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " - "AMR frame' trx=%u ts=%u at fn=%u.\n", - trx_chan_desc[chan].name, - l1t->trx->nr, tn, fn); - goto free_bad_msg; - } - break; - default: -inval_mode2: - LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please " - "fix!\n"); - goto free_bad_msg; - } - if (len < 0) { - LOGP(DL1C, LOGL_ERROR, "Cannot send invalid AMR " - "payload\n"); - goto free_bad_msg; - } - if (msgb_l2len(msg_tch) != len) { - LOGP(DL1C, LOGL_ERROR, "Cannot send payload with " - "invalid length! (expecing %d, received %d)\n", - len, msgb_l2len(msg_tch)); -free_bad_msg: - /* free message */ - msgb_free(msg_tch); - msg_tch = NULL; - goto send_frame; - } - } + msgb_enqueue(&l1ts->dl_prims, l1sap->oph.msg); -send_frame: - *_msg_tch = msg_tch; - *_msg_facch = msg_facch; + return 0; } -static ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) -{ - struct msgb *msg_tch = NULL, *msg_facch = NULL; - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - uint8_t tch_mode = chan_state->tch_mode; - ubit_t *burst, **bursts_p = &chan_state->dl_bursts; - static ubit_t bits[148]; - - /* send burst, if we already got a frame */ - if (bid > 0) { - if (!*bursts_p) - return NULL; - goto send_burst; - } - tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, - (((fn + 4) % 26) >> 2) & 1); - - /* alloc burst memory, if not already, - * otherwise shift buffer by 4 bursts for interleaving */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 928); - if (!*bursts_p) - return NULL; - } else { - memcpy(*bursts_p, *bursts_p + 464, 464); - memset(*bursts_p + 464, 0, 464); - } - - /* no message at all */ - if (!msg_tch && !msg_facch) { - LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " - "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); - goto send_burst; - } - - /* encode bursts (priorize FACCH) */ - if (msg_facch) - tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch), - 1); - else if (tch_mode == GSM48_CMODE_SPEECH_AMR) - /* the first FN 4,13,21 defines that CMI is included in frame, - * the first FN 0,8,17 defines that CMR is included in frame. - */ - tch_afs_encode(*bursts_p, msg_tch->l2h + 2, - msgb_l2len(msg_tch) - 2, (((fn + 4) % 26) >> 2) & 1, - chan_state->codec, chan_state->codecs, - chan_state->dl_ft, - chan_state->dl_cmr); - else - tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1); - - /* free message */ - if (msg_tch) - msgb_free(msg_tch); - if (msg_facch) - msgb_free(msg_facch); - -send_burst: - /* compose burst */ - burst = *bursts_p + bid * 116; - memset(bits, 0, 3); - memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); - memcpy(bits + 87, burst + 58, 58); - memset(bits + 145, 0, 3); - - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - return bits; -} +/* + * ready-to-send indication (to upper layer) + */ -static ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid) +/* RTS for data frame */ +static int rts_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) { - struct msgb *msg_tch = NULL, *msg_facch = NULL; + uint8_t chan_nr, link_id; + struct msgb *msg; + struct osmo_phsap_prim *l1sap; struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - uint8_t tch_mode = chan_state->tch_mode; - ubit_t *burst, **bursts_p = &chan_state->dl_bursts; - static ubit_t bits[148]; - - /* send burst, if we already got a frame */ - if (bid > 0) { - if (!*bursts_p) - return NULL; - goto send_burst; - } - - /* get TCH and/or FACCH */ - tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, - (((fn + 4) % 26) >> 2) & 1); - - /* check for FACCH alignment */ - if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) { - LOGP(DL1C, LOGL_ERROR, "%s Cannot transmit FACCH starting on " - "even frames, please fix RTS!\n", - trx_chan_desc[chan].name); - msgb_free(msg_facch); - msg_facch = NULL; - } - /* alloc burst memory, if not already, - * otherwise shift buffer by 2 bursts for interleaving */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 696); - if (!*bursts_p) - return NULL; - } else { - memcpy(*bursts_p, *bursts_p + 232, 232); - if (chan_state->dl_ongoing_facch) { - memcpy(*bursts_p + 232, *bursts_p + 464, 232); - memset(*bursts_p + 464, 0, 232); - } else { - memset(*bursts_p + 232, 0, 232); - } - } + /* get data for RTS indication */ + chan_nr = trx_chan_desc[chan].chan_nr | tn; + link_id = trx_chan_desc[chan].link_id; - /* no message at all */ - if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) { - LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " - "trx=%u ts=%u at fn=%u to transmit.\n", - trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); - goto send_burst; + if (!chan_nr) { + LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " + "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); + return -ENODEV; } - /* encode bursts (priorize FACCH) */ - if (msg_facch) { - tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch)); - chan_state->dl_ongoing_facch = 1; /* first of two tch frames */ - } else if (chan_state->dl_ongoing_facch) /* second of two tch frames */ - chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */ - else if (tch_mode == GSM48_CMODE_SPEECH_AMR) - /* the first FN 4,13,21 or 5,14,22 defines that CMI is included - * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is - * included in frame. */ - tch_ahs_encode(*bursts_p, msg_tch->l2h + 2, - msgb_l2len(msg_tch) - 2, (((fn + 4) % 26) >> 2) & 1, - chan_state->codec, chan_state->codecs, - chan_state->dl_ft, - chan_state->dl_cmr); - else - tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch)); - - /* free message */ - if (msg_tch) - msgb_free(msg_tch); - if (msg_facch) - msgb_free(msg_facch); - -send_burst: - /* compose burst */ - burst = *bursts_p + bid * 116; - memset(bits, 0, 3); - memcpy(bits + 3, burst, 58); - memcpy(bits + 61, tsc[gsm_ts_tsc(ts)], 26); - memcpy(bits + 87, burst + 58, 58); - memset(bits + 145, 0, 3); - - LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - return bits; -} - - -/* - * RX on uplink (indication to upper layer) - */ - -static int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa) -{ - uint8_t chan_nr; - struct osmo_phsap_prim l1sap; - uint8_t ra; - int rc; - - chan_nr = trx_chan_desc[chan].chan_nr | tn; - - LOGP(DL1C, LOGL_NOTICE, "Received Access Burst on %s fn=%u toa=%.2f\n", - trx_chan_desc[chan].name, fn, toa); + LOGP(DL1C, LOGL_INFO, "PH-RTS.ind: chan=%s chan_nr=0x%02x " + "link_id=0x%02x fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, + chan_nr, link_id, fn, tn, l1t->trx->nr); - /* decode */ - rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic); - if (rc) { - LOGP(DL1C, LOGL_NOTICE, "Received bad AB frame at fn=%u " - "(%u/51)\n", fn, fn % 51); - return 0; - } + /* send clock information to loops process */ + if (L1SAP_IS_LINK_SACCH(link_id)) + trx_loop_sacch_clock(l1t, chan_nr, &l1ts->chan_state[chan]); - /* compose primitive */ /* generate prim */ - memset(&l1sap, 0, sizeof(l1sap)); - osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, - NULL); - l1sap.u.rach_ind.chan_nr = chan_nr; - l1sap.u.rach_ind.ra = ra; -#ifdef TA_TEST -#warning TIMING ADVANCE TEST-HACK IS ENABLED!!! - toa *= 10; -#endif - l1sap.u.rach_ind.acc_delay = (toa >= 0) ? toa : 0; - l1sap.u.rach_ind.fn = fn; - - /* forward primitive */ - l1sap_up(l1t->trx, &l1sap); + msg = l1sap_msgb_alloc(200); + if (!msg) + return -ENOMEM; + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.link_id = link_id; + l1sap->u.data.fn = fn; - return 0; + return l1sap_up(l1t->trx, l1sap); } -/*! \brief a single burst was received by the PHY, process it */ -static int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa) +static int rts_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, int facch) { + uint8_t chan_nr, link_id; + struct msgb *msg; + struct osmo_phsap_prim *l1sap; struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - sbit_t *burst, **bursts_p = &chan_state->ul_bursts; - uint32_t *first_fn = &chan_state->ul_first_fn; - uint8_t *mask = &chan_state->ul_mask; - float *rssi_sum = &chan_state->rssi_sum; - uint8_t *rssi_num = &chan_state->rssi_num; - float *toa_sum = &chan_state->toa_sum; - uint8_t *toa_num = &chan_state->toa_num; - uint8_t l2[GSM_MACBLOCK_LEN], l2_len; - int n_errors, n_bits_total; - int rc; - - /* handle rach, if handover rach detection is turned on */ - if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); - - LOGP(DL1C, LOGL_DEBUG, "Data received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 464); - if (!*bursts_p) - return -ENOMEM; - } + int rc = 0; - /* clear burst & store frame number of first burst */ - if (bid == 0) { - memset(*bursts_p, 0, 464); - *mask = 0x0; - *first_fn = fn; - *rssi_sum = 0; - *rssi_num = 0; - *toa_sum = 0; - *toa_num = 0; - } + /* get data for RTS indication */ + chan_nr = trx_chan_desc[chan].chan_nr | tn; + link_id = trx_chan_desc[chan].link_id; - /* update mask + rssi */ - *mask |= (1 << bid); - *rssi_sum += rssi; - (*rssi_num)++; - *toa_sum += toa; - (*toa_num)++; - - /* copy burst to buffer of 4 bursts */ - burst = *bursts_p + bid * 116; - memcpy(burst, bits + 3, 58); - memcpy(burst + 58, bits + 87, 58); - - /* send burst information to loops process */ - if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { - trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | tn, - chan_state, rssi, toa); + if (!chan_nr) { + LOGP(DL1C, LOGL_FATAL, "RTS func for %s with non-existing " + "chan_nr %d\n", trx_chan_desc[chan].name, chan_nr); + return -ENODEV; } - /* wait until complete set of bursts */ - if (bid != 3) - return 0; - - /* check for complete set of bursts */ - if ((*mask & 0xf) != 0xf) { - LOGP(DL1C, LOGL_NOTICE, "Received incomplete data frame at " - "fn=%u (%u/%u) for %s\n", *first_fn, - (*first_fn) % l1ts->mf_period, l1ts->mf_period, - trx_chan_desc[chan].name); - - /* we require first burst to have correct FN */ - if (!(*mask & 0x1)) { - *mask = 0x0; - return 0; - } - } - *mask = 0x0; - - /* decode */ - rc = xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total); - if (rc) { - LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u " - "(%u/%u) for %s\n", *first_fn, - (*first_fn) % l1ts->mf_period, l1ts->mf_period, - trx_chan_desc[chan].name); - l2_len = 0; - } else - l2_len = GSM_MACBLOCK_LEN; - - /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, - n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); - - return compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num); -} + LOGP(DL1C, LOGL_INFO, "TCH RTS.ind: chan=%s chan_nr=0x%02x " + "fn=%u ts=%u trx=%u\n", trx_chan_desc[chan].name, + chan_nr, fn, tn, l1t->trx->nr); -static int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - sbit_t *burst, **bursts_p = &chan_state->ul_bursts; - uint8_t *mask = &chan_state->ul_mask; - float *rssi_sum = &chan_state->rssi_sum; - uint8_t *rssi_num = &chan_state->rssi_num; - float *toa_sum = &chan_state->toa_sum; - uint8_t *toa_num = &chan_state->toa_num; - uint8_t l2[54+1]; - int n_errors, n_bits_total; - int rc; - - LOGP(DL1C, LOGL_DEBUG, "PDTCH received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 464); - if (!*bursts_p) + /* only send, if FACCH is selected */ + if (facch) { + /* generate prim */ + msg = l1sap_msgb_alloc(200); + if (!msg) return -ENOMEM; - } - - /* clear burst */ - if (bid == 0) { - memset(*bursts_p, 0, 464); - *mask = 0x0; - *rssi_sum = 0; - *rssi_num = 0; - *toa_sum = 0; - *toa_num = 0; - } - - /* update mask + rssi */ - *mask |= (1 << bid); - *rssi_sum += rssi; - (*rssi_num)++; - *toa_sum += toa; - (*toa_num)++; - - /* copy burst to buffer of 4 bursts */ - burst = *bursts_p + bid * 116; - memcpy(burst, bits + 3, 58); - memcpy(burst + 58, bits + 87, 58); - - /* wait until complete set of bursts */ - if (bid != 3) - return 0; - - /* check for complete set of bursts */ - if ((*mask & 0xf) != 0xf) { - LOGP(DL1C, LOGL_NOTICE, "Received incomplete PDTCH block " - "ending at fn=%u (%u/%u) for %s\n", fn, - fn % l1ts->mf_period, l1ts->mf_period, - trx_chan_desc[chan].name); - } - *mask = 0x0; - - /* decode */ - rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total); - - /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, - n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_PH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.data.chan_nr = chan_nr; + l1sap->u.data.link_id = link_id; + l1sap->u.data.fn = fn; - if (rc <= 0) { - LOGP(DL1C, LOGL_NOTICE, "Received bad PDTCH block ending at " - "fn=%u (%u/%u) for %s\n", fn, fn % l1ts->mf_period, - l1ts->mf_period, trx_chan_desc[chan].name); - return 0; + rc = l1sap_up(l1t->trx, l1sap); } - l2[0] = 7; /* valid frame */ - - return compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, - l2, rc + 1, *rssi_sum / *rssi_num); -} - -static int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa) -{ - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - sbit_t *burst, **bursts_p = &chan_state->ul_bursts; - uint8_t *mask = &chan_state->ul_mask; - uint8_t rsl_cmode = chan_state->rsl_cmode; - uint8_t tch_mode = chan_state->tch_mode; - uint8_t tch_data[128]; /* just to be safe */ - int rc, amr = 0; - int n_errors, n_bits_total; - - /* handle rach, if handover rach detection is turned on */ - if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); - - LOGP(DL1C, LOGL_DEBUG, "TCH/F received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 928); - if (!*bursts_p) + /* dont send, if TCH is in signalling only mode */ + if (l1ts->chan_state[chan].rsl_cmode != RSL_CMOD_SPD_SIGN) { + /* generate prim */ + msg = l1sap_msgb_alloc(200); + if (!msg) return -ENOMEM; - } - - /* clear burst */ - if (bid == 0) { - memset(*bursts_p + 464, 0, 464); - *mask = 0x0; - } - - /* update mask */ - *mask |= (1 << bid); - - /* copy burst to end of buffer of 8 bursts */ - burst = *bursts_p + bid * 116 + 464; - memcpy(burst, bits + 3, 58); - memcpy(burst + 58, bits + 87, 58); - - /* wait until complete set of bursts */ - if (bid != 3) - return 0; - - /* check for complete set of bursts */ - if ((*mask & 0xf) != 0xf) { - LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " - "at fn=%u (%u/%u) for %s\n", fn, - fn % l1ts->mf_period, l1ts->mf_period, - trx_chan_desc[chan].name); - } - *mask = 0x0; - - /* decode - * also shift buffer by 4 bursts for interleaving */ - switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1 - : tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR */ - rc = tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total); - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - rc = tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total); - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - /* the first FN 0,8,17 defines that CMI is included in frame, - * the first FN 4,13,21 defines that CMR is included in frame. - * NOTE: A frame ends 7 FN after start. - */ - rc = tch_afs_decode(tch_data + 2, *bursts_p, - (((fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec, - chan_state->codecs, &chan_state->ul_ft, - &chan_state->ul_cmr, &n_errors, &n_bits_total); - if (rc) - trx_loop_amr_input(l1t, - trx_chan_desc[chan].chan_nr | tn, chan_state, - (float)n_errors/(float)n_bits_total); - amr = 2; /* we store tch_data + 2 header bytes */ - /* only good speech frames get rtp header */ - if (rc != GSM_MACBLOCK_LEN && rc >= 4) { - rc = amr_compose_payload(tch_data, - chan_state->codec[chan_state->ul_cmr], - chan_state->codec[chan_state->ul_ft], 0); - } - break; - default: - LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n", - tch_mode); - return -EINVAL; - } - memcpy(*bursts_p, *bursts_p + 464, 464); - - /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, - n_errors, n_bits_total, rssi, toa); - - /* Check if the frame is bad */ - if (rc < 0) { - LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " - "fn=%u for %s\n", fn, trx_chan_desc[chan].name); - goto bfi; - } - if (rc < 4) { - LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " - "fn=%u for %s with codec mode %d (out of range)\n", - fn, trx_chan_desc[chan].name, rc); - goto bfi; - } + l1sap = msgb_l1sap_prim(msg); + osmo_prim_init(&l1sap->oph, SAP_GSM_PH, PRIM_TCH_RTS, + PRIM_OP_INDICATION, msg); + l1sap->u.tch.chan_nr = chan_nr; + l1sap->u.tch.fn = fn; - /* FACCH */ - if (rc == GSM_MACBLOCK_LEN) { - compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi); -bfi: - if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { - /* indicate bad frame */ - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* FR */ - memset(tch_data, 0, GSM_FR_BYTES); - rc = GSM_FR_BYTES; - break; - case GSM48_CMODE_SPEECH_EFR: /* EFR */ - memset(tch_data, 0, GSM_EFR_BYTES); - rc = GSM_EFR_BYTES; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - rc = amr_compose_payload(tch_data, - chan_state->codec[chan_state->dl_cmr], - chan_state->codec[chan_state->dl_ft], - 1); - if (rc < 2) - break; - memset(tch_data + 2, 0, rc - 2); - break; - default: - LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, " - "please fix!\n"); - return -EINVAL; - } - } + return l1sap_up(l1t->trx, l1sap); } - if (rsl_cmode != RSL_CMOD_SPD_SPEECH) - return 0; - - /* TCH or BFI */ - return compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, - tch_data, rc); + return rc; } -static int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, - float toa) +/* RTS for full rate traffic frame */ +static int rts_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) { - struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; - sbit_t *burst, **bursts_p = &chan_state->ul_bursts; - uint8_t *mask = &chan_state->ul_mask; - uint8_t rsl_cmode = chan_state->rsl_cmode; - uint8_t tch_mode = chan_state->tch_mode; - uint8_t tch_data[128]; /* just to be safe */ - int rc, amr = 0; - int n_errors, n_bits_total; - - /* handle rach, if handover rach detection is turned on */ - if (chan_state->ho_rach_detect == 1) - return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); - - LOGP(DL1C, LOGL_DEBUG, "TCH/H received %s fn=%u ts=%u trx=%u bid=%u\n", - trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); - - /* alloc burst memory, if not already */ - if (!*bursts_p) { - *bursts_p = talloc_zero_size(tall_bts_ctx, 696); - if (!*bursts_p) - return -ENOMEM; - } - - /* clear burst */ - if (bid == 0) { - memset(*bursts_p + 464, 0, 232); - *mask = 0x0; - } - - /* update mask */ - *mask |= (1 << bid); - - /* copy burst to end of buffer of 6 bursts */ - burst = *bursts_p + bid * 116 + 464; - memcpy(burst, bits + 3, 58); - memcpy(burst + 58, bits + 87, 58); - - /* wait until complete set of bursts */ - if (bid != 1) - return 0; - - /* check for complete set of bursts */ - if ((*mask & 0x3) != 0x3) { - LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " - "at fn=%u (%u/%u) for %s\n", fn, - fn % l1ts->mf_period, l1ts->mf_period, - trx_chan_desc[chan].name); - } - *mask = 0x0; - - /* skip second of two TCH frames of FACCH was received */ - if (chan_state->ul_ongoing_facch) { - chan_state->ul_ongoing_facch = 0; - memcpy(*bursts_p, *bursts_p + 232, 232); - memcpy(*bursts_p + 232, *bursts_p + 464, 232); - goto bfi; - } - - /* decode - * also shift buffer by 4 bursts for interleaving */ - switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1 - : tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* HR or signalling */ - /* Note on FN-10: If we are at FN 10, we decoded an even aligned - * TCH/FACCH frame, because our burst buffer carries 6 bursts. - * Even FN ending at: 10,11,19,20,2,3 - */ - rc = tch_hr_decode(tch_data, *bursts_p, - (((fn + 26 - 10) % 26) >> 2) & 1, - &n_errors, &n_bits_total); - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - /* the first FN 0,8,17 or 1,9,18 defines that CMI is included - * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR - * is included in frame. - */ - rc = tch_ahs_decode(tch_data + 2, *bursts_p, - (((fn + 26 - 10) % 26) >> 2) & 1, - (((fn + 26 - 10) % 26) >> 2) & 1, chan_state->codec, - chan_state->codecs, &chan_state->ul_ft, - &chan_state->ul_cmr, &n_errors, &n_bits_total); - if (rc) - trx_loop_amr_input(l1t, - trx_chan_desc[chan].chan_nr | tn, chan_state, - (float)n_errors/(float)n_bits_total); - amr = 2; /* we store tch_data + 2 two */ - /* only good speech frames get rtp header */ - if (rc != GSM_MACBLOCK_LEN && rc >= 4) { - rc = amr_compose_payload(tch_data, - chan_state->codec[chan_state->ul_cmr], - chan_state->codec[chan_state->ul_ft], 0); - } - break; - default: - LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n", - tch_mode); - return -EINVAL; - } - memcpy(*bursts_p, *bursts_p + 232, 232); - memcpy(*bursts_p + 232, *bursts_p + 464, 232); - - /* Send uplnk measurement information to L2 */ - l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, - n_errors, n_bits_total, rssi, toa); - - /* Check if the frame is bad */ - if (rc < 0) { - LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " - "fn=%u for %s\n", fn, trx_chan_desc[chan].name); - goto bfi; - } - if (rc < 4) { - LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " - "fn=%u for %s with codec mode %d (out of range)\n", - fn, trx_chan_desc[chan].name, rc); - goto bfi; - } - - /* FACCH */ - if (rc == GSM_MACBLOCK_LEN) { - chan_state->ul_ongoing_facch = 1; - compose_ph_data_ind(l1t, tn, - (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi); -bfi: - if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { - /* indicate bad frame */ - switch (tch_mode) { - case GSM48_CMODE_SPEECH_V1: /* HR */ - tch_data[0] = 0x70; /* F = 0, FT = 111 */ - memset(tch_data + 1, 0, 14); - rc = 15; - break; - case GSM48_CMODE_SPEECH_AMR: /* AMR */ - rc = amr_compose_payload(tch_data, - chan_state->codec[chan_state->dl_cmr], - chan_state->codec[chan_state->dl_ft], - 1); - if (rc < 2) - break; - memset(tch_data + 2, 0, rc - 2); - break; - default: - LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, " - "please fix!\n"); - return -EINVAL; - } - } - } + /* TCH/F may include FACCH on every 4th burst */ + return rts_tch_common(l1t, tn, fn, chan, 1); +} - if (rsl_cmode != RSL_CMOD_SPD_SPEECH) - return 0; - /* TCH or BFI */ - /* Note on FN 19 or 20: If we received the last burst of a frame, - * it actually starts at FN 8 or 9. A burst starting there, overlaps - * with the slot 12, so an extra FN must be substracted to get correct - * start of frame. - */ - return compose_tch_ind(l1t, tn, - (fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME, - chan, tch_data, rc); +/* RTS for half rate traffic frame */ +static int rts_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan) +{ + /* the FN 4/5, 13/14, 21/22 defines that FACCH may be included. */ + return rts_tch_common(l1t, tn, fn, chan, ((fn % 26) >> 2) & 1); } - /* * multiframe structure */ diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h new file mode 100644 index 0000000..ea3e620 --- /dev/null +++ b/src/osmo-bts-trx/scheduler_backend.h @@ -0,0 +1,79 @@ +#pragma once + +typedef int trx_sched_rts_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan); + +typedef ubit_t *trx_sched_dl_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan, + uint8_t bid); + +typedef int trx_sched_ul_func(struct l1sched_trx *l1t, uint8_t tn, + uint32_t fn, enum trx_chan_type chan, + uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); + +struct trx_chan_desc { + /*! \brief Is this on a PDCH (PS) ? */ + int pdch; + /*! \brief TRX Channel Type */ + enum trx_chan_type chan; + /*! \brief Channel Number (like in RSL) */ + uint8_t chan_nr; + /*! \brief Link ID (like in RSL) */ + uint8_t link_id; + /*! \brief Human-readable name */ + const char *name; + /*! \brief function to call when we want to generate RTS.req to L2 */ + trx_sched_rts_func *rts_fn; + /*! \brief function to call when DATA.req received from L2 */ + trx_sched_dl_func *dl_fn; + /*! \brief function to call when burst received from PHY */ + trx_sched_ul_func *ul_fn; + /*! \breif is this channel automatically active at start? */ + int auto_active; +}; +extern const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX]; + +extern const ubit_t _sched_tsc[8][26]; +const ubit_t _sched_fcch_burst[148]; +const ubit_t _sched_sch_train[64]; + +struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, + enum trx_chan_type chan); + +int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi); + +int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); + +ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid); +int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); +int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa); + diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c new file mode 100644 index 0000000..ec53fbf --- /dev/null +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -0,0 +1,1234 @@ +/* Scheduler worker functiosn for OsmoBTS-TRX */ + +/* (C) 2013 by Andreas Eversberg + * (C) 2015 by Alexander Chemeris + * (C) 2015 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "l1_if.h" +#include "scheduler.h" +#include "scheduler_backend.h" +#include "gsm0503_coding.h" +#include "trx_if.h" +#include "loops.h" +#include "amr.h" + +extern void *tall_bts_ctx; + +/* Enable this to multiply TOA of RACH by 10. + * This is usefull to check tenth of timing advances with RSSI test tool. + * Note that regular phones will not work when using this test! */ +//#define TA_TEST + + +/* + * TX on downlink + */ + +/* an IDLE burst returns nothing. on C0 it is replaced by dummy burst */ +ubit_t *tx_idle_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); + + return NULL; +} + +ubit_t *tx_fcch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); + + /* BURST BYPASS */ + + return (ubit_t *) _sched_fcch_burst; +} + +ubit_t *tx_sch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + static ubit_t bits[148], burst[78]; + uint8_t sb_info[4]; + struct gsm_time t; + uint8_t t3p, bsic; + + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr); + + /* BURST BYPASS */ + + /* create SB info from GSM time and BSIC */ + gsm_fn2gsmtime(&t, fn); + t3p = t.t3 / 10; + bsic = l1t->trx->bts->bsic; + sb_info[0] = + ((bsic & 0x3f) << 2) | + ((t.t1 & 0x600) >> 9); + sb_info[1] = + ((t.t1 & 0x1fe) >> 1); + sb_info[2] = + ((t.t1 & 0x001) << 7) | + ((t.t2 & 0x1f) << 2) | + ((t3p & 0x6) >> 1); + sb_info[3] = + (t3p & 0x1); + + /* encode bursts */ + sch_encode(burst, sb_info); + + /* compose burst */ + memset(bits, 0, 3); + memcpy(bits + 3, burst, 39); + memcpy(bits + 42, _sched_sch_train, 64); + memcpy(bits + 106, burst + 39, 39); + memset(bits + 145, 0, 3); + + return bits; +} + +ubit_t *tx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct msgb *msg = NULL; /* make GCC happy */ + ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; + static ubit_t bits[148]; + + /* send burst, if we already got a frame */ + if (bid > 0) { + if (!*bursts_p) + return NULL; + goto send_burst; + } + + /* get mac block from queue */ + msg = _sched_dequeue_prim(l1t, tn, fn, chan); + if (msg) + goto got_msg; + + LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " + "trx=%u ts=%u at fn=%u to transmit.\n", + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); + +no_msg: + /* free burst memory */ + if (*bursts_p) { + talloc_free(*bursts_p); + *bursts_p = NULL; + } + return NULL; + +got_msg: + /* check validity of message */ + if (msgb_l2len(msg) != GSM_MACBLOCK_LEN) { + LOGP(DL1C, LOGL_FATAL, "Prim not 23 bytes, please FIX! " + "(len=%d)\n", msgb_l2len(msg)); + /* free message */ + msgb_free(msg); + goto no_msg; + } + + /* BURST BYPASS */ + + /* handle loss detection of sacch */ + if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { + /* count and send BFI */ + if (++(l1ts->chan_state[chan].lost) > 1) { + /* TODO: Should we pass old TOA here? Otherwise we risk + * unnecessary decreasing TA */ + + /* Send uplnk measurement information to L2 */ + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + 456, 456, -110, 0); + + _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110); + } + } + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 464); + if (!*bursts_p) + return NULL; + } + + /* encode bursts */ + xcch_encode(*bursts_p, msg->l2h); + + /* free message */ + msgb_free(msg); + +send_burst: + /* compose burst */ + burst = *bursts_p + bid * 116; + memset(bits, 0, 3); + memcpy(bits + 3, burst, 58); + memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26); + memcpy(bits + 87, burst + 58, 58); + memset(bits + 145, 0, 3); + + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + return bits; +} + +ubit_t *tx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct msgb *msg = NULL; /* make GCC happy */ + ubit_t *burst, **bursts_p = &l1ts->chan_state[chan].dl_bursts; + static ubit_t bits[148]; + int rc; + + /* send burst, if we already got a frame */ + if (bid > 0) { + if (!*bursts_p) + return NULL; + goto send_burst; + } + + /* get mac block from queue */ + msg = _sched_dequeue_prim(l1t, tn, fn, chan); + if (msg) + goto got_msg; + + LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " + "trx=%u ts=%u at fn=%u to transmit.\n", + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); + +no_msg: + /* free burst memory */ + if (*bursts_p) { + talloc_free(*bursts_p); + *bursts_p = NULL; + } + return NULL; + +got_msg: + /* BURST BYPASS */ + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 464); + if (!*bursts_p) + return NULL; + } + + /* encode bursts */ + rc = pdtch_encode(*bursts_p, msg->l2h, msg->tail - msg->l2h); + + /* check validity of message */ + if (rc) { + LOGP(DL1C, LOGL_FATAL, "Prim invalid length, please FIX! " + "(len=%d)\n", rc); + /* free message */ + msgb_free(msg); + goto no_msg; + } + + /* free message */ + msgb_free(msg); + +send_burst: + /* compose burst */ + burst = *bursts_p + bid * 116; + memset(bits, 0, 3); + memcpy(bits + 3, burst, 58); + memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26); + memcpy(bits + 87, burst + 58, 58); + memset(bits + 145, 0, 3); + + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + return bits; +} + +static void tx_tch_common(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, struct msgb **_msg_tch, + struct msgb **_msg_facch, int codec_mode_request) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct msgb *msg1, *msg2, *msg_tch = NULL, *msg_facch = NULL; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + uint8_t rsl_cmode = chan_state->rsl_cmode; + uint8_t tch_mode = chan_state->tch_mode; + struct osmo_phsap_prim *l1sap; + + /* handle loss detection of received TCH frames */ + if (rsl_cmode == RSL_CMOD_SPD_SPEECH + && ++(chan_state->lost) > 5) { + uint8_t tch_data[GSM_FR_BYTES]; + int len; + + LOGP(DL1C, LOGL_NOTICE, "Missing TCH bursts detected, sending " + "BFI for %s\n", trx_chan_desc[chan].name); + + /* indicate bad frame */ + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR / HR */ + if (chan != TRXC_TCHF) { /* HR */ + tch_data[0] = 0x70; /* F = 0, FT = 111 */ + memset(tch_data + 1, 0, 14); + len = 15; + break; + } + memset(tch_data, 0, GSM_FR_BYTES); + len = GSM_FR_BYTES; + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + if (chan != TRXC_TCHF) + goto inval_mode1; + memset(tch_data, 0, GSM_EFR_BYTES); + len = GSM_EFR_BYTES; + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + len = amr_compose_payload(tch_data, + chan_state->codec[chan_state->dl_cmr], + chan_state->codec[chan_state->dl_ft], 1); + if (len < 2) + break; + memset(tch_data + 2, 0, len - 2); + _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len); + break; + default: +inval_mode1: + LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please " + "fix!\n"); + len = 0; + } + if (len) + _sched_compose_tch_ind(l1t, tn, 0, chan, tch_data, len); + } + + /* get frame and unlink from queue */ + msg1 = _sched_dequeue_prim(l1t, tn, fn, chan); + msg2 = _sched_dequeue_prim(l1t, tn, fn, chan); + if (msg1) { + l1sap = msgb_l1sap_prim(msg1); + if (l1sap->oph.primitive == PRIM_TCH) { + msg_tch = msg1; + if (msg2) { + l1sap = msgb_l1sap_prim(msg2); + if (l1sap->oph.primitive == PRIM_TCH) { + LOGP(DL1C, LOGL_FATAL, "TCH twice, " + "please FIX! "); + msgb_free(msg2); + } else + msg_facch = msg2; + } + } else { + msg_facch = msg1; + if (msg2) { + l1sap = msgb_l1sap_prim(msg2); + if (l1sap->oph.primitive != PRIM_TCH) { + LOGP(DL1C, LOGL_FATAL, "FACCH twice, " + "please FIX! "); + msgb_free(msg2); + } else + msg_tch = msg2; + } + } + } else if (msg2) { + l1sap = msgb_l1sap_prim(msg2); + if (l1sap->oph.primitive == PRIM_TCH) + msg_tch = msg2; + else + msg_facch = msg2; + } + + /* check validity of message */ + if (msg_facch && msgb_l2len(msg_facch) != GSM_MACBLOCK_LEN) { + LOGP(DL1C, LOGL_FATAL, "Prim not 23 bytes, please FIX! " + "(len=%d)\n", msgb_l2len(msg_facch)); + /* free message */ + msgb_free(msg_facch); + msg_facch = NULL; + } + + /* check validity of message, get AMR ft and cmr */ + if (!msg_facch && msg_tch) { + int len; + uint8_t bfi, cmr_codec, ft_codec; + int cmr, ft, i; + + if (rsl_cmode != RSL_CMOD_SPD_SPEECH) { + LOGP(DL1C, LOGL_NOTICE, "%s Dropping speech frame, " + "because we are not in speech mode trx=%u " + "ts=%u at fn=%u.\n", trx_chan_desc[chan].name, + l1t->trx->nr, tn, fn); + goto free_bad_msg; + } + + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR / HR */ + if (chan != TRXC_TCHF) { /* HR */ + len = 15; + if (msgb_l2len(msg_tch) >= 1 + && (msg_tch->l2h[0] & 0xf0) != 0x00) { + LOGP(DL1C, LOGL_NOTICE, "%s " + "Transmitting 'bad " + "HR frame' trx=%u ts=%u at " + "fn=%u.\n", + trx_chan_desc[chan].name, + l1t->trx->nr, tn, fn); + goto free_bad_msg; + } + break; + } + len = GSM_FR_BYTES; + if (msgb_l2len(msg_tch) >= 1 + && (msg_tch->l2h[0] >> 4) != 0xd) { + LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " + "FR frame' trx=%u ts=%u at fn=%u.\n", + trx_chan_desc[chan].name, + l1t->trx->nr, tn, fn); + goto free_bad_msg; + } + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + if (chan != TRXC_TCHF) + goto inval_mode2; + len = GSM_EFR_BYTES; + if (msgb_l2len(msg_tch) >= 1 + && (msg_tch->l2h[0] >> 4) != 0xc) { + LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " + "EFR frame' trx=%u ts=%u at fn=%u.\n", + trx_chan_desc[chan].name, + l1t->trx->nr, tn, fn); + goto free_bad_msg; + } + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + len = amr_decompose_payload(msg_tch->l2h, + msgb_l2len(msg_tch), &cmr_codec, &ft_codec, + &bfi); + cmr = -1; + ft = -1; + for (i = 0; i < chan_state->codecs; i++) { + if (chan_state->codec[i] == cmr_codec) + cmr = i; + if (chan_state->codec[i] == ft_codec) + ft = i; + } + if (cmr >= 0) { /* new request */ + chan_state->dl_cmr = cmr; + /* disable AMR loop */ + trx_loop_amr_set(chan_state, 0); + } else { + /* enable AMR loop */ + trx_loop_amr_set(chan_state, 1); + } + if (ft < 0) { + LOGP(DL1C, LOGL_ERROR, "%s Codec (FT = %d) " + " of RTP frame not in list. " + "trx=%u ts=%u\n", + trx_chan_desc[chan].name, ft_codec, + l1t->trx->nr, tn); + goto free_bad_msg; + } + if (codec_mode_request && chan_state->dl_ft != ft) { + LOGP(DL1C, LOGL_NOTICE, "%s Codec (FT = %d) " + " of RTP cannot be changed now, but in " + "next frame. trx=%u ts=%u\n", + trx_chan_desc[chan].name, ft_codec, + l1t->trx->nr, tn); + goto free_bad_msg; + } + chan_state->dl_ft = ft; + if (bfi) { + LOGP(DL1C, LOGL_NOTICE, "%s Transmitting 'bad " + "AMR frame' trx=%u ts=%u at fn=%u.\n", + trx_chan_desc[chan].name, + l1t->trx->nr, tn, fn); + goto free_bad_msg; + } + break; + default: +inval_mode2: + LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, please " + "fix!\n"); + goto free_bad_msg; + } + if (len < 0) { + LOGP(DL1C, LOGL_ERROR, "Cannot send invalid AMR " + "payload\n"); + goto free_bad_msg; + } + if (msgb_l2len(msg_tch) != len) { + LOGP(DL1C, LOGL_ERROR, "Cannot send payload with " + "invalid length! (expecing %d, received %d)\n", + len, msgb_l2len(msg_tch)); +free_bad_msg: + /* free message */ + msgb_free(msg_tch); + msg_tch = NULL; + goto send_frame; + } + } + +send_frame: + *_msg_tch = msg_tch; + *_msg_facch = msg_facch; +} + +ubit_t *tx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + struct msgb *msg_tch = NULL, *msg_facch = NULL; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + uint8_t tch_mode = chan_state->tch_mode; + ubit_t *burst, **bursts_p = &chan_state->dl_bursts; + static ubit_t bits[148]; + + /* send burst, if we already got a frame */ + if (bid > 0) { + if (!*bursts_p) + return NULL; + goto send_burst; + } + + tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, + (((fn + 4) % 26) >> 2) & 1); + + /* BURST BYPASS */ + + /* alloc burst memory, if not already, + * otherwise shift buffer by 4 bursts for interleaving */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 928); + if (!*bursts_p) + return NULL; + } else { + memcpy(*bursts_p, *bursts_p + 464, 464); + memset(*bursts_p + 464, 0, 464); + } + + /* no message at all */ + if (!msg_tch && !msg_facch) { + LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " + "trx=%u ts=%u at fn=%u to transmit.\n", + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); + goto send_burst; + } + + /* encode bursts (priorize FACCH) */ + if (msg_facch) + tch_fr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch), + 1); + else if (tch_mode == GSM48_CMODE_SPEECH_AMR) + /* the first FN 4,13,21 defines that CMI is included in frame, + * the first FN 0,8,17 defines that CMR is included in frame. + */ + tch_afs_encode(*bursts_p, msg_tch->l2h + 2, + msgb_l2len(msg_tch) - 2, (((fn + 4) % 26) >> 2) & 1, + chan_state->codec, chan_state->codecs, + chan_state->dl_ft, + chan_state->dl_cmr); + else + tch_fr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch), 1); + + /* free message */ + if (msg_tch) + msgb_free(msg_tch); + if (msg_facch) + msgb_free(msg_facch); + +send_burst: + /* compose burst */ + burst = *bursts_p + bid * 116; + memset(bits, 0, 3); + memcpy(bits + 3, burst, 58); + memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26); + memcpy(bits + 87, burst + 58, 58); + memset(bits + 145, 0, 3); + + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + return bits; +} + +ubit_t *tx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid) +{ + struct msgb *msg_tch = NULL, *msg_facch = NULL; + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct gsm_bts_trx_ts *ts = &l1t->trx->ts[tn]; + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + uint8_t tch_mode = chan_state->tch_mode; + ubit_t *burst, **bursts_p = &chan_state->dl_bursts; + static ubit_t bits[148]; + + /* send burst, if we already got a frame */ + if (bid > 0) { + if (!*bursts_p) + return NULL; + goto send_burst; + } + + /* get TCH and/or FACCH */ + tx_tch_common(l1t, tn, fn, chan, bid, &msg_tch, &msg_facch, + (((fn + 4) % 26) >> 2) & 1); + + /* check for FACCH alignment */ + if (msg_facch && ((((fn + 4) % 26) >> 2) & 1)) { + LOGP(DL1C, LOGL_ERROR, "%s Cannot transmit FACCH starting on " + "even frames, please fix RTS!\n", + trx_chan_desc[chan].name); + msgb_free(msg_facch); + msg_facch = NULL; + } + + /* BURST BYPASS */ + + /* alloc burst memory, if not already, + * otherwise shift buffer by 2 bursts for interleaving */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 696); + if (!*bursts_p) + return NULL; + } else { + memcpy(*bursts_p, *bursts_p + 232, 232); + if (chan_state->dl_ongoing_facch) { + memcpy(*bursts_p + 232, *bursts_p + 464, 232); + memset(*bursts_p + 464, 0, 232); + } else { + memset(*bursts_p + 232, 0, 232); + } + } + + /* no message at all */ + if (!msg_tch && !msg_facch && !chan_state->dl_ongoing_facch) { + LOGP(DL1C, LOGL_INFO, "%s has not been served !! No prim for " + "trx=%u ts=%u at fn=%u to transmit.\n", + trx_chan_desc[chan].name, l1t->trx->nr, tn, fn); + goto send_burst; + } + + /* encode bursts (priorize FACCH) */ + if (msg_facch) { + tch_hr_encode(*bursts_p, msg_facch->l2h, msgb_l2len(msg_facch)); + chan_state->dl_ongoing_facch = 1; /* first of two tch frames */ + } else if (chan_state->dl_ongoing_facch) /* second of two tch frames */ + chan_state->dl_ongoing_facch = 0; /* we are done with FACCH */ + else if (tch_mode == GSM48_CMODE_SPEECH_AMR) + /* the first FN 4,13,21 or 5,14,22 defines that CMI is included + * in frame, the first FN 0,8,17 or 1,9,18 defines that CMR is + * included in frame. */ + tch_ahs_encode(*bursts_p, msg_tch->l2h + 2, + msgb_l2len(msg_tch) - 2, (((fn + 4) % 26) >> 2) & 1, + chan_state->codec, chan_state->codecs, + chan_state->dl_ft, + chan_state->dl_cmr); + else + tch_hr_encode(*bursts_p, msg_tch->l2h, msgb_l2len(msg_tch)); + + /* free message */ + if (msg_tch) + msgb_free(msg_tch); + if (msg_facch) + msgb_free(msg_facch); + +send_burst: + /* compose burst */ + burst = *bursts_p + bid * 116; + memset(bits, 0, 3); + memcpy(bits + 3, burst, 58); + memcpy(bits + 61, _sched_tsc[gsm_ts_tsc(ts)], 26); + memcpy(bits + 87, burst + 58, 58); + memset(bits + 145, 0, 3); + + LOGP(DL1C, LOGL_DEBUG, "Transmitting %s fn=%u ts=%u trx=%u burst=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + return bits; +} + + +/* + * RX on uplink (indication to upper layer) + */ + +int rx_rach_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa) +{ + uint8_t chan_nr; + struct osmo_phsap_prim l1sap; + uint8_t ra; + int rc; + + chan_nr = trx_chan_desc[chan].chan_nr | tn; + + LOGP(DL1C, LOGL_NOTICE, "Received Access Burst on %s fn=%u toa=%.2f\n", + trx_chan_desc[chan].name, fn, toa); + + /* decode */ + rc = rach_decode(&ra, bits + 8 + 41, l1t->trx->bts->bsic); + if (rc) { + LOGP(DL1C, LOGL_NOTICE, "Received bad AB frame at fn=%u " + "(%u/51)\n", fn, fn % 51); + return 0; + } + + /* compose primitive */ + /* generate prim */ + memset(&l1sap, 0, sizeof(l1sap)); + osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_PH_RACH, PRIM_OP_INDICATION, + NULL); + l1sap.u.rach_ind.chan_nr = chan_nr; + l1sap.u.rach_ind.ra = ra; +#ifdef TA_TEST +#warning TIMING ADVANCE TEST-HACK IS ENABLED!!! + toa *= 10; +#endif + l1sap.u.rach_ind.acc_delay = (toa >= 0) ? toa : 0; + l1sap.u.rach_ind.fn = fn; + + /* forward primitive */ + l1sap_up(l1t->trx, &l1sap); + + return 0; +} + +/*! \brief a single burst was received by the PHY, process it */ +int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + sbit_t *burst, **bursts_p = &chan_state->ul_bursts; + uint32_t *first_fn = &chan_state->ul_first_fn; + uint8_t *mask = &chan_state->ul_mask; + float *rssi_sum = &chan_state->rssi_sum; + uint8_t *rssi_num = &chan_state->rssi_num; + float *toa_sum = &chan_state->toa_sum; + uint8_t *toa_num = &chan_state->toa_num; + uint8_t l2[GSM_MACBLOCK_LEN], l2_len; + int n_errors, n_bits_total; + int rc; + + /* handle rach, if handover rach detection is turned on */ + if (chan_state->ho_rach_detect == 1) + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); + + LOGP(DL1C, LOGL_DEBUG, "Data received %s fn=%u ts=%u trx=%u bid=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 464); + if (!*bursts_p) + return -ENOMEM; + } + + /* clear burst & store frame number of first burst */ + if (bid == 0) { + memset(*bursts_p, 0, 464); + *mask = 0x0; + *first_fn = fn; + *rssi_sum = 0; + *rssi_num = 0; + *toa_sum = 0; + *toa_num = 0; + } + + /* update mask + rssi */ + *mask |= (1 << bid); + *rssi_sum += rssi; + (*rssi_num)++; + *toa_sum += toa; + (*toa_num)++; + + /* copy burst to buffer of 4 bursts */ + burst = *bursts_p + bid * 116; + memcpy(burst, bits + 3, 58); + memcpy(burst + 58, bits + 87, 58); + + /* send burst information to loops process */ + if (L1SAP_IS_LINK_SACCH(trx_chan_desc[chan].link_id)) { + trx_loop_sacch_input(l1t, trx_chan_desc[chan].chan_nr | tn, + chan_state, rssi, toa); + } + + /* wait until complete set of bursts */ + if (bid != 3) + return 0; + + /* check for complete set of bursts */ + if ((*mask & 0xf) != 0xf) { + LOGP(DL1C, LOGL_NOTICE, "Received incomplete data frame at " + "fn=%u (%u/%u) for %s\n", *first_fn, + (*first_fn) % l1ts->mf_period, l1ts->mf_period, + trx_chan_desc[chan].name); + + /* we require first burst to have correct FN */ + if (!(*mask & 0x1)) { + *mask = 0x0; + return 0; + } + } + *mask = 0x0; + + /* decode */ + rc = xcch_decode(l2, *bursts_p, &n_errors, &n_bits_total); + if (rc) { + LOGP(DL1C, LOGL_NOTICE, "Received bad data frame at fn=%u " + "(%u/%u) for %s\n", *first_fn, + (*first_fn) % l1ts->mf_period, l1ts->mf_period, + trx_chan_desc[chan].name); + l2_len = 0; + } else + l2_len = GSM_MACBLOCK_LEN; + + /* Send uplnk measurement information to L2 */ + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); + + return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num); +} + +int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + sbit_t *burst, **bursts_p = &chan_state->ul_bursts; + uint8_t *mask = &chan_state->ul_mask; + float *rssi_sum = &chan_state->rssi_sum; + uint8_t *rssi_num = &chan_state->rssi_num; + float *toa_sum = &chan_state->toa_sum; + uint8_t *toa_num = &chan_state->toa_num; + uint8_t l2[54+1]; + int n_errors, n_bits_total; + int rc; + + LOGP(DL1C, LOGL_DEBUG, "PDTCH received %s fn=%u ts=%u trx=%u bid=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 464); + if (!*bursts_p) + return -ENOMEM; + } + + /* clear burst */ + if (bid == 0) { + memset(*bursts_p, 0, 464); + *mask = 0x0; + *rssi_sum = 0; + *rssi_num = 0; + *toa_sum = 0; + *toa_num = 0; + } + + /* update mask + rssi */ + *mask |= (1 << bid); + *rssi_sum += rssi; + (*rssi_num)++; + *toa_sum += toa; + (*toa_num)++; + + /* copy burst to buffer of 4 bursts */ + burst = *bursts_p + bid * 116; + memcpy(burst, bits + 3, 58); + memcpy(burst + 58, bits + 87, 58); + + /* wait until complete set of bursts */ + if (bid != 3) + return 0; + + /* check for complete set of bursts */ + if ((*mask & 0xf) != 0xf) { + LOGP(DL1C, LOGL_NOTICE, "Received incomplete PDTCH block " + "ending at fn=%u (%u/%u) for %s\n", fn, + fn % l1ts->mf_period, l1ts->mf_period, + trx_chan_desc[chan].name); + } + *mask = 0x0; + + /* decode */ + rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total); + + /* Send uplnk measurement information to L2 */ + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, + n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); + + if (rc <= 0) { + LOGP(DL1C, LOGL_NOTICE, "Received bad PDTCH block ending at " + "fn=%u (%u/%u) for %s\n", fn, fn % l1ts->mf_period, + l1ts->mf_period, trx_chan_desc[chan].name); + return 0; + } + + l2[0] = 7; /* valid frame */ + + return _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, + l2, rc + 1, *rssi_sum / *rssi_num); +} + +int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + sbit_t *burst, **bursts_p = &chan_state->ul_bursts; + uint8_t *mask = &chan_state->ul_mask; + uint8_t rsl_cmode = chan_state->rsl_cmode; + uint8_t tch_mode = chan_state->tch_mode; + uint8_t tch_data[128]; /* just to be safe */ + int rc, amr = 0; + int n_errors, n_bits_total; + + /* handle rach, if handover rach detection is turned on */ + if (chan_state->ho_rach_detect == 1) + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); + + LOGP(DL1C, LOGL_DEBUG, "TCH/F received %s fn=%u ts=%u trx=%u bid=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 928); + if (!*bursts_p) + return -ENOMEM; + } + + /* clear burst */ + if (bid == 0) { + memset(*bursts_p + 464, 0, 464); + *mask = 0x0; + } + + /* update mask */ + *mask |= (1 << bid); + + /* copy burst to end of buffer of 8 bursts */ + burst = *bursts_p + bid * 116 + 464; + memcpy(burst, bits + 3, 58); + memcpy(burst + 58, bits + 87, 58); + + /* wait until complete set of bursts */ + if (bid != 3) + return 0; + + /* check for complete set of bursts */ + if ((*mask & 0xf) != 0xf) { + LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " + "at fn=%u (%u/%u) for %s\n", fn, + fn % l1ts->mf_period, l1ts->mf_period, + trx_chan_desc[chan].name); + } + *mask = 0x0; + + /* decode + * also shift buffer by 4 bursts for interleaving */ + switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1 + : tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR */ + rc = tch_fr_decode(tch_data, *bursts_p, 1, 0, &n_errors, &n_bits_total); + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + rc = tch_fr_decode(tch_data, *bursts_p, 1, 1, &n_errors, &n_bits_total); + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + /* the first FN 0,8,17 defines that CMI is included in frame, + * the first FN 4,13,21 defines that CMR is included in frame. + * NOTE: A frame ends 7 FN after start. + */ + rc = tch_afs_decode(tch_data + 2, *bursts_p, + (((fn + 26 - 7) % 26) >> 2) & 1, chan_state->codec, + chan_state->codecs, &chan_state->ul_ft, + &chan_state->ul_cmr, &n_errors, &n_bits_total); + if (rc) + trx_loop_amr_input(l1t, + trx_chan_desc[chan].chan_nr | tn, chan_state, + (float)n_errors/(float)n_bits_total); + amr = 2; /* we store tch_data + 2 header bytes */ + /* only good speech frames get rtp header */ + if (rc != GSM_MACBLOCK_LEN && rc >= 4) { + rc = amr_compose_payload(tch_data, + chan_state->codec[chan_state->ul_cmr], + chan_state->codec[chan_state->ul_ft], 0); + } + break; + default: + LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n", + tch_mode); + return -EINVAL; + } + memcpy(*bursts_p, *bursts_p + 464, 464); + + /* Send uplnk measurement information to L2 */ + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, + n_errors, n_bits_total, rssi, toa); + + /* Check if the frame is bad */ + if (rc < 0) { + LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " + "fn=%u for %s\n", fn, trx_chan_desc[chan].name); + goto bfi; + } + if (rc < 4) { + LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " + "fn=%u for %s with codec mode %d (out of range)\n", + fn, trx_chan_desc[chan].name, rc); + goto bfi; + } + + /* FACCH */ + if (rc == GSM_MACBLOCK_LEN) { + _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, + tch_data + amr, GSM_MACBLOCK_LEN, rssi); +bfi: + if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { + /* indicate bad frame */ + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* FR */ + memset(tch_data, 0, GSM_FR_BYTES); + rc = GSM_FR_BYTES; + break; + case GSM48_CMODE_SPEECH_EFR: /* EFR */ + memset(tch_data, 0, GSM_EFR_BYTES); + rc = GSM_EFR_BYTES; + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + rc = amr_compose_payload(tch_data, + chan_state->codec[chan_state->dl_cmr], + chan_state->codec[chan_state->dl_ft], + 1); + if (rc < 2) + break; + memset(tch_data + 2, 0, rc - 2); + break; + default: + LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, " + "please fix!\n"); + return -EINVAL; + } + } + } + + if (rsl_cmode != RSL_CMOD_SPD_SPEECH) + return 0; + + /* TCH or BFI */ + return _sched_compose_tch_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, + tch_data, rc); +} + +int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, + enum trx_chan_type chan, uint8_t bid, sbit_t *bits, int8_t rssi, + float toa) +{ + struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); + struct l1sched_chan_state *chan_state = &l1ts->chan_state[chan]; + sbit_t *burst, **bursts_p = &chan_state->ul_bursts; + uint8_t *mask = &chan_state->ul_mask; + uint8_t rsl_cmode = chan_state->rsl_cmode; + uint8_t tch_mode = chan_state->tch_mode; + uint8_t tch_data[128]; /* just to be safe */ + int rc, amr = 0; + int n_errors, n_bits_total; + + /* handle rach, if handover rach detection is turned on */ + if (chan_state->ho_rach_detect == 1) + return rx_rach_fn(l1t, tn, fn, chan, bid, bits, rssi, toa); + + LOGP(DL1C, LOGL_DEBUG, "TCH/H received %s fn=%u ts=%u trx=%u bid=%u\n", + trx_chan_desc[chan].name, fn, tn, l1t->trx->nr, bid); + + /* alloc burst memory, if not already */ + if (!*bursts_p) { + *bursts_p = talloc_zero_size(tall_bts_ctx, 696); + if (!*bursts_p) + return -ENOMEM; + } + + /* clear burst */ + if (bid == 0) { + memset(*bursts_p + 464, 0, 232); + *mask = 0x0; + } + + /* update mask */ + *mask |= (1 << bid); + + /* copy burst to end of buffer of 6 bursts */ + burst = *bursts_p + bid * 116 + 464; + memcpy(burst, bits + 3, 58); + memcpy(burst + 58, bits + 87, 58); + + /* wait until complete set of bursts */ + if (bid != 1) + return 0; + + /* check for complete set of bursts */ + if ((*mask & 0x3) != 0x3) { + LOGP(DL1C, LOGL_NOTICE, "Received incomplete TCH frame ending " + "at fn=%u (%u/%u) for %s\n", fn, + fn % l1ts->mf_period, l1ts->mf_period, + trx_chan_desc[chan].name); + } + *mask = 0x0; + + /* skip second of two TCH frames of FACCH was received */ + if (chan_state->ul_ongoing_facch) { + chan_state->ul_ongoing_facch = 0; + memcpy(*bursts_p, *bursts_p + 232, 232); + memcpy(*bursts_p + 232, *bursts_p + 464, 232); + goto bfi; + } + + /* decode + * also shift buffer by 4 bursts for interleaving */ + switch ((rsl_cmode != RSL_CMOD_SPD_SPEECH) ? GSM48_CMODE_SPEECH_V1 + : tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* HR or signalling */ + /* Note on FN-10: If we are at FN 10, we decoded an even aligned + * TCH/FACCH frame, because our burst buffer carries 6 bursts. + * Even FN ending at: 10,11,19,20,2,3 + */ + rc = tch_hr_decode(tch_data, *bursts_p, + (((fn + 26 - 10) % 26) >> 2) & 1, + &n_errors, &n_bits_total); + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + /* the first FN 0,8,17 or 1,9,18 defines that CMI is included + * in frame, the first FN 4,13,21 or 5,14,22 defines that CMR + * is included in frame. + */ + rc = tch_ahs_decode(tch_data + 2, *bursts_p, + (((fn + 26 - 10) % 26) >> 2) & 1, + (((fn + 26 - 10) % 26) >> 2) & 1, chan_state->codec, + chan_state->codecs, &chan_state->ul_ft, + &chan_state->ul_cmr, &n_errors, &n_bits_total); + if (rc) + trx_loop_amr_input(l1t, + trx_chan_desc[chan].chan_nr | tn, chan_state, + (float)n_errors/(float)n_bits_total); + amr = 2; /* we store tch_data + 2 two */ + /* only good speech frames get rtp header */ + if (rc != GSM_MACBLOCK_LEN && rc >= 4) { + rc = amr_compose_payload(tch_data, + chan_state->codec[chan_state->ul_cmr], + chan_state->codec[chan_state->ul_ft], 0); + } + break; + default: + LOGP(DL1C, LOGL_ERROR, "TCH mode %u invalid, please fix!\n", + tch_mode); + return -EINVAL; + } + memcpy(*bursts_p, *bursts_p + 232, 232); + memcpy(*bursts_p + 232, *bursts_p + 464, 232); + + /* Send uplnk measurement information to L2 */ + l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr|tn, + n_errors, n_bits_total, rssi, toa); + + /* Check if the frame is bad */ + if (rc < 0) { + LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " + "fn=%u for %s\n", fn, trx_chan_desc[chan].name); + goto bfi; + } + if (rc < 4) { + LOGP(DL1C, LOGL_NOTICE, "Received bad TCH frame ending at " + "fn=%u for %s with codec mode %d (out of range)\n", + fn, trx_chan_desc[chan].name, rc); + goto bfi; + } + + /* FACCH */ + if (rc == GSM_MACBLOCK_LEN) { + chan_state->ul_ongoing_facch = 1; + _sched_compose_ph_data_ind(l1t, tn, + (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, + tch_data + amr, GSM_MACBLOCK_LEN, rssi); +bfi: + if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { + /* indicate bad frame */ + switch (tch_mode) { + case GSM48_CMODE_SPEECH_V1: /* HR */ + tch_data[0] = 0x70; /* F = 0, FT = 111 */ + memset(tch_data + 1, 0, 14); + rc = 15; + break; + case GSM48_CMODE_SPEECH_AMR: /* AMR */ + rc = amr_compose_payload(tch_data, + chan_state->codec[chan_state->dl_cmr], + chan_state->codec[chan_state->dl_ft], + 1); + if (rc < 2) + break; + memset(tch_data + 2, 0, rc - 2); + break; + default: + LOGP(DL1C, LOGL_ERROR, "TCH mode invalid, " + "please fix!\n"); + return -EINVAL; + } + } + } + + if (rsl_cmode != RSL_CMOD_SPD_SPEECH) + return 0; + + /* TCH or BFI */ + /* Note on FN 19 or 20: If we received the last burst of a frame, + * it actually starts at FN 8 or 9. A burst starting there, overlaps + * with the slot 12, so an extra FN must be substracted to get correct + * start of frame. + */ + return _sched_compose_tch_ind(l1t, tn, + (fn + GSM_HYPERFRAME - 10 - ((fn%26)==19) - ((fn%26)==20)) % GSM_HYPERFRAME, + chan, tch_data, rc); +} -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:24:05 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:24:05 +0100 Subject: [PATCH 6/7] TRX: scheduler: Remove dependency to trx_if.[ch] In-Reply-To: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> References: <1454523846-13022-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454523846-13022-6-git-send-email-laforge@gnumonks.org> From: Harald Welte --- src/osmo-bts-trx/scheduler.c | 14 +++----------- src/osmo-bts-trx/scheduler_backend.h | 1 + src/osmo-bts-trx/scheduler_trx.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/osmo-bts-trx/scheduler.c b/src/osmo-bts-trx/scheduler.c index 10f8972..dee46ed 100644 --- a/src/osmo-bts-trx/scheduler.c +++ b/src/osmo-bts-trx/scheduler.c @@ -38,7 +38,6 @@ #include "scheduler.h" #include "scheduler_backend.h" -//#include "trx_if.h" extern void *tall_bts_ctx; @@ -1325,10 +1324,8 @@ int trx_sched_set_lchan(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t link_i } /* disable handover detection (on deactivation) */ - if (!active) { - struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); - trx_if_cmd_nohandover(l1h, tn, ss); - } + if (!active) + _sched_act_rach_det(l1t, tn, ss, 0); return rc; } @@ -1340,7 +1337,6 @@ int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmo { uint8_t tn = L1SAP_CHAN2TS(chan_nr); struct l1sched_ts *l1ts = l1sched_trx_get_ts(l1t, tn); - struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); uint8_t ss = l1sap_chan2ss(chan_nr); int i; int rc = -EINVAL; @@ -1385,11 +1381,7 @@ int trx_sched_set_mode(struct l1sched_trx *l1t, uint8_t chan_nr, uint8_t rsl_cmo * of transceiver link). * disable handover, if state is still set, since we might not know * the actual state of transceiver (due to loss of link) */ - if (handover) { - trx_if_cmd_handover(l1h, tn, ss); - } else { - trx_if_cmd_nohandover(l1h, tn, ss); - } + _sched_act_rach_det(l1t, tn, ss, handover); return rc; } diff --git a/src/osmo-bts-trx/scheduler_backend.h b/src/osmo-bts-trx/scheduler_backend.h index b808455..9f663cd 100644 --- a/src/osmo-bts-trx/scheduler_backend.h +++ b/src/osmo-bts-trx/scheduler_backend.h @@ -79,3 +79,4 @@ int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, const ubit_t *_sched_dl_burst(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); int _sched_rts(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn); +void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 0aeb835..5629a64 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -1458,3 +1458,13 @@ new_clock: return 0; } + +void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate) +{ + struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); + + if (activate) + trx_if_cmd_handover(l1h, tn, ss); + else + trx_if_cmd_nohandover(l1h, tn, ss); +} -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:37:19 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:37:19 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction Message-ID: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> From: Harald Welte This way we can model a flexible mapping between any number of PHYs, each having multiple instances, and then map BTSs with TRXx on top of those PHYs. --- doc/examples/octphy/osmo-bts.cfg | 8 +- include/osmo-bts/Makefile.am | 2 +- include/osmo-bts/bts.h | 3 +- include/osmo-bts/bts_model.h | 5 + include/osmo-bts/gsm_data.h | 15 -- include/osmo-bts/phy_link.h | 115 +++++++++++ include/osmo-bts/scheduler.h | 4 +- include/osmo-bts/vty.h | 7 +- src/common/Makefile.am | 2 +- src/common/bts.c | 33 +++- src/common/main.c | 20 ++ src/common/phy_link.c | 155 +++++++++++++++ src/common/scheduler.c | 6 +- src/common/vty.c | 194 ++++++++++++++++++- src/osmo-bts-octphy/l1_if.c | 133 ++++++++----- src/osmo-bts-octphy/l1_if.h | 31 ++- src/osmo-bts-octphy/l1_oml.c | 96 +++++---- src/osmo-bts-octphy/main.c | 1 + src/osmo-bts-octphy/octphy_hw_api.c | 14 +- src/osmo-bts-octphy/octphy_vty.c | 198 +++++++++++-------- src/osmo-bts-trx/l1_if.c | 84 ++++---- src/osmo-bts-trx/l1_if.h | 18 +- src/osmo-bts-trx/main.c | 56 ++---- src/osmo-bts-trx/scheduler_trx.c | 16 +- src/osmo-bts-trx/trx_if.c | 124 +++++++++--- src/osmo-bts-trx/trx_if.h | 1 + src/osmo-bts-trx/trx_vty.c | 377 ++++++++++++++++++++++-------------- 27 files changed, 1220 insertions(+), 498 deletions(-) create mode 100644 include/osmo-bts/phy_link.h create mode 100644 src/common/phy_link.c diff --git a/doc/examples/octphy/osmo-bts.cfg b/doc/examples/octphy/osmo-bts.cfg index 07bcae0..4f27c8d 100644 --- a/doc/examples/octphy/osmo-bts.cfg +++ b/doc/examples/octphy/osmo-bts.cfg @@ -20,9 +20,13 @@ log stderr line vty no login ! +phy 0 + octphy hw-addr 00:0C:90:2e:80:1e + octphy net-device eth0.2342 + instance 0 bts 0 band 1800 ipa unit-id 1234 0 oml remote-ip 127.0.0.1 - phy-hw-addr 00:0C:90:2e:80:1e - phy-netdev eth0.2342 + trx 0 + phy 0 instance 0 diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index af88a1a..d0b55ff 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,4 +1,4 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \ - power_control.h scheduler.h scheduler_backend.h + power_control.h scheduler.h scheduler_backend.h phy_link.h diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index 9e21186..af0b305 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -21,13 +21,12 @@ void destroy_bts(struct gsm_bts *bts); int work_bts(struct gsm_bts *bts); int bts_link_estab(struct gsm_bts *bts); int trx_link_estab(struct gsm_bts_trx *trx); +int trx_set_available(struct gsm_bts_trx *trx, int avail); void bts_new_si(void *arg); void bts_setup_slot(struct gsm_bts_trx_ts *slot, uint8_t comb); int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg); struct msgb *bts_agch_dequeue(struct gsm_bts *bts); -void bts_update_agch_max_queue_length(struct gsm_bts *bts); -int bts_agch_max_queue_length(int T, int bcch_conf); int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, int is_ag_res); diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 41b5e93..dfea988 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -8,6 +8,9 @@ #include +struct phy_link; +struct phy_instance; + /* BTS model specific functions needed by the common code */ int bts_model_init(struct gsm_bts *bts); @@ -32,6 +35,8 @@ int bts_model_vty_init(struct gsm_bts *bts); void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink); +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst); int bts_model_oml_estab(struct gsm_bts *bts); diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 6a7bca8..f9e6ed1 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -119,21 +119,6 @@ enum lchan_ciph_state { #include "openbsc/gsm_data_shared.h" -struct femtol1_hdl; - -static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - -struct trx_l1h; - -static inline struct trx_l1h *trx_l1h_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - - void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state); /* cipher code */ diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h new file mode 100644 index 0000000..b9fc412 --- /dev/null +++ b/include/osmo-bts/phy_link.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include + +#include + +#include + +struct gsm_bts_trx; + +enum phy_link_type { + PHY_LINK_T_NONE, + PHY_LINK_T_SYSMOBTS, + PHY_LINK_T_OSMOTRX, +}; + +enum phy_link_state { + PHY_LINK_SHUTDOWN, + PHY_LINK_CONNECTING, + PHY_LINK_CONNECTED, +}; + +/* A PHY link represents the connection to a given PHYsical layer + * implementation. That PHY link contains 1...N PHY instances, one for + * each TRX */ +struct phy_link { + struct llist_head list; + int num; + enum phy_link_type type; + enum phy_link_state state; + struct llist_head instances; + char *description; + union { + struct { + } sysmobts; + struct { + char *transceiver_ip; + uint16_t base_port_local; + uint16_t base_port_remote; + struct osmo_fd trx_ofd_clk; + + uint32_t clock_advance; + uint32_t rts_advance; + + int rxgain_valid; + int rxgain; + int rxgain_sent; + + int power_valid; + int power; + int power_oml; + int power_sent; + } osmotrx; + struct { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* Network device name */ + char *netdev_name; + + /* configuration */ + uint32_t rf_port_index; + uint32_t rx_gain_db; + uint32_t tx_atten_db; + + struct octphy_hdl *hdl; + } octphy; + } u; +}; + +struct phy_instance { + /* liked inside phy_link.linstances */ + struct llist_head list; + int num; + char *description; + + /* pointer to the PHY link to which we belong */ + struct phy_link *phy_link; + + /* back-pointer to the TRX to which we're associated */ + struct gsm_bts_trx *trx; + + union { + struct { + } sysmobts; + struct { + struct trx_l1h *hdl; + } osmotrx; + struct { + /* logical transceiver number within one PHY */ + uint32_t trx_id; + } octphy; + } u; +}; + +struct phy_link *phy_link_by_num(int num); +struct phy_link *phy_link_create(void *ctx, int num); +void phy_link_destroy(struct phy_link *plink); +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state); +int phy_links_open(void); + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num); +struct phy_instance *phy_instance_create(struct phy_link *plink, int num); +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx); +void phy_instance_destroy(struct phy_instance *pinst); +const char *phy_instance_name(struct phy_instance *pinst); + +void phy_user_statechg_notif(struct phy_instance *pinst, enum phy_link_state link_state); + +static inline struct phy_instance *trx_phy_instance(struct gsm_bts_trx *trx) +{ + return trx->role_bts.l1h; +} + +int bts_model_phy_link_open(struct phy_link *plink); diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 13ef051..b11e6f1 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -1,6 +1,8 @@ #ifndef TRX_SCHEDULER_H #define TRX_SCHEDULER_H +#include + /* These types define the different channels on a multiframe. * Each channel has queues and can be activated individually. */ @@ -133,7 +135,7 @@ extern uint32_t transceiver_last_fn; /*! \brief Initialize the scheudler data structures */ -int trx_sched_init(struct l1sched_trx *l1t); +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx); /*! \brief De-initialize the scheudler data structures */ void trx_sched_exit(struct l1sched_trx *l1t); diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h index 546729c..5d8d4a7 100644 --- a/include/osmo-bts/vty.h +++ b/include/osmo-bts/vty.h @@ -5,7 +5,12 @@ #include enum bts_vty_node { - BTS_NODE = _LAST_OSMOVTY_NODE + 1, + /* PHY_NODE must come before BTS node to ensure the phy + * instances are created at the time the TRX nodes want to refer + * to them */ + PHY_NODE = _LAST_OSMOVTY_NODE + 1, + PHY_INST_NODE, + BTS_NODE, TRX_NODE, }; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index fea205c..8df6513 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -8,6 +8,6 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ - l1sap.c cbch.c power_control.c main.c + l1sap.c cbch.c power_control.c main.c phy_link.c libl1sched_a_SOURCES = scheduler.c diff --git a/src/common/bts.c b/src/common/bts.c index 43f4c25..a775329 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -44,6 +44,8 @@ #include #include +static void bts_update_agch_max_queue_length(struct gsm_bts *bts); +static int bts_agch_max_queue_length(int T, int bcch_conf); struct gsm_network bts_gsmnet = { .bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list }, @@ -72,6 +74,8 @@ static int bts_signal_cbfn(unsigned int subsys, unsigned int signal, return 0; } +/* Initialize the BTS (and TRX) data structures, called before config + * file reading */ int bts_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; @@ -255,6 +259,31 @@ int trx_link_estab(struct gsm_bts_trx *trx) return 0; } +/* set the availability of the TRX (used by PHY driver) */ +int trx_set_available(struct gsm_bts_trx *trx, int avail) +{ + int tn; + + LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n", + trx->nr, avail); + if (avail) { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->mo); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->bb_transc.mo); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); + } else { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + } + return 0; +} + int lchan_init_lapdm(struct gsm_lchan *lchan) { struct lapdm_channel *lc = &lchan->lapdm_ch; @@ -271,7 +300,7 @@ int lchan_init_lapdm(struct gsm_lchan *lchan) #define CCCH_RACH_RATIO_COMBINED256 (256*1/9) #define CCCH_RACH_RATIO_SEPARATE256 (256*10/55) -int bts_agch_max_queue_length(int T, int bcch_conf) +static int bts_agch_max_queue_length(int T, int bcch_conf) { int S, ccch_rach_ratio256, i; int T_group = 0; @@ -310,7 +339,7 @@ int bts_agch_max_queue_length(int T, int bcch_conf) return (T + 2 * S) * ccch_rach_ratio256 / 256; } -void bts_update_agch_max_queue_length(struct gsm_bts *bts) +static void bts_update_agch_max_queue_length(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm48_system_information_type_3 *si3; diff --git a/src/common/main.c b/src/common/main.c index fabe482..e454a28 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -284,6 +285,19 @@ int bts_main(int argc, char **argv) exit(1); } + if (!phy_link_by_num(0)) { + fprintf(stderr, "You need to configure at last phy0\n"); + exit(1); + } + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (!trx->role_bts.l1h) { + fprintf(stderr, "TRX %u has no associated PHY instance\n", + trx->nr); + exit(1); + } + } + write_pid_file("osmo-bts"); bts_controlif_setup(bts); @@ -317,6 +331,12 @@ int bts_main(int argc, char **argv) exit(2); } + rc = phy_links_open(); + if (rc < 0) { + fprintf(stderr, "unable ot open PHY link(s)\n"); + exit(2); + } + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { diff --git a/src/common/phy_link.c b/src/common/phy_link.c new file mode 100644 index 0000000..9442349 --- /dev/null +++ b/src/common/phy_link.c @@ -0,0 +1,155 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +static LLIST_HEAD(g_phy_links); + +struct phy_link *phy_link_by_num(int num) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + if (plink->num == num) + return plink; + } + + return NULL; +} + +struct phy_link *phy_link_create(void *ctx, int num) +{ + struct phy_link *plink = talloc_zero(ctx, struct phy_link); + + if (phy_link_by_num(num)) + return NULL; + + plink = talloc_zero(ctx, struct phy_link); + plink->num = num; + plink->state = PHY_LINK_SHUTDOWN; + INIT_LLIST_HEAD(&plink->instances); + llist_add_tail(&plink->list, &g_phy_links); + + return plink; +} + +const struct value_string phy_link_state_vals[] = { + { PHY_LINK_SHUTDOWN, "shutdown" }, + { PHY_LINK_CONNECTING, "connectiong" }, + { PHY_LINK_CONNECTED, "connected" }, + { 0, NULL } +}; + +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) +{ + struct phy_instance *pinst; + + LOGP(DL1C, LOGL_INFO, "PHY link state change %s -> %s\n", + get_value_string(phy_link_state_vals, plink->state), + get_value_string(phy_link_state_vals, state)); + + /* notify all TRX associated with this phy */ + llist_for_each_entry(pinst, &plink->instances, list) { + struct gsm_bts_trx *trx = pinst->trx; + if (!trx) + continue; + + switch (state) { + case PHY_LINK_CONNECTED: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n"); + trx_set_available(trx, 1); + break; + default: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n"); + trx_set_available(trx, 0); + break; + } + } + + plink->state = state; +} + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num) +{ + struct phy_instance *pinst; + + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->num == num) + return pinst; + } + return NULL; +} + +struct phy_instance *phy_instance_create(struct phy_link *plink, int num) +{ + struct phy_instance *pinst = talloc_zero(plink, struct phy_instance); + + if (phy_instance_by_num(plink, num)) + return NULL; + + pinst = talloc_zero(plink, struct phy_instance); + pinst->num = num; + pinst->phy_link = plink; + llist_add_tail(&pinst->list, &plink->instances); + + return pinst; +} + +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx) +{ + trx->role_bts.l1h = pinst; + pinst->trx = trx; +} + +void phy_instance_destroy(struct phy_instance *pinst) +{ + /* remove from list of instances in the link */ + llist_del(&pinst->list); + + /* remove reverse link from TRX */ + OSMO_ASSERT(pinst->trx->role_bts.l1h == pinst); + pinst->trx->role_bts.l1h = NULL; + pinst->trx = NULL; + + talloc_free(pinst); +} + +void phy_link_destroy(struct phy_link *plink) +{ + struct phy_instance *pinst, *pinst2; + + llist_for_each_entry_safe(pinst, pinst2, &plink->instances, list) + phy_instance_destroy(pinst); + + talloc_free(plink); +} + +int phy_links_open(void) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + int rc; + + rc = bts_model_phy_link_open(plink); + if (rc < 0) + return rc; + } + + return 0; +} + +const char *phy_instance_name(struct phy_instance *pinst) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), "phy%u.%u", pinst->phy_link->num, + pinst->num); + return buf; +} diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 64d89ac..de09fbf 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -134,11 +134,13 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { * init / exit */ -int trx_sched_init(struct l1sched_trx *l1t) +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx) { uint8_t tn; int i; + l1t->trx = trx; + LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { @@ -191,7 +193,7 @@ void trx_sched_exit(struct l1sched_trx *l1t) void trx_sched_reset(struct l1sched_trx *l1t) { trx_sched_exit(l1t); - trx_sched_init(l1t); + trx_sched_init(l1t, l1t->trx); } struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, diff --git a/src/common/vty.c b/src/common/vty.c index 4fd65d0..94ccdbe 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,13 @@ int bts_vty_go_parent(struct vty *vty) { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -60,6 +68,7 @@ int bts_vty_go_parent(struct vty *vty) vty->index = trx->bts; } break; + case PHY_NODE: default: vty->node = CONFIG_NODE; } @@ -71,6 +80,8 @@ int bts_vty_is_config_node(struct vty *vty, int node) switch (node) { case TRX_NODE: case BTS_NODE: + case PHY_NODE: + case PHY_INST_NODE: return 1; default: return 0; @@ -81,6 +92,17 @@ gDEFUN(ournode_exit, ournode_exit_cmd, "exit", "Exit current node, go down to provious node") { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; + case PHY_NODE: + vty->node = CONFIG_NODE; + vty->index = NULL; + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -141,6 +163,7 @@ static struct cmd_node trx_node = { 1, }; + DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, "trx <0-254>", "Select a TRX to configure\n" "TRX number\n") @@ -151,7 +174,7 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, trx = gsm_bts_trx_num(bts, trx_nr); if (!trx) { - vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%d%s", + vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%u%s", trx_nr, bts->num_trx - 1, VTY_NEWLINE); return CMD_WARNING; } @@ -232,6 +255,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) llist_for_each_entry(trx, &bts->trx_list, list) { struct trx_power_params *tpp = &trx->power_params; + struct phy_instance *pinst = trx_phy_instance(trx); vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); if (trx->power_params.user_gain_mdB) @@ -246,6 +270,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " ms-power-control %s%s", trx->ms_power_control == 0 ? "dsp" : "osmo", VTY_NEWLINE); + vty_out(vty, " phy %u instance %u%s", pinst->phy_link->num, + pinst->num, VTY_NEWLINE); bts_model_config_write_trx(vty, trx); } @@ -262,6 +288,35 @@ static int config_write_bts(struct vty *vty) return CMD_SUCCESS; } +static void config_write_phy_single(struct vty *vty, struct phy_link *plink) +{ + int i; + + vty_out(vty, "phy %u%s", plink->num, VTY_NEWLINE); + bts_model_config_write_phy(vty, plink); + + for (i = 0; i < 255; i++) { + struct phy_instance *pinst = phy_instance_by_num(plink, i); + if (!pinst) + break; + vty_out(vty, " instance %u%s", pinst->num, VTY_NEWLINE); + } +} + +static int config_write_phy(struct vty *vty) +{ + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + config_write_phy_single(vty, plink); + } + + return CMD_SUCCESS; +} + static int config_write_dummy(struct vty *vty) { return CMD_SUCCESS; @@ -532,6 +587,33 @@ DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd, return CMD_SUCCESS; } +DEFUN(cfg_trx_phy, cfg_trx_phy_cmd, + "phy <0-255> instance <0-255>", + "Configure PHY Link+Instance for this TRX\n" + "PHY Link number\n" "PHY instance\n" "PHY Instance number") +{ + struct gsm_bts_trx *trx = vty->index; + struct phy_link *plink = phy_link_by_num(atoi(argv[0])); + struct phy_instance *pinst; + + if (!plink) { + vty_out(vty, "phy%s does not exist%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + pinst = phy_instance_by_num(plink, atoi(argv[1])); + if (!pinst) { + vty_out(vty, "phy%s instance %s does not exit%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + trx->role_bts.l1h = pinst; + pinst->trx = trx; + + return CMD_SUCCESS; +} /* ====================================================================== * SHOW @@ -702,6 +784,106 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, return CMD_SUCCESS; } +static struct cmd_node phy_node = { + PHY_NODE, + "%s(phy)#", + 1, +}; + +static struct cmd_node phy_inst_node = { + PHY_INST_NODE, + "%s(phy-inst)#", + 1, +}; + +DEFUN(cfg_phy, cfg_phy_cmd, + "phy <0-255>", + "Select a PHY to configure\n" "PHY number\n") +{ + int phy_nr = atoi(argv[0]); + struct phy_link *plink; + + plink = phy_link_by_num(phy_nr); + if (!plink) + plink = phy_link_create(tall_bts_ctx, phy_nr); + if (!plink) + return CMD_WARNING; + + vty->index = plink; + vty->index_sub = &plink->description; + vty->node = PHY_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_inst, cfg_phy_inst_cmd, + "instance <0-255>", + "Select a PHY instance to configure\n" "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + pinst = phy_instance_create(plink, inst_nr); + if (!pinst) { + vty_out(vty, "Unable to create phy%u instance %u%s", + plink->num, inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + } + + vty->index = pinst; + vty->index_sub = &pinst->description; + vty->node = PHY_INST_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_inst, cfg_phy_no_inst_cmd, + "no instance <0-255>" + NO_STR "Select a PHY instance to remove\n", "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + vty_out(vty, "No such instance %u%s", inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + phy_instance_destroy(pinst); + + return CMD_SUCCESS; +} + +#if 0 +DEFUN(cfg_phy_type, cfg_phy_type_cmd, + "type (sysmobts|osmo-trx|virtual)", + "configure the type of the PHY\n" + "sysmocom sysmoBTS PHY\n" + "OsmoTRX based PHY\n" + "Virtual PHY (GSMTAP based)\n") +{ + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Cannot change type of active PHY%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[0], "sysmobts")) + plink->type = PHY_LINK_T_SYSMOBTS; + else if (!strcmp(argv[0], "osmo-trx")) + plink->type = PHY_LINK_T_OSMOTRX; + else if (!strcmp(argv[0], "virtual")) + plink->type = PHY_LINK_T_VIRTUAL; +} +#endif + DEFUN(bts_t_t_l_jitter_buf, bts_t_t_l_jitter_buf_cmd, "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>", @@ -813,10 +995,20 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) install_element(TRX_NODE, &cfg_trx_pr_step_size_cmd); install_element(TRX_NODE, &cfg_trx_pr_step_interval_cmd); install_element(TRX_NODE, &cfg_trx_ms_power_control_cmd); + install_element(TRX_NODE, &cfg_trx_phy_cmd); install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd); install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd); install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd); + install_element(CONFIG_NODE, &cfg_phy_cmd); + install_node(&phy_node, config_write_phy); + install_default(PHY_NODE); + install_element(PHY_NODE, &cfg_phy_inst_cmd); + install_element(PHY_NODE, &cfg_phy_no_inst_cmd); + + install_node(&phy_inst_node, config_write_dummy); + install_default(PHY_INST_NODE); + return 0; } diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index db6e032..f73e4f9 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -109,6 +110,17 @@ osmocom_to_octphy_band(enum gsm_band osmo_band, unsigned int arfcn) } }; +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id) +{ + struct phy_instance *pinst; + + pinst = phy_instance_by_num(fl1h->phy_link, trx_id); + if (!pinst) + return NULL; + + return pinst->trx; +} + struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id) { @@ -282,10 +294,9 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, } /* For OctPHY, this only about sending state changes to BSC */ -int l1if_activate_rf(struct octphy_hdl *fl1h, int on) +int l1if_activate_rf(struct gsm_bts_trx *trx, int on) { int i; - struct gsm_bts_trx *trx = fl1h->priv; if (on) { /* signal availability */ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); @@ -422,7 +433,8 @@ static void empty_req_from_rts_ind(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_E static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *l1msg = l1p_msgb_alloc(); uint32_t u32Fn; uint8_t u8Tn, subCh, sapi = 0; @@ -489,7 +501,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -508,7 +520,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -527,7 +539,8 @@ done: static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, sapi, ss; @@ -565,7 +578,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -590,7 +603,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -686,32 +699,37 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) return rc; } +int bts_model_phy_link_open(struct phy_link *plink) +{ + if (plink->u.octphy.hdl) + l1if_close(plink->u.octphy.hdl); + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + plink->u.octphy.hdl = l1if_open(plink); + if (!plink->u.octphy.hdl) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* do we need to iterate over the list of instances and do some + * instance-specific initialization? */ + + /* FIXME: delay this until we know the PHY responds */ + phy_link_state_set(plink, PHY_LINK_CONNECTED); + + return 0; +} + int bts_model_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; - struct octphy_hdl *fl1h; LOGP(DL1C, LOGL_NOTICE, "model_init()\n"); btsb = bts_role_bts(bts); btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); - fl1h = talloc_zero(bts, struct octphy_hdl); - if (!fl1h) - return -ENOMEM; - - INIT_LLIST_HEAD(&fl1h->wlc_list); - INIT_LLIST_HEAD(&fl1h->wlc_postponed); - fl1h->priv = bts->c0; - bts->c0->role_bts.l1h = fl1h; - /* FIXME: what is the nominal transmit power of the PHY/board? */ - bts->c0->nominal_power = 15; - - /* configure some reasonable defaults, to be overridden by VTY */ - fl1h->config.rf_port_index = 0; - fl1h->config.rx_gain_db = 70; - fl1h->config.tx_atten_db = 0; - bts_model_vty_init(bts); return 0; @@ -750,23 +768,15 @@ static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m) static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn) { - struct gsm_bts_trx *trx = fl1->priv; - struct gsm_bts *bts = trx->bts; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, trx_id); struct osmo_phsap_prim l1sap; /* increment the primitive count for the alive timer */ fl1->alive_prim_cnt++; /* ignore every time indication, except for c0 */ - if (trx != bts->c0) - return 0; - - if (trx_id != trx->nr) { - LOGP(DL1C, LOGL_FATAL, - "TRX id %d from response does not match the L1 context trx %d\n", - trx_id, trx->nr); + if (trx != trx->bts->c0) return 0; - } memset(&l1sap, 0, sizeof(l1sap)); osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, @@ -783,7 +793,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_READY_TO_SEND_INDICATION_EVT *evt, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, evt->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct osmo_phsap_prim *l1sap; struct gsm_time g_time; @@ -908,7 +918,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *data_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, data_ind->TrxId.byTrxId); uint8_t chan_nr, link_id; struct osmo_phsap_prim *l1sap; uint32_t fn; @@ -992,7 +1002,7 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_RACH_INDICATION_EVT *ra_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, ra_ind->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm_lchan *lchan; @@ -1131,7 +1141,7 @@ static int rx_octvc1_resp(struct msgb *msg, uint32_t msg_id, uint32_t trans_id) if (wlc->cb) { /* call-back function must take msgb * ownership. */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(fl1h, msg, wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1534,15 +1544,35 @@ static int octphy_write_cb(struct osmo_fd *fd, struct msgb *msg) return rc; } -int l1if_open(struct octphy_hdl *fl1h) +struct octphy_hdl *l1if_open(struct phy_link *plink) { + struct octphy_hdl *fl1h; struct ifreq ifr; int sfd, rc; - char *phy_dev = fl1h->netdev_name; + char *phy_dev = plink->u.octphy.netdev_name; + + fl1h = talloc_zero(plink, struct octphy_hdl); + if (!fl1h) + return NULL; + + INIT_LLIST_HEAD(&fl1h->wlc_list); + INIT_LLIST_HEAD(&fl1h->wlc_postponed); + fl1h->phy_link = plink; +#if 0 + bts->c0->role_bts.l1h = fl1h; + /* FIXME: what is the nominal transmit power of the PHY/board? */ + bts->c0->nominal_power = 15; + + /* configure some reasonable defaults, to be overridden by VTY */ + fl1h->config.rf_port_index = 0; + fl1h->config.rx_gain_db = 70; + fl1h->config.tx_atten_db = 0; +#endif if (!phy_dev) { LOGP(DL1C, LOGL_ERROR, "You have to specify a phy-netdev\n"); - return -EINVAL; + talloc_free(fl1h); + return NULL; } LOGP(DL1C, LOGL_NOTICE, "Opening L1 interface for OctPHY (%s)\n", @@ -1553,7 +1583,8 @@ int l1if_open(struct octphy_hdl *fl1h) if (sfd < 0) { LOGP(DL1C, LOGL_FATAL, "Error opening PHY socket: %s\n", strerror(errno)); - return -EIO; + talloc_free(fl1h); + return NULL; } /* resolve the string device name to an ifindex */ @@ -1564,18 +1595,21 @@ int l1if_open(struct octphy_hdl *fl1h) LOGP(DL1C, LOGL_FATAL, "Error using network device %s: %s\n", phy_dev, strerror(errno)); close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } fl1h->session_id = rand(); - /* set fl1h->phy_addr, which we use as sendto() destionation */ + /* set fl1h->phy_addr, which we use as sendto() destination */ fl1h->phy_addr.sll_family = AF_PACKET; fl1h->phy_addr.sll_protocol = htons(cOCTPKT_HDR_ETHERTYPE); fl1h->phy_addr.sll_ifindex = ifr.ifr_ifindex; fl1h->phy_addr.sll_hatype = ARPHRD_ETHER; - fl1h->phy_addr.sll_halen = 6; - /* sll_addr is filled by bts_model_vty code */ + fl1h->phy_addr.sll_halen = ETH_ALEN; + /* plink->phy_addr.sll_addr is filled by bts_model_vty code */ + memcpy(fl1h->phy_addr.sll_addr, plink->u.octphy.phy_addr.sll_addr, + ETH_ALEN); /* Write queue / osmo_fd registration */ osmo_wqueue_init(&fl1h->phy_wq, 10); @@ -1588,10 +1622,11 @@ int l1if_open(struct octphy_hdl *fl1h) rc = osmo_fd_register(&fl1h->phy_wq.bfd); if (rc < 0) { close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } - return 0; + return fl1h; } int l1if_close(struct octphy_hdl *fl1h) diff --git a/src/osmo-bts-octphy/l1_if.h b/src/osmo-bts-octphy/l1_if.h index 4277865..2dee178 100644 --- a/src/osmo-bts-octphy/l1_if.h +++ b/src/osmo-bts-octphy/l1_if.h @@ -13,16 +13,16 @@ #include #include +#include #include struct octphy_hdl { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* packet socket to talk with PHY */ struct osmo_wqueue phy_wq; - /* MAC address of th PHY */ - struct sockaddr_ll phy_addr; - /* Network device name */ - char *netdev_name; /* address parameters of the PHY */ uint32_t session_id; @@ -33,12 +33,6 @@ struct octphy_hdl { uint32_t clkmgr_state; struct { - uint32_t rf_port_index; - uint32_t rx_gain_db; - uint32_t tx_atten_db; - } config; - - struct { struct { char *name; char *description; @@ -72,8 +66,8 @@ struct octphy_hdl { struct llist_head wlc_postponed; int wlc_postponed_len; - /* private pointer, points back to TRX */ - void *priv; + /* back pointer to the PHY link */ + struct phy_link *phy_link; struct osmo_timer_list alive_timer; uint32_t alive_prim_cnt; @@ -82,15 +76,10 @@ struct octphy_hdl { int opened; }; -static inline struct octphy_hdl *trx_octphy_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - void l1if_fill_msg_hdr(tOCTVC1_MSG_HEADER *mh, struct msgb *msg, struct octphy_hdl *fl1h, uint32_t msg_type, uint32_t api_cmd); -typedef int l1if_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, void *data); +typedef int l1if_compl_cb(struct octphy_hdl *fl1, struct msgb *l1_msg, void *data); /* send a request primitive to the L1 and schedule completion call-back */ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, @@ -100,19 +89,21 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id); -int l1if_open(struct octphy_hdl *fl1h); +struct octphy_hdl *l1if_open(struct phy_link *plink); int l1if_close(struct octphy_hdl *hdl); int l1if_trx_open(struct gsm_bts_trx *trx); int l1if_trx_close_all(struct gsm_bts *bts); int l1if_enable_events(struct gsm_bts_trx *trx); -int l1if_activate_rf(struct octphy_hdl *fl1h, int on); +int l1if_activate_rf(struct gsm_bts_trx *trx, int on); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT * data_ind); +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id); + struct msgb *l1p_msgb_alloc(void); /* tch.c */ diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c index 318c384..627b238 100644 --- a/src/osmo-bts-octphy/l1_oml.c +++ b/src/osmo-bts-octphy/l1_oml.c @@ -348,10 +348,11 @@ static void sapi_clear_queue(struct llist_head *queue) } } -static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; uint8_t sapi; uint8_t direction; @@ -361,7 +362,7 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ar); - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ar->LchId); sapi = ar->LchId.bySAPI; @@ -411,7 +412,8 @@ err: static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD *lac; @@ -420,7 +422,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) l1if_fill_msg_hdr(&lac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CID); - lac->TrxId.byTrxId = lchan->ts->trx->nr; + lac->TrxId.byTrxId = pinst->u.octphy.trx_id; lac->LchId.byTimeslotNb = lchan->ts->nr; lac->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); lac->LchId.bySAPI = cmd->sapi; @@ -451,10 +453,11 @@ static tOCTVC1_GSM_CIPHERING_ID_ENUM rsl2l1_ciph[] = { [4] = cOCTVC1_GSM_CIPHERING_ID_ENUM_A5_3 }; -static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *pcr = (tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_lchan *lchan; @@ -470,6 +473,7 @@ static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d exit(-1); } + trx = trx_by_l1h(fl1, pcr->TrxId.byTrxId); OSMO_ASSERT(pcr->TrxId.byTrxId == trx->nr); ts = &trx->ts[pcr->PchId.byTimeslotNb]; /* for some strange reason the response does not tell which @@ -508,8 +512,8 @@ err: static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct gsm_bts_trx *trx = lchan->ts->trx; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CMD *pcc; @@ -518,6 +522,7 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c l1if_fill_msg_hdr(&pcc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CID); + pcc->TrxId.byTrxId = pinst->u.octphy.trx_id; pcc->PchId.byTimeslotNb = lchan->ts->nr; pcc->ulSubchannelNb = lchan_to_GsmL1_SubCh_t(lchan); pcc->ulDirection = cmd->dir; @@ -627,7 +632,8 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir) static int lchan_deactivate_sapis(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; int i, res; @@ -654,10 +660,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan) return res; } -static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_deact_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *ldr = (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; struct sapi_cmd *cmd; uint8_t status; @@ -666,7 +673,7 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * release it before returning */ mOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ldr); - OSMO_ASSERT(ldr->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ldr->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ldr->LchId); @@ -725,7 +732,8 @@ err: static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CMD *ldc; @@ -734,6 +742,7 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd l1if_fill_msg_hdr(&ldc->Header, msg, fl1h,cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CID); + ldc->TrxId.byTrxId = pinst->u.octphy.trx_id; ldc->LchId.byTimeslotNb = lchan->ts->nr; ldc->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); ldc->LchId.byDirection = cmd->dir; @@ -1031,7 +1040,8 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir) int lchan_activate(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -1069,7 +1079,7 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan) return 0; } -static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int enable_events_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *mser = (tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *) resp->l2h; @@ -1088,7 +1098,8 @@ static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, vo int l1if_enable_events(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_CMD *mse; @@ -1112,9 +1123,8 @@ int l1if_enable_events(struct gsm_bts_trx *trx) dst = talloc_strdup(ctx, (const char *) src); \ } while (0) -static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *aisr = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *) resp->l2h; @@ -1136,7 +1146,8 @@ static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, voi int l1if_check_app_sys_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_CMD *ais; @@ -1152,9 +1163,8 @@ int l1if_check_app_sys_version(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, app_info_sys_compl_cb, 0); } -static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h; @@ -1178,7 +1188,8 @@ static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_check_app_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_CMD *ai; @@ -1194,8 +1205,11 @@ int l1if_check_app_version(struct gsm_bts_trx *trx) } /* call-back once the TRX_OPEN_CID response arrives */ -static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int trx_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { + struct gsm_bts_trx *trx; + struct phy_instance *pinst; + tOCTVC1_GSM_MSG_TRX_OPEN_RSP *or = (tOCTVC1_GSM_MSG_TRX_OPEN_RSP *) resp->l2h; @@ -1203,8 +1217,8 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d * release it before returning */ mOCTVC1_GSM_MSG_TRX_OPEN_RSP_SWAP(or); - - OSMO_ASSERT(or->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1h, or->TrxId.byTrxId); + pinst = trx_phy_instance(trx); LOGP(DL1C, LOGL_INFO, "TRX-OPEN.resp(trx=%u) = %s\n", trx->nr, octvc1_rc2string(or->Header.ulReturnCode)); @@ -1221,7 +1235,6 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d opstart_compl(&trx->mo); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); octphy_hw_get_pcb_info(fl1h); octphy_hw_get_rf_port_info(fl1h, 0); octphy_hw_get_rf_ant_rx_config(fl1h, 0, 0); @@ -1238,22 +1251,24 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_trx_open(struct gsm_bts_trx *trx) { /* putting it all together */ - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_OPEN_CMD *oc; oc = (tOCTVC1_GSM_MSG_TRX_OPEN_CMD *) msgb_put(msg, sizeof(*oc)); l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_OPEN_CID); - oc->ulRfPortIndex = fl1h->config.rf_port_index; - oc->TrxId.byTrxId = trx->nr; + oc->ulRfPortIndex = plink->u.octphy.rf_port_index; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->Config.ulBand = osmocom_to_octphy_band(trx->bts->band, trx->arfcn); oc->Config.usArfcn = trx->arfcn; oc->Config.usTsc = trx->bts->bsic & 0x7; oc->Config.usBcchArfcn = trx->bts->c0->arfcn; - oc->RfConfig.ulRxGainDb = fl1h->config.rx_gain_db; + oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db; /* FIXME: compute this based on nominal transmit power, etc. */ - oc->RfConfig.ulTxAttndB = fl1h->config.tx_atten_db; + oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db; LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, " "tsc=%u, rx_gain=%u, tx_atten=%u)\n", @@ -1266,7 +1281,7 @@ int l1if_trx_open(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, trx_open_compl_cb, NULL); } -static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int trx_close_all_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h; @@ -1283,7 +1298,9 @@ static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *da int l1if_trx_close_all(struct gsm_bts *bts) { - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); +#warning "Truly iterate over all TRX in this BTS" + struct phy_instance *pinst = trx_phy_instance(bts->c0); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac; @@ -1325,11 +1342,12 @@ static int trx_init(struct gsm_bts_trx *trx) * PHYSICAL CHANNE ACTIVATION ***********************************************************************/ -static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *) resp->l2h; uint8_t ts_nr; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_abis_mo *mo; @@ -1337,9 +1355,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); ts_nr = ar->PchId.byTimeslotNb; - - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); OSMO_ASSERT(ts_nr <= ARRAY_SIZE(trx->ts)); ts = &trx->ts[ts_nr]; @@ -1367,7 +1384,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * static int ts_connect(struct gsm_bts_trx_ts *ts) { - struct octphy_hdl *fl1h = trx_octphy_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) oc; @@ -1376,7 +1394,7 @@ static int ts_connect(struct gsm_bts_trx_ts *ts) l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CID); - oc->TrxId.byTrxId = ts->trx->nr; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->PchId.byTimeslotNb = ts->nr; oc->ulChannelType = pchan_to_logChComb[ts->pchan]; @@ -1430,8 +1448,7 @@ int bts_model_oml_estab(struct gsm_bts *bts) int i; for (i = 0; i < bts->num_trx; i++) { struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - l1if_activate_rf(fl1h, 1); + l1if_activate_rf(trx, 1); } return 0; } @@ -1447,8 +1464,7 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1 = trx_octphy_hdl(trx); - return l1if_activate_rf(fl1, 0); + return l1if_activate_rf(trx, 0); } int bts_model_trx_close(struct gsm_bts_trx *trx) diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c index 1f516e4..d237e42 100644 --- a/src/osmo-bts-octphy/main.c +++ b/src/osmo-bts-octphy/main.c @@ -56,6 +56,7 @@ static struct gsm_bts *bts; int bts_model_print_help() { + return 0; } int bts_model_handle_options(int argc, char **argv) diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c index 5291742..ec7c4be 100644 --- a/src/osmo-bts-octphy/octphy_hw_api.c +++ b/src/osmo-bts-octphy/octphy_hw_api.c @@ -35,7 +35,7 @@ #include /* Chapter 12.1 */ -static int get_pcb_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int get_pcb_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_PCB_INFO_RSP *pir = (tOCTVC1_HW_MSG_PCB_INFO_RSP *) resp->l2h; @@ -69,7 +69,7 @@ int octphy_hw_get_pcb_info(struct octphy_hdl *fl1h) } /* Chapter 12.9 */ -static int rf_port_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *pir = @@ -114,7 +114,7 @@ static const struct value_string radio_std_vals[] = { }; /* Chapter 12.10 */ -static int rf_port_stats_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_stats_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr = @@ -167,7 +167,7 @@ static const struct value_string rx_gain_mode_vals[] = { }; /* Chapter 12.13 */ -static int rf_ant_rx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_rx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *arc = @@ -209,7 +209,7 @@ int octphy_hw_get_rf_ant_rx_config(struct octphy_hdl *fl1h, uint32_t port_idx, } /* Chapter 12.14 */ -static int rf_ant_tx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_tx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *atc = @@ -292,7 +292,7 @@ static const struct value_string clocksync_state_vals[] = { }; /* Chapter 12.15 */ -static int get_clock_sync_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *cir = @@ -326,7 +326,7 @@ int octphy_hw_get_clock_sync_info(struct octphy_hdl *fl1h) } /* Chapter 12.16 */ -static int get_clock_sync_stats_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_stats_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr = diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c index dbc903a..e2000e9 100644 --- a/src/osmo-bts-octphy/octphy_vty.c +++ b/src/osmo-bts-octphy/octphy_vty.c @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -51,149 +52,189 @@ SHOW_STR \ TRX_STR +#define OCT_STR "OCTPHY Um interface\n" + static struct gsm_bts *vty_bts; /* configuration */ -DEFUN(cfg_bts_phy_hwaddr, cfg_bts_phy_hwaddr_cmd, - "phy-hw-addr HWADDR", - "Configure the hardware addess of the OCTPHY\n" +DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd, + "octphy hw-addr HWADDR", + OCT_STR "Configure the hardware addess of the OCTPHY\n" "hardware address in aa:bb:cc:dd:ee:ff format\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; int rc; - rc = osmo_macaddr_parse(fl1h->phy_addr.sll_addr, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + rc = osmo_macaddr_parse(plink->u.octphy.phy_addr.sll_addr, argv[0]); if (rc < 0) return CMD_WARNING; return CMD_SUCCESS; } -DEFUN(cfg_bts_phy_netdev, cfg_bts_phy_netdev_cmd, - "phy-netdev NAME", - "Configure the hardware device towards the OCTPHY\n" +DEFUN(cfg_phy_netdev, cfg_phy_netdev_cmd, + "octphy net-device NAME", + OCT_STR "Configure the hardware device towards the OCTPHY\n" "Ethernet device name\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - if (fl1h->netdev_name) - talloc_free(fl1h->netdev_name); - fl1h->netdev_name = talloc_strdup(fl1h, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (plink->u.octphy.netdev_name) + talloc_free(plink->u.octphy.netdev_name); + plink->u.octphy.netdev_name = talloc_strdup(plink, argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rf_port_idx, cfg_trx_rf_port_idx_cmd, - "rf-port-index <0-255>", - "Configure the RF Port for this TRX\n" +DEFUN(cfg_phy_rf_port_idx, cfg_phy_rf_port_idx_cmd, + "octphy rf-port-index <0-255>", + OCT_STR "Configure the RF Port for this TRX\n" "RF Port Index\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - fl1h->config.rf_port_index = atoi(argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + plink->u.octphy.rf_port_index = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rx_gain_db, cfg_trx_rx_gain_db_cmd, - "rx-gain <0-73>", - "Configure the Rx Gain in dB\n" +DEFUN(cfg_phy_rx_gain_db, cfg_phy_rx_gain_db_cmd, + "octphy rx-gain <0-73>", + OCT_STR "Configure the Rx Gain in dB\n" "Rx gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.rx_gain_db = atoi(argv[0]); + plink->u.octphy.rx_gain_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_tx_atten_db, cfg_trx_tx_atten_db_cmd, - "tx-attenuation <0-359>", - "Configure the Tx Attenuation in quarter-dB\n" +DEFUN(cfg_phy_tx_atten_db, cfg_phy_tx_atten_db_cmd, + "octphy tx-attenuation <0-359>", + OCT_STR "Configure the Tx Attenuation in quarter-dB\n" "Tx attenuation in quarter-dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.tx_atten_db = atoi(argv[0]); + plink->u.octphy.tx_atten_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(get_rf_port_stats, get_rf_port_stats_cmd, - "get-rf-port-stats <0-1>", - "Obtain statistics for the RF Port\n" +DEFUN(show_rf_port_stats, show_rf_port_stats_cmd, + "show phy <0-255> rf-port-stats <0-1>", + "Show statistics for the RF Port\n" "RF Port Number\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); - octphy_hw_get_rf_port_stats(fl1h, atoi(argv[0])); + octphy_hw_get_rf_port_stats(plink->u.octphy.hdl, atoi(argv[1])); + + /* FIXME */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } -DEFUN(get_clk_sync_stats, get_clk_sync_stats_cmd, - "get-clk-sync-stats", +DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd, + "show phy <0-255> clk-sync-stats", "Obtain statistics for the Clock Sync Manager\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + + octphy_hw_get_clock_sync_stats(plink->u.octphy.hdl); - octphy_hw_get_clock_sync_stats(fl1h); + /* FIXME */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.octphy.netdev_name) + vty_out(vty, " netdev %s%s", plink->u.octphy.netdev_name, + VTY_NEWLINE); + + vty_out(vty, " hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", + plink->u.octphy.phy_addr.sll_addr[0], + plink->u.octphy.phy_addr.sll_addr[1], + plink->u.octphy.phy_addr.sll_addr[2], + plink->u.octphy.phy_addr.sll_addr[3], + plink->u.octphy.phy_addr.sll_addr[4], + plink->u.octphy.phy_addr.sll_addr[5], + VTY_NEWLINE); + vty_out(vty, " rx-gain %u%s", plink->u.octphy.rx_gain_db, + VTY_NEWLINE); + vty_out(vty, " tx-attenuation %u%s", plink->u.octphy.tx_atten_db, + VTY_NEWLINE); + vty_out(vty, " rf-port-index %u%s", plink->u.octphy.rf_port_index, + VTY_NEWLINE); +} + void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); - - if (fl1h->netdev_name) - vty_out(vty, " phy-netdev %s%s", fl1h->netdev_name, - VTY_NEWLINE); if (btsb->auto_band) vty_out(vty, " auto-band%s", VTY_NEWLINE); - vty_out(vty, " phy-hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", - fl1h->phy_addr.sll_addr[0], fl1h->phy_addr.sll_addr[1], - fl1h->phy_addr.sll_addr[2], fl1h->phy_addr.sll_addr[3], - fl1h->phy_addr.sll_addr[4], fl1h->phy_addr.sll_addr[5], - VTY_NEWLINE); } void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - - vty_out(vty, " rx-gain %u%s", fl1h->config.rx_gain_db, - VTY_NEWLINE); - vty_out(vty, " tx-attenuation %u%s", fl1h->config.tx_atten_db, - VTY_NEWLINE); } DEFUN(show_sys_info, show_sys_info_cmd, - "show trx <0-255> system-information", + "show phy <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); struct octphy_hdl *fl1h; - int i; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - fl1h = trx_octphy_hdl(trx); + fl1h = plink->u.octphy.hdl; vty_out(vty, "System Platform: '%s', Version: '%s'%s", fl1h->info.system.platform, fl1h->info.system.version, @@ -210,15 +251,14 @@ int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; - install_element(BTS_NODE, &cfg_bts_phy_hwaddr_cmd); - install_element(BTS_NODE, &cfg_bts_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_hwaddr_cmd); + install_element(PHY_NODE, &cfg_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_rf_port_idx_cmd); + install_element(PHY_NODE, &cfg_phy_rx_gain_db_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_db_cmd); - install_element(TRX_NODE, &cfg_trx_rf_port_idx_cmd); - install_element(TRX_NODE, &cfg_trx_rx_gain_db_cmd); - install_element(TRX_NODE, &cfg_trx_tx_atten_db_cmd); - - install_element_ve(&get_rf_port_stats_cmd); - install_element_ve(&get_clk_sync_stats_cmd); + install_element_ve(&show_rf_port_stats_cmd); + install_element_ve(&show_clk_sync_stats_cmd); install_element_ve(&show_sys_info_cmd); return 0; @@ -226,13 +266,5 @@ int bts_model_vty_init(struct gsm_bts *bts) int bts_model_ctrl_cmds_install(struct gsm_bts *bts) { - /* FIXME: really ugly hack: We can only initialize the L1 intrface - * after reading the config file, and this is the only call-back after - * vty_read_config_fioe() at this point. Will be cleaned up with the - * phy interface generalization patches coming up soon as part of the - * multi-trx work */ - struct octphy_hdl *fl1h = bts->c0->role_bts.l1h; - l1if_open(fl1h); - return 0; } diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index edd4b7b..befaffd 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -59,7 +59,7 @@ static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = { * create/destroy trx l1 instance */ -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) +struct trx_l1h *l1if_open(struct phy_instance *pinst) { struct trx_l1h *l1h; int rc; @@ -67,11 +67,9 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) l1h = talloc_zero(tall_bts_ctx, struct trx_l1h); if (!l1h) return NULL; - l1h->trx = trx; - l1h->l1s.trx = trx; - trx->role_bts.l1h = l1h; + l1h->phy_inst = pinst; - trx_sched_init(&l1h->l1s); + trx_sched_init(&l1h->l1s, pinst->trx); rc = trx_if_open(l1h); if (rc < 0) { @@ -83,7 +81,6 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) err: l1if_close(l1h); - trx->role_bts.l1h = NULL; return NULL; } @@ -100,7 +97,8 @@ void l1if_reset(struct trx_l1h *l1h) static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) { - struct gsm_bts_trx *trx = l1h->trx; + struct phy_instance *pinst = l1h->phy_inst; + struct gsm_bts_trx *trx = pinst->trx; uint8_t tn; /* HACK, we should change state when we receive first clock from @@ -132,10 +130,10 @@ static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) int check_transceiver_availability(struct gsm_bts *bts, int avail) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; check_transceiver_availability_trx(l1h, avail); } return 0; @@ -147,6 +145,7 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail) */ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) { + struct phy_link *plink = l1h->phy_inst->phy_link; uint8_t tn; if (!transceiver_available) @@ -177,18 +176,23 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) } /* after power on */ - if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) { - trx_if_cmd_setrxgain(l1h, l1h->config.rxgain); - l1h->config.rxgain_sent = 1; - } - if (l1h->config.power_valid && !l1h->config.power_sent) { - trx_if_cmd_setpower(l1h, l1h->config.power); - l1h->config.power_sent = 1; + if (l1h->phy_inst->num == 0) { + if (plink->u.osmotrx.rxgain_valid && + !plink->u.osmotrx.rxgain_sent) { + trx_if_cmd_setrxgain(l1h, plink->u.osmotrx.rxgain); + plink->u.osmotrx.rxgain_sent = 1; + } + if (plink->u.osmotrx.power_valid && + !plink->u.osmotrx.power_sent) { + trx_if_cmd_setpower(l1h, plink->u.osmotrx.power); + plink->u.osmotrx.power_sent = 1; + } } if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) { trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly); l1h->config.maxdly_sent = 1; } + for (tn = 0; tn < TRX_NR_TS; tn++) { if (l1h->config.slottype_valid[tn] && !l1h->config.slottype_sent[tn]) { @@ -203,8 +207,10 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) if (!l1h->config.poweron && !l1h->config.poweron_sent) { trx_if_cmd_poweroff(l1h); l1h->config.poweron_sent = 1; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -216,17 +222,20 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) int l1if_provision_transceiver(struct gsm_bts *bts) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t tn; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.arfcn_sent = 0; l1h->config.tsc_sent = 0; l1h->config.bsic_sent = 0; l1h->config.poweron_sent = 0; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -242,7 +251,8 @@ int l1if_provision_transceiver(struct gsm_bts *bts) /* initialize the layer1 */ static int trx_init(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; /* power on transceiver, if not already */ if (!l1h->config.poweron) { @@ -264,7 +274,8 @@ static int trx_init(struct gsm_bts_trx *trx) /* deactivate transceiver */ int bts_model_trx_close(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; enum gsm_phys_chan_config pchan = trx->ts[0].pchan; /* close all logical channels and reset timeslots */ @@ -308,7 +319,6 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t bsic = bts->bsic; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); @@ -318,7 +328,8 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) { l1h->config.bsic = bsic; l1h->config.bsic_valid = 1; @@ -335,7 +346,9 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) /* set trx attributes */ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint16_t arfcn = trx->arfcn; if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) { @@ -345,10 +358,10 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) l1if_provision_transceiver_trx(l1h); } - if (l1h->config.power_oml) { - l1h->config.power = trx->max_power_red; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; + if (plink->u.osmotrx.power_oml && pinst->num == 0) { + plink->u.osmotrx.power = trx->max_power_red; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; l1if_provision_transceiver_trx(l1h); } @@ -358,7 +371,8 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) /* set ts attributes */ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) { - struct trx_l1h *l1h = trx_l1h_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn = ts->nr; uint16_t tsc = ts->tsc; enum gsm_phys_chan_config pchan = ts->pchan; @@ -439,6 +453,7 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan, static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, enum osmo_mph_info_type type, uint8_t cause) { + struct phy_instance *pinst = l1h->phy_inst; struct osmo_phsap_prim l1sap; memset(&l1sap, 0, sizeof(l1sap)); @@ -448,7 +463,7 @@ static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, l1sap.u.info.u.act_cnf.chan_nr = chan_nr; l1sap.u.info.u.act_cnf.cause = cause; - return l1sap_up(l1h->trx, &l1sap); + return l1sap_up(pinst->trx, &l1sap); } int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn) @@ -503,7 +518,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint /* primitive from common part */ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; struct msgb *msg = l1sap->oph.msg; uint8_t chan_nr; uint8_t tn, ss; diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index f492687..187303c 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -2,6 +2,7 @@ #define L1_IF_H_TRX #include +#include struct trx_config { uint8_t poweron; /* poweron(1) or poweroff(0) */ @@ -19,15 +20,6 @@ struct trx_config { uint8_t bsic; int bsic_sent; - int rxgain_valid; - int rxgain; - int rxgain_sent; - - int power_valid; - int power; - int power_oml; - int power_sent; - int maxdly_valid; int maxdly; int maxdly_sent; @@ -42,7 +34,8 @@ struct trx_config { struct trx_l1h { struct llist_head trx_ctrl_list; - struct gsm_bts_trx *trx; + //struct gsm_bts_trx *trx; + struct phy_instance *phy_inst; struct osmo_fd trx_ofd_ctrl; struct osmo_timer_list trx_ctrl_timer; @@ -55,7 +48,7 @@ struct trx_l1h { struct l1sched_trx l1s; }; -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx); +struct trx_l1h *l1if_open(struct phy_instance *pinst); void l1if_close(struct trx_l1h *l1h); void l1if_reset(struct trx_l1h *l1h); int check_transceiver_availability(struct gsm_bts *bts, int avail); @@ -69,7 +62,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx->role_bts.l1h; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; return &l1h->l1s; } diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index aa6987c..40cbcac 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -58,42 +59,13 @@ #include "l1_if.h" #include "trx_if.h" -int bts_model_init(struct gsm_bts *bts) -{ - void *l1h; - struct gsm_bts_trx *trx; - struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - - btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); - if (!settsc_enabled && !setbsic_enabled) - settsc_enabled = setbsic_enabled = 1; - - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = l1if_open(trx); - if (!l1h) { - LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n"); - goto error; - } - +#if 0 trx->role_bts.l1h = l1h; trx->nominal_power = 23; l1if_reset(l1h); - } - - bts_model_vty_init(bts); +#endif - return 0; - -error: - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx->role_bts.l1h; - if (l1h) - l1if_close(l1h); - } - - return -EIO; -} /* dummy, since no direct dsp support */ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) @@ -103,10 +75,6 @@ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) void bts_model_print_help() { - printf( - " -I --local-trx-ip Local IP for transceiver to connect (default=%s)\n" - , transceiver_ip - ); } int bts_model_handle_options(int argc, char **argv) @@ -116,21 +84,16 @@ int bts_model_handle_options(int argc, char **argv) while (1) { int option_idx = 0, c; static const struct option long_options[] = { - /* specific to this hardware */ - { "local-trx-ip", 1, 0, 'I' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "I:", + c = getopt_long(argc, argv, "", long_options, &option_idx); if (c == -1) break; switch (c) { - case 'I': - transceiver_ip = strdup(optarg); - break; default: num_errors++; break; @@ -140,6 +103,17 @@ int bts_model_handle_options(int argc, char **argv) return num_errors; } +int bts_model_init(struct gsm_bts *bts) +{ + struct gsm_bts_role_bts *btsb = bts_role_bts(bts); + + btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); + + bts_model_vty_init(bts); + + return 0; +} + int main(int argc, char **argv) { return bts_main(argc, argv); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index ac9212b..87d21ff 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -1268,8 +1268,9 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) /* process every TRX */ llist_for_each_entry(trx, &bts->trx_list, list) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); - struct l1sched_trx *l1t = trx_l1sched_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + struct l1sched_trx *l1t = &l1h->l1s; /* we don't schedule, if power is off */ if (!trx_if_powered(l1h)) @@ -1323,10 +1324,12 @@ no_clock: /* flush pending messages of transceiver */ /* close all logical channels and reset timeslots */ llist_for_each_entry(trx, &bts->trx_list, list) { - trx_if_flush(trx_l1h_hdl(trx)); - trx_sched_reset(trx_l1sched_hdl(trx)); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + trx_if_flush(l1h); + trx_sched_reset(&l1h->l1s); if (trx->nr == 0) - trx_if_cmd_poweroff(trx_l1h_hdl(trx)); + trx_if_cmd_poweroff(l1h); } /* tell BSC */ @@ -1461,7 +1464,8 @@ new_clock: void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate) { - struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); + struct phy_instance *pinst = trx_phy_instance(l1t->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (activate) trx_if_cmd_handover(l1h, tn, ss); diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index dbe6f68..6743d0b 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -2,6 +2,7 @@ * OpenBTS TRX interface handling * * Copyright (C) 2013 Andreas Eversberg + * Copyright (C) 2016 Harald Welte * * All Rights Reserved * @@ -34,6 +35,7 @@ #include #include +#include #include #include #include @@ -45,7 +47,6 @@ //#define TOA_RSSI_DEBUG int transceiver_available = 0; -const char *transceiver_ip = "127.0.0.1"; int settsc_enabled = 0; int setbsic_enabled = 0; @@ -56,8 +57,9 @@ int setbsic_enabled = 0; static uint16_t base_port_local = 5800; /* open socket */ -static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, - int (*cb)(struct osmo_fd *fd, unsigned int what)) +static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host, + uint16_t port_local, uint16_t port_remote, + int (*cb)(struct osmo_fd *fd, unsigned int what)) { struct sockaddr_storage sas; struct sockaddr *sa = (struct sockaddr *)&sas; @@ -71,8 +73,8 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, ofd->data = priv; /* Listen / Binds */ - rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, transceiver_ip, - port, OSMO_SOCK_F_BIND); + rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, host, + port_local, OSMO_SOCK_F_BIND); if (rc < 0) return rc; @@ -84,10 +86,10 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_port = htons(ntohs(sin->sin_port) - 100); + sin->sin_port = htons(port_remote); } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_port = htons(ntohs(sin6->sin6_port) - 100); + sin6->sin6_port = htons(port_remote); } else { return -EINVAL; } @@ -96,7 +98,6 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (rc) return rc; - return 0; } @@ -115,13 +116,11 @@ static void trx_udp_close(struct osmo_fd *ofd) * clock */ -static struct osmo_fd trx_ofd_clk; - - /* get clock from clock socket */ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) { - struct trx_l1h *l1h = ofd->data; + struct phy_link *plink = ofd->data; + struct phy_instance *pinst = phy_instance_by_num(plink, 0); char buf[1500]; int len; uint32_t fn; @@ -146,7 +145,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) "correctly, correcting to fn=%u\n", fn); } - trx_sched_clock(l1h->trx->bts, fn); + trx_sched_clock(pinst->trx->bts, fn); return 0; } @@ -168,8 +167,8 @@ static void trx_ctrl_send(struct trx_l1h *l1h) return; tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list); - LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd, - l1h->trx->nr); + LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to %s\n", tcm->cmd, + phy_instance_name(l1h->phy_inst)); /* send command */ send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0); @@ -184,8 +183,8 @@ static void trx_ctrl_timer_cb(void *data) { struct trx_l1h *l1h = data; - LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n", - l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for %s\n", + phy_instance_name(l1h->phy_inst)); trx_ctrl_send(l1h); } @@ -232,7 +231,8 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd, int trx_if_cmd_poweroff(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWEROFF", ""); else return 0; @@ -240,7 +240,8 @@ int trx_if_cmd_poweroff(struct trx_l1h *l1h) int trx_if_cmd_poweron(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWERON", ""); else return 0; @@ -324,6 +325,7 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss) static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) { struct trx_l1h *l1h = ofd->data; + struct phy_instance *pinst = l1h->phy_inst; char buf[1500]; int len, resp; @@ -374,11 +376,12 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) sscanf(p + 1, "%d", &resp); if (resp) { LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE, - "transceiver (trx=%d) rejected TRX command " - "with response: '%s'\n", l1h->trx->nr, buf); + "transceiver (%s) rejected TRX command " + "with response: '%s'\n", + phy_instance_name(pinst), buf); rsp_error: if (tcm->critical) { - bts_shutdown(l1h->trx->bts, "SIGINT"); + bts_shutdown(pinst->trx->bts, "SIGINT"); /* keep tcm list, so process is stopped */ return -EIO; } @@ -493,11 +496,67 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr, * open/close */ +int bts_model_phy_link_open(struct phy_link *plink) +{ + struct phy_instance *pinst; + int rc; + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + /* open the shared/common clock socket */ + rc = trx_udp_open(plink, &plink->u.osmotrx.trx_ofd_clk, + plink->u.osmotrx.transceiver_ip, + plink->u.osmotrx.base_port_local, + plink->u.osmotrx.base_port_remote, + trx_clk_read_cb); + if (rc < 0) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* open the individual instances with their ctrl+data sockets */ + llist_for_each_entry(pinst, &plink->instances, list) { + pinst->u.osmotrx.hdl = l1if_open(pinst); + if (!pinst->u.osmotrx.hdl) + goto cleanup; + } + + return 0; + +cleanup: + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->u.osmotrx.hdl) { + trx_if_close(pinst->u.osmotrx.hdl); + pinst->u.osmotrx.hdl = NULL; + } + } + trx_udp_close(&plink->u.osmotrx.trx_ofd_clk); + return -1; +} + +static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data) +{ + struct phy_link *plink = pinst->phy_link; + uint16_t inc = 1; + + if (is_data) + inc = 2; + + if (remote) + return plink->u.osmotrx.base_port_remote + (pinst->num << 1) + inc; + else + return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc; +} + int trx_if_open(struct trx_l1h *l1h) { + struct phy_instance *pinst = l1h->phy_inst; + struct phy_link *plink = pinst->phy_link; int rc; - LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "Open transceiver for %s\n", + phy_instance_name(pinst)); /* initialize ctrl queue */ INIT_LLIST_HEAD(&l1h->trx_ctrl_list); @@ -511,19 +570,24 @@ int trx_if_open(struct trx_l1h *l1h) LOGP(DTRX, LOGL_NOTICE, "Waiting for transceiver send clock\n"); } rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl, - base_port_local + (l1h->trx->nr << 1) + 1, trx_ctrl_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 0), + compute_port(pinst, 1, 0), trx_ctrl_read_cb); if (rc < 0) goto err; rc = trx_udp_open(l1h, &l1h->trx_ofd_data, - base_port_local + (l1h->trx->nr << 1) + 2, trx_data_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 1), + compute_port(pinst, 1, 1), trx_data_read_cb); if (rc < 0) goto err; /* enable all slots */ l1h->config.slotmask = 0xff; - if (l1h->trx->nr == 0) - trx_if_cmd_poweroff(l1h); + /* FIXME: why was this only for TRX0 ? */ + //if (l1h->trx->nr == 0) + trx_if_cmd_poweroff(l1h); return 0; @@ -548,13 +612,13 @@ void trx_if_flush(struct trx_l1h *l1h) void trx_if_close(struct trx_l1h *l1h) { - LOGP(DTRX, LOGL_NOTICE, "Close transceiver for trx=%u\n", l1h->trx->nr); + struct phy_instance *pinst = l1h->phy_inst; + LOGP(DTRX, LOGL_NOTICE, "Close transceiver for %s\n", + phy_instance_name(pinst)); trx_if_flush(l1h); /* close sockets */ - if (l1h->trx->nr == 0) - trx_udp_close(&trx_ofd_clk); trx_udp_close(&l1h->trx_ofd_ctrl); trx_udp_close(&l1h->trx_ofd_data); } diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index 3862e2b..1ea0da9 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -6,6 +6,7 @@ extern const char *transceiver_ip; extern int settsc_enabled; extern int setbsic_enabled; +struct trx_l1h; struct trx_ctrl_msg { struct llist_head list; diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index a4a7909..b273e94 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -45,6 +45,8 @@ #include "trx_if.h" #include "loops.h" +#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n" + static struct gsm_bts *vty_bts; DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", @@ -53,7 +55,6 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", struct gsm_bts *bts = vty_bts; struct gsm_bts_trx *trx; struct trx_l1h *l1h; - uint8_t tn; if (!transceiver_available) { vty_out(vty, "transceiver is not connected%s", VTY_NEWLINE); @@ -63,7 +64,8 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + l1h = pinst->u.osmotrx.hdl; vty_out(vty, "TRX %d%s", trx->nr, VTY_NEWLINE); vty_out(vty, " %s%s", (l1h->config.poweron) ? "poweron":"poweroff", @@ -85,56 +87,70 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", VTY_NEWLINE); else vty_out(vty, " bisc : undefined%s", VTY_NEWLINE); - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain : %d%s", l1h->config.rxgain, + } + + return CMD_SUCCESS; +} + + +static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst) +{ + uint8_t tn; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + vty_out(vty, "PHY Instance %s%s", + phy_instance_name(pinst), VTY_NEWLINE); + if (l1h->config.maxdly_valid) + vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + VTY_NEWLINE); + else + vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); + for (tn = 0; tn < TRX_NR_TS; tn++) { + if (!((1 << tn) & l1h->config.slotmask)) + vty_out(vty, " slot #%d: unsupported%s", tn, VTY_NEWLINE); - else - vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE); - if (l1h->config.power_valid) - vty_out(vty, " power : %d%s", l1h->config.power, + else if (l1h->config.slottype_valid[tn]) + vty_out(vty, " slot #%d: type %d%s", tn, + l1h->config.slottype[tn], VTY_NEWLINE); else - vty_out(vty, " power : undefined%s", VTY_NEWLINE); - if (l1h->config.maxdly_valid) - vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + vty_out(vty, " slot #%d: undefined%s", tn, VTY_NEWLINE); - else - vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); - for (tn = 0; tn < TRX_NR_TS; tn++) { - if (!((1 << tn) & l1h->config.slotmask)) - vty_out(vty, " slot #%d: unsupported%s", tn, - VTY_NEWLINE); - else if (l1h->config.slottype_valid[tn]) - vty_out(vty, " slot #%d: type %d%s", tn, - l1h->config.slottype[tn], - VTY_NEWLINE); - else - vty_out(vty, " slot #%d: undefined%s", tn, - VTY_NEWLINE); - } } - - return CMD_SUCCESS; } -DEFUN(cfg_bts_fn_advance, cfg_bts_fn_advance_cmd, - "fn-advance <0-30>", - "Set the number of frames to be transmitted to transceiver in advance " - "of current FN\n" - "Advance in frames\n") +static void show_phy_single(struct vty *vty, struct phy_link *plink) { - trx_clock_advance = atoi(argv[0]); + struct phy_instance *pinst; - return CMD_SUCCESS; + vty_out(vty, "PHY %u%s", plink->num, VTY_NEWLINE); + + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " rx-gain : %d dB%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + else + vty_out(vty, " rx-gain : undefined%s", VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) + vty_out(vty, " tx-attenuation : %d dB%s", + plink->u.osmotrx.power, VTY_NEWLINE); + else + vty_out(vty, " tx-attenuation : undefined%s", VTY_NEWLINE); + + llist_for_each_entry(pinst, &plink->instances, list) + show_phy_inst_single(vty, pinst); } -DEFUN(cfg_bts_rts_advance, cfg_bts_rts_advance_cmd, - "rts-advance <0-30>", - "Set the number of frames to be requested (PCU) in advance of current " - "FN. Do not change this, unless you have a good reason!\n" - "Advance in frames\n") +DEFUN(show_phy, show_phy_cmd, "show phy", + SHOW_STR "Display information about the available PHYs") { - trx_rts_advance = atoi(argv[0]); + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + show_phy_single(vty, plink); + } return CMD_SUCCESS; } @@ -220,63 +236,14 @@ DEFUN(cfg_bts_no_setbsic, cfg_bts_no_setbsic_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_rxgain, cfg_trx_rxgain_cmd, - "rxgain <0-50>", - "Set the receiver gain in dB\n" - "Gain in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.rxgain = atoi(argv[0]); - l1h->config.rxgain_valid = 1; - l1h->config.rxgain_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_power, cfg_trx_power_cmd, - "power <0-50>", - "Set the transmitter power dampening\n" - "Power dampening in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = atoi(argv[0]); - l1h->config.power_oml = 0; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_poweroml_, cfg_trx_power_oml_cmd, - "power oml", - "Set the transmitter power dampening\n" - "Given by NM_ATT_RF_MAXPOWR_R (max power reduction) via OML\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = trx->max_power_red; - l1h->config.power_oml = 1; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, - "maxdly <0-31>", +DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd, + "osmotrx maxdly <0-31>", "Set the maximum delay of GSM symbols\n" "GSM symbols (approx. 1.1km per symbol)\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly = atoi(argv[0]); l1h->config.maxdly_valid = 1; @@ -286,7 +253,7 @@ DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, +DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd, "slotmask (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0)", "Set the supported slots\n" "TS0 supported\nTS0 unsupported\nTS1 supported\nTS1 unsupported\n" @@ -294,8 +261,8 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, "TS4 supported\nTS4 unsupported\nTS5 supported\nTS5 unsupported\n" "TS6 supported\nTS6 unsupported\nTS7 supported\nTS7 unsupported\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn; l1h->config.slotmask = 0; @@ -306,76 +273,167 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_no_rxgain, cfg_trx_no_rxgain_cmd, - "no rxgain <0-50>", - NO_STR "Unset the receiver gain in dB\n" + +DEFUN(cfg_phy_fn_advance, cfg_phy_fn_advance_cmd, + "osmotrx fn-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be transmitted to transceiver in advance " + "of current FN\n" + "Advance in frames\n") +{ + trx_clock_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rts_advance, cfg_phy_rts_advance_cmd, + "osmotrx rts-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be requested (PCU) in advance of current " + "FN. Do not change this, unless you have a good reason!\n" + "Advance in frames\n") +{ + trx_rts_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rxgain, cfg_phy_rxgain_cmd, + "osmotrx rx-gain <0-50>", + OSMOTRX_STR + "Set the receiver gain in dB\n" "Gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.rxgain_valid = 0; + plink->u.osmotrx.rxgain = atoi(argv[0]); + plink->u.osmotrx.rxgain_valid = 1; + plink->u.osmotrx.rxgain_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_power, cfg_trx_no_power_cmd, - "no power <0-50>", - NO_STR "Unset the transmitter power dampening\n" - "Power dampening in dB\n") +DEFUN(cfg_phy_tx_atten, cfg_phy_tx_atten_cmd, + "osmotrx tx-attenuation <0-50>", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Fixed attenuation in dB, overriding OML\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.power_valid = 0; + plink->u.osmotrx.power = atoi(argv[0]); + plink->u.osmotrx.power_oml = 0; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_maxdly, cfg_trx_no_maxdly_cmd, - "no maxdly <0-31>", - NO_STR "Unset the maximum delay of GSM symbols\n" - "GSM symbols (approx. 1.1km per symbol)\n") +DEFUN(cfg_phy_tx_atten_oml, cfg_phy_tx_atten_oml_cmd, + "osmotrx tx-attenuation oml", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Use NM_ATT_RF_MAXPOWR_R (max power reduction) from BSC via OML\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_oml = 1; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_rxgain, cfg_phy_no_rxgain_cmd, + "no osmotrx rx-gain", + NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.rxgain_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_tx_atten, cfg_phy_no_tx_atten_cmd, + "no osmotrx tx-attenuation", + NO_STR OSMOTRX_STR "Unset the transmitter attenuation\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd, + "no osmotrx maxdly", + NO_STR "Unset the maximum delay of GSM symbols\n") +{ + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly_valid = 0; return CMD_SUCCESS; } -void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +DEFUN(cfg_phy_transc_ip, cfg_phy_transc_ip_cmd, + "osmotrx ip HOST", + OSMOTRX_STR + "Set remote IP address\n" + "IP address of OsmoTRX\n") { - vty_out(vty, " fn-advance %d%s", trx_clock_advance, VTY_NEWLINE); - vty_out(vty, " rts-advance %d%s", trx_rts_advance, VTY_NEWLINE); + struct phy_link *plink = vty->index; - if (trx_ms_power_loop) - vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, - VTY_NEWLINE); - else - vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); - vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", - VTY_NEWLINE); - if (settsc_enabled) - vty_out(vty, " settsc%s", VTY_NEWLINE); - if (setbsic_enabled) - vty_out(vty, " setbsic%s", VTY_NEWLINE); + if (plink->u.osmotrx.transceiver_ip) + talloc_free(plink->u.osmotrx.transceiver_ip); + plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, argv[0]); + + return CMD_SUCCESS; } -void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd, + "osmotrx base-port (local|remote) <0-65535>", + OSMOTRX_STR "Set base UDP port number\n" "Local UDP port\n" + "Remote UDP port\n" "UDP base port number\n") { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + if (!strcmp(argv[0], "local")) + plink->u.osmotrx.base_port_local = atoi(argv[1]); + else + plink->u.osmotrx.base_port_remote = atoi(argv[1]); + + return CMD_SUCCESS; +} - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain %d%s", l1h->config.rxgain, VTY_NEWLINE); - if (l1h->config.power_valid) { - if (l1h->config.power_oml) - vty_out(vty, " power oml%s", VTY_NEWLINE); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.osmotrx.transceiver_ip) + vty_out(vty, " osmotrx ip %s%s", + plink->u.osmotrx.transceiver_ip, VTY_NEWLINE); + + vty_out(vty, " osmotrx fn-advance %d%s", + plink->u.osmotrx.clock_advance, VTY_NEWLINE); + vty_out(vty, " osmotrx rts-advance %d%s", + plink->u.osmotrx.rts_advance, VTY_NEWLINE); + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " osmotrx rx-gain %d%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) { + if (plink->u.osmotrx.power_oml) + vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE); else - vty_out(vty, " power %d%s", l1h->config.power, - VTY_NEWLINE); + vty_out(vty, " osmotrx tx-attenuation %d%s", + plink->u.osmotrx.power, VTY_NEWLINE); } +} + +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst) +{ + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + if (l1h->config.maxdly_valid) vty_out(vty, " maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE); if (l1h->config.slotmask != 0xff) @@ -391,14 +449,32 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); } +void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +{ + if (trx_ms_power_loop) + vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, + VTY_NEWLINE); + else + vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); + vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", + VTY_NEWLINE); + if (settsc_enabled) + vty_out(vty, " settsc%s", VTY_NEWLINE); + if (setbsic_enabled) + vty_out(vty, " setbsic%s", VTY_NEWLINE); +} + +void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +{ +} + int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; install_element_ve(&show_transceiver_cmd); + install_element_ve(&show_phy_cmd); - install_element(BTS_NODE, &cfg_bts_fn_advance_cmd); - install_element(BTS_NODE, &cfg_bts_rts_advance_cmd); install_element(BTS_NODE, &cfg_bts_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_no_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_timing_advance_loop_cmd); @@ -408,14 +484,19 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_no_settsc_cmd); install_element(BTS_NODE, &cfg_bts_no_setbsic_cmd); - install_element(TRX_NODE, &cfg_trx_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_power_cmd); - install_element(TRX_NODE, &cfg_trx_power_oml_cmd); - install_element(TRX_NODE, &cfg_trx_maxdly_cmd); - install_element(TRX_NODE, &cfg_trx_slotmask_cmd); - install_element(TRX_NODE, &cfg_trx_no_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_no_power_cmd); - install_element(TRX_NODE, &cfg_trx_no_maxdly_cmd); + install_element(PHY_NODE, &cfg_phy_base_port_cmd); + install_element(PHY_NODE, &cfg_phy_fn_advance_cmd); + install_element(PHY_NODE, &cfg_phy_rts_advance_cmd); + install_element(PHY_NODE, &cfg_phy_transc_ip_cmd); + install_element(PHY_NODE, &cfg_phy_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_oml_cmd); + install_element(PHY_NODE, &cfg_phy_no_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_no_tx_atten_cmd); + + install_element(PHY_INST_NODE, &cfg_phyinst_slotmask_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdly_cmd); return 0; } -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:37:20 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:37:20 +0100 Subject: [PATCH 2/3] don't touch OML MO when PHY link is established In-Reply-To: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> References: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454524641-14400-2-git-send-email-laforge@gnumonks.org> From: Harald Welte It seems the right thing to do: Once we know a PHY link is established, the associated OML managed objects should change their state accordingly. However, given all the hackery we do with MO states, this actually breaks things, rather than helping. So I'm disabling that part for now, but this needs to be re-visited at some point. --- src/common/bts.c | 16 ++++++++-------- src/common/phy_link.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common/bts.c b/src/common/bts.c index a775329..1dd518c 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -267,19 +267,19 @@ int trx_set_available(struct gsm_bts_trx *trx, int avail) LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n", trx->nr, avail); if (avail) { - oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); - oml_mo_tx_sw_act_rep(&trx->mo); - oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK); - oml_mo_tx_sw_act_rep(&trx->bb_transc.mo); - + /* FIXME: This needs to be sorted out */ +#if 0 + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); +#endif } else { - oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); - oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_NOT_INSTALLED); for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) - oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED); } return 0; } diff --git a/src/common/phy_link.c b/src/common/phy_link.c index 9442349..816d3c0 100644 --- a/src/common/phy_link.c +++ b/src/common/phy_link.c @@ -65,7 +65,7 @@ void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n"); trx_set_available(trx, 1); break; - default: + case PHY_LINK_SHUTDOWN: LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n"); trx_set_available(trx, 0); break; -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 18:37:21 2016 From: laforge at gnumonks.org (laforge at gnumonks.org) Date: Wed, 3 Feb 2016 19:37:21 +0100 Subject: [PATCH 3/3] port sysmobts to phy_link/phy_instance abstraction In-Reply-To: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> References: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454524641-14400-3-git-send-email-laforge@gnumonks.org> From: Harald Welte --- include/osmo-bts/phy_link.h | 1 + src/osmo-bts-sysmo/l1_if.c | 59 ++++++++++++--- src/osmo-bts-sysmo/l1_if.h | 22 +++++- src/osmo-bts-sysmo/main.c | 34 ++------- src/osmo-bts-sysmo/oml.c | 1 + src/osmo-bts-sysmo/sysmobts_vty.c | 146 +++++++++++++++++++++++--------------- 6 files changed, 166 insertions(+), 97 deletions(-) diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h index b9fc412..ec3a915 100644 --- a/include/osmo-bts/phy_link.h +++ b/include/osmo-bts/phy_link.h @@ -82,6 +82,7 @@ struct phy_instance { union { struct { + struct femtol1_hdl *hdl; } sysmobts; struct { struct trx_l1h *hdl; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 8457a74..b64136b 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1,6 +1,6 @@ /* Interface handler for Sysmocom L1 */ -/* (C) 2011-2014 by Harald Welte +/* (C) 2011-2016 by Harald Welte * (C) 2014 by Holger Hans Peter Freyther * * All Rights Reserved @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -579,7 +580,7 @@ static int handle_mph_time_ind(struct femtol1_hdl *fl1, GsmL1_MphTimeInd_t *time_ind, struct msgb *msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct osmo_phsap_prim l1sap; uint32_t fn; @@ -705,7 +706,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *rts_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; @@ -834,7 +835,7 @@ static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); uint8_t chan_nr, link_id; struct msgb *sap_msg; struct osmo_phsap_prim *l1sap; @@ -900,7 +901,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role; struct gsm_lchan *lchan; @@ -1021,7 +1022,8 @@ int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg) if (wlc->cb) { /* call-back function must take * ownership of msgb */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(femtol1_hdl_trx(fl1h), msg, + wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1053,7 +1055,8 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) if (wlc->cb) { /* call-back function must take * ownership of msgb */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(femtol1_hdl_trx(fl1h), msg, + wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1166,7 +1169,7 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on) { struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); - struct gsm_bts_trx *trx = hdl->priv; + struct gsm_bts_trx *trx = hdl->phy_inst->trx; if (on) { sysp->id = SuperFemto_PrimId_ActivateRfReq; @@ -1478,7 +1481,7 @@ static int get_hwinfo_eeprom(struct femtol1_hdl *fl1h) return 0; } -struct femtol1_hdl *l1if_open(void *priv) +struct femtol1_hdl *l1if_open(struct phy_instance *pinst) { struct femtol1_hdl *fl1h; int rc; @@ -1495,12 +1498,12 @@ struct femtol1_hdl *l1if_open(void *priv) FEMTOBTS_API_VERSION & 0xff); #endif - fl1h = talloc_zero(priv, struct femtol1_hdl); + fl1h = talloc_zero(pinst, struct femtol1_hdl); if (!fl1h) return NULL; INIT_LLIST_HEAD(&fl1h->wlc_list); - fl1h->priv = priv; + fl1h->phy_inst = pinst; fl1h->clk_cal = 0; fl1h->clk_use_eeprom = 1; fl1h->min_qual_rach = MIN_QUAL_RACH; @@ -1535,6 +1538,8 @@ struct femtol1_hdl *l1if_open(void *priv) return NULL; } + l1if_reset(fl1h); + return fl1h; } @@ -1662,3 +1667,35 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h) } #endif + +int bts_model_phy_link_open(struct phy_link *plink) +{ + struct phy_instance *pinst = phy_instance_by_num(plink, 0); + struct gsm_bts *bts; + + OSMO_ASSERT(pinst); + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + pinst->u.sysmobts.hdl = l1if_open(pinst); + if (!pinst->u.sysmobts.hdl) { + LOGP(DL1C, LOGL_FATAL, "Cannot open L1 interface\n"); + return -EIO; + } + + bts = pinst->trx->bts; + if (pinst->trx == bts->c0) { + int rc; + rc = sysmobts_get_nominal_power(bts->c0); + if (rc < 0) { + LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal " + "transmit power. Assuming 23dBm.\n"); + } + bts->c0->nominal_power = rc; + bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc); + } + + phy_link_state_set(plink, PHY_LINK_CONNECTED); + + return 0; +} diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 3f2938f..de4f2a3 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -7,6 +7,8 @@ #include #include +#include + #include enum { @@ -52,7 +54,7 @@ struct femtol1_hdl { char *calib_path; struct llist_head wlc_list; - void *priv; /* user reference */ + struct phy_instance *phy_inst; /* Reference to PHY instance */ struct osmo_timer_list alive_timer; unsigned int alive_prim_cnt; @@ -78,6 +80,9 @@ struct femtol1_hdl { struct calib_send_state st; uint8_t last_rf_mute[8]; + + /* for l1_fwd */ + void *priv; }; #define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) @@ -91,7 +96,7 @@ int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, int l1if_gsm_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, l1if_compl_cb *cb, void *cb_data); -struct femtol1_hdl *l1if_open(void *priv); +struct femtol1_hdl *l1if_open(struct phy_instance *pinst); int l1if_close(struct femtol1_hdl *hdl); int l1if_reset(struct femtol1_hdl *hdl); int l1if_activate_rf(struct femtol1_hdl *hdl, int on); @@ -134,4 +139,17 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h); /* public helpers for test */ int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h, struct msgb *msg, struct gsm_lchan *lchan); + +static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx) +{ + struct phy_instance *pinst = trx_phy_instance(trx); + OSMO_ASSERT(pinst); + return pinst->u.sysmobts.hdl; +} + +static inline struct gsm_bts_trx *femtol1_hdl_trx(struct femtol1_hdl *fl1h) +{ + OSMO_ASSERT(fl1h->phy_inst); + return fl1h->phy_inst->trx; +} #endif /* _FEMTO_L1_H */ diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index d468a71..bde7a94 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -86,21 +86,13 @@ void clk_cal_use_eeprom(struct gsm_bts *bts) int bts_model_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; - struct femtol1_hdl *fl1h; struct stat st; - struct osmo_fd accept_fd, read_fd; + static struct osmo_fd accept_fd, read_fd; int rc; btsb = bts_role_bts(bts); btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); - clk_cal_use_eeprom(bts); - - if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) { - LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n"); - exit(23); - } - rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd); if (rc < 0) { fprintf(stderr, "Error creating the OML router: %s rc=%d\n", @@ -108,23 +100,12 @@ int bts_model_init(struct gsm_bts *bts) exit(1); } - fl1h = l1if_open(bts->c0); - if (!fl1h) { - LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n"); - return -EIO; - } - fl1h->dsp_trace_f = dsp_trace; - - bts->c0->role_bts.l1h = fl1h; + clk_cal_use_eeprom(bts); - rc = sysmobts_get_nominal_power(bts->c0); - if (rc < 0) { - LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal " - "transmit power. Assuming 23dBm.\n"); - rc = 23; + if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) { + LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n"); + exit(23); } - bts->c0->nominal_power = rc; - bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc); bts_model_vty_init(bts); @@ -133,10 +114,6 @@ int bts_model_init(struct gsm_bts *bts) int bts_model_oml_estab(struct gsm_bts *bts) { - struct femtol1_hdl *fl1h = bts->c0->role_bts.l1h; - - l1if_reset(fl1h); - return 0; } @@ -205,6 +182,7 @@ int bts_model_handle_options(int argc, char **argv) switch (c) { case 'p': dsp_trace = strtoul(optarg, NULL, 16); +#warning use dsp_trace!!! break; case 'M': pcu_direct = 1; diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index adc0241..cd03b22 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 4a37b5d..19122dc 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -84,24 +85,24 @@ DEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_clkcal_eeprom, cfg_trx_clkcal_eeprom_cmd, +DEFUN(cfg_phy_clkcal_eeprom, cfg_phy_clkcal_eeprom_cmd, "clock-calibration eeprom", "Use the eeprom clock calibration value\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 1; return CMD_SUCCESS; } -DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, +DEFUN(cfg_phy_clkcal_def, cfg_phy_clkcal_def_cmd, "clock-calibration default", "Set the clock calibration value\n" "Default Clock DAC value\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = 0xffff; @@ -110,13 +111,13 @@ DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, } #ifdef HW_SYSMOBTS_V1 -DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, +DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd, "clock-calibration <0-4095>", "Set the clock calibration value\n" "Clock DAC value\n") { unsigned int clkcal = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = clkcal & 0xfff; @@ -124,13 +125,13 @@ DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, return CMD_SUCCESS; } #else -DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, +DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd, "clock-calibration <-4095-4095>", "Set the clock calibration value\n" "Offset in PPB\n") { int clkcal = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = clkcal; @@ -139,7 +140,7 @@ DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, } #endif -DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, +DEFUN(cfg_phy_clksrc, cfg_phy_clksrc_cmd, "clock-source (tcxo|ocxo|ext|gps)", "Set the clock source value\n" "Use the TCXO\n" @@ -147,8 +148,8 @@ DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, "Use an external clock\n" "Use the GPS pps\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; int rc; rc = get_string_value(femtobts_clksrc_names, argv[0]); @@ -160,12 +161,12 @@ DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd, +DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd, "trx-calibration-path PATH", "Set the path name to TRX calibration data\n" "Path name\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; if (fl1h->calib_path) talloc_free(fl1h->calib_path); @@ -188,26 +189,26 @@ DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_min_qual_rach, cfg_trx_min_qual_rach_cmd, +DEFUN(cfg_phy_min_qual_rach, cfg_phy_min_qual_rach_cmd, "min-qual-rach <-100-100>", "Set the minimum quality level of RACH burst to be accpeted\n" "C/I level in tenth of dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->min_qual_rach = strtof(argv[0], NULL) / 10.0f; return CMD_SUCCESS; } -DEFUN(cfg_trx_min_qual_norm, cfg_trx_min_qual_norm_cmd, +DEFUN(cfg_phy_min_qual_norm, cfg_phy_min_qual_norm_cmd, "min-qual-norm <-100-100>", "Set the minimum quality level of normal burst to be accpeted\n" "C/I level in tenth of dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->min_qual_norm = strtof(argv[0], NULL) / 10.0f; @@ -286,18 +287,24 @@ DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd, DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR) { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; unsigned int flag ; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, 0); + if (!pinst) { + vty_out(vty, "Cannot find PHY instance number 0%s", + VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; flag = get_string_value(femtobts_tracef_names, argv[1]); l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f | flag); @@ -306,18 +313,24 @@ DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR) DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR) { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; unsigned int flag ; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, 0); + if (!pinst) { + vty_out(vty, "Cannot find PHY instance number 0%s", + VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; flag = get_string_value(femtobts_tracef_names, argv[1]); l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f & ~flag); @@ -325,20 +338,28 @@ DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR) } DEFUN(show_sys_info, show_sys_info_cmd, - "show trx <0-0> system-information", + "show phy <0-255> instance <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + int inst_nr = atoi(argv[1]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; int i; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, inst_nr); + if (!plink) { + vty_out(vty, "Cannot find PHY instance %u%s", + phy_nr, VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; vty_out(vty, "DSP Version: %u.%u.%u, FPGA Version: %u.%u.%u%s", fl1h->hw_info.dsp_version[0], @@ -471,7 +492,14 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + if (trx->nominal_power != sysmobts_get_nominal_power(trx)) + vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power, + VTY_NEWLINE); +} + +static void write_phy_inst(struct vty *vty, struct phy_instance *pinst) +{ + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; if (fl1h->clk_use_eeprom) vty_out(vty, " clock-calibration eeprom%s", VTY_NEWLINE); @@ -488,9 +516,14 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f, VTY_NEWLINE); - if (trx->nominal_power != sysmobts_get_nominal_power(trx)) - vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power, - VTY_NEWLINE); +} + +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + struct phy_instance *pinst; + + llist_for_each_entry(pinst, &plink->instances, list) + write_phy_inst(vty, pinst); } int bts_model_vty_init(struct gsm_bts *bts) @@ -529,15 +562,16 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_auto_band_cmd); install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_eeprom_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd); - install_element(TRX_NODE, &cfg_trx_clksrc_cmd); - install_element(TRX_NODE, &cfg_trx_cal_path_cmd); install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd); - install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd); - install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd); install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_eeprom_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_def_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clksrc_cmd); + install_element(PHY_INST_NODE, &cfg_phy_cal_path_cmd); + install_element(PHY_INST_NODE, &cfg_phy_min_qual_rach_cmd); + install_element(PHY_INST_NODE, &cfg_phy_min_qual_norm_cmd); + return 0; } -- 2.7.0 From laforge at gnumonks.org Wed Feb 3 20:21:32 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 3 Feb 2016 21:21:32 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction In-Reply-To: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> References: <1454524641-14400-1-git-send-email-laforge@gnumonks.org> Message-ID: <20160203202132.GC2572@nataraja> Dear all, please ignore the phy_link patchset, I'm cleaning it up further, three were some left-over FIXME and 'if 0' blocks that I forgot about. Also apologies for the repeat posting of the previous trx-split patchset, the mails appeared to be stuck somewhere while I assumed they didnt' get through due to wrong configuration. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Thu Feb 4 07:12:19 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 4 Feb 2016 08:12:19 +0100 Subject: Moving from trac to a single redmine Message-ID: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> Hi guys, I think some of us would like to move to redmine and start using public tickets more frequently. So in case we move there are some topics to be discussed and I would like to start with a couple of them right now. Tickets: Redmine has a global linear sequence of ticket numbers. If we move from many tracs to a single redmine we can either: * not import tickets * only import from one project * deal with changing ticket numbers In terms of installations the GMR trac is broken in regard to tickets, there are some for SDR that are probably not being fixed anytime soon, baseband might be relevant and OpenBSC is unlikely to be relevant. I don't think we have ever used ticket reference in OpenBSC commit messages so in terms of OpenBSC having changing ticket numbers would not be a big deal. E.g. we could add a custom field with the old trac number? Wiki: We have external references that should be redirected to the new place. Is there any way besides maintaining a list in the apache2/nginx configuration and making redirects as we find broken references? Can we proactively manage this? Is anybody willing to come up with a script and nginx configuration for doing this? kind regards holger From holger at freyther.de Thu Feb 4 12:39:26 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 4 Feb 2016 13:39:26 +0100 Subject: [PATCH 1/2] Expand bitvec interface In-Reply-To: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> References: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <3B14C07F-1982-4000-9029-B8F22B82A0BB@freyther.de> > On 02 Feb 2016, at 12:19, suraev at alumni.ntnu.no wrote: > > Dear Max, > + memcpy(tmp, bv->data, 2); > + return osmo_load16be(tmp) >> (16 - num_bits); load16be is working byte by byte as well so what do we win by this load? > +/*! \brief fill num_bits with \fill starting from the current position > + * returns 0 on success, negative otherwise (out of vector boundary) > + */ > +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill) > +{ > + unsigned i, stop = bv->cur_bit + num_bits; > + for (i = bv->cur_bit; i < stop; i++) > + if (bitvec_set_bit(bv, fill) < 0) > + return -EINVAL; > + > + return 0; > +} > + > /*! \brief pad all remaining bits up to num_bits */ > int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) > { > - unsigned int i; > - > - for (i = bv->cur_bit; i <= up_to_bit; i++) > - bitvec_set_bit(bv, L); > + int n = up_to_bit - bv->cur_bit + 1; > + if (n < 1) > + return 0; so we are going from unsigned to int and then 'n' is "converted" to unsigned int as well. Is this what we want? > +/*! \brief convert enum to corresponding character */ > +char bit_value_to_char(enum bit_value v) > +{ > + switch (v) { > + case ZERO: return '0'; > + case ONE: return '1'; > + case L: return 'L'; > + case H: return 'H'; > + } > + /* make compiler happy - "avoid control reaches end of non-void function" warning: */ seeing is believing? Which gcc? I had proposed to use __builtin_unreachable here. If we know we don't end up there, put this into the "branch" and the warning is gone. Or abort() or __builtin_trap. > + return '?'; > +} > + > +/*! \brief prints bit vector to provided string > + * It's caller's responcibility to ensure that we won't shoot him in the foot. typo, how long is "str"? So either pass a size or write it in the comment of how long it needs to be depending on cur_bit? And what does the _r stand for? Is it similiar to the libc _r functions where an external buffer/pointer is provided? > +/* we assume that x have at least 1 non-b bit */ > +static inline unsigned _leading_bits(uint8_t x, bool b) _ and __ are reserved for the system, let us not use it. By having this method as static we already don't pollute the global namespace. > +/*! \brief Return number (bits) of uninterrupted run of \b in \bv starting from the MSB */ Are you sure that \b and \bv refer to the params? not like \param b, \param bv? Did you look at the documentation generated by doxygen? > - fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out))); > + printf("out: %s\n", osmo_hexdump(out, sizeof(out))); why? more output to be tracked? we could not ignore stderr if we want to? > > OSMO_ASSERT(out[0] == 0xff); > OSMO_ASSERT(out[in_size+1] == 0xff); > @@ -72,11 +145,77 @@ static void test_unhex(const char *hex) > > int main(int argc, char **argv) > { > + srand(time(NULL)); why? From holger at freyther.de Thu Feb 4 12:45:32 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 4 Feb 2016 13:45:32 +0100 Subject: [PATCH 2/2] Add T4 bit map compression routines In-Reply-To: <1454411973-30799-2-git-send-email-suraev@alumni.ntnu.no> References: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> <1454411973-30799-2-git-send-email-suraev@alumni.ntnu.no> Message-ID: <17B228F2-69F8-4DD9-81E7-5700AC62ABA4@freyther.de> > On 02 Feb 2016, at 12:19, suraev at alumni.ntnu.no wrote: > > > +unsigned _term[2][64] = { same comment, _ is a namespace not for us. Please adjust it. Make it static const to not pollute the namespace and keep it in the rodata segment. > +enum dec_state { > + EXPECT_TERM, // only TERM is expected, keep parsing with the same color code > + TOO_LONG, // that's what she said Try to avoid comments like that. Please don't use C99 comments and have a more technical description. The rest looks fine but I have no knowledge about T4. thanks holger From holger at freyther.de Thu Feb 4 12:53:06 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 4 Feb 2016 13:53:06 +0100 Subject: FIXME: TODO: do better In-Reply-To: <20160128133239.GD1755@dub6> References: <20160128133239.GD1755@dub6> Message-ID: > On 28 Jan 2016, at 14:32, Neels Hofmeyr wrote: > > Would anyone like to prevent this commit from reaching master? ;) of course. I will even unplug your heated blanket! The silent_call handling doesn't fit from an architectural point of view. It is used to demonstrate a security implication of carrying a mobile phone. We simply open a channel and then don't do anything with it. At the same time one will receive measurement reports and could more easily triangulate or actively try to determine where the phone is. As such this feature needs to always "accept" a new "Complete layer3 information" (as of GSM 08.08). The original todo is indeed not a good one as it has absolutely no meta information. Thinking about the code my goal was to define a more clear ownership of the "MSC" side of an operation. So instead of starting a generic "close soon" timer (or the loc operation timer) have something that takes ownership of the first message. This would mean we dispatch "complete layer3 information" differently than follow up messages. As with many parts this part of the architecture has never been fixed/implemented/corrected as the current is working good enough(tm). We can either remove the comment, leave it as such or fix the above text and put it into the code as a fixme/todo. holger From suraev at alumni.ntnu.no Thu Feb 4 13:17:00 2016 From: suraev at alumni.ntnu.no (=?UTF-8?B?TWF4ICjimK0p?=) Date: Thu, 4 Feb 2016 14:17:00 +0100 Subject: [PATCH 1/2] Expand bitvec interface In-Reply-To: <3B14C07F-1982-4000-9029-B8F22B82A0BB@freyther.de> References: <1454411973-30799-1-git-send-email-suraev@alumni.ntnu.no> <3B14C07F-1982-4000-9029-B8F22B82A0BB@freyther.de> Message-ID: <56B34F4C.5020708@alumni.ntnu.no> 04.02.2016 13:39, Holger Freyther ?????: >> + memcpy(tmp, bv->data, 2); >> + return osmo_load16be(tmp) >> (16 - num_bits); > > load16be is working byte by byte as well so what do we win by this load? > I don't really get this - win compared to what? This is new function, not replacement for some old code. >> +/*! \brief fill num_bits with \fill starting from the current position >> + * returns 0 on success, negative otherwise (out of vector boundary) >> + */ >> +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill) >> +{ >> + unsigned i, stop = bv->cur_bit + num_bits; >> + for (i = bv->cur_bit; i < stop; i++) >> + if (bitvec_set_bit(bv, fill) < 0) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> /*! \brief pad all remaining bits up to num_bits */ >> int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) >> { >> - unsigned int i; >> - >> - for (i = bv->cur_bit; i <= up_to_bit; i++) >> - bitvec_set_bit(bv, L); >> + int n = up_to_bit - bv->cur_bit + 1; >> + if (n < 1) >> + return 0; > > so we are going from unsigned to int and then 'n' is "converted" to unsigned int as well. Is this what we want? > Yes. By the time we use n as unsigned we've explicitly checked already that it's positive. On the other hand the diff between 2 unsigned ints can be signed. > >> +/*! \brief convert enum to corresponding character */ >> +char bit_value_to_char(enum bit_value v) >> +{ >> + switch (v) { >> + case ZERO: return '0'; >> + case ONE: return '1'; >> + case L: return 'L'; >> + case H: return 'H'; >> + } >> + /* make compiler happy - "avoid control reaches end of non-void function" warning: */ > > seeing is believing? Which gcc? I had proposed to use __builtin_unreachable here. If we know we don't end up there, put this into the "branch" and the warning is gone. Or abort() or __builtin_trap. > I think __builtin_unreachable is deprecated but abort() in default: branch will do the trick. > > > >> + return '?'; >> +} >> + >> +/*! \brief prints bit vector to provided string >> + * It's caller's responcibility to ensure that we won't shoot him in the foot. > > typo, how long is "str"? So either pass a size or write it in the comment of how long it needs to be depending on cur_bit? And what does the _r stand for? Is it similiar to the libc _r functions where an external buffer/pointer is provided? > The name was suggested by Harald in earlier review. The string should be at least cur_bit+1 bytes long. > >> +/* we assume that x have at least 1 non-b bit */ >> +static inline unsigned _leading_bits(uint8_t x, bool b) > > _ and __ are reserved for the system, let us not use it. By having this method as static we already don't pollute the global namespace. > So how shall it be called to make it clear that this is internal to implementation/file? > >> +/*! \brief Return number (bits) of uninterrupted run of \b in \bv starting from the MSB */ > > Are you sure that \b and \bv refer to the params? not like \param b, \param bv? Did you look at the documentation generated by doxygen? Indeed, it should be \param, or better yet - full comment instead of brief one. > > >> - fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out))); >> + printf("out: %s\n", osmo_hexdump(out, sizeof(out))); > > why? more output to be tracked? we could not ignore stderr if we want to? > We could but since it's tests I'd rather have it under VCS in bitvec_test.ok explicitly. I think we only should ignore volatile things. > > >> >> OSMO_ASSERT(out[0] == 0xff); >> OSMO_ASSERT(out[in_size+1] == 0xff); >> @@ -72,11 +145,77 @@ static void test_unhex(const char *hex) >> >> int main(int argc, char **argv) >> { >> + srand(time(NULL)); > > why? > Leftover from the time I was thinking of adding tests with random values. Can be safely removed. cheers, Max. From dwillmann at sysmocom.de Thu Feb 4 14:35:18 2016 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Thu, 04 Feb 2016 15:35:18 +0100 Subject: [PATCH 3/3] gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly In-Reply-To: <20160203181253.GB2572@nataraja> (sfid-20160203_191512_984670_59F8426C) References: <31daf439e34a6f4b1b6a323ab84e437371f972d5.1454521570.git.daniel@totalueberwachung.de> <20160203181253.GB2572@nataraja> (sfid-20160203_191512_984670_59F8426C) Message-ID: <1454596518.856.105.camel@sysmocom.de> Hi Harald, On Wed, 2016-02-03 at 19:12 +0100, Harald Welte wrote: > On Wed, Feb 03, 2016 at 06:53:31PM +0100, Daniel Willmann wrote: > > + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, > > + &pdp->qos_neg0, > > + sizeof(pdp->qos_neg0))) { > > + gsn->missing++; > > + GTP_LOGPKG(LOGL_ERROR, peer, > > + pack, len, > > + "Missing conditional information field\n"); > > + if (gsn->cb_conf) > > + gsn->cb_conf(type, EOF, pdp, cbp); > > + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); > > + pdp_freepdp(pdp); */ > > + return EOF; > > + } > > + > > + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { > > + gsn->missing++; > > + GTP_LOGPKG(LOGL_ERROR, peer, > > + pack, len, > > + "Missing conditional information field\n"); > > + if (gsn->cb_conf) > > + gsn->cb_conf(type, EOF, pdp, cbp); > > + /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); > > + pdp_freepdp(pdp); */ > > + return EOF; > > + } > > This looks like a bit too much of copy+paste to me. Can't we put that true. Unfortunately, the whole code looks like this and I tried to stick with the "style". > into a separate function, or if not, at least a macro that hides all the > verbosity and the copy+paste? Also, why is ther a commented-out section > about cb_delete_context involved? A function or macro will need 7 variables passed to it which makes the whole thing quite ugly (unless the macro makes assumptions about the local variable names). I have now put the error handling code at the end of the function and jump to it in case of an error. We lose the ability to infer the missing element from the line number of the log message, but I don't think it's a big issue. The message is still logged and wireshark can be used for debugging as well. The section about cb_delete_context was there before (and still is in other parts of the code). I have removed it in that function now. Regards Daniel -- - Daniel Willmann http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From dwillmann at sysmocom.de Thu Feb 4 14:38:12 2016 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Thu, 4 Feb 2016 15:38:12 +0100 Subject: [PATCH 1/1] gtp: Handle gtpv1 in gtp_update_pdp_conf() correctly In-Reply-To: <1454596518.856.105.camel@sysmocom.de> References: <1454596518.856.105.camel@sysmocom.de> Message-ID: <80cf42b077621bce0323cda270a8adfbe8a6098a.1454596571.git.daniel@totalueberwachung.de> libgtp cannot understand its own update pdp request (in gtp v1) Only require the conditional and mandatory fields for gtpv1 and not others. Refer to 3GPP TS 29.060 Ch. 7.3.4 --- gtp/gtp.c | 120 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 63 insertions(+), 57 deletions(-) diff --git a/gtp/gtp.c b/gtp/gtp.c index 2a6ecd7..12cb492 100644 --- a/gtp/gtp.c +++ b/gtp/gtp.c @@ -2187,9 +2187,8 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, gsn->err_unknownpdp++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Unknown PDP context: %u\n", get_tei(pack)); - if (gsn->cb_conf) - gsn->cb_conf(type, EOF, NULL, cbp); - return EOF; + pdp = NULL; + goto err_out; } /* Register that we have received a valid teic from GGSN */ @@ -2200,23 +2199,12 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, gsn->invalid++; GTP_LOGPKG(LOGL_ERROR, peer, pack, len, "Invalid message format\n"); - if (gsn->cb_conf) - gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; + goto err_out; } /* Extract cause value (mandatory) */ if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { - gsn->missing++; - GTP_LOGPKG(LOGL_ERROR, peer, pack, len, - "Missing mandatory information field\n"); - if (gsn->cb_conf) - gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; + goto err_missing; } /* Extract recovery (optional) */ @@ -2226,51 +2214,69 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, } /* Check all conditional information elements */ - if (GTPCAUSE_ACC_REQ != cause) { - if (gsn->cb_conf) - gsn->cb_conf(type, cause, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return 0; - } else { - /* Check for missing conditionary information elements */ - if (!(gtpie_exist(ie, GTPIE_QOS_PROFILE0, 0) && - gtpie_exist(ie, GTPIE_REORDER, 0) && - gtpie_exist(ie, GTPIE_FL_DI, 0) && - gtpie_exist(ie, GTPIE_FL_C, 0) && - gtpie_exist(ie, GTPIE_CHARGING_ID, 0) && - gtpie_exist(ie, GTPIE_EUA, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 0) && - gtpie_exist(ie, GTPIE_GSN_ADDR, 1))) { - gsn->missing++; - GTP_LOGPKG(LOGL_ERROR, peer, pack, - len, - "Missing conditional information field\n"); - if (gsn->cb_conf) - gsn->cb_conf(type, EOF, pdp, cbp); - /* if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); - pdp_freepdp(pdp); */ - return EOF; + /* TODO: This does not handle GGSN-initiated update responses */ + if (GTPCAUSE_ACC_REQ == cause) { + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + &pdp->qos_neg0, + sizeof(pdp->qos_neg0))) { + goto err_missing; + } + + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + goto err_missing; + } + + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + goto err_missing; + } } - /* Update pdp with new values */ - gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_neg0, sizeof(pdp->qos_neg0)); - gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder); - gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru); - gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc); - gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid); - gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, - &pdp->eua.v, sizeof(pdp->eua.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, - &pdp->gsnrc.v, sizeof(pdp->gsnrc.v)); - gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, - &pdp->gsnru.v, sizeof(pdp->gsnru.v)); + if (version == 1) { + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + goto err_missing; + } - if (gsn->cb_conf) - gsn->cb_conf(type, cause, pdp, cbp); - return 0; /* Succes */ + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + goto err_missing; + } + } + + if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) { + goto err_missing; + } + + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { + goto err_missing; + } + + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { + goto err_missing; + } + + if (version == 1) { + if (gtpie_gettlv + (ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l, + &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) { + goto err_missing; + } + } } + + if (gsn->cb_conf) + gsn->cb_conf(type, cause, pdp, cbp); + return 0; /* Succes */ + +err_missing: + gsn->missing++; + GTP_LOGPKG(LOGL_ERROR, peer, pack, len, + "Missing information field\n"); +err_out: + if (gsn->cb_conf) + gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; } /* API: Send Delete PDP Context Request */ -- 2.1.4 From jerlbeck at sysmocom.de Thu Feb 4 17:59:05 2016 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Thu, 4 Feb 2016 18:59:05 +0100 Subject: EDGE over osmo-pcu Message-ID: <56B39169.4050302@sysmocom.de> Hi everybody, we have just done the first download of an Internet page using the current bleeding EDGE development version of the OSMO-PCU. Supported are MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. The download of 'www.osmocom.org' has been documented in a PCAP file and can be downloaded from https://openbsc.osmocom.org/trac/wiki/osmo-pcu To decode the data blocks, an experimental patch for the gsmtab dissector is also available from there. Cheers Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From sipos.csaba at kvk.uni-obuda.hu Thu Feb 4 21:40:05 2016 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Thu, 4 Feb 2016 22:40:05 +0100 (CET) Subject: EDGE over osmo-pcu In-Reply-To: <56B39169.4050302@sysmocom.de> References: <56B39169.4050302@sysmocom.de> Message-ID: <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> Hi Jacob, Congratulations and thank you for all your hard work. I hope I can do some testing on the weekend with a B200. I will also update the wiki article if needed. Just one question: for MCS5-9 in the downlink there is no need to update the Osmo-TRX code? Does it support 8PSK as it is now? Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Jacob Erlbeck" C?mzett: osmocom-net-gprs at lists.osmocom.org M?solatot kap: openbsc at lists.osmocom.org Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 18:59:05 T?rgy: EDGE over osmo-pcu Hi everybody, we have just done the first download of an Internet page using the current bleeding EDGE development version of the OSMO-PCU. Supported are MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. The download of 'www.osmocom.org' has been documented in a PCAP file and can be downloaded from https://openbsc.osmocom.org/trac/wiki/osmo-pcu To decode the data blocks, an experimental patch for the gsmtab dissector is also available from there. Cheers Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From alexander.chemeris at gmail.com Thu Feb 4 22:25:30 2016 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Thu, 4 Feb 2016 14:25:30 -0800 Subject: EDGE over osmo-pcu In-Reply-To: <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: Hi Sipos, Osmo-trx does not support 8-PSK at this moment, so you should implement it if you want to test it. ;) Please excuse typos. Written with a touchscreen keyboard. -- Regards, Alexander Chemeris CEO Fairwaves, Inc. https://fairwaves.co On Feb 4, 2016 1:43 PM, "Sipos Csaba" wrote: > Hi Jacob, > > Congratulations and thank you for all your hard work. > > I hope I can do some testing on the weekend with a B200. I will also > update the wiki article if needed. > > Just one question: for MCS5-9 in the downlink there is no need to update > the Osmo-TRX code? Does it support 8PSK as it is now? > > Regards, > Csaba > > ----- Eredeti ?zenet ----- > Felad?: "Jacob Erlbeck" > C?mzett: osmocom-net-gprs at lists.osmocom.org > M?solatot kap: openbsc at lists.osmocom.org > Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 18:59:05 > T?rgy: EDGE over osmo-pcu > > Hi everybody, > > we have just done the first download of an Internet page using the > current bleeding EDGE development version of the OSMO-PCU. Supported are > MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. > > The download of 'www.osmocom.org' has been documented in a PCAP file and > can be downloaded from > > https://openbsc.osmocom.org/trac/wiki/osmo-pcu > > To decode the data blocks, an experimental patch for the gsmtab > dissector is also available from there. > > Cheers > > Jacob > > -- > - Jacob Erlbeck http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte > -------------- next part -------------- An HTML attachment was scrubbed... URL: From sipos.csaba at kvk.uni-obuda.hu Thu Feb 4 22:58:52 2016 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Thu, 4 Feb 2016 23:58:52 +0100 (CET) Subject: EDGE over osmo-pcu In-Reply-To: References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <1432656151.1221952.1454626732370.JavaMail.zimbra@kvk.uni-obuda.hu> Hi Alexander, Thats what I was afraid of :-) Anyway, even having EDGE with GMSK MCSs is a huge step forward, so I can't say anything but thank you, and I hope I can contribute with some testing and protocol analysis. :-) Now we are using OpenBSC in two lab exercises and I hope to extend it with SDR and EDGE. I can't wait to try it :-) Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Alexander Chemeris" C?mzett: "Sipos Csaba" M?solatot kap: "OpenBSC Mailing List" , osmocom-net-gprs at lists.osmocom.org, "Jacob Erlbeck" Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 23:25:30 T?rgy: Re: EDGE over osmo-pcu Hi Sipos, Osmo-trx does not support 8-PSK at this moment, so you should implement it if you want to test it. ;) Please excuse typos. Written with a touchscreen keyboard. -- Regards, Alexander Chemeris CEO Fairwaves, Inc. https://fairwaves.co On Feb 4, 2016 1:43 PM, "Sipos Csaba" wrote: > Hi Jacob, > > Congratulations and thank you for all your hard work. > > I hope I can do some testing on the weekend with a B200. I will also > update the wiki article if needed. > > Just one question: for MCS5-9 in the downlink there is no need to update > the Osmo-TRX code? Does it support 8PSK as it is now? > > Regards, > Csaba > > ----- Eredeti ?zenet ----- > Felad?: "Jacob Erlbeck" > C?mzett: osmocom-net-gprs at lists.osmocom.org > M?solatot kap: openbsc at lists.osmocom.org > Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 18:59:05 > T?rgy: EDGE over osmo-pcu > > Hi everybody, > > we have just done the first download of an Internet page using the > current bleeding EDGE development version of the OSMO-PCU. Supported are > MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. > > The download of 'www.osmocom.org' has been documented in a PCAP file and > can be downloaded from > > https://openbsc.osmocom.org/trac/wiki/osmo-pcu > > To decode the data blocks, an experimental patch for the gsmtab > dissector is also available from there. > > Cheers > > Jacob > > -- > - Jacob Erlbeck http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte > From alexander.chemeris at gmail.com Thu Feb 4 23:32:30 2016 From: alexander.chemeris at gmail.com (Alexander Chemeris) Date: Thu, 4 Feb 2016 15:32:30 -0800 Subject: EDGE over osmo-pcu In-Reply-To: <1432656151.1221952.1454626732370.JavaMail.zimbra@kvk.uni-obuda.hu> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> <1432656151.1221952.1454626732370.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: Sipos, All thanks for this EDGE development goes to Jacob/Sysmocom. We at Fairwaves haven't looked at it yet. We're planning to add 8PSK to osmo-trx, but we don't have a roadmap for it yet. Please excuse typos. Written with a touchscreen keyboard. -- Regards, Alexander Chemeris CEO Fairwaves, Inc. https://fairwaves.co On Feb 4, 2016 3:01 PM, "Sipos Csaba" wrote: > Hi Alexander, > > Thats what I was afraid of :-) > > Anyway, even having EDGE with GMSK MCSs is a huge step forward, so I can't > say anything but thank you, and I hope I can contribute with some testing > and protocol analysis. :-) > > Now we are using OpenBSC in two lab exercises and I hope to extend it with > SDR and EDGE. I can't wait to try it :-) > > Regards, > Csaba > > ----- Eredeti ?zenet ----- > Felad?: "Alexander Chemeris" > C?mzett: "Sipos Csaba" > M?solatot kap: "OpenBSC Mailing List" , > osmocom-net-gprs at lists.osmocom.org, "Jacob Erlbeck" > Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 23:25:30 > T?rgy: Re: EDGE over osmo-pcu > > Hi Sipos, > > Osmo-trx does not support 8-PSK at this moment, so you should implement it > if you want to test it. ;) > > Please excuse typos. Written with a touchscreen keyboard. > > -- > Regards, > Alexander Chemeris > CEO Fairwaves, Inc. > https://fairwaves.co > On Feb 4, 2016 1:43 PM, "Sipos Csaba" > wrote: > > > Hi Jacob, > > > > Congratulations and thank you for all your hard work. > > > > I hope I can do some testing on the weekend with a B200. I will also > > update the wiki article if needed. > > > > Just one question: for MCS5-9 in the downlink there is no need to update > > the Osmo-TRX code? Does it support 8PSK as it is now? > > > > Regards, > > Csaba > > > > ----- Eredeti ?zenet ----- > > Felad?: "Jacob Erlbeck" > > C?mzett: osmocom-net-gprs at lists.osmocom.org > > M?solatot kap: openbsc at lists.osmocom.org > > Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 18:59:05 > > T?rgy: EDGE over osmo-pcu > > > > Hi everybody, > > > > we have just done the first download of an Internet page using the > > current bleeding EDGE development version of the OSMO-PCU. Supported are > > MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. > > > > The download of 'www.osmocom.org' has been documented in a PCAP file and > > can be downloaded from > > > > https://openbsc.osmocom.org/trac/wiki/osmo-pcu > > > > To decode the data blocks, an experimental patch for the gsmtab > > dissector is also available from there. > > > > Cheers > > > > Jacob > > > > -- > > - Jacob Erlbeck http://www.sysmocom.de/ > > ======================================================================= > > * sysmocom - systems for mobile communications GmbH > > * Alt-Moabit 93 > > * 10559 Berlin, Germany > > * Sitz / Registered office: Berlin, HRB 134158 B > > * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jerlbeck at sysmocom.de Fri Feb 5 10:22:40 2016 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Fri, 5 Feb 2016 11:22:40 +0100 Subject: EDGE over osmo-pcu In-Reply-To: <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <56B477F0.2030508@sysmocom.de> Hi Sipos On 04.02.2016 22:40, Sipos Csaba wrote: > > Congratulations and thank you for all your hard work. Thank you. And many thanks to Sysmocom and On-Waves to make this possible. > > I hope I can do some testing on the weekend with a B200. I will also update the wiki article if needed. It is not in master yet and my development (wip) branch is still a mess (GPRS is b0rken in the latter), but this should improve soon. I'll put the revised commits to jerlbeck/master first. > Just one question: for MCS5-9 in the downlink there is no need to update the Osmo-TRX code? Does it support 8PSK as it is now? I've only tested it with the sysmobts with direct DSP access so far and haven't looked at the Osmo-TRX or the pcu-if socket based connection to the BTS. But currently the CS/MCS choice is only communicated indirectly via the RLC block size which is unique for each coding scheme. The CPS (coding and puncturing scheme) is also not passed explicitly, only within the header which is different for each MCS header type. So the API for downlink blocks hasn't change, and it should only depend of the MCS encoding/decoding capabilities of the RF DSP/software. Regards Jacob > ----- Eredeti ?zenet ----- > Felad?: "Jacob Erlbeck" > C?mzett: osmocom-net-gprs at lists.osmocom.org > M?solatot kap: openbsc at lists.osmocom.org > Elk?ld?tt ?zenetek: Cs?t?rt?k, 2016. Febru?r 4. 18:59:05 > T?rgy: EDGE over osmo-pcu > > Hi everybody, > > we have just done the first download of an Internet page using the > current bleeding EDGE development version of the OSMO-PCU. Supported are > MCS-1 to MCS-9 in downlink and MCS-1 to MCS-4 in uplink direction. > > The download of 'www.osmocom.org' has been documented in a PCAP file and > can be downloaded from > > https://openbsc.osmocom.org/trac/wiki/osmo-pcu > > To decode the data blocks, an experimental patch for the gsmtab > dissector is also available from there. > > Cheers > > Jacob > -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From laforge at gnumonks.org Fri Feb 5 11:41:22 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 5 Feb 2016 12:41:22 +0100 Subject: [PATCH 2/3] don't touch OML MO when PHY link is established In-Reply-To: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> References: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454672483-15150-2-git-send-email-laforge@gnumonks.org> It seems the right thing to do: Once we know a PHY link is established, the associated OML managed objects should change their state accordingly. However, given all the hackery we do with MO states, this actually breaks things, rather than helping. So I'm disabling that part for now, but this needs to be re-visited at some point. --- src/common/bts.c | 16 ++++++++-------- src/common/phy_link.c | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/common/bts.c b/src/common/bts.c index 2d0ad8e..222a82c 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -266,19 +266,19 @@ int trx_set_available(struct gsm_bts_trx *trx, int avail) LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n", trx->nr, avail); if (avail) { - oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); - oml_mo_tx_sw_act_rep(&trx->mo); - oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK); - oml_mo_tx_sw_act_rep(&trx->bb_transc.mo); - + /* FIXME: This needs to be sorted out */ +#if 0 + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); +#endif } else { - oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); - oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_NOT_INSTALLED); for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) - oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_NOT_INSTALLED); } return 0; } diff --git a/src/common/phy_link.c b/src/common/phy_link.c index 4103ede..0a77fec 100644 --- a/src/common/phy_link.c +++ b/src/common/phy_link.c @@ -67,7 +67,7 @@ void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n"); trx_set_available(trx, 1); break; - default: + case PHY_LINK_SHUTDOWN: LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n"); trx_set_available(trx, 0); break; -- 2.7.0 From laforge at gnumonks.org Fri Feb 5 11:41:23 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 5 Feb 2016 12:41:23 +0100 Subject: [PATCH 3/3] port sysmobts to phy_link/phy_instance abstraction In-Reply-To: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> References: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> Message-ID: <1454672483-15150-3-git-send-email-laforge@gnumonks.org> --- include/osmo-bts/phy_link.h | 1 + src/osmo-bts-sysmo/l1_if.c | 59 ++++++++++++--- src/osmo-bts-sysmo/l1_if.h | 22 +++++- src/osmo-bts-sysmo/main.c | 42 ++++------- src/osmo-bts-sysmo/oml.c | 1 + src/osmo-bts-sysmo/sysmobts_vty.c | 146 +++++++++++++++++++++++--------------- tests/sysmobts/sysmobts_test.c | 4 ++ 7 files changed, 178 insertions(+), 97 deletions(-) diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h index b9fc412..ec3a915 100644 --- a/include/osmo-bts/phy_link.h +++ b/include/osmo-bts/phy_link.h @@ -82,6 +82,7 @@ struct phy_instance { union { struct { + struct femtol1_hdl *hdl; } sysmobts; struct { struct trx_l1h *hdl; diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c index 8457a74..b64136b 100644 --- a/src/osmo-bts-sysmo/l1_if.c +++ b/src/osmo-bts-sysmo/l1_if.c @@ -1,6 +1,6 @@ /* Interface handler for Sysmocom L1 */ -/* (C) 2011-2014 by Harald Welte +/* (C) 2011-2016 by Harald Welte * (C) 2014 by Holger Hans Peter Freyther * * All Rights Reserved @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -579,7 +580,7 @@ static int handle_mph_time_ind(struct femtol1_hdl *fl1, GsmL1_MphTimeInd_t *time_ind, struct msgb *msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct osmo_phsap_prim l1sap; uint32_t fn; @@ -705,7 +706,7 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1, GsmL1_PhReadyToSendInd_t *rts_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct msgb *resp_msg; GsmL1_PhDataReq_t *data_req; @@ -834,7 +835,7 @@ static int process_meas_res(struct gsm_bts_trx *trx, uint8_t chan_nr, static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); uint8_t chan_nr, link_id; struct msgb *sap_msg; struct osmo_phsap_prim *l1sap; @@ -900,7 +901,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1, GsmL1_PhDataInd_t *data_i static int handle_ph_ra_ind(struct femtol1_hdl *fl1, GsmL1_PhRaInd_t *ra_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = femtol1_hdl_trx(fl1); struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts->role; struct gsm_lchan *lchan; @@ -1021,7 +1022,8 @@ int l1if_handle_l1prim(int wq, struct femtol1_hdl *fl1h, struct msgb *msg) if (wlc->cb) { /* call-back function must take * ownership of msgb */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(femtol1_hdl_trx(fl1h), msg, + wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1053,7 +1055,8 @@ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) if (wlc->cb) { /* call-back function must take * ownership of msgb */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(femtol1_hdl_trx(fl1h), msg, + wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1166,7 +1169,7 @@ int l1if_activate_rf(struct femtol1_hdl *hdl, int on) { struct msgb *msg = sysp_msgb_alloc(); SuperFemto_Prim_t *sysp = msgb_sysprim(msg); - struct gsm_bts_trx *trx = hdl->priv; + struct gsm_bts_trx *trx = hdl->phy_inst->trx; if (on) { sysp->id = SuperFemto_PrimId_ActivateRfReq; @@ -1478,7 +1481,7 @@ static int get_hwinfo_eeprom(struct femtol1_hdl *fl1h) return 0; } -struct femtol1_hdl *l1if_open(void *priv) +struct femtol1_hdl *l1if_open(struct phy_instance *pinst) { struct femtol1_hdl *fl1h; int rc; @@ -1495,12 +1498,12 @@ struct femtol1_hdl *l1if_open(void *priv) FEMTOBTS_API_VERSION & 0xff); #endif - fl1h = talloc_zero(priv, struct femtol1_hdl); + fl1h = talloc_zero(pinst, struct femtol1_hdl); if (!fl1h) return NULL; INIT_LLIST_HEAD(&fl1h->wlc_list); - fl1h->priv = priv; + fl1h->phy_inst = pinst; fl1h->clk_cal = 0; fl1h->clk_use_eeprom = 1; fl1h->min_qual_rach = MIN_QUAL_RACH; @@ -1535,6 +1538,8 @@ struct femtol1_hdl *l1if_open(void *priv) return NULL; } + l1if_reset(fl1h); + return fl1h; } @@ -1662,3 +1667,35 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h) } #endif + +int bts_model_phy_link_open(struct phy_link *plink) +{ + struct phy_instance *pinst = phy_instance_by_num(plink, 0); + struct gsm_bts *bts; + + OSMO_ASSERT(pinst); + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + pinst->u.sysmobts.hdl = l1if_open(pinst); + if (!pinst->u.sysmobts.hdl) { + LOGP(DL1C, LOGL_FATAL, "Cannot open L1 interface\n"); + return -EIO; + } + + bts = pinst->trx->bts; + if (pinst->trx == bts->c0) { + int rc; + rc = sysmobts_get_nominal_power(bts->c0); + if (rc < 0) { + LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal " + "transmit power. Assuming 23dBm.\n"); + } + bts->c0->nominal_power = rc; + bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc); + } + + phy_link_state_set(plink, PHY_LINK_CONNECTED); + + return 0; +} diff --git a/src/osmo-bts-sysmo/l1_if.h b/src/osmo-bts-sysmo/l1_if.h index 3f2938f..de4f2a3 100644 --- a/src/osmo-bts-sysmo/l1_if.h +++ b/src/osmo-bts-sysmo/l1_if.h @@ -7,6 +7,8 @@ #include #include +#include + #include enum { @@ -52,7 +54,7 @@ struct femtol1_hdl { char *calib_path; struct llist_head wlc_list; - void *priv; /* user reference */ + struct phy_instance *phy_inst; /* Reference to PHY instance */ struct osmo_timer_list alive_timer; unsigned int alive_prim_cnt; @@ -78,6 +80,9 @@ struct femtol1_hdl { struct calib_send_state st; uint8_t last_rf_mute[8]; + + /* for l1_fwd */ + void *priv; }; #define msgb_l1prim(msg) ((GsmL1_Prim_t *)(msg)->l1h) @@ -91,7 +96,7 @@ int l1if_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, int l1if_gsm_req_compl(struct femtol1_hdl *fl1h, struct msgb *msg, l1if_compl_cb *cb, void *cb_data); -struct femtol1_hdl *l1if_open(void *priv); +struct femtol1_hdl *l1if_open(struct phy_instance *pinst); int l1if_close(struct femtol1_hdl *hdl); int l1if_reset(struct femtol1_hdl *hdl); int l1if_activate_rf(struct femtol1_hdl *hdl, int on); @@ -134,4 +139,17 @@ int l1if_rf_clock_info_correct(struct femtol1_hdl *fl1h); /* public helpers for test */ int bts_check_for_ciph_cmd(struct femtol1_hdl *fl1h, struct msgb *msg, struct gsm_lchan *lchan); + +static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx) +{ + struct phy_instance *pinst = trx_phy_instance(trx); + OSMO_ASSERT(pinst); + return pinst->u.sysmobts.hdl; +} + +static inline struct gsm_bts_trx *femtol1_hdl_trx(struct femtol1_hdl *fl1h) +{ + OSMO_ASSERT(fl1h->phy_inst); + return fl1h->phy_inst->trx; +} #endif /* _FEMTO_L1_H */ diff --git a/src/osmo-bts-sysmo/main.c b/src/osmo-bts-sysmo/main.c index d468a71..68a4be8 100644 --- a/src/osmo-bts-sysmo/main.c +++ b/src/osmo-bts-sysmo/main.c @@ -86,21 +86,13 @@ void clk_cal_use_eeprom(struct gsm_bts *bts) int bts_model_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; - struct femtol1_hdl *fl1h; struct stat st; - struct osmo_fd accept_fd, read_fd; + static struct osmo_fd accept_fd, read_fd; int rc; btsb = bts_role_bts(bts); btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); - clk_cal_use_eeprom(bts); - - if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) { - LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n"); - exit(23); - } - rc = oml_router_init(bts, OML_ROUTER_PATH, &accept_fd, &read_fd); if (rc < 0) { fprintf(stderr, "Error creating the OML router: %s rc=%d\n", @@ -108,23 +100,12 @@ int bts_model_init(struct gsm_bts *bts) exit(1); } - fl1h = l1if_open(bts->c0); - if (!fl1h) { - LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n"); - return -EIO; - } - fl1h->dsp_trace_f = dsp_trace; - - bts->c0->role_bts.l1h = fl1h; + clk_cal_use_eeprom(bts); - rc = sysmobts_get_nominal_power(bts->c0); - if (rc < 0) { - LOGP(DL1C, LOGL_NOTICE, "Cannot determine nominal " - "transmit power. Assuming 23dBm.\n"); - rc = 23; + if (stat(SYSMOBTS_RF_LOCK_PATH, &st) == 0) { + LOGP(DL1C, LOGL_NOTICE, "Not starting BTS due to RF_LOCK file present\n"); + exit(23); } - bts->c0->nominal_power = rc; - bts->c0->power_params.trx_p_max_out_mdBm = to_mdB(rc); bts_model_vty_init(bts); @@ -133,10 +114,6 @@ int bts_model_init(struct gsm_bts *bts) int bts_model_oml_estab(struct gsm_bts *bts) { - struct femtol1_hdl *fl1h = bts->c0->role_bts.l1h; - - l1if_reset(fl1h); - return 0; } @@ -205,6 +182,7 @@ int bts_model_handle_options(int argc, char **argv) switch (c) { case 'p': dsp_trace = strtoul(optarg, NULL, 16); +#warning use dsp_trace!!! break; case 'M': pcu_direct = 1; @@ -222,6 +200,14 @@ int bts_model_handle_options(int argc, char **argv) return num_errors; } +void bts_model_phy_link_set_defaults(struct phy_link *plink) +{ +} + +void bts_model_phy_instance_set_defaults(struct phy_instance *pinst) +{ +} + void bts_model_abis_close(struct gsm_bts *bts) { /* for now, we simply terminate the program and re-spawn */ diff --git a/src/osmo-bts-sysmo/oml.c b/src/osmo-bts-sysmo/oml.c index adc0241..cd03b22 100644 --- a/src/osmo-bts-sysmo/oml.c +++ b/src/osmo-bts-sysmo/oml.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/src/osmo-bts-sysmo/sysmobts_vty.c b/src/osmo-bts-sysmo/sysmobts_vty.c index 4a37b5d..19122dc 100644 --- a/src/osmo-bts-sysmo/sysmobts_vty.c +++ b/src/osmo-bts-sysmo/sysmobts_vty.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -84,24 +85,24 @@ DEFUN(cfg_bts_no_auto_band, cfg_bts_no_auto_band_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_clkcal_eeprom, cfg_trx_clkcal_eeprom_cmd, +DEFUN(cfg_phy_clkcal_eeprom, cfg_phy_clkcal_eeprom_cmd, "clock-calibration eeprom", "Use the eeprom clock calibration value\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 1; return CMD_SUCCESS; } -DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, +DEFUN(cfg_phy_clkcal_def, cfg_phy_clkcal_def_cmd, "clock-calibration default", "Set the clock calibration value\n" "Default Clock DAC value\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = 0xffff; @@ -110,13 +111,13 @@ DEFUN(cfg_trx_clkcal_def, cfg_trx_clkcal_def_cmd, } #ifdef HW_SYSMOBTS_V1 -DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, +DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd, "clock-calibration <0-4095>", "Set the clock calibration value\n" "Clock DAC value\n") { unsigned int clkcal = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = clkcal & 0xfff; @@ -124,13 +125,13 @@ DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, return CMD_SUCCESS; } #else -DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, +DEFUN(cfg_phy_clkcal, cfg_phy_clkcal_cmd, "clock-calibration <-4095-4095>", "Set the clock calibration value\n" "Offset in PPB\n") { int clkcal = atoi(argv[0]); - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->clk_use_eeprom = 0; fl1h->clk_cal = clkcal; @@ -139,7 +140,7 @@ DEFUN(cfg_trx_clkcal, cfg_trx_clkcal_cmd, } #endif -DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, +DEFUN(cfg_phy_clksrc, cfg_phy_clksrc_cmd, "clock-source (tcxo|ocxo|ext|gps)", "Set the clock source value\n" "Use the TCXO\n" @@ -147,8 +148,8 @@ DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, "Use an external clock\n" "Use the GPS pps\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; int rc; rc = get_string_value(femtobts_clksrc_names, argv[0]); @@ -160,12 +161,12 @@ DEFUN(cfg_trx_clksrc, cfg_trx_clksrc_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_cal_path, cfg_trx_cal_path_cmd, +DEFUN(cfg_phy_cal_path, cfg_phy_cal_path_cmd, "trx-calibration-path PATH", "Set the path name to TRX calibration data\n" "Path name\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; if (fl1h->calib_path) talloc_free(fl1h->calib_path); @@ -188,26 +189,26 @@ DEFUN_DEPRECATED(cfg_trx_ul_power_target, cfg_trx_ul_power_target_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_min_qual_rach, cfg_trx_min_qual_rach_cmd, +DEFUN(cfg_phy_min_qual_rach, cfg_phy_min_qual_rach_cmd, "min-qual-rach <-100-100>", "Set the minimum quality level of RACH burst to be accpeted\n" "C/I level in tenth of dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->min_qual_rach = strtof(argv[0], NULL) / 10.0f; return CMD_SUCCESS; } -DEFUN(cfg_trx_min_qual_norm, cfg_trx_min_qual_norm_cmd, +DEFUN(cfg_phy_min_qual_norm, cfg_phy_min_qual_norm_cmd, "min-qual-norm <-100-100>", "Set the minimum quality level of normal burst to be accpeted\n" "C/I level in tenth of dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + struct phy_instance *pinst = vty->index; + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; fl1h->min_qual_norm = strtof(argv[0], NULL) / 10.0f; @@ -286,18 +287,24 @@ DEFUN(show_dsp_trace_f, show_dsp_trace_f_cmd, DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR) { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; unsigned int flag ; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, 0); + if (!pinst) { + vty_out(vty, "Cannot find PHY instance number 0%s", + VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; flag = get_string_value(femtobts_tracef_names, argv[1]); l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f | flag); @@ -306,18 +313,24 @@ DEFUN(dsp_trace_f, dsp_trace_f_cmd, "HIDDEN", TRX_STR) DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR) { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; unsigned int flag ; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, 0); + if (!pinst) { + vty_out(vty, "Cannot find PHY instance number 0%s", + VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; flag = get_string_value(femtobts_tracef_names, argv[1]); l1if_set_trace_flags(fl1h, fl1h->dsp_trace_f & ~flag); @@ -325,20 +338,28 @@ DEFUN(no_dsp_trace_f, no_dsp_trace_f_cmd, "HIDDEN", NO_STR TRX_STR) } DEFUN(show_sys_info, show_sys_info_cmd, - "show trx <0-0> system-information", + "show phy <0-255> instance <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + int inst_nr = atoi(argv[1]); + struct phy_link *plink = phy_link_by_num(phy_nr); + struct phy_instance *pinst; struct femtol1_hdl *fl1h; int i; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY link %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - fl1h = trx_femtol1_hdl(trx); + pinst = phy_instance_by_num(plink, inst_nr); + if (!plink) { + vty_out(vty, "Cannot find PHY instance %u%s", + phy_nr, VTY_NEWLINE); + return CMD_WARNING; + } + fl1h = pinst->u.sysmobts.hdl; vty_out(vty, "DSP Version: %u.%u.%u, FPGA Version: %u.%u.%u%s", fl1h->hw_info.dsp_version[0], @@ -471,7 +492,14 @@ void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { - struct femtol1_hdl *fl1h = trx_femtol1_hdl(trx); + if (trx->nominal_power != sysmobts_get_nominal_power(trx)) + vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power, + VTY_NEWLINE); +} + +static void write_phy_inst(struct vty *vty, struct phy_instance *pinst) +{ + struct femtol1_hdl *fl1h = pinst->u.sysmobts.hdl; if (fl1h->clk_use_eeprom) vty_out(vty, " clock-calibration eeprom%s", VTY_NEWLINE); @@ -488,9 +516,14 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); vty_out(vty, " min-qual-norm %.0f%s", fl1h->min_qual_norm * 10.0f, VTY_NEWLINE); - if (trx->nominal_power != sysmobts_get_nominal_power(trx)) - vty_out(vty, " nominal-tx-power %d%s", trx->nominal_power, - VTY_NEWLINE); +} + +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + struct phy_instance *pinst; + + llist_for_each_entry(pinst, &plink->instances, list) + write_phy_inst(vty, pinst); } int bts_model_vty_init(struct gsm_bts *bts) @@ -529,15 +562,16 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_auto_band_cmd); install_element(BTS_NODE, &cfg_bts_no_auto_band_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_eeprom_cmd); - install_element(TRX_NODE, &cfg_trx_clkcal_def_cmd); - install_element(TRX_NODE, &cfg_trx_clksrc_cmd); - install_element(TRX_NODE, &cfg_trx_cal_path_cmd); install_element(TRX_NODE, &cfg_trx_ul_power_target_cmd); - install_element(TRX_NODE, &cfg_trx_min_qual_rach_cmd); - install_element(TRX_NODE, &cfg_trx_min_qual_norm_cmd); install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_eeprom_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clkcal_def_cmd); + install_element(PHY_INST_NODE, &cfg_phy_clksrc_cmd); + install_element(PHY_INST_NODE, &cfg_phy_cal_path_cmd); + install_element(PHY_INST_NODE, &cfg_phy_min_qual_rach_cmd); + install_element(PHY_INST_NODE, &cfg_phy_min_qual_norm_cmd); + return 0; } diff --git a/tests/sysmobts/sysmobts_test.c b/tests/sysmobts/sysmobts_test.c index b835dc2..6ae7623 100644 --- a/tests/sysmobts/sysmobts_test.c +++ b/tests/sysmobts/sysmobts_test.c @@ -265,3 +265,7 @@ int bts_model_oml_estab(struct gsm_bts *bts) { return 0; } void bts_model_abis_close(struct gsm_bts *bts) { } +void bts_model_phy_link_set_defaults(struct phy_link *plink) +{ } +void bts_model_phy_instance_set_defaults(struct phy_instance *pinst) +{ } -- 2.7.0 From laforge at gnumonks.org Fri Feb 5 11:41:21 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 5 Feb 2016 12:41:21 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction Message-ID: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> This way we can model a flexible mapping between any number of PHYs, each having multiple instances, and then map BTSs with TRXx on top of those PHYs. --- doc/examples/octphy/osmo-bts.cfg | 8 +- doc/phy_link.txt | 57 ++++++ doc/startup.txt | 42 ++++ include/osmo-bts/Makefile.am | 2 +- include/osmo-bts/bts.h | 2 +- include/osmo-bts/bts_model.h | 8 + include/osmo-bts/gsm_data.h | 15 -- include/osmo-bts/phy_link.h | 115 +++++++++++ include/osmo-bts/scheduler.h | 4 +- include/osmo-bts/vty.h | 7 +- src/common/Makefile.am | 2 +- src/common/bts.c | 30 ++- src/common/main.c | 20 ++ src/common/phy_link.c | 159 +++++++++++++++ src/common/scheduler.c | 6 +- src/common/vty.c | 194 +++++++++++++++++- src/osmo-bts-octphy/l1_if.c | 170 +++++++++++----- src/osmo-bts-octphy/l1_if.h | 31 ++- src/osmo-bts-octphy/l1_oml.c | 163 ++++++++------- src/osmo-bts-octphy/main.c | 3 +- src/osmo-bts-octphy/octphy_hw_api.c | 14 +- src/osmo-bts-octphy/octphy_vty.c | 198 +++++++++++-------- src/osmo-bts-trx/l1_if.c | 84 ++++---- src/osmo-bts-trx/l1_if.h | 18 +- src/osmo-bts-trx/main.c | 78 +++----- src/osmo-bts-trx/scheduler_trx.c | 33 ++-- src/osmo-bts-trx/trx_if.c | 133 +++++++++---- src/osmo-bts-trx/trx_if.h | 1 + src/osmo-bts-trx/trx_vty.c | 381 ++++++++++++++++++++++-------------- 29 files changed, 1424 insertions(+), 554 deletions(-) create mode 100644 doc/phy_link.txt create mode 100644 doc/startup.txt create mode 100644 include/osmo-bts/phy_link.h create mode 100644 src/common/phy_link.c diff --git a/doc/examples/octphy/osmo-bts.cfg b/doc/examples/octphy/osmo-bts.cfg index 07bcae0..4f27c8d 100644 --- a/doc/examples/octphy/osmo-bts.cfg +++ b/doc/examples/octphy/osmo-bts.cfg @@ -20,9 +20,13 @@ log stderr line vty no login ! +phy 0 + octphy hw-addr 00:0C:90:2e:80:1e + octphy net-device eth0.2342 + instance 0 bts 0 band 1800 ipa unit-id 1234 0 oml remote-ip 127.0.0.1 - phy-hw-addr 00:0C:90:2e:80:1e - phy-netdev eth0.2342 + trx 0 + phy 0 instance 0 diff --git a/doc/phy_link.txt b/doc/phy_link.txt new file mode 100644 index 0000000..c49e328 --- /dev/null +++ b/doc/phy_link.txt @@ -0,0 +1,57 @@ + +== OsmoBTS PHY interface abstraction + +The OsmoBTS PHY interface serves as an abstraction layer between given +PHY hardware and the actual logical transceivers (TRXs) of a BTS inside +the OsmoBTS code base. + + +=== PHY link + +A PHY link is a physical connection / link towards a given PHY. This +might be, for example, + +* a set of file descriptors to device nodes in the /dev/ directory + (sysmobts, litecell15) +* a packet socket for sending raw Ethernet frames to an OCTPHY +* a set of UDP sockets for interacting with OsmoTRX + +Each PHY interface has a set of attribute/parameters and a list of 1 to +n PHY instances. + +PHY links are numbered 0..n globally inside OsmoBTS. + +Each PHY link is configured via the VTY using its individual top-level +vty node. Given the different bts-model / phy specific properties, the +VTY configuration options (if any) of the PHY instance differ between +BTS models. + +The PHY links and instances must be configured above the BTS/TRX nodes +in the configuration file. If the file is saved via the VTY, the code +automatically ensures this. + + +=== PHY instance + +A PHY instance is an instance of a PHY, accessed via a PHY link. + +In the case of osmo-bts-sysmo and osmo-bts-trx, there is only one +instance in every PHY link. This is due to the fact that the API inside +that PHY link does not permit for distinguishing multiple different +logical TRXs. + +Other PHY implementations like the OCTPHY however do support addressing +multiple PHY instances via a single PHY link. + +PHY instances are numbered 0..n inside each PHY link. + +Each PHY instance is configured via the VTY as a separate node beneath each +PHY link. Given the different bts-model / phy specific properties, the +VTY configuration options (if any) of the PHY instance differ between +BTS models. + + +=== Mapping PHY instances to TRXs + +Each TRX node in the VTY must use the 'phy N instance M' command in +order to specify which PHY instance is allocated to this specific TRX. diff --git a/doc/startup.txt b/doc/startup.txt new file mode 100644 index 0000000..cc64375 --- /dev/null +++ b/doc/startup.txt @@ -0,0 +1,42 @@ + +== start-up / sequencing during OsmoBTS start + +The start-up procedure of OsmoBTS can be described as follows: + +|=== +| bts-specific | main() | +| common | bts_main() | initialization of talloc contexts +| common | bts_log_init() | initialization of logging +| common | handle_options() | common option parsing +| bts-specific | bts_model_handle_options() | model-specific option parsing +| common | gsm_bts_alloc() | allocation of BTS/TRX/TS data structures +| common | vty_init() | Initialziation of VTY core, libosmo-abis and osmo-bts VTY +| common | main() | Setting of scheduler RR priority (if configured) +| common | main() | Initialization of GSMTAP (if configured) +| common | bts_init() | configuration of defaults in bts/trx/s object +| bts-specific | bts_model_init | ? +| common | abis_init() | Initialization of libosmo-abis +| common | vty_read_config_file() | Reading of configuration file +| bts-specific | bts_model_phy_link_set_defaults() | Called for every PHY link created +| bts-specific | bts_model_phy_instance_set_defaults() | Called for every PHY Instance created +| common | bts_controlif_setup() | Initialization of Control Interface +| bts-specific | bts_model_ctrl_cmds_install() +| common | telnet_init() | Initialization of telnet interface +| common | pcu_sock_init() | Initializaiton of PCU socket +| common | main() | Installation of signal handlers +| common | abis_open() | Start of the A-bis connection to BSC +| common | phy_links_open() | Iterate over list of configured PHY links +| bts-specific | bts_model_phy_link_open() | Open each of the configured PHY links +| common | write_pid_file() | Generate the pid file +| common | osmo_daemonize() | Fork as daemon in background (if configured) +| common | bts_main() | Run main loop until global variable quit >= 2 +| bts-specific | bts_model_oml_estab() | Called by core once OML link is established +| bts-specific | bts_model_check_oml() | called each time OML sets some attributes on a MO, checks if attributes are valid +| bts-specific | bts_model_apply_oml() | called each time OML sets some attributes on a MO, stores attribute contents in data structures +| bts-specific | bts_model_opstart() | for NM_OC_BTS, NM_OC_SITE_MANAGER, NM_OC_GPRS_NSE, NM_OC_GPRS_CELL, NMO_OC_GPRS_NSVC +| bts-specific | bts_model_opstart() | for NM_OC_RADIO_CARRIER for each trx +| bts-specific | bts_model_opstart() | for NM_OC_BASEB_TRANSC for each trx +| bts-specific | bts_model_opstart() | for NM_OC_CHANNEL for each timeslot on each trx +| bts-specific | bts_model_change_power() | change transmit power for each trx (power ramp-up/ramp-down + +| bts-specific | bts_model_abis_close() | called when either one of the RSL links or the OML link are down diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index af88a1a..d0b55ff 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,4 +1,4 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ handover.h msg_utils.h tx_power.h control_if.h cbch.h l1sap.h \ - power_control.h scheduler.h scheduler_backend.h + power_control.h scheduler.h scheduler_backend.h phy_link.h diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h index 9e21186..ec58edd 100644 --- a/include/osmo-bts/bts.h +++ b/include/osmo-bts/bts.h @@ -21,12 +21,12 @@ void destroy_bts(struct gsm_bts *bts); int work_bts(struct gsm_bts *bts); int bts_link_estab(struct gsm_bts *bts); int trx_link_estab(struct gsm_bts_trx *trx); +int trx_set_available(struct gsm_bts_trx *trx, int avail); void bts_new_si(void *arg); void bts_setup_slot(struct gsm_bts_trx_ts *slot, uint8_t comb); int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg); struct msgb *bts_agch_dequeue(struct gsm_bts *bts); -void bts_update_agch_max_queue_length(struct gsm_bts *bts); int bts_agch_max_queue_length(int T, int bcch_conf); int bts_ccch_copy_msg(struct gsm_bts *bts, uint8_t *out_buf, struct gsm_time *gt, int is_ag_res); diff --git a/include/osmo-bts/bts_model.h b/include/osmo-bts/bts_model.h index 41b5e93..6252557 100644 --- a/include/osmo-bts/bts_model.h +++ b/include/osmo-bts/bts_model.h @@ -8,6 +8,9 @@ #include +struct phy_link; +struct phy_instance; + /* BTS model specific functions needed by the common code */ int bts_model_init(struct gsm_bts *bts); @@ -32,6 +35,8 @@ int bts_model_vty_init(struct gsm_bts *bts); void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts); void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink); +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst); int bts_model_oml_estab(struct gsm_bts *bts); @@ -47,4 +52,7 @@ int bts_model_ctrl_cmds_install(struct gsm_bts *bts); int bts_model_handle_options(int argc, char **argv); void bts_model_print_help(); +void bts_model_phy_link_set_defaults(struct phy_link *plink); +void bts_model_phy_instance_set_defaults(struct phy_instance *pinst); + #endif diff --git a/include/osmo-bts/gsm_data.h b/include/osmo-bts/gsm_data.h index 6a7bca8..f9e6ed1 100644 --- a/include/osmo-bts/gsm_data.h +++ b/include/osmo-bts/gsm_data.h @@ -119,21 +119,6 @@ enum lchan_ciph_state { #include "openbsc/gsm_data_shared.h" -struct femtol1_hdl; - -static inline struct femtol1_hdl *trx_femtol1_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - -struct trx_l1h; - -static inline struct trx_l1h *trx_l1h_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - - void lchan_set_state(struct gsm_lchan *lchan, enum gsm_lchan_state state); /* cipher code */ diff --git a/include/osmo-bts/phy_link.h b/include/osmo-bts/phy_link.h new file mode 100644 index 0000000..b9fc412 --- /dev/null +++ b/include/osmo-bts/phy_link.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include + +#include + +#include + +struct gsm_bts_trx; + +enum phy_link_type { + PHY_LINK_T_NONE, + PHY_LINK_T_SYSMOBTS, + PHY_LINK_T_OSMOTRX, +}; + +enum phy_link_state { + PHY_LINK_SHUTDOWN, + PHY_LINK_CONNECTING, + PHY_LINK_CONNECTED, +}; + +/* A PHY link represents the connection to a given PHYsical layer + * implementation. That PHY link contains 1...N PHY instances, one for + * each TRX */ +struct phy_link { + struct llist_head list; + int num; + enum phy_link_type type; + enum phy_link_state state; + struct llist_head instances; + char *description; + union { + struct { + } sysmobts; + struct { + char *transceiver_ip; + uint16_t base_port_local; + uint16_t base_port_remote; + struct osmo_fd trx_ofd_clk; + + uint32_t clock_advance; + uint32_t rts_advance; + + int rxgain_valid; + int rxgain; + int rxgain_sent; + + int power_valid; + int power; + int power_oml; + int power_sent; + } osmotrx; + struct { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* Network device name */ + char *netdev_name; + + /* configuration */ + uint32_t rf_port_index; + uint32_t rx_gain_db; + uint32_t tx_atten_db; + + struct octphy_hdl *hdl; + } octphy; + } u; +}; + +struct phy_instance { + /* liked inside phy_link.linstances */ + struct llist_head list; + int num; + char *description; + + /* pointer to the PHY link to which we belong */ + struct phy_link *phy_link; + + /* back-pointer to the TRX to which we're associated */ + struct gsm_bts_trx *trx; + + union { + struct { + } sysmobts; + struct { + struct trx_l1h *hdl; + } osmotrx; + struct { + /* logical transceiver number within one PHY */ + uint32_t trx_id; + } octphy; + } u; +}; + +struct phy_link *phy_link_by_num(int num); +struct phy_link *phy_link_create(void *ctx, int num); +void phy_link_destroy(struct phy_link *plink); +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state); +int phy_links_open(void); + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num); +struct phy_instance *phy_instance_create(struct phy_link *plink, int num); +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx); +void phy_instance_destroy(struct phy_instance *pinst); +const char *phy_instance_name(struct phy_instance *pinst); + +void phy_user_statechg_notif(struct phy_instance *pinst, enum phy_link_state link_state); + +static inline struct phy_instance *trx_phy_instance(struct gsm_bts_trx *trx) +{ + return trx->role_bts.l1h; +} + +int bts_model_phy_link_open(struct phy_link *plink); diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h index 13ef051..b11e6f1 100644 --- a/include/osmo-bts/scheduler.h +++ b/include/osmo-bts/scheduler.h @@ -1,6 +1,8 @@ #ifndef TRX_SCHEDULER_H #define TRX_SCHEDULER_H +#include + /* These types define the different channels on a multiframe. * Each channel has queues and can be activated individually. */ @@ -133,7 +135,7 @@ extern uint32_t transceiver_last_fn; /*! \brief Initialize the scheudler data structures */ -int trx_sched_init(struct l1sched_trx *l1t); +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx); /*! \brief De-initialize the scheudler data structures */ void trx_sched_exit(struct l1sched_trx *l1t); diff --git a/include/osmo-bts/vty.h b/include/osmo-bts/vty.h index 546729c..5d8d4a7 100644 --- a/include/osmo-bts/vty.h +++ b/include/osmo-bts/vty.h @@ -5,7 +5,12 @@ #include enum bts_vty_node { - BTS_NODE = _LAST_OSMOVTY_NODE + 1, + /* PHY_NODE must come before BTS node to ensure the phy + * instances are created at the time the TRX nodes want to refer + * to them */ + PHY_NODE = _LAST_OSMOVTY_NODE + 1, + PHY_INST_NODE, + BTS_NODE, TRX_NODE, }; diff --git a/src/common/Makefile.am b/src/common/Makefile.am index fea205c..8df6513 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -8,6 +8,6 @@ libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ load_indication.c pcu_sock.c handover.c msg_utils.c \ tx_power.c bts_ctrl_commands.c bts_ctrl_lookup.c \ - l1sap.c cbch.c power_control.c main.c + l1sap.c cbch.c power_control.c main.c phy_link.c libl1sched_a_SOURCES = scheduler.c diff --git a/src/common/bts.c b/src/common/bts.c index 43f4c25..2d0ad8e 100644 --- a/src/common/bts.c +++ b/src/common/bts.c @@ -44,6 +44,7 @@ #include #include +static void bts_update_agch_max_queue_length(struct gsm_bts *bts); struct gsm_network bts_gsmnet = { .bts_list = { &bts_gsmnet.bts_list, &bts_gsmnet.bts_list }, @@ -72,6 +73,8 @@ static int bts_signal_cbfn(unsigned int subsys, unsigned int signal, return 0; } +/* Initialize the BTS (and TRX) data structures, called before config + * file reading */ int bts_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; @@ -255,6 +258,31 @@ int trx_link_estab(struct gsm_bts_trx *trx) return 0; } +/* set the availability of the TRX (used by PHY driver) */ +int trx_set_available(struct gsm_bts_trx *trx, int avail) +{ + int tn; + + LOGP(DSUM, LOGL_INFO, "TRX(%d): Setting available = %d\n", + trx->nr, avail); + if (avail) { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->mo); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OK); + oml_mo_tx_sw_act_rep(&trx->bb_transc.mo); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY); + } else { + oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + oml_mo_state_chg(&trx->bb_transc.mo, -1, NM_AVSTATE_OFF_LINE); + + for (tn = 0; tn < ARRAY_SIZE(trx->ts); tn++) + oml_mo_state_chg(&trx->ts[tn].mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OFF_LINE); + } + return 0; +} + int lchan_init_lapdm(struct gsm_lchan *lchan) { struct lapdm_channel *lc = &lchan->lapdm_ch; @@ -310,7 +338,7 @@ int bts_agch_max_queue_length(int T, int bcch_conf) return (T + 2 * S) * ccch_rach_ratio256 / 256; } -void bts_update_agch_max_queue_length(struct gsm_bts *bts) +static void bts_update_agch_max_queue_length(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm48_system_information_type_3 *si3; diff --git a/src/common/main.c b/src/common/main.c index fabe482..e454a28 100644 --- a/src/common/main.c +++ b/src/common/main.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -284,6 +285,19 @@ int bts_main(int argc, char **argv) exit(1); } + if (!phy_link_by_num(0)) { + fprintf(stderr, "You need to configure at last phy0\n"); + exit(1); + } + + llist_for_each_entry(trx, &bts->trx_list, list) { + if (!trx->role_bts.l1h) { + fprintf(stderr, "TRX %u has no associated PHY instance\n", + trx->nr); + exit(1); + } + } + write_pid_file("osmo-bts"); bts_controlif_setup(bts); @@ -317,6 +331,12 @@ int bts_main(int argc, char **argv) exit(2); } + rc = phy_links_open(); + if (rc < 0) { + fprintf(stderr, "unable ot open PHY link(s)\n"); + exit(2); + } + if (daemonize) { rc = osmo_daemonize(); if (rc < 0) { diff --git a/src/common/phy_link.c b/src/common/phy_link.c new file mode 100644 index 0000000..4103ede --- /dev/null +++ b/src/common/phy_link.c @@ -0,0 +1,159 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +static LLIST_HEAD(g_phy_links); + +struct phy_link *phy_link_by_num(int num) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + if (plink->num == num) + return plink; + } + + return NULL; +} + +struct phy_link *phy_link_create(void *ctx, int num) +{ + struct phy_link *plink = talloc_zero(ctx, struct phy_link); + + if (phy_link_by_num(num)) + return NULL; + + plink = talloc_zero(ctx, struct phy_link); + plink->num = num; + plink->state = PHY_LINK_SHUTDOWN; + INIT_LLIST_HEAD(&plink->instances); + llist_add_tail(&plink->list, &g_phy_links); + + bts_model_phy_link_set_defaults(plink); + + return plink; +} + +const struct value_string phy_link_state_vals[] = { + { PHY_LINK_SHUTDOWN, "shutdown" }, + { PHY_LINK_CONNECTING, "connectiong" }, + { PHY_LINK_CONNECTED, "connected" }, + { 0, NULL } +}; + +void phy_link_state_set(struct phy_link *plink, enum phy_link_state state) +{ + struct phy_instance *pinst; + + LOGP(DL1C, LOGL_INFO, "PHY link state change %s -> %s\n", + get_value_string(phy_link_state_vals, plink->state), + get_value_string(phy_link_state_vals, state)); + + /* notify all TRX associated with this phy */ + llist_for_each_entry(pinst, &plink->instances, list) { + struct gsm_bts_trx *trx = pinst->trx; + if (!trx) + continue; + + switch (state) { + case PHY_LINK_CONNECTED: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(1)\n"); + trx_set_available(trx, 1); + break; + default: + LOGP(DL1C, LOGL_INFO, "trx_set_avail(0)\n"); + trx_set_available(trx, 0); + break; + } + } + + plink->state = state; +} + +struct phy_instance *phy_instance_by_num(struct phy_link *plink, int num) +{ + struct phy_instance *pinst; + + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->num == num) + return pinst; + } + return NULL; +} + +struct phy_instance *phy_instance_create(struct phy_link *plink, int num) +{ + struct phy_instance *pinst = talloc_zero(plink, struct phy_instance); + + if (phy_instance_by_num(plink, num)) + return NULL; + + pinst = talloc_zero(plink, struct phy_instance); + pinst->num = num; + pinst->phy_link = plink; + llist_add_tail(&pinst->list, &plink->instances); + + bts_model_phy_instance_set_defaults(pinst); + + return pinst; +} + +void phy_instance_link_to_trx(struct phy_instance *pinst, struct gsm_bts_trx *trx) +{ + trx->role_bts.l1h = pinst; + pinst->trx = trx; +} + +void phy_instance_destroy(struct phy_instance *pinst) +{ + /* remove from list of instances in the link */ + llist_del(&pinst->list); + + /* remove reverse link from TRX */ + OSMO_ASSERT(pinst->trx->role_bts.l1h == pinst); + pinst->trx->role_bts.l1h = NULL; + pinst->trx = NULL; + + talloc_free(pinst); +} + +void phy_link_destroy(struct phy_link *plink) +{ + struct phy_instance *pinst, *pinst2; + + llist_for_each_entry_safe(pinst, pinst2, &plink->instances, list) + phy_instance_destroy(pinst); + + talloc_free(plink); +} + +int phy_links_open(void) +{ + struct phy_link *plink; + + llist_for_each_entry(plink, &g_phy_links, list) { + int rc; + + rc = bts_model_phy_link_open(plink); + if (rc < 0) + return rc; + } + + return 0; +} + +const char *phy_instance_name(struct phy_instance *pinst) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), "phy%u.%u", pinst->phy_link->num, + pinst->num); + return buf; +} diff --git a/src/common/scheduler.c b/src/common/scheduler.c index 64d89ac..de09fbf 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -134,11 +134,13 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = { * init / exit */ -int trx_sched_init(struct l1sched_trx *l1t) +int trx_sched_init(struct l1sched_trx *l1t, struct gsm_bts_trx *trx) { uint8_t tn; int i; + l1t->trx = trx; + LOGP(DL1C, LOGL_NOTICE, "Init scheduler for trx=%u\n", l1t->trx->nr); for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { @@ -191,7 +193,7 @@ void trx_sched_exit(struct l1sched_trx *l1t) void trx_sched_reset(struct l1sched_trx *l1t) { trx_sched_exit(l1t); - trx_sched_init(l1t); + trx_sched_init(l1t, l1t->trx); } struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn, diff --git a/src/common/vty.c b/src/common/vty.c index 4fd65d0..94ccdbe 100644 --- a/src/common/vty.c +++ b/src/common/vty.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,13 @@ int bts_vty_go_parent(struct vty *vty) { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -60,6 +68,7 @@ int bts_vty_go_parent(struct vty *vty) vty->index = trx->bts; } break; + case PHY_NODE: default: vty->node = CONFIG_NODE; } @@ -71,6 +80,8 @@ int bts_vty_is_config_node(struct vty *vty, int node) switch (node) { case TRX_NODE: case BTS_NODE: + case PHY_NODE: + case PHY_INST_NODE: return 1; default: return 0; @@ -81,6 +92,17 @@ gDEFUN(ournode_exit, ournode_exit_cmd, "exit", "Exit current node, go down to provious node") { switch (vty->node) { + case PHY_INST_NODE: + vty->node = PHY_NODE; + { + struct phy_instance *pinst = vty->index; + vty->index = pinst->phy_link; + } + break; + case PHY_NODE: + vty->node = CONFIG_NODE; + vty->index = NULL; + break; case TRX_NODE: vty->node = BTS_NODE; { @@ -141,6 +163,7 @@ static struct cmd_node trx_node = { 1, }; + DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, "trx <0-254>", "Select a TRX to configure\n" "TRX number\n") @@ -151,7 +174,7 @@ DEFUN(cfg_bts_trx, cfg_bts_trx_cmd, trx = gsm_bts_trx_num(bts, trx_nr); if (!trx) { - vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%d%s", + vty_out(vty, "Unknown TRX %u. Aavialable TRX are: 0..%u%s", trx_nr, bts->num_trx - 1, VTY_NEWLINE); return CMD_WARNING; } @@ -232,6 +255,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) llist_for_each_entry(trx, &bts->trx_list, list) { struct trx_power_params *tpp = &trx->power_params; + struct phy_instance *pinst = trx_phy_instance(trx); vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); if (trx->power_params.user_gain_mdB) @@ -246,6 +270,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " ms-power-control %s%s", trx->ms_power_control == 0 ? "dsp" : "osmo", VTY_NEWLINE); + vty_out(vty, " phy %u instance %u%s", pinst->phy_link->num, + pinst->num, VTY_NEWLINE); bts_model_config_write_trx(vty, trx); } @@ -262,6 +288,35 @@ static int config_write_bts(struct vty *vty) return CMD_SUCCESS; } +static void config_write_phy_single(struct vty *vty, struct phy_link *plink) +{ + int i; + + vty_out(vty, "phy %u%s", plink->num, VTY_NEWLINE); + bts_model_config_write_phy(vty, plink); + + for (i = 0; i < 255; i++) { + struct phy_instance *pinst = phy_instance_by_num(plink, i); + if (!pinst) + break; + vty_out(vty, " instance %u%s", pinst->num, VTY_NEWLINE); + } +} + +static int config_write_phy(struct vty *vty) +{ + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + config_write_phy_single(vty, plink); + } + + return CMD_SUCCESS; +} + static int config_write_dummy(struct vty *vty) { return CMD_SUCCESS; @@ -532,6 +587,33 @@ DEFUN(cfg_trx_ms_power_control, cfg_trx_ms_power_control_cmd, return CMD_SUCCESS; } +DEFUN(cfg_trx_phy, cfg_trx_phy_cmd, + "phy <0-255> instance <0-255>", + "Configure PHY Link+Instance for this TRX\n" + "PHY Link number\n" "PHY instance\n" "PHY Instance number") +{ + struct gsm_bts_trx *trx = vty->index; + struct phy_link *plink = phy_link_by_num(atoi(argv[0])); + struct phy_instance *pinst; + + if (!plink) { + vty_out(vty, "phy%s does not exist%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + pinst = phy_instance_by_num(plink, atoi(argv[1])); + if (!pinst) { + vty_out(vty, "phy%s instance %s does not exit%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + trx->role_bts.l1h = pinst; + pinst->trx = trx; + + return CMD_SUCCESS; +} /* ====================================================================== * SHOW @@ -702,6 +784,106 @@ DEFUN(cfg_trx_no_gsmtap_sapi, cfg_trx_no_gsmtap_sapi_cmd, return CMD_SUCCESS; } +static struct cmd_node phy_node = { + PHY_NODE, + "%s(phy)#", + 1, +}; + +static struct cmd_node phy_inst_node = { + PHY_INST_NODE, + "%s(phy-inst)#", + 1, +}; + +DEFUN(cfg_phy, cfg_phy_cmd, + "phy <0-255>", + "Select a PHY to configure\n" "PHY number\n") +{ + int phy_nr = atoi(argv[0]); + struct phy_link *plink; + + plink = phy_link_by_num(phy_nr); + if (!plink) + plink = phy_link_create(tall_bts_ctx, phy_nr); + if (!plink) + return CMD_WARNING; + + vty->index = plink; + vty->index_sub = &plink->description; + vty->node = PHY_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_inst, cfg_phy_inst_cmd, + "instance <0-255>", + "Select a PHY instance to configure\n" "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + pinst = phy_instance_create(plink, inst_nr); + if (!pinst) { + vty_out(vty, "Unable to create phy%u instance %u%s", + plink->num, inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + } + + vty->index = pinst; + vty->index_sub = &pinst->description; + vty->node = PHY_INST_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_inst, cfg_phy_no_inst_cmd, + "no instance <0-255>" + NO_STR "Select a PHY instance to remove\n", "PHY Instance number\n") +{ + int inst_nr = atoi(argv[0]); + struct phy_link *plink = vty->index; + struct phy_instance *pinst; + + pinst = phy_instance_by_num(plink, inst_nr); + if (!pinst) { + vty_out(vty, "No such instance %u%s", inst_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + phy_instance_destroy(pinst); + + return CMD_SUCCESS; +} + +#if 0 +DEFUN(cfg_phy_type, cfg_phy_type_cmd, + "type (sysmobts|osmo-trx|virtual)", + "configure the type of the PHY\n" + "sysmocom sysmoBTS PHY\n" + "OsmoTRX based PHY\n" + "Virtual PHY (GSMTAP based)\n") +{ + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Cannot change type of active PHY%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[0], "sysmobts")) + plink->type = PHY_LINK_T_SYSMOBTS; + else if (!strcmp(argv[0], "osmo-trx")) + plink->type = PHY_LINK_T_OSMOTRX; + else if (!strcmp(argv[0], "virtual")) + plink->type = PHY_LINK_T_VIRTUAL; +} +#endif + DEFUN(bts_t_t_l_jitter_buf, bts_t_t_l_jitter_buf_cmd, "bts <0-0> trx <0-0> ts <0-7> lchan <0-1> rtp jitter-buffer <0-10000>", @@ -813,10 +995,20 @@ int bts_vty_init(struct gsm_bts *bts, const struct log_info *cat) install_element(TRX_NODE, &cfg_trx_pr_step_size_cmd); install_element(TRX_NODE, &cfg_trx_pr_step_interval_cmd); install_element(TRX_NODE, &cfg_trx_ms_power_control_cmd); + install_element(TRX_NODE, &cfg_trx_phy_cmd); install_element(ENABLE_NODE, &bts_t_t_l_jitter_buf_cmd); install_element(ENABLE_NODE, &bts_t_t_l_loopback_cmd); install_element(ENABLE_NODE, &no_bts_t_t_l_loopback_cmd); + install_element(CONFIG_NODE, &cfg_phy_cmd); + install_node(&phy_node, config_write_phy); + install_default(PHY_NODE); + install_element(PHY_NODE, &cfg_phy_inst_cmd); + install_element(PHY_NODE, &cfg_phy_no_inst_cmd); + + install_node(&phy_inst_node, config_write_dummy); + install_default(PHY_INST_NODE); + return 0; } diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index db6e032..3215aa1 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -109,6 +110,17 @@ osmocom_to_octphy_band(enum gsm_band osmo_band, unsigned int arfcn) } }; +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id) +{ + struct phy_instance *pinst; + + pinst = phy_instance_by_num(fl1h->phy_link, trx_id); + if (!pinst) + return NULL; + + return pinst->trx; +} + struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id) { @@ -282,10 +294,9 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, } /* For OctPHY, this only about sending state changes to BSC */ -int l1if_activate_rf(struct octphy_hdl *fl1h, int on) +int l1if_activate_rf(struct gsm_bts_trx *trx, int on) { int i; - struct gsm_bts_trx *trx = fl1h->priv; if (on) { /* signal availability */ oml_mo_state_chg(&trx->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_OK); @@ -422,7 +433,8 @@ static void empty_req_from_rts_ind(tOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_E static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *l1msg = l1p_msgb_alloc(); uint32_t u32Fn; uint8_t u8Tn, subCh, sapi = 0; @@ -489,7 +501,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -508,7 +520,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, l1msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -527,7 +539,8 @@ done: static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, struct osmo_phsap_prim *l1sap) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct gsm_lchan *lchan; uint32_t u32Fn; uint8_t u8Tn, subCh, sapi, ss; @@ -565,7 +578,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&data_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_DATA_CID); - data_req->TrxId.byTrxId = trx->nr; + data_req->TrxId.byTrxId = pinst->u.octphy.trx_id; data_req->LchId.byTimeslotNb = u8Tn; data_req->LchId.bySAPI = sapi; data_req->LchId.bySubChannelNb = subCh; @@ -590,7 +603,7 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg, l1if_fill_msg_hdr(&empty_frame_req->Header, nmsg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_REQUEST_LOGICAL_CHANNEL_EMPTY_FRAME_CID); - empty_frame_req->TrxId.byTrxId = trx->nr; + empty_frame_req->TrxId.byTrxId = pinst->u.octphy.trx_id; empty_frame_req->LchId.byTimeslotNb = u8Tn; empty_frame_req->LchId.bySAPI = sapi; empty_frame_req->LchId.bySubChannelNb = subCh; @@ -686,32 +699,78 @@ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) return rc; } +static int trx_close_all_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) +{ + tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car = + (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h; + + /* in a completion call-back, we take msgb ownership and must + * release it before returning */ + + mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP_SWAP(car); + + /* we now know that the PHY link is connected */ + phy_link_state_set(fl1->phy_link, PHY_LINK_CONNECTED); + + msgb_free(resp); + + return 0; +} + +static int phy_link_trx_close_all(struct phy_link *plink) +{ + struct octphy_hdl *fl1h = plink->u.octphy.hdl; + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac; + + cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *) + msgb_put(msg, sizeof(*cac)); + l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CID); + + mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD_SWAP(cac); + + return l1if_req_compl(fl1h, msg, trx_close_all_cb, NULL); +} + +int bts_model_phy_link_open(struct phy_link *plink) +{ + if (plink->u.octphy.hdl) + l1if_close(plink->u.octphy.hdl); + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + plink->u.octphy.hdl = l1if_open(plink); + if (!plink->u.octphy.hdl) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* do we need to iterate over the list of instances and do some + * instance-specific initialization? */ + + /* close all TRXs that might still exist in this link from + * previous execitions / sessions */ + phy_link_trx_close_all(plink); + + /* in the call-back to the above we will set the link state to + * connected */ + + return 0; +} + int bts_model_init(struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb; - struct octphy_hdl *fl1h; LOGP(DL1C, LOGL_NOTICE, "model_init()\n"); btsb = bts_role_bts(bts); btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2) | CIPHER_A5(3); - fl1h = talloc_zero(bts, struct octphy_hdl); - if (!fl1h) - return -ENOMEM; - - INIT_LLIST_HEAD(&fl1h->wlc_list); - INIT_LLIST_HEAD(&fl1h->wlc_postponed); - fl1h->priv = bts->c0; - bts->c0->role_bts.l1h = fl1h; /* FIXME: what is the nominal transmit power of the PHY/board? */ bts->c0->nominal_power = 15; - /* configure some reasonable defaults, to be overridden by VTY */ - fl1h->config.rf_port_index = 0; - fl1h->config.rx_gain_db = 70; - fl1h->config.tx_atten_db = 0; - bts_model_vty_init(bts); return 0; @@ -750,23 +809,15 @@ static void dump_meas_res(int ll, tOCTVC1_GSM_MEASUREMENT_INFO * m) static int handle_mph_time_ind(struct octphy_hdl *fl1, uint8_t trx_id, uint32_t fn) { - struct gsm_bts_trx *trx = fl1->priv; - struct gsm_bts *bts = trx->bts; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, trx_id); struct osmo_phsap_prim l1sap; /* increment the primitive count for the alive timer */ fl1->alive_prim_cnt++; /* ignore every time indication, except for c0 */ - if (trx != bts->c0) - return 0; - - if (trx_id != trx->nr) { - LOGP(DL1C, LOGL_FATAL, - "TRX id %d from response does not match the L1 context trx %d\n", - trx_id, trx->nr); + if (trx != trx->bts->c0) return 0; - } memset(&l1sap, 0, sizeof(l1sap)); osmo_prim_init(&l1sap.oph, SAP_GSM_PH, PRIM_MPH_INFO, @@ -783,7 +834,7 @@ static int handle_ph_readytosend_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_READY_TO_SEND_INDICATION_EVT *evt, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, evt->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct osmo_phsap_prim *l1sap; struct gsm_time g_time; @@ -908,7 +959,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT *data_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, data_ind->TrxId.byTrxId); uint8_t chan_nr, link_id; struct osmo_phsap_prim *l1sap; uint32_t fn; @@ -992,7 +1043,7 @@ static int handle_ph_rach_ind(struct octphy_hdl *fl1, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_RACH_INDICATION_EVT *ra_ind, struct msgb *l1p_msg) { - struct gsm_bts_trx *trx = fl1->priv; + struct gsm_bts_trx *trx = trx_by_l1h(fl1, ra_ind->TrxId.byTrxId); struct gsm_bts *bts = trx->bts; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); struct gsm_lchan *lchan; @@ -1131,7 +1182,7 @@ static int rx_octvc1_resp(struct msgb *msg, uint32_t msg_id, uint32_t trans_id) if (wlc->cb) { /* call-back function must take msgb * ownership. */ - rc = wlc->cb(fl1h->priv, msg, wlc->cb_data); + rc = wlc->cb(fl1h, msg, wlc->cb_data); } else { rc = 0; msgb_free(msg); @@ -1485,6 +1536,18 @@ static int rx_octphy_msg(struct msgb *msg) return rc; } +void bts_model_phy_link_set_defaults(struct phy_link *plink) +{ + /* configure some reasonable defaults, to be overridden by VTY */ + plink->u.octphy.rf_port_index = 0; + plink->u.octphy.rx_gain_db = 70; + plink->u.octphy.tx_atten_db = 0; +} + +void bts_model_phy_instance_set_defaults(struct phy_instance *pinst) +{ +} + /*********************************************************************** * octphy socket / main loop integration ***********************************************************************/ @@ -1534,15 +1597,25 @@ static int octphy_write_cb(struct osmo_fd *fd, struct msgb *msg) return rc; } -int l1if_open(struct octphy_hdl *fl1h) +struct octphy_hdl *l1if_open(struct phy_link *plink) { + struct octphy_hdl *fl1h; struct ifreq ifr; int sfd, rc; - char *phy_dev = fl1h->netdev_name; + char *phy_dev = plink->u.octphy.netdev_name; + + fl1h = talloc_zero(plink, struct octphy_hdl); + if (!fl1h) + return NULL; + + INIT_LLIST_HEAD(&fl1h->wlc_list); + INIT_LLIST_HEAD(&fl1h->wlc_postponed); + fl1h->phy_link = plink; if (!phy_dev) { LOGP(DL1C, LOGL_ERROR, "You have to specify a phy-netdev\n"); - return -EINVAL; + talloc_free(fl1h); + return NULL; } LOGP(DL1C, LOGL_NOTICE, "Opening L1 interface for OctPHY (%s)\n", @@ -1553,7 +1626,8 @@ int l1if_open(struct octphy_hdl *fl1h) if (sfd < 0) { LOGP(DL1C, LOGL_FATAL, "Error opening PHY socket: %s\n", strerror(errno)); - return -EIO; + talloc_free(fl1h); + return NULL; } /* resolve the string device name to an ifindex */ @@ -1564,18 +1638,21 @@ int l1if_open(struct octphy_hdl *fl1h) LOGP(DL1C, LOGL_FATAL, "Error using network device %s: %s\n", phy_dev, strerror(errno)); close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } fl1h->session_id = rand(); - /* set fl1h->phy_addr, which we use as sendto() destionation */ + /* set fl1h->phy_addr, which we use as sendto() destination */ fl1h->phy_addr.sll_family = AF_PACKET; fl1h->phy_addr.sll_protocol = htons(cOCTPKT_HDR_ETHERTYPE); fl1h->phy_addr.sll_ifindex = ifr.ifr_ifindex; fl1h->phy_addr.sll_hatype = ARPHRD_ETHER; - fl1h->phy_addr.sll_halen = 6; - /* sll_addr is filled by bts_model_vty code */ + fl1h->phy_addr.sll_halen = ETH_ALEN; + /* plink->phy_addr.sll_addr is filled by bts_model_vty code */ + memcpy(fl1h->phy_addr.sll_addr, plink->u.octphy.phy_addr.sll_addr, + ETH_ALEN); /* Write queue / osmo_fd registration */ osmo_wqueue_init(&fl1h->phy_wq, 10); @@ -1588,10 +1665,11 @@ int l1if_open(struct octphy_hdl *fl1h) rc = osmo_fd_register(&fl1h->phy_wq.bfd); if (rc < 0) { close(sfd); - return -EIO; + talloc_free(fl1h); + return NULL; } - return 0; + return fl1h; } int l1if_close(struct octphy_hdl *fl1h) diff --git a/src/osmo-bts-octphy/l1_if.h b/src/osmo-bts-octphy/l1_if.h index 4277865..2dee178 100644 --- a/src/osmo-bts-octphy/l1_if.h +++ b/src/osmo-bts-octphy/l1_if.h @@ -13,16 +13,16 @@ #include #include +#include #include struct octphy_hdl { + /* MAC address of the PHY */ + struct sockaddr_ll phy_addr; + /* packet socket to talk with PHY */ struct osmo_wqueue phy_wq; - /* MAC address of th PHY */ - struct sockaddr_ll phy_addr; - /* Network device name */ - char *netdev_name; /* address parameters of the PHY */ uint32_t session_id; @@ -33,12 +33,6 @@ struct octphy_hdl { uint32_t clkmgr_state; struct { - uint32_t rf_port_index; - uint32_t rx_gain_db; - uint32_t tx_atten_db; - } config; - - struct { struct { char *name; char *description; @@ -72,8 +66,8 @@ struct octphy_hdl { struct llist_head wlc_postponed; int wlc_postponed_len; - /* private pointer, points back to TRX */ - void *priv; + /* back pointer to the PHY link */ + struct phy_link *phy_link; struct osmo_timer_list alive_timer; uint32_t alive_prim_cnt; @@ -82,15 +76,10 @@ struct octphy_hdl { int opened; }; -static inline struct octphy_hdl *trx_octphy_hdl(struct gsm_bts_trx *trx) -{ - return trx->role_bts.l1h; -} - void l1if_fill_msg_hdr(tOCTVC1_MSG_HEADER *mh, struct msgb *msg, struct octphy_hdl *fl1h, uint32_t msg_type, uint32_t api_cmd); -typedef int l1if_compl_cb(struct gsm_bts_trx *trx, struct msgb *l1_msg, void *data); +typedef int l1if_compl_cb(struct octphy_hdl *fl1, struct msgb *l1_msg, void *data); /* send a request primitive to the L1 and schedule completion call-back */ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, @@ -100,19 +89,21 @@ int l1if_req_compl(struct octphy_hdl *fl1h, struct msgb *msg, struct gsm_lchan *get_lchan_by_lchid(struct gsm_bts_trx *trx, tOCTVC1_GSM_LOGICAL_CHANNEL_ID *lch_id); -int l1if_open(struct octphy_hdl *fl1h); +struct octphy_hdl *l1if_open(struct phy_link *plink); int l1if_close(struct octphy_hdl *hdl); int l1if_trx_open(struct gsm_bts_trx *trx); int l1if_trx_close_all(struct gsm_bts *bts); int l1if_enable_events(struct gsm_bts_trx *trx); -int l1if_activate_rf(struct octphy_hdl *fl1h, int on); +int l1if_activate_rf(struct gsm_bts_trx *trx, int on); int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, tOCTVC1_GSM_MSG_TRX_LOGICAL_CHANNEL_DATA_INDICATION_EVT * data_ind); +struct gsm_bts_trx *trx_by_l1h(struct octphy_hdl *fl1h, unsigned int trx_id); + struct msgb *l1p_msgb_alloc(void); /* tch.c */ diff --git a/src/osmo-bts-octphy/l1_oml.c b/src/osmo-bts-octphy/l1_oml.c index 318c384..c50f1d6 100644 --- a/src/osmo-bts-octphy/l1_oml.c +++ b/src/osmo-bts-octphy/l1_oml.c @@ -348,10 +348,11 @@ static void sapi_clear_queue(struct llist_head *queue) } } -static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; uint8_t sapi; uint8_t direction; @@ -361,7 +362,7 @@ static int lchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ar); - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ar->LchId); sapi = ar->LchId.bySAPI; @@ -411,7 +412,8 @@ err: static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CMD *lac; @@ -420,7 +422,7 @@ static int mph_send_activate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) l1if_fill_msg_hdr(&lac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_LOGICAL_CHANNEL_CID); - lac->TrxId.byTrxId = lchan->ts->trx->nr; + lac->TrxId.byTrxId = pinst->u.octphy.trx_id; lac->LchId.byTimeslotNb = lchan->ts->nr; lac->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); lac->LchId.bySAPI = cmd->sapi; @@ -451,10 +453,11 @@ static tOCTVC1_GSM_CIPHERING_ID_ENUM rsl2l1_ciph[] = { [4] = cOCTVC1_GSM_CIPHERING_ID_ENUM_A5_3 }; -static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int set_ciph_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *pcr = (tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_lchan *lchan; @@ -470,6 +473,7 @@ static int set_ciph_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d exit(-1); } + trx = trx_by_l1h(fl1, pcr->TrxId.byTrxId); OSMO_ASSERT(pcr->TrxId.byTrxId == trx->nr); ts = &trx->ts[pcr->PchId.byTimeslotNb]; /* for some strange reason the response does not tell which @@ -508,8 +512,8 @@ err: static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct gsm_bts_trx *trx = lchan->ts->trx; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CMD *pcc; @@ -518,6 +522,7 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c l1if_fill_msg_hdr(&pcc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CID); + pcc->TrxId.byTrxId = pinst->u.octphy.trx_id; pcc->PchId.byTimeslotNb = lchan->ts->nr; pcc->ulSubchannelNb = lchan_to_GsmL1_SubCh_t(lchan); pcc->ulDirection = cmd->dir; @@ -627,7 +632,8 @@ static int check_sapi_release(struct gsm_lchan *lchan, int sapi, int dir) static int lchan_deactivate_sapis(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; int i, res; @@ -654,10 +660,11 @@ static int lchan_deactivate_sapis(struct gsm_lchan *lchan) return res; } -static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int lchan_deact_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *ldr = (tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP *) resp->l2h; + struct gsm_bts_trx *trx; struct gsm_lchan *lchan; struct sapi_cmd *cmd; uint8_t status; @@ -666,7 +673,7 @@ static int lchan_deact_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * release it before returning */ mOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_RSP_SWAP(ldr); - OSMO_ASSERT(ldr->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1, ldr->TrxId.byTrxId); lchan = get_lchan_by_lchid(trx, &ldr->LchId); @@ -725,7 +732,8 @@ err: static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CMD *ldc; @@ -734,6 +742,7 @@ static int mph_send_deactivate_req(struct gsm_lchan *lchan, struct sapi_cmd *cmd l1if_fill_msg_hdr(&ldc->Header, msg, fl1h,cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_DEACTIVATE_LOGICAL_CHANNEL_CID); + ldc->TrxId.byTrxId = pinst->u.octphy.trx_id; ldc->LchId.byTimeslotNb = lchan->ts->nr; ldc->LchId.bySubChannelNb = lchan_to_GsmL1_SubCh_t(lchan); ldc->LchId.byDirection = cmd->dir; @@ -1031,7 +1040,8 @@ static void enqueue_sapi_act_cmd(struct gsm_lchan *lchan, int sapi, int dir) int lchan_activate(struct gsm_lchan *lchan) { - struct octphy_hdl *fl1h = trx_octphy_hdl(lchan->ts->trx); + struct phy_instance *pinst = trx_phy_instance(lchan->ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; const struct lchan_sapis *s4l = &sapis_for_lchan[lchan->type]; unsigned int i; @@ -1069,7 +1079,7 @@ int l1if_rsl_chan_act(struct gsm_lchan *lchan) return 0; } -static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int enable_events_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *mser = (tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_RSP *) resp->l2h; @@ -1088,7 +1098,8 @@ static int enable_events_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, vo int l1if_enable_events(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_API_SYSTEM_MODIFY_SESSION_EVT_CMD *mse; @@ -1112,9 +1123,8 @@ int l1if_enable_events(struct gsm_bts_trx *trx) dst = talloc_strdup(ctx, (const char *) src); \ } while (0) -static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_sys_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *aisr = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_RSP *) resp->l2h; @@ -1136,7 +1146,8 @@ static int app_info_sys_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, voi int l1if_check_app_sys_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_SYSTEM_CMD *ais; @@ -1152,9 +1163,8 @@ int l1if_check_app_sys_version(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, app_info_sys_compl_cb, 0); } -static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int app_info_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { - struct octphy_hdl *fl1h = resp->dst; tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *air = (tOCTVC1_MAIN_MSG_APPLICATION_INFO_RSP *) resp->l2h; @@ -1178,7 +1188,8 @@ static int app_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_check_app_version(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_MAIN_MSG_APPLICATION_INFO_CMD *ai; @@ -1193,9 +1204,50 @@ int l1if_check_app_version(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, app_info_compl_cb, 0); } +static int trx_close_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) +{ + tOCTVC1_GSM_MSG_TRX_CLOSE_RSP *car = + (tOCTVC1_GSM_MSG_TRX_CLOSE_RSP *) resp->l2h; + + /* in a completion call-back, we take msgb ownership and must + * release it before returning */ + + mOCTVC1_GSM_MSG_TRX_CLOSE_RSP_SWAP(car); + + LOGP(DL1C, LOGL_INFO, "Rx TRX-CLOSE.conf(%u)\n", car->TrxId.byTrxId); + + msgb_free(resp); + + return 0; +} + +static int trx_close(struct gsm_bts_trx *trx) +{ + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct octphy_hdl *fl1h = plink->u.octphy.hdl; + struct msgb *msg = l1p_msgb_alloc(); + tOCTVC1_GSM_MSG_TRX_CLOSE_CMD *cac; + + cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_CMD *) + msgb_put(msg, sizeof(*cac)); + l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, + cOCTVC1_GSM_MSG_TRX_CLOSE_CID); + + cac->TrxId.byTrxId = pinst->u.octphy.trx_id; + + LOGP(DL1C, LOGL_INFO, "Tx TRX-CLOSE.req(%u)\n", cac->TrxId.byTrxId); + + mOCTVC1_GSM_MSG_TRX_CLOSE_CMD_SWAP(cac); + + return l1if_req_compl(fl1h, msg, trx_close_cb, NULL); +} + /* call-back once the TRX_OPEN_CID response arrives */ -static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int trx_open_compl_cb(struct octphy_hdl *fl1h, struct msgb *resp, void *data) { + struct gsm_bts_trx *trx; + tOCTVC1_GSM_MSG_TRX_OPEN_RSP *or = (tOCTVC1_GSM_MSG_TRX_OPEN_RSP *) resp->l2h; @@ -1203,8 +1255,7 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d * release it before returning */ mOCTVC1_GSM_MSG_TRX_OPEN_RSP_SWAP(or); - - OSMO_ASSERT(or->TrxId.byTrxId == trx->nr); + trx = trx_by_l1h(fl1h, or->TrxId.byTrxId); LOGP(DL1C, LOGL_INFO, "TRX-OPEN.resp(trx=%u) = %s\n", trx->nr, octvc1_rc2string(or->Header.ulReturnCode)); @@ -1221,7 +1272,6 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d opstart_compl(&trx->mo); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); octphy_hw_get_pcb_info(fl1h); octphy_hw_get_rf_port_info(fl1h, 0); octphy_hw_get_rf_ant_rx_config(fl1h, 0, 0); @@ -1238,22 +1288,24 @@ static int trx_open_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *d int l1if_trx_open(struct gsm_bts_trx *trx) { /* putting it all together */ - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_OPEN_CMD *oc; oc = (tOCTVC1_GSM_MSG_TRX_OPEN_CMD *) msgb_put(msg, sizeof(*oc)); l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_OPEN_CID); - oc->ulRfPortIndex = fl1h->config.rf_port_index; - oc->TrxId.byTrxId = trx->nr; + oc->ulRfPortIndex = plink->u.octphy.rf_port_index; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->Config.ulBand = osmocom_to_octphy_band(trx->bts->band, trx->arfcn); oc->Config.usArfcn = trx->arfcn; oc->Config.usTsc = trx->bts->bsic & 0x7; oc->Config.usBcchArfcn = trx->bts->c0->arfcn; - oc->RfConfig.ulRxGainDb = fl1h->config.rx_gain_db; + oc->RfConfig.ulRxGainDb = plink->u.octphy.rx_gain_db; /* FIXME: compute this based on nominal transmit power, etc. */ - oc->RfConfig.ulTxAttndB = fl1h->config.tx_atten_db; + oc->RfConfig.ulTxAttndB = plink->u.octphy.tx_atten_db; LOGP(DL1C, LOGL_INFO, "Tx TRX-OPEN.req(trx=%u, rf_port=%u, arfcn=%u, " "tsc=%u, rx_gain=%u, tx_atten=%u)\n", @@ -1266,38 +1318,6 @@ int l1if_trx_open(struct gsm_bts_trx *trx) return l1if_req_compl(fl1h, msg, trx_open_compl_cb, NULL); } -static int trx_close_all_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) -{ - tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *car = - (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP *) resp->l2h; - - /* in a completion call-back, we take msgb ownership and must - * release it before returning */ - - mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_RSP_SWAP(car); - - msgb_free(resp); - - return 0; -} - -int l1if_trx_close_all(struct gsm_bts *bts) -{ - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); - struct msgb *msg = l1p_msgb_alloc(); - tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *cac; - - cac = (tOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD *) - msgb_put(msg, sizeof(*cac)); - l1if_fill_msg_hdr(&cac->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, - cOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CID); - - mOCTVC1_GSM_MSG_TRX_CLOSE_ALL_CMD_SWAP(cac); - - return l1if_req_compl(fl1h, msg, trx_close_all_cb, NULL); -} - - uint32_t trx_get_hlayer1(struct gsm_bts_trx * trx) { return 0; @@ -1313,8 +1333,6 @@ static int trx_init(struct gsm_bts_trx *trx) /* return oml_mo_opstart_nack(&trx->mo, NM_NACK_CANT_PERFORM); */ } - l1if_trx_close_all(trx->bts); - l1if_check_app_version(trx); l1if_check_app_sys_version(trx); @@ -1325,11 +1343,12 @@ static int trx_init(struct gsm_bts_trx *trx) * PHYSICAL CHANNE ACTIVATION ***********************************************************************/ -static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int pchan_act_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *ar = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP *) resp->l2h; uint8_t ts_nr; + struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; struct gsm_abis_mo *mo; @@ -1337,9 +1356,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * * release it before returning */ mOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_RSP_SWAP(ar); + trx = trx_by_l1h(fl1, ar->TrxId.byTrxId); ts_nr = ar->PchId.byTimeslotNb; - - OSMO_ASSERT(ar->TrxId.byTrxId == trx->nr); OSMO_ASSERT(ts_nr <= ARRAY_SIZE(trx->ts)); ts = &trx->ts[ts_nr]; @@ -1367,7 +1385,8 @@ static int pchan_act_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void * static int ts_connect(struct gsm_bts_trx_ts *ts) { - struct octphy_hdl *fl1h = trx_octphy_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct octphy_hdl *fl1h = pinst->phy_link->u.octphy.hdl; struct msgb *msg = l1p_msgb_alloc(); tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *oc = (tOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CMD *) oc; @@ -1376,7 +1395,7 @@ static int ts_connect(struct gsm_bts_trx_ts *ts) l1if_fill_msg_hdr(&oc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, cOCTVC1_GSM_MSG_TRX_ACTIVATE_PHYSICAL_CHANNEL_CID); - oc->TrxId.byTrxId = ts->trx->nr; + oc->TrxId.byTrxId = pinst->u.octphy.trx_id; oc->PchId.byTimeslotNb = ts->nr; oc->ulChannelType = pchan_to_logChComb[ts->pchan]; @@ -1430,8 +1449,7 @@ int bts_model_oml_estab(struct gsm_bts *bts) int i; for (i = 0; i < bts->num_trx; i++) { struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i); - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - l1if_activate_rf(fl1h, 1); + l1if_activate_rf(trx, 1); } return 0; } @@ -1447,14 +1465,13 @@ int bts_model_chg_adm_state(struct gsm_bts *bts, struct gsm_abis_mo *mo, int bts_model_trx_deact_rf(struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1 = trx_octphy_hdl(trx); - return l1if_activate_rf(fl1, 0); + return l1if_activate_rf(trx, 0); } int bts_model_trx_close(struct gsm_bts_trx *trx) { /* FIXME: close only one TRX */ - return l1if_trx_close_all(trx->bts); + return trx_close(trx); } diff --git a/src/osmo-bts-octphy/main.c b/src/osmo-bts-octphy/main.c index 1f516e4..0f4d0dd 100644 --- a/src/osmo-bts-octphy/main.c +++ b/src/osmo-bts-octphy/main.c @@ -52,10 +52,9 @@ extern int pcu_direct; -static struct gsm_bts *bts; - int bts_model_print_help() { + return 0; } int bts_model_handle_options(int argc, char **argv) diff --git a/src/osmo-bts-octphy/octphy_hw_api.c b/src/osmo-bts-octphy/octphy_hw_api.c index 5291742..ec7c4be 100644 --- a/src/osmo-bts-octphy/octphy_hw_api.c +++ b/src/osmo-bts-octphy/octphy_hw_api.c @@ -35,7 +35,7 @@ #include /* Chapter 12.1 */ -static int get_pcb_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, void *data) +static int get_pcb_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_PCB_INFO_RSP *pir = (tOCTVC1_HW_MSG_PCB_INFO_RSP *) resp->l2h; @@ -69,7 +69,7 @@ int octphy_hw_get_pcb_info(struct octphy_hdl *fl1h) } /* Chapter 12.9 */ -static int rf_port_info_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_info_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_RSP *pir = @@ -114,7 +114,7 @@ static const struct value_string radio_std_vals[] = { }; /* Chapter 12.10 */ -static int rf_port_stats_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_port_stats_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_STATS_RSP *psr = @@ -167,7 +167,7 @@ static const struct value_string rx_gain_mode_vals[] = { }; /* Chapter 12.13 */ -static int rf_ant_rx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_rx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_RX_CONFIG_RSP *arc = @@ -209,7 +209,7 @@ int octphy_hw_get_rf_ant_rx_config(struct octphy_hdl *fl1h, uint32_t port_idx, } /* Chapter 12.14 */ -static int rf_ant_tx_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int rf_ant_tx_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_RF_PORT_INFO_ANTENNA_TX_CONFIG_RSP *atc = @@ -292,7 +292,7 @@ static const struct value_string clocksync_state_vals[] = { }; /* Chapter 12.15 */ -static int get_clock_sync_compl_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_compl_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_INFO_RSP *cir = @@ -326,7 +326,7 @@ int octphy_hw_get_clock_sync_info(struct octphy_hdl *fl1h) } /* Chapter 12.16 */ -static int get_clock_sync_stats_cb(struct gsm_bts_trx *trx, struct msgb *resp, +static int get_clock_sync_stats_cb(struct octphy_hdl *fl1, struct msgb *resp, void *data) { tOCTVC1_HW_MSG_CLOCK_SYNC_MGR_STATS_RSP *csr = diff --git a/src/osmo-bts-octphy/octphy_vty.c b/src/osmo-bts-octphy/octphy_vty.c index dbc903a..6e58ad4 100644 --- a/src/osmo-bts-octphy/octphy_vty.c +++ b/src/osmo-bts-octphy/octphy_vty.c @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -51,149 +52,189 @@ SHOW_STR \ TRX_STR +#define OCT_STR "OCTPHY Um interface\n" + static struct gsm_bts *vty_bts; /* configuration */ -DEFUN(cfg_bts_phy_hwaddr, cfg_bts_phy_hwaddr_cmd, - "phy-hw-addr HWADDR", - "Configure the hardware addess of the OCTPHY\n" +DEFUN(cfg_phy_hwaddr, cfg_phy_hwaddr_cmd, + "octphy hw-addr HWADDR", + OCT_STR "Configure the hardware addess of the OCTPHY\n" "hardware address in aa:bb:cc:dd:ee:ff format\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; int rc; - rc = osmo_macaddr_parse(fl1h->phy_addr.sll_addr, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + rc = osmo_macaddr_parse(plink->u.octphy.phy_addr.sll_addr, argv[0]); if (rc < 0) return CMD_WARNING; return CMD_SUCCESS; } -DEFUN(cfg_bts_phy_netdev, cfg_bts_phy_netdev_cmd, - "phy-netdev NAME", - "Configure the hardware device towards the OCTPHY\n" +DEFUN(cfg_phy_netdev, cfg_phy_netdev_cmd, + "octphy net-device NAME", + OCT_STR "Configure the hardware device towards the OCTPHY\n" "Ethernet device name\n") { - struct gsm_bts *bts = vty->index; - struct gsm_bts_trx *trx = bts->c0; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - if (fl1h->netdev_name) - talloc_free(fl1h->netdev_name); - fl1h->netdev_name = talloc_strdup(fl1h, argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + if (plink->u.octphy.netdev_name) + talloc_free(plink->u.octphy.netdev_name); + plink->u.octphy.netdev_name = talloc_strdup(plink, argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rf_port_idx, cfg_trx_rf_port_idx_cmd, - "rf-port-index <0-255>", - "Configure the RF Port for this TRX\n" +DEFUN(cfg_phy_rf_port_idx, cfg_phy_rf_port_idx_cmd, + "octphy rf-port-index <0-255>", + OCT_STR "Configure the RF Port for this TRX\n" "RF Port Index\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; - fl1h->config.rf_port_index = atoi(argv[0]); + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + plink->u.octphy.rf_port_index = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_rx_gain_db, cfg_trx_rx_gain_db_cmd, - "rx-gain <0-73>", - "Configure the Rx Gain in dB\n" +DEFUN(cfg_phy_rx_gain_db, cfg_phy_rx_gain_db_cmd, + "octphy rx-gain <0-73>", + OCT_STR "Configure the Rx Gain in dB\n" "Rx gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.rx_gain_db = atoi(argv[0]); + plink->u.octphy.rx_gain_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(cfg_trx_tx_atten_db, cfg_trx_tx_atten_db_cmd, - "tx-attenuation <0-359>", - "Configure the Tx Attenuation in quarter-dB\n" +DEFUN(cfg_phy_tx_atten_db, cfg_phy_tx_atten_db_cmd, + "octphy tx-attenuation <0-359>", + OCT_STR "Configure the Tx Attenuation in quarter-dB\n" "Tx attenuation in quarter-dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); + struct phy_link *plink = vty->index; + + if (plink->state != PHY_LINK_SHUTDOWN) { + vty_out(vty, "Can only reconfigure a PHY link that is down%s", + VTY_NEWLINE); + return CMD_WARNING; + } - fl1h->config.tx_atten_db = atoi(argv[0]); + plink->u.octphy.tx_atten_db = atoi(argv[0]); return CMD_SUCCESS; } -DEFUN(get_rf_port_stats, get_rf_port_stats_cmd, - "get-rf-port-stats <0-1>", - "Obtain statistics for the RF Port\n" +DEFUN(show_rf_port_stats, show_rf_port_stats_cmd, + "show phy <0-255> rf-port-stats <0-1>", + "Show statistics for the RF Port\n" "RF Port Number\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); - octphy_hw_get_rf_port_stats(fl1h, atoi(argv[0])); + octphy_hw_get_rf_port_stats(plink->u.octphy.hdl, atoi(argv[1])); + + /* FIXME: Actually print to VTY, not just log */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } -DEFUN(get_clk_sync_stats, get_clk_sync_stats_cmd, - "get-clk-sync-stats", +DEFUN(show_clk_sync_stats, show_clk_sync_stats_cmd, + "show phy <0-255> clk-sync-stats", "Obtain statistics for the Clock Sync Manager\n") { - struct octphy_hdl *fl1h = trx_octphy_hdl(vty_bts->c0); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); + + octphy_hw_get_clock_sync_stats(plink->u.octphy.hdl); - octphy_hw_get_clock_sync_stats(fl1h); + /* FIXME: Actually print to VTY, not just log */ + vty_out(vty, "Please check the log file for the response%s", + VTY_NEWLINE); return CMD_SUCCESS; } +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.octphy.netdev_name) + vty_out(vty, " netdev %s%s", plink->u.octphy.netdev_name, + VTY_NEWLINE); + + vty_out(vty, " hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", + plink->u.octphy.phy_addr.sll_addr[0], + plink->u.octphy.phy_addr.sll_addr[1], + plink->u.octphy.phy_addr.sll_addr[2], + plink->u.octphy.phy_addr.sll_addr[3], + plink->u.octphy.phy_addr.sll_addr[4], + plink->u.octphy.phy_addr.sll_addr[5], + VTY_NEWLINE); + vty_out(vty, " rx-gain %u%s", plink->u.octphy.rx_gain_db, + VTY_NEWLINE); + vty_out(vty, " tx-attenuation %u%s", plink->u.octphy.tx_atten_db, + VTY_NEWLINE); + vty_out(vty, " rf-port-index %u%s", plink->u.octphy.rf_port_index, + VTY_NEWLINE); +} + void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - struct octphy_hdl *fl1h = trx_octphy_hdl(bts->c0); - - if (fl1h->netdev_name) - vty_out(vty, " phy-netdev %s%s", fl1h->netdev_name, - VTY_NEWLINE); if (btsb->auto_band) vty_out(vty, " auto-band%s", VTY_NEWLINE); - vty_out(vty, " phy-hw-addr %02x:%02x:%02x:%02x:%02x:%02x%s", - fl1h->phy_addr.sll_addr[0], fl1h->phy_addr.sll_addr[1], - fl1h->phy_addr.sll_addr[2], fl1h->phy_addr.sll_addr[3], - fl1h->phy_addr.sll_addr[4], fl1h->phy_addr.sll_addr[5], - VTY_NEWLINE); } void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) { - struct octphy_hdl *fl1h = trx_octphy_hdl(trx); - - vty_out(vty, " rx-gain %u%s", fl1h->config.rx_gain_db, - VTY_NEWLINE); - vty_out(vty, " tx-attenuation %u%s", fl1h->config.tx_atten_db, - VTY_NEWLINE); } DEFUN(show_sys_info, show_sys_info_cmd, - "show trx <0-255> system-information", + "show phy <0-255> system-information", SHOW_TRX_STR "Display information about system\n") { - int trx_nr = atoi(argv[0]); - struct gsm_bts_trx *trx = gsm_bts_trx_num(vty_bts, trx_nr); + int phy_nr = atoi(argv[0]); + struct phy_link *plink = phy_link_by_num(phy_nr); struct octphy_hdl *fl1h; - int i; - if (!trx) { - vty_out(vty, "Cannot find TRX number %u%s", - trx_nr, VTY_NEWLINE); + if (!plink) { + vty_out(vty, "Cannot find PHY number %u%s", + phy_nr, VTY_NEWLINE); return CMD_WARNING; } - fl1h = trx_octphy_hdl(trx); + fl1h = plink->u.octphy.hdl; vty_out(vty, "System Platform: '%s', Version: '%s'%s", fl1h->info.system.platform, fl1h->info.system.version, @@ -210,15 +251,14 @@ int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; - install_element(BTS_NODE, &cfg_bts_phy_hwaddr_cmd); - install_element(BTS_NODE, &cfg_bts_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_hwaddr_cmd); + install_element(PHY_NODE, &cfg_phy_netdev_cmd); + install_element(PHY_NODE, &cfg_phy_rf_port_idx_cmd); + install_element(PHY_NODE, &cfg_phy_rx_gain_db_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_db_cmd); - install_element(TRX_NODE, &cfg_trx_rf_port_idx_cmd); - install_element(TRX_NODE, &cfg_trx_rx_gain_db_cmd); - install_element(TRX_NODE, &cfg_trx_tx_atten_db_cmd); - - install_element_ve(&get_rf_port_stats_cmd); - install_element_ve(&get_clk_sync_stats_cmd); + install_element_ve(&show_rf_port_stats_cmd); + install_element_ve(&show_clk_sync_stats_cmd); install_element_ve(&show_sys_info_cmd); return 0; @@ -226,13 +266,5 @@ int bts_model_vty_init(struct gsm_bts *bts) int bts_model_ctrl_cmds_install(struct gsm_bts *bts) { - /* FIXME: really ugly hack: We can only initialize the L1 intrface - * after reading the config file, and this is the only call-back after - * vty_read_config_fioe() at this point. Will be cleaned up with the - * phy interface generalization patches coming up soon as part of the - * multi-trx work */ - struct octphy_hdl *fl1h = bts->c0->role_bts.l1h; - l1if_open(fl1h); - return 0; } diff --git a/src/osmo-bts-trx/l1_if.c b/src/osmo-bts-trx/l1_if.c index edd4b7b..befaffd 100644 --- a/src/osmo-bts-trx/l1_if.c +++ b/src/osmo-bts-trx/l1_if.c @@ -59,7 +59,7 @@ static const uint8_t transceiver_chan_types[_GSM_PCHAN_MAX] = { * create/destroy trx l1 instance */ -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) +struct trx_l1h *l1if_open(struct phy_instance *pinst) { struct trx_l1h *l1h; int rc; @@ -67,11 +67,9 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) l1h = talloc_zero(tall_bts_ctx, struct trx_l1h); if (!l1h) return NULL; - l1h->trx = trx; - l1h->l1s.trx = trx; - trx->role_bts.l1h = l1h; + l1h->phy_inst = pinst; - trx_sched_init(&l1h->l1s); + trx_sched_init(&l1h->l1s, pinst->trx); rc = trx_if_open(l1h); if (rc < 0) { @@ -83,7 +81,6 @@ struct trx_l1h *l1if_open(struct gsm_bts_trx *trx) err: l1if_close(l1h); - trx->role_bts.l1h = NULL; return NULL; } @@ -100,7 +97,8 @@ void l1if_reset(struct trx_l1h *l1h) static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) { - struct gsm_bts_trx *trx = l1h->trx; + struct phy_instance *pinst = l1h->phy_inst; + struct gsm_bts_trx *trx = pinst->trx; uint8_t tn; /* HACK, we should change state when we receive first clock from @@ -132,10 +130,10 @@ static void check_transceiver_availability_trx(struct trx_l1h *l1h, int avail) int check_transceiver_availability(struct gsm_bts *bts, int avail) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; check_transceiver_availability_trx(l1h, avail); } return 0; @@ -147,6 +145,7 @@ int check_transceiver_availability(struct gsm_bts *bts, int avail) */ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) { + struct phy_link *plink = l1h->phy_inst->phy_link; uint8_t tn; if (!transceiver_available) @@ -177,18 +176,23 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) } /* after power on */ - if (l1h->config.rxgain_valid && !l1h->config.rxgain_sent) { - trx_if_cmd_setrxgain(l1h, l1h->config.rxgain); - l1h->config.rxgain_sent = 1; - } - if (l1h->config.power_valid && !l1h->config.power_sent) { - trx_if_cmd_setpower(l1h, l1h->config.power); - l1h->config.power_sent = 1; + if (l1h->phy_inst->num == 0) { + if (plink->u.osmotrx.rxgain_valid && + !plink->u.osmotrx.rxgain_sent) { + trx_if_cmd_setrxgain(l1h, plink->u.osmotrx.rxgain); + plink->u.osmotrx.rxgain_sent = 1; + } + if (plink->u.osmotrx.power_valid && + !plink->u.osmotrx.power_sent) { + trx_if_cmd_setpower(l1h, plink->u.osmotrx.power); + plink->u.osmotrx.power_sent = 1; + } } if (l1h->config.maxdly_valid && !l1h->config.maxdly_sent) { trx_if_cmd_setmaxdly(l1h, l1h->config.maxdly); l1h->config.maxdly_sent = 1; } + for (tn = 0; tn < TRX_NR_TS; tn++) { if (l1h->config.slottype_valid[tn] && !l1h->config.slottype_sent[tn]) { @@ -203,8 +207,10 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) if (!l1h->config.poweron && !l1h->config.poweron_sent) { trx_if_cmd_poweroff(l1h); l1h->config.poweron_sent = 1; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -216,17 +222,20 @@ int l1if_provision_transceiver_trx(struct trx_l1h *l1h) int l1if_provision_transceiver(struct gsm_bts *bts) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t tn; llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.arfcn_sent = 0; l1h->config.tsc_sent = 0; l1h->config.bsic_sent = 0; l1h->config.poweron_sent = 0; - l1h->config.rxgain_sent = 0; - l1h->config.power_sent = 0; + if (l1h->phy_inst->num == 0) { + plink->u.osmotrx.rxgain_sent = 0; + plink->u.osmotrx.power_sent = 0; + } l1h->config.maxdly_sent = 0; for (tn = 0; tn < TRX_NR_TS; tn++) l1h->config.slottype_sent[tn] = 0; @@ -242,7 +251,8 @@ int l1if_provision_transceiver(struct gsm_bts *bts) /* initialize the layer1 */ static int trx_init(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; /* power on transceiver, if not already */ if (!l1h->config.poweron) { @@ -264,7 +274,8 @@ static int trx_init(struct gsm_bts_trx *trx) /* deactivate transceiver */ int bts_model_trx_close(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; enum gsm_phys_chan_config pchan = trx->ts[0].pchan; /* close all logical channels and reset timeslots */ @@ -308,7 +319,6 @@ int bts_model_adjst_ms_pwr(struct gsm_lchan *lchan) static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) { struct gsm_bts_trx *trx; - struct trx_l1h *l1h; uint8_t bsic = bts->bsic; struct gsm_bts_role_bts *btsb = bts_role_bts(bts); @@ -318,7 +328,8 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (l1h->config.bsic != bsic || !l1h->config.bsic_valid) { l1h->config.bsic = bsic; l1h->config.bsic_valid = 1; @@ -335,7 +346,9 @@ static uint8_t trx_set_bts(struct gsm_bts *bts, struct tlv_parsed *new_attr) /* set trx attributes */ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint16_t arfcn = trx->arfcn; if (l1h->config.arfcn != arfcn || !l1h->config.arfcn_valid) { @@ -345,10 +358,10 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) l1if_provision_transceiver_trx(l1h); } - if (l1h->config.power_oml) { - l1h->config.power = trx->max_power_red; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; + if (plink->u.osmotrx.power_oml && pinst->num == 0) { + plink->u.osmotrx.power = trx->max_power_red; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; l1if_provision_transceiver_trx(l1h); } @@ -358,7 +371,8 @@ static uint8_t trx_set_trx(struct gsm_bts_trx *trx) /* set ts attributes */ static uint8_t trx_set_ts(struct gsm_bts_trx_ts *ts) { - struct trx_l1h *l1h = trx_l1h_hdl(ts->trx); + struct phy_instance *pinst = trx_phy_instance(ts->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn = ts->nr; uint16_t tsc = ts->tsc; enum gsm_phys_chan_config pchan = ts->pchan; @@ -439,6 +453,7 @@ static int l1if_set_ciphering(struct trx_l1h *l1h, struct gsm_lchan *lchan, static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, enum osmo_mph_info_type type, uint8_t cause) { + struct phy_instance *pinst = l1h->phy_inst; struct osmo_phsap_prim l1sap; memset(&l1sap, 0, sizeof(l1sap)); @@ -448,7 +463,7 @@ static int mph_info_chan_confirm(struct trx_l1h *l1h, uint8_t chan_nr, l1sap.u.info.u.act_cnf.chan_nr = chan_nr; l1sap.u.info.u.act_cnf.cause = cause; - return l1sap_up(l1h->trx, &l1sap); + return l1sap_up(pinst->trx, &l1sap); } int l1if_mph_time_ind(struct gsm_bts *bts, uint32_t fn) @@ -503,7 +518,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint /* primitive from common part */ int bts_model_l1sap_down(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; struct msgb *msg = l1sap->oph.msg; uint8_t chan_nr; uint8_t tn, ss; diff --git a/src/osmo-bts-trx/l1_if.h b/src/osmo-bts-trx/l1_if.h index f492687..187303c 100644 --- a/src/osmo-bts-trx/l1_if.h +++ b/src/osmo-bts-trx/l1_if.h @@ -2,6 +2,7 @@ #define L1_IF_H_TRX #include +#include struct trx_config { uint8_t poweron; /* poweron(1) or poweroff(0) */ @@ -19,15 +20,6 @@ struct trx_config { uint8_t bsic; int bsic_sent; - int rxgain_valid; - int rxgain; - int rxgain_sent; - - int power_valid; - int power; - int power_oml; - int power_sent; - int maxdly_valid; int maxdly; int maxdly_sent; @@ -42,7 +34,8 @@ struct trx_config { struct trx_l1h { struct llist_head trx_ctrl_list; - struct gsm_bts_trx *trx; + //struct gsm_bts_trx *trx; + struct phy_instance *phy_inst; struct osmo_fd trx_ofd_ctrl; struct osmo_timer_list trx_ctrl_timer; @@ -55,7 +48,7 @@ struct trx_l1h { struct l1sched_trx l1s; }; -struct trx_l1h *l1if_open(struct gsm_bts_trx *trx); +struct trx_l1h *l1if_open(struct phy_instance *pinst); void l1if_close(struct trx_l1h *l1h); void l1if_reset(struct trx_l1h *l1h); int check_transceiver_availability(struct gsm_bts *bts, int avail); @@ -69,7 +62,8 @@ int l1if_process_meas_res(struct gsm_bts_trx *trx, uint8_t tn, uint32_t fn, uint static inline struct l1sched_trx *trx_l1sched_hdl(struct gsm_bts_trx *trx) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx->role_bts.l1h; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; return &l1h->l1s; } diff --git a/src/osmo-bts-trx/main.c b/src/osmo-bts-trx/main.c index aa6987c..62e8fe9 100644 --- a/src/osmo-bts-trx/main.c +++ b/src/osmo-bts-trx/main.c @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -58,43 +59,6 @@ #include "l1_if.h" #include "trx_if.h" -int bts_model_init(struct gsm_bts *bts) -{ - void *l1h; - struct gsm_bts_trx *trx; - struct gsm_bts_role_bts *btsb = bts_role_bts(bts); - - btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); - if (!settsc_enabled && !setbsic_enabled) - settsc_enabled = setbsic_enabled = 1; - - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = l1if_open(trx); - if (!l1h) { - LOGP(DL1C, LOGL_FATAL, "Cannot open L1 Interface\n"); - goto error; - } - - trx->role_bts.l1h = l1h; - trx->nominal_power = 23; - - l1if_reset(l1h); - } - - bts_model_vty_init(bts); - - return 0; - -error: - llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx->role_bts.l1h; - if (l1h) - l1if_close(l1h); - } - - return -EIO; -} - /* dummy, since no direct dsp support */ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) { @@ -103,10 +67,6 @@ uint32_t trx_get_hlayer1(struct gsm_bts_trx *trx) void bts_model_print_help() { - printf( - " -I --local-trx-ip Local IP for transceiver to connect (default=%s)\n" - , transceiver_ip - ); } int bts_model_handle_options(int argc, char **argv) @@ -116,21 +76,16 @@ int bts_model_handle_options(int argc, char **argv) while (1) { int option_idx = 0, c; static const struct option long_options[] = { - /* specific to this hardware */ - { "local-trx-ip", 1, 0, 'I' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "I:", + c = getopt_long(argc, argv, "", long_options, &option_idx); if (c == -1) break; switch (c) { - case 'I': - transceiver_ip = strdup(optarg); - break; default: num_errors++; break; @@ -140,6 +95,35 @@ int bts_model_handle_options(int argc, char **argv) return num_errors; } +int bts_model_init(struct gsm_bts *bts) +{ + struct gsm_bts_role_bts *btsb = bts_role_bts(bts); + + btsb->support.ciphers = CIPHER_A5(1) | CIPHER_A5(2); + + /* FIXME: this needs to be overridden with the real hardrware + * value */ + bts->c0->nominal_power = 23; + + bts_model_vty_init(bts); + + return 0; +} + +void bts_model_phy_link_set_defaults(struct phy_link *plink) +{ + plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, "127.0.0.1"); + plink->u.osmotrx.base_port_local = 5800; + plink->u.osmotrx.base_port_remote = 5700; + plink->u.osmotrx.clock_advance = 20; + plink->u.osmotrx.rts_advance = 5; + plink->u.osmotrx.power_oml = 1; +} + +void bts_model_phy_instance_set_defaults(struct phy_instance *pinst) +{ +} + int main(int argc, char **argv) { return bts_main(argc, argv); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index ac9212b..15c05e8 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -55,12 +55,6 @@ uint32_t transceiver_last_fn; static struct timeval transceiver_clock_tv; static struct osmo_timer_list transceiver_clock_timer; -/* clock advance for the transceiver */ -uint32_t trx_clock_advance = 20; - -/* advance RTS to give some time for data processing. (especially PCU) */ -uint32_t trx_rts_advance = 5; /* about 20ms */ - /* Enable this to multiply TOA of RACH by 10. * This is usefull to check tenth of timing advances with RSSI test tool. * Note that regular phones will not work when using this test! */ @@ -1262,14 +1256,16 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) /* send time indication */ l1if_mph_time_ind(bts, fn); - /* advance frame number, so the transceiver has more time until - * it must be transmitted. */ - fn = (fn + trx_clock_advance) % GSM_HYPERFRAME; - /* process every TRX */ llist_for_each_entry(trx, &bts->trx_list, list) { - struct trx_l1h *l1h = trx_l1h_hdl(trx); - struct l1sched_trx *l1t = trx_l1sched_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + struct phy_link *plink = pinst->phy_link; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + struct l1sched_trx *l1t = &l1h->l1s; + + /* advance frame number, so the transceiver has more + * time until it must be transmitted. */ + fn = (fn + plink->u.osmotrx.clock_advance) % GSM_HYPERFRAME; /* we don't schedule, if power is off */ if (!trx_if_powered(l1h)) @@ -1279,7 +1275,7 @@ static int trx_sched_fn(struct gsm_bts *bts, uint32_t fn) for (tn = 0; tn < ARRAY_SIZE(l1t->ts); tn++) { /* ready-to-send */ _sched_rts(l1t, tn, - (fn + trx_rts_advance) % GSM_HYPERFRAME); + (fn + plink->u.osmotrx.rts_advance) % GSM_HYPERFRAME); /* get burst for FN */ bits = _sched_dl_burst(l1t, tn, fn); if (!bits) { @@ -1323,10 +1319,12 @@ no_clock: /* flush pending messages of transceiver */ /* close all logical channels and reset timeslots */ llist_for_each_entry(trx, &bts->trx_list, list) { - trx_if_flush(trx_l1h_hdl(trx)); - trx_sched_reset(trx_l1sched_hdl(trx)); + struct phy_instance *pinst = trx_phy_instance(trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + trx_if_flush(l1h); + trx_sched_reset(&l1h->l1s); if (trx->nr == 0) - trx_if_cmd_poweroff(trx_l1h_hdl(trx)); + trx_if_cmd_poweroff(l1h); } /* tell BSC */ @@ -1461,7 +1459,8 @@ new_clock: void _sched_act_rach_det(struct l1sched_trx *l1t, uint8_t tn, uint8_t ss, int activate) { - struct trx_l1h *l1h = trx_l1h_hdl(l1t->trx); + struct phy_instance *pinst = trx_phy_instance(l1t->trx); + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; if (activate) trx_if_cmd_handover(l1h, tn, ss); diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index dbe6f68..a4c16dc 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -2,6 +2,7 @@ * OpenBTS TRX interface handling * * Copyright (C) 2013 Andreas Eversberg + * Copyright (C) 2016 Harald Welte * * All Rights Reserved * @@ -34,6 +35,7 @@ #include #include +#include #include #include #include @@ -45,7 +47,6 @@ //#define TOA_RSSI_DEBUG int transceiver_available = 0; -const char *transceiver_ip = "127.0.0.1"; int settsc_enabled = 0; int setbsic_enabled = 0; @@ -53,11 +54,10 @@ int setbsic_enabled = 0; * socket */ -static uint16_t base_port_local = 5800; - /* open socket */ -static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, - int (*cb)(struct osmo_fd *fd, unsigned int what)) +static int trx_udp_open(void *priv, struct osmo_fd *ofd, const char *host, + uint16_t port_local, uint16_t port_remote, + int (*cb)(struct osmo_fd *fd, unsigned int what)) { struct sockaddr_storage sas; struct sockaddr *sa = (struct sockaddr *)&sas; @@ -71,8 +71,8 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, ofd->data = priv; /* Listen / Binds */ - rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, transceiver_ip, - port, OSMO_SOCK_F_BIND); + rc = osmo_sock_init_ofd(ofd, AF_UNSPEC, SOCK_DGRAM, 0, host, + port_local, OSMO_SOCK_F_BIND); if (rc < 0) return rc; @@ -84,10 +84,10 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; - sin->sin_port = htons(ntohs(sin->sin_port) - 100); + sin->sin_port = htons(port_remote); } else if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - sin6->sin6_port = htons(ntohs(sin6->sin6_port) - 100); + sin6->sin6_port = htons(port_remote); } else { return -EINVAL; } @@ -96,7 +96,6 @@ static int trx_udp_open(void *priv, struct osmo_fd *ofd, uint16_t port, if (rc) return rc; - return 0; } @@ -115,13 +114,11 @@ static void trx_udp_close(struct osmo_fd *ofd) * clock */ -static struct osmo_fd trx_ofd_clk; - - /* get clock from clock socket */ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) { - struct trx_l1h *l1h = ofd->data; + struct phy_link *plink = ofd->data; + struct phy_instance *pinst = phy_instance_by_num(plink, 0); char buf[1500]; int len; uint32_t fn; @@ -146,7 +143,7 @@ static int trx_clk_read_cb(struct osmo_fd *ofd, unsigned int what) "correctly, correcting to fn=%u\n", fn); } - trx_sched_clock(l1h->trx->bts, fn); + trx_sched_clock(pinst->trx->bts, fn); return 0; } @@ -168,8 +165,8 @@ static void trx_ctrl_send(struct trx_l1h *l1h) return; tcm = llist_entry(l1h->trx_ctrl_list.next, struct trx_ctrl_msg, list); - LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to trx=%u\n", tcm->cmd, - l1h->trx->nr); + LOGP(DTRX, LOGL_DEBUG, "Sending control '%s' to %s\n", tcm->cmd, + phy_instance_name(l1h->phy_inst)); /* send command */ send(l1h->trx_ofd_ctrl.fd, tcm->cmd, strlen(tcm->cmd)+1, 0); @@ -184,8 +181,8 @@ static void trx_ctrl_timer_cb(void *data) { struct trx_l1h *l1h = data; - LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for trx=%d\n", - l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "No response from transceiver for %s\n", + phy_instance_name(l1h->phy_inst)); trx_ctrl_send(l1h); } @@ -232,7 +229,8 @@ static int trx_ctrl_cmd(struct trx_l1h *l1h, int critical, const char *cmd, int trx_if_cmd_poweroff(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWEROFF", ""); else return 0; @@ -240,7 +238,8 @@ int trx_if_cmd_poweroff(struct trx_l1h *l1h) int trx_if_cmd_poweron(struct trx_l1h *l1h) { - if (l1h->trx->nr == 0) + struct phy_instance *pinst = l1h->phy_inst; + if (pinst->num == 0) return trx_ctrl_cmd(l1h, 1, "POWERON", ""); else return 0; @@ -324,6 +323,7 @@ int trx_if_cmd_nohandover(struct trx_l1h *l1h, uint8_t tn, uint8_t ss) static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) { struct trx_l1h *l1h = ofd->data; + struct phy_instance *pinst = l1h->phy_inst; char buf[1500]; int len, resp; @@ -374,11 +374,12 @@ static int trx_ctrl_read_cb(struct osmo_fd *ofd, unsigned int what) sscanf(p + 1, "%d", &resp); if (resp) { LOGP(DTRX, (tcm->critical) ? LOGL_FATAL : LOGL_NOTICE, - "transceiver (trx=%d) rejected TRX command " - "with response: '%s'\n", l1h->trx->nr, buf); + "transceiver (%s) rejected TRX command " + "with response: '%s'\n", + phy_instance_name(pinst), buf); rsp_error: if (tcm->critical) { - bts_shutdown(l1h->trx->bts, "SIGINT"); + bts_shutdown(pinst->trx->bts, "SIGINT"); /* keep tcm list, so process is stopped */ return -EIO; } @@ -493,37 +494,91 @@ int trx_if_data(struct trx_l1h *l1h, uint8_t tn, uint32_t fn, uint8_t pwr, * open/close */ +int bts_model_phy_link_open(struct phy_link *plink) +{ + struct phy_instance *pinst; + int rc; + + phy_link_state_set(plink, PHY_LINK_CONNECTING); + + /* open the shared/common clock socket */ + rc = trx_udp_open(plink, &plink->u.osmotrx.trx_ofd_clk, + plink->u.osmotrx.transceiver_ip, + plink->u.osmotrx.base_port_local, + plink->u.osmotrx.base_port_remote, + trx_clk_read_cb); + if (rc < 0) { + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + return -1; + } + + /* open the individual instances with their ctrl+data sockets */ + llist_for_each_entry(pinst, &plink->instances, list) { + pinst->u.osmotrx.hdl = l1if_open(pinst); + if (!pinst->u.osmotrx.hdl) + goto cleanup; + } + + return 0; + +cleanup: + phy_link_state_set(plink, PHY_LINK_SHUTDOWN); + llist_for_each_entry(pinst, &plink->instances, list) { + if (pinst->u.osmotrx.hdl) { + trx_if_close(pinst->u.osmotrx.hdl); + pinst->u.osmotrx.hdl = NULL; + } + } + trx_udp_close(&plink->u.osmotrx.trx_ofd_clk); + return -1; +} + +static uint16_t compute_port(struct phy_instance *pinst, int remote, int is_data) +{ + struct phy_link *plink = pinst->phy_link; + uint16_t inc = 1; + + if (is_data) + inc = 2; + + if (remote) + return plink->u.osmotrx.base_port_remote + (pinst->num << 1) + inc; + else + return plink->u.osmotrx.base_port_local + (pinst->num << 1) + inc; +} + int trx_if_open(struct trx_l1h *l1h) { + struct phy_instance *pinst = l1h->phy_inst; + struct phy_link *plink = pinst->phy_link; int rc; - LOGP(DTRX, LOGL_NOTICE, "Open transceiver for trx=%u\n", l1h->trx->nr); + LOGP(DTRX, LOGL_NOTICE, "Open transceiver for %s\n", + phy_instance_name(pinst)); /* initialize ctrl queue */ INIT_LLIST_HEAD(&l1h->trx_ctrl_list); /* open sockets */ - if (l1h->trx->nr == 0) { - rc = trx_udp_open(l1h, &trx_ofd_clk, base_port_local, - trx_clk_read_cb); - if (rc < 0) - return rc; - LOGP(DTRX, LOGL_NOTICE, "Waiting for transceiver send clock\n"); - } rc = trx_udp_open(l1h, &l1h->trx_ofd_ctrl, - base_port_local + (l1h->trx->nr << 1) + 1, trx_ctrl_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 0), + compute_port(pinst, 1, 0), trx_ctrl_read_cb); if (rc < 0) goto err; rc = trx_udp_open(l1h, &l1h->trx_ofd_data, - base_port_local + (l1h->trx->nr << 1) + 2, trx_data_read_cb); + plink->u.osmotrx.transceiver_ip, + compute_port(pinst, 0, 1), + compute_port(pinst, 1, 1), trx_data_read_cb); if (rc < 0) goto err; /* enable all slots */ l1h->config.slotmask = 0xff; - if (l1h->trx->nr == 0) - trx_if_cmd_poweroff(l1h); + /* FIXME: why was this only for TRX0 ? */ + //if (l1h->trx->nr == 0) + trx_if_cmd_poweroff(l1h); return 0; @@ -548,13 +603,13 @@ void trx_if_flush(struct trx_l1h *l1h) void trx_if_close(struct trx_l1h *l1h) { - LOGP(DTRX, LOGL_NOTICE, "Close transceiver for trx=%u\n", l1h->trx->nr); + struct phy_instance *pinst = l1h->phy_inst; + LOGP(DTRX, LOGL_NOTICE, "Close transceiver for %s\n", + phy_instance_name(pinst)); trx_if_flush(l1h); /* close sockets */ - if (l1h->trx->nr == 0) - trx_udp_close(&trx_ofd_clk); trx_udp_close(&l1h->trx_ofd_ctrl); trx_udp_close(&l1h->trx_ofd_data); } diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index 3862e2b..1ea0da9 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -6,6 +6,7 @@ extern const char *transceiver_ip; extern int settsc_enabled; extern int setbsic_enabled; +struct trx_l1h; struct trx_ctrl_msg { struct llist_head list; diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index a4a7909..d2feea4 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -45,6 +45,8 @@ #include "trx_if.h" #include "loops.h" +#define OSMOTRX_STR "OsmoTRX Transceiver configuration\n" + static struct gsm_bts *vty_bts; DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", @@ -53,7 +55,6 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", struct gsm_bts *bts = vty_bts; struct gsm_bts_trx *trx; struct trx_l1h *l1h; - uint8_t tn; if (!transceiver_available) { vty_out(vty, "transceiver is not connected%s", VTY_NEWLINE); @@ -63,7 +64,8 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", } llist_for_each_entry(trx, &bts->trx_list, list) { - l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = trx_phy_instance(trx); + l1h = pinst->u.osmotrx.hdl; vty_out(vty, "TRX %d%s", trx->nr, VTY_NEWLINE); vty_out(vty, " %s%s", (l1h->config.poweron) ? "poweron":"poweroff", @@ -85,56 +87,70 @@ DEFUN(show_transceiver, show_transceiver_cmd, "show transceiver", VTY_NEWLINE); else vty_out(vty, " bisc : undefined%s", VTY_NEWLINE); - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain : %d%s", l1h->config.rxgain, + } + + return CMD_SUCCESS; +} + + +static void show_phy_inst_single(struct vty *vty, struct phy_instance *pinst) +{ + uint8_t tn; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + + vty_out(vty, "PHY Instance %s%s", + phy_instance_name(pinst), VTY_NEWLINE); + if (l1h->config.maxdly_valid) + vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + VTY_NEWLINE); + else + vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); + for (tn = 0; tn < TRX_NR_TS; tn++) { + if (!((1 << tn) & l1h->config.slotmask)) + vty_out(vty, " slot #%d: unsupported%s", tn, VTY_NEWLINE); - else - vty_out(vty, " rxgain : undefined%s", VTY_NEWLINE); - if (l1h->config.power_valid) - vty_out(vty, " power : %d%s", l1h->config.power, + else if (l1h->config.slottype_valid[tn]) + vty_out(vty, " slot #%d: type %d%s", tn, + l1h->config.slottype[tn], VTY_NEWLINE); else - vty_out(vty, " power : undefined%s", VTY_NEWLINE); - if (l1h->config.maxdly_valid) - vty_out(vty, " maxdly : %d%s", l1h->config.maxdly, + vty_out(vty, " slot #%d: undefined%s", tn, VTY_NEWLINE); - else - vty_out(vty, " maxdly : undefined%s", VTY_NEWLINE); - for (tn = 0; tn < TRX_NR_TS; tn++) { - if (!((1 << tn) & l1h->config.slotmask)) - vty_out(vty, " slot #%d: unsupported%s", tn, - VTY_NEWLINE); - else if (l1h->config.slottype_valid[tn]) - vty_out(vty, " slot #%d: type %d%s", tn, - l1h->config.slottype[tn], - VTY_NEWLINE); - else - vty_out(vty, " slot #%d: undefined%s", tn, - VTY_NEWLINE); - } } - - return CMD_SUCCESS; } -DEFUN(cfg_bts_fn_advance, cfg_bts_fn_advance_cmd, - "fn-advance <0-30>", - "Set the number of frames to be transmitted to transceiver in advance " - "of current FN\n" - "Advance in frames\n") +static void show_phy_single(struct vty *vty, struct phy_link *plink) { - trx_clock_advance = atoi(argv[0]); + struct phy_instance *pinst; - return CMD_SUCCESS; + vty_out(vty, "PHY %u%s", plink->num, VTY_NEWLINE); + + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " rx-gain : %d dB%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + else + vty_out(vty, " rx-gain : undefined%s", VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) + vty_out(vty, " tx-attenuation : %d dB%s", + plink->u.osmotrx.power, VTY_NEWLINE); + else + vty_out(vty, " tx-attenuation : undefined%s", VTY_NEWLINE); + + llist_for_each_entry(pinst, &plink->instances, list) + show_phy_inst_single(vty, pinst); } -DEFUN(cfg_bts_rts_advance, cfg_bts_rts_advance_cmd, - "rts-advance <0-30>", - "Set the number of frames to be requested (PCU) in advance of current " - "FN. Do not change this, unless you have a good reason!\n" - "Advance in frames\n") +DEFUN(show_phy, show_phy_cmd, "show phy", + SHOW_STR "Display information about the available PHYs") { - trx_rts_advance = atoi(argv[0]); + int i; + + for (i = 0; i < 255; i++) { + struct phy_link *plink = phy_link_by_num(i); + if (!plink) + break; + show_phy_single(vty, plink); + } return CMD_SUCCESS; } @@ -220,63 +236,14 @@ DEFUN(cfg_bts_no_setbsic, cfg_bts_no_setbsic_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_rxgain, cfg_trx_rxgain_cmd, - "rxgain <0-50>", - "Set the receiver gain in dB\n" - "Gain in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - l1h->config.rxgain = atoi(argv[0]); - l1h->config.rxgain_valid = 1; - l1h->config.rxgain_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_power, cfg_trx_power_cmd, - "power <0-50>", - "Set the transmitter power dampening\n" - "Power dampening in dB\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = atoi(argv[0]); - l1h->config.power_oml = 0; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_poweroml_, cfg_trx_power_oml_cmd, - "power oml", - "Set the transmitter power dampening\n" - "Given by NM_ATT_RF_MAXPOWR_R (max power reduction) via OML\n") -{ - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); - - l1h->config.power = trx->max_power_red; - l1h->config.power_oml = 1; - l1h->config.power_valid = 1; - l1h->config.power_sent = 0; - l1if_provision_transceiver_trx(l1h); - - return CMD_SUCCESS; -} - -DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, - "maxdly <0-31>", +DEFUN(cfg_phyinst_maxdly, cfg_phyinst_maxdly_cmd, + "osmotrx maxdly <0-31>", "Set the maximum delay of GSM symbols\n" "GSM symbols (approx. 1.1km per symbol)\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly = atoi(argv[0]); l1h->config.maxdly_valid = 1; @@ -286,7 +253,7 @@ DEFUN(cfg_trx_maxdly, cfg_trx_maxdly_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, +DEFUN(cfg_phyinst_slotmask, cfg_phyinst_slotmask_cmd, "slotmask (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0) (1|0)", "Set the supported slots\n" "TS0 supported\nTS0 unsupported\nTS1 supported\nTS1 unsupported\n" @@ -294,8 +261,8 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, "TS4 supported\nTS4 unsupported\nTS5 supported\nTS5 unsupported\n" "TS6 supported\nTS6 unsupported\nTS7 supported\nTS7 unsupported\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; uint8_t tn; l1h->config.slotmask = 0; @@ -306,76 +273,171 @@ DEFUN(cfg_trx_slotmask, cfg_trx_slotmask_cmd, return CMD_SUCCESS; } -DEFUN(cfg_trx_no_rxgain, cfg_trx_no_rxgain_cmd, - "no rxgain <0-50>", - NO_STR "Unset the receiver gain in dB\n" + +DEFUN(cfg_phy_fn_advance, cfg_phy_fn_advance_cmd, + "osmotrx fn-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be transmitted to transceiver in advance " + "of current FN\n" + "Advance in frames\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.clock_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rts_advance, cfg_phy_rts_advance_cmd, + "osmotrx rts-advance <0-30>", + OSMOTRX_STR + "Set the number of frames to be requested (PCU) in advance of current " + "FN. Do not change this, unless you have a good reason!\n" + "Advance in frames\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.rts_advance = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_rxgain, cfg_phy_rxgain_cmd, + "osmotrx rx-gain <0-50>", + OSMOTRX_STR + "Set the receiver gain in dB\n" "Gain in dB\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.rxgain_valid = 0; + plink->u.osmotrx.rxgain = atoi(argv[0]); + plink->u.osmotrx.rxgain_valid = 1; + plink->u.osmotrx.rxgain_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_power, cfg_trx_no_power_cmd, - "no power <0-50>", - NO_STR "Unset the transmitter power dampening\n" - "Power dampening in dB\n") +DEFUN(cfg_phy_tx_atten, cfg_phy_tx_atten_cmd, + "osmotrx tx-attenuation <0-50>", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Fixed attenuation in dB, overriding OML\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; - l1h->config.power_valid = 0; + plink->u.osmotrx.power = atoi(argv[0]); + plink->u.osmotrx.power_oml = 0; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; return CMD_SUCCESS; } -DEFUN(cfg_trx_no_maxdly, cfg_trx_no_maxdly_cmd, - "no maxdly <0-31>", - NO_STR "Unset the maximum delay of GSM symbols\n" - "GSM symbols (approx. 1.1km per symbol)\n") +DEFUN(cfg_phy_tx_atten_oml, cfg_phy_tx_atten_oml_cmd, + "osmotrx tx-attenuation oml", + OSMOTRX_STR + "Set the transmitter attenuation\n" + "Use NM_ATT_RF_MAXPOWR_R (max power reduction) from BSC via OML\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_oml = 1; + plink->u.osmotrx.power_valid = 1; + plink->u.osmotrx.power_sent = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_rxgain, cfg_phy_no_rxgain_cmd, + "no osmotrx rx-gain", + NO_STR OSMOTRX_STR "Unset the receiver gain in dB\n") +{ + struct phy_link *plink = vty->index; + + plink->u.osmotrx.rxgain_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phy_no_tx_atten, cfg_phy_no_tx_atten_cmd, + "no osmotrx tx-attenuation", + NO_STR OSMOTRX_STR "Unset the transmitter attenuation\n") { - struct gsm_bts_trx *trx = vty->index; - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + plink->u.osmotrx.power_valid = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_phyinst_no_maxdly, cfg_phyinst_no_maxdly_cmd, + "no osmotrx maxdly", + NO_STR "Unset the maximum delay of GSM symbols\n") +{ + struct phy_instance *pinst = vty->index; + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; l1h->config.maxdly_valid = 0; return CMD_SUCCESS; } -void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +DEFUN(cfg_phy_transc_ip, cfg_phy_transc_ip_cmd, + "osmotrx ip HOST", + OSMOTRX_STR + "Set remote IP address\n" + "IP address of OsmoTRX\n") { - vty_out(vty, " fn-advance %d%s", trx_clock_advance, VTY_NEWLINE); - vty_out(vty, " rts-advance %d%s", trx_rts_advance, VTY_NEWLINE); + struct phy_link *plink = vty->index; - if (trx_ms_power_loop) - vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, - VTY_NEWLINE); - else - vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); - vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", - VTY_NEWLINE); - if (settsc_enabled) - vty_out(vty, " settsc%s", VTY_NEWLINE); - if (setbsic_enabled) - vty_out(vty, " setbsic%s", VTY_NEWLINE); + if (plink->u.osmotrx.transceiver_ip) + talloc_free(plink->u.osmotrx.transceiver_ip); + plink->u.osmotrx.transceiver_ip = talloc_strdup(plink, argv[0]); + + return CMD_SUCCESS; } -void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +DEFUN(cfg_phy_base_port, cfg_phy_base_port_cmd, + "osmotrx base-port (local|remote) <0-65535>", + OSMOTRX_STR "Set base UDP port number\n" "Local UDP port\n" + "Remote UDP port\n" "UDP base port number\n") { - struct trx_l1h *l1h = trx_l1h_hdl(trx); + struct phy_link *plink = vty->index; + + if (!strcmp(argv[0], "local")) + plink->u.osmotrx.base_port_local = atoi(argv[1]); + else + plink->u.osmotrx.base_port_remote = atoi(argv[1]); + + return CMD_SUCCESS; +} - if (l1h->config.rxgain_valid) - vty_out(vty, " rxgain %d%s", l1h->config.rxgain, VTY_NEWLINE); - if (l1h->config.power_valid) { - if (l1h->config.power_oml) - vty_out(vty, " power oml%s", VTY_NEWLINE); +void bts_model_config_write_phy(struct vty *vty, struct phy_link *plink) +{ + if (plink->u.osmotrx.transceiver_ip) + vty_out(vty, " osmotrx ip %s%s", + plink->u.osmotrx.transceiver_ip, VTY_NEWLINE); + + vty_out(vty, " osmotrx fn-advance %d%s", + plink->u.osmotrx.clock_advance, VTY_NEWLINE); + vty_out(vty, " osmotrx rts-advance %d%s", + plink->u.osmotrx.rts_advance, VTY_NEWLINE); + if (plink->u.osmotrx.rxgain_valid) + vty_out(vty, " osmotrx rx-gain %d%s", + plink->u.osmotrx.rxgain, VTY_NEWLINE); + if (plink->u.osmotrx.power_valid) { + if (plink->u.osmotrx.power_oml) + vty_out(vty, " osmotrx tx-attenuation oml%s", VTY_NEWLINE); else - vty_out(vty, " power %d%s", l1h->config.power, - VTY_NEWLINE); + vty_out(vty, " osmotrx tx-attenuation %d%s", + plink->u.osmotrx.power, VTY_NEWLINE); } +} + +void bts_model_config_write_phy_inst(struct vty *vty, struct phy_instance *pinst) +{ + struct trx_l1h *l1h = pinst->u.osmotrx.hdl; + if (l1h->config.maxdly_valid) vty_out(vty, " maxdly %d%s", l1h->config.maxdly, VTY_NEWLINE); if (l1h->config.slotmask != 0xff) @@ -391,14 +453,32 @@ void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) VTY_NEWLINE); } +void bts_model_config_write_bts(struct vty *vty, struct gsm_bts *bts) +{ + if (trx_ms_power_loop) + vty_out(vty, " ms-power-loop %d%s", trx_target_rssi, + VTY_NEWLINE); + else + vty_out(vty, " no ms-power-loop%s", VTY_NEWLINE); + vty_out(vty, " %stiming-advance-loop%s", (trx_ta_loop) ? "":"no ", + VTY_NEWLINE); + if (settsc_enabled) + vty_out(vty, " settsc%s", VTY_NEWLINE); + if (setbsic_enabled) + vty_out(vty, " setbsic%s", VTY_NEWLINE); +} + +void bts_model_config_write_trx(struct vty *vty, struct gsm_bts_trx *trx) +{ +} + int bts_model_vty_init(struct gsm_bts *bts) { vty_bts = bts; install_element_ve(&show_transceiver_cmd); + install_element_ve(&show_phy_cmd); - install_element(BTS_NODE, &cfg_bts_fn_advance_cmd); - install_element(BTS_NODE, &cfg_bts_rts_advance_cmd); install_element(BTS_NODE, &cfg_bts_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_no_ms_power_loop_cmd); install_element(BTS_NODE, &cfg_bts_timing_advance_loop_cmd); @@ -408,14 +488,19 @@ int bts_model_vty_init(struct gsm_bts *bts) install_element(BTS_NODE, &cfg_bts_no_settsc_cmd); install_element(BTS_NODE, &cfg_bts_no_setbsic_cmd); - install_element(TRX_NODE, &cfg_trx_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_power_cmd); - install_element(TRX_NODE, &cfg_trx_power_oml_cmd); - install_element(TRX_NODE, &cfg_trx_maxdly_cmd); - install_element(TRX_NODE, &cfg_trx_slotmask_cmd); - install_element(TRX_NODE, &cfg_trx_no_rxgain_cmd); - install_element(TRX_NODE, &cfg_trx_no_power_cmd); - install_element(TRX_NODE, &cfg_trx_no_maxdly_cmd); + install_element(PHY_NODE, &cfg_phy_base_port_cmd); + install_element(PHY_NODE, &cfg_phy_fn_advance_cmd); + install_element(PHY_NODE, &cfg_phy_rts_advance_cmd); + install_element(PHY_NODE, &cfg_phy_transc_ip_cmd); + install_element(PHY_NODE, &cfg_phy_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_cmd); + install_element(PHY_NODE, &cfg_phy_tx_atten_oml_cmd); + install_element(PHY_NODE, &cfg_phy_no_rxgain_cmd); + install_element(PHY_NODE, &cfg_phy_no_tx_atten_cmd); + + install_element(PHY_INST_NODE, &cfg_phyinst_slotmask_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_maxdly_cmd); + install_element(PHY_INST_NODE, &cfg_phyinst_no_maxdly_cmd); return 0; } -- 2.7.0 From holger at freyther.de Fri Feb 5 12:11:44 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 5 Feb 2016 13:11:44 +0100 Subject: Cosmetic early RTP sending issue and please test Message-ID: <22A38B5B-030B-4489-90D8-E372F8D4D0EC@freyther.de> Hi, before the l1sap changes were merged I fixed a case where after a ip.access CRCX with recvonly mode the BTS would already start to send RTP frames to UDP port 0 which will trigger an ICMP unreachable. This is not harmful but still a bug. After the l1sap merge the sysmobts is still doing it when it receives a TCH frame and all other bts models behave like before the bugfix. The below diff copies this into the common code. Besides administratives work I try to work on the SMSC, so if anyone could testdrive this patch and check for ICMP errors it would be greatly appreciated. holger -------------- next part -------------- A non-text attachment was scrubbed... Name: 20160205_recv_only_l1sap.diff Type: application/octet-stream Size: 754 bytes Desc: not available URL: From holger at freyther.de Fri Feb 5 12:37:00 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 5 Feb 2016 13:37:00 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction In-Reply-To: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> References: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> Message-ID: <5608F327-0F8A-4027-BB71-6E43B8805833@freyther.de> > On 05 Feb 2016, at 12:41, Harald Welte wrote: > > > +struct phy_link *phy_link_create(void *ctx, int num) > +{ > + struct phy_link *plink = talloc_zero(ctx, struct phy_link); > + > + if (phy_link_by_num(num)) > + return NULL; > + > + plink = talloc_zero(ctx, struct phy_link); small memleak. plink being assigned twice. > > +struct phy_instance *phy_instance_create(struct phy_link *plink, int num) > +{ > + struct phy_instance *pinst = talloc_zero(plink, struct phy_instance); > + > + if (phy_instance_by_num(plink, num)) > + return NULL; > + > + pinst = talloc_zero(plink, struct phy_instance); same small leak. > @@ -518,6 +522,7 @@ static int mph_send_config_ciphering(struct gsm_lchan *lchan, struct sapi_cmd *c > l1if_fill_msg_hdr(&pcc->Header, msg, fl1h, cOCTVC1_MSG_TYPE_COMMAND, > cOCTVC1_GSM_MSG_TRX_MODIFY_PHYSICAL_CHANNEL_CIPHERING_CID); > > + pcc->TrxId.byTrxId = pinst->u.octphy.trx_id; ah nice, is there another way we could check that all primitives have all zero based indices set? okay ran out of time here. The octphy change looked good, mechanical, already fixing byTrxId assignment in case there will be more than one phy. holger From suraev at alumni.ntnu.no Fri Feb 5 12:55:37 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Fri, 5 Feb 2016 13:55:37 +0100 Subject: [PATCH 1/2] Expand bitvec interface Message-ID: <1454676938-6783-1-git-send-email-suraev@alumni.ntnu.no> From: Max Add bit filling, shifting and other functions necessary for bit compression implementation. Add corresponding tests. --- include/osmocom/core/bitvec.h | 9 +++ src/bitvec.c | 134 +++++++++++++++++++++++++++++++++++++-- tests/bitvec/bitvec_test.c | 141 +++++++++++++++++++++++++++++++++++++++++- tests/bitvec/bitvec_test.ok | 119 +++++++++++++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 7 deletions(-) diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h index a7e6fc4..5314cf2 100644 --- a/include/osmocom/core/bitvec.h +++ b/include/osmocom/core/bitvec.h @@ -4,6 +4,7 @@ /* (C) 2009 by Harald Welte * (C) 2012 Ivan Klyuchnikov + * (C) 2015 Sysmocom s.f.m.c. GmbH * * All Rights Reserved * @@ -41,6 +42,7 @@ #include #include +#include /*! \brief A single GSM bit * @@ -82,5 +84,12 @@ unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer); unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer); uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len); int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len); +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill); +char bit_value_to_char(enum bit_value v); +void bitvec_to_string_r(const struct bitvec *bv, char *str); +void bitvec_zero(struct bitvec *bv); +unsigned bitvec_rl(const struct bitvec *bv, bool b); +void bitvec_shiftl(struct bitvec *bv, unsigned int n); +int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits); /*! @} */ diff --git a/src/bitvec.c b/src/bitvec.c index b5d2c24..592bfc2 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -34,7 +34,9 @@ #include #include #include +#include +#include #include #define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit) @@ -224,6 +226,18 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits) return 0; } +/*! \brief get multiple bits (num_bits) from beginning of vector (MSB side) */ +int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits) +{ + if (num_bits > 15 || bv->cur_bit < num_bits) + return -EINVAL; + + if (num_bits < 9) + return bv->data[0] >> (8 - num_bits); + + return osmo_load16be(bv->data) >> (16 - num_bits); +} + /*! \brief get multiple bits (based on numeric value) from current pos */ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits) { @@ -242,15 +256,27 @@ int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits) return ui; } +/*! \brief fill num_bits with \fill starting from the current position + * returns 0 on success, negative otherwise (out of vector boundary) + */ +int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill) +{ + unsigned i, stop = bv->cur_bit + num_bits; + for (i = bv->cur_bit; i < stop; i++) + if (bitvec_set_bit(bv, fill) < 0) + return -EINVAL; + + return 0; +} + /*! \brief pad all remaining bits up to num_bits */ int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) { - unsigned int i; - - for (i = bv->cur_bit; i <= up_to_bit; i++) - bitvec_set_bit(bv, L); + int n = up_to_bit - bv->cur_bit + 1; + if (n < 1) + return 0; - return 0; + return bitvec_fill(bv, n, L); } /*! \brief find first bit set in bit vector */ @@ -446,4 +472,102 @@ int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t va return 0; } +/*! \brief convert enum to corresponding character */ +char bit_value_to_char(enum bit_value v) +{ + switch (v) { + case ZERO: return '0'; + case ONE: return '1'; + case L: return 'L'; + case H: return 'H'; + default: abort(); + } +} + +/*! \brief prints bit vector to provided string + * It's caller's responsibility to ensure that we won't shoot him in the foot: + * the provided buffer should be at lest cur_bit + 1 bytes long + */ +void bitvec_to_string_r(const struct bitvec *bv, char *str) +{ + unsigned i, pos = 0; + char *cur = str; + for (i = 0; i < bv->cur_bit; i++) { + if (0 == i % 8) + *cur++ = ' '; + *cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i)); + pos++; + } + *cur = 0; +} + +/* we assume that x have at least 1 non-b bit */ +static inline unsigned leading_bits(uint8_t x, bool b) +{ + if (b) { + if (x < 0x80) return 0; + if (x < 0xC0) return 1; + if (x < 0xE0) return 2; + if (x < 0xF0) return 3; + if (x < 0xF8) return 4; + if (x < 0xFC) return 5; + if (x < 0xFE) return 6; + } else { + if (x > 0x7F) return 0; + if (x > 0x3F) return 1; + if (x > 0x1F) return 2; + if (x > 0xF) return 3; + if (x > 7) return 4; + if (x > 3) return 5; + if (x > 1) return 6; + } + return 7; +} +/*! \brief force bit vector to all 0 and current bit to the beginnig of the vector */ +void bitvec_zero(struct bitvec *bv) +{ + bv->cur_bit = 0; + memset(bv->data, 0, bv->data_len); +} + +/*! \brief Return number (bits) of uninterrupted bit run in vector starting from the MSB + * \param[in] bv The boolean vector to work on + * \param[in] b The boolean, sequence of which is looked at from the vector start + * \returns Number of consecutive bits of \p b in \p bv + */ +unsigned bitvec_rl(const struct bitvec *bv, bool b) +{ + unsigned i; + for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) { + if ( (b ? 0xFF : 0) != bv->data[i]) + return i * 8 + leading_bits(bv->data[i], b); + } + + return bv->cur_bit; +} + +/*! \brief Shifts bitvec to the left, n MSB bits lost */ +void bitvec_shiftl(struct bitvec *bv, unsigned n) +{ + if (0 == n) + return; + if (n >= bv->cur_bit) { + bitvec_zero(bv); + return; + } + + memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8); + + uint8_t tmp[2]; + unsigned i; + for (i = 0; i < bv->data_len - 2; i++) { + uint16_t t = osmo_load16be(bv->data + i); + osmo_store16be(t << (n % 8), &tmp); + bv->data[i] = tmp[0]; + } + + bv->data[bv->data_len - 1] <<= (n % 8); + bv->cur_bit -= n; +} + /*! @} */ diff --git a/tests/bitvec/bitvec_test.c b/tests/bitvec/bitvec_test.c index 7d131e0..800a040 100644 --- a/tests/bitvec/bitvec_test.c +++ b/tests/bitvec/bitvec_test.c @@ -3,9 +3,82 @@ #include #include #include +#include +#include +#include #include #include +#include + +#define BIN_PATTERN "%d%d%d%d%d%d%d%d" +#define BIN(byte) \ + (byte & 0x80 ? 1 : 0), \ + (byte & 0x40 ? 1 : 0), \ + (byte & 0x20 ? 1 : 0), \ + (byte & 0x10 ? 1 : 0), \ + (byte & 0x08 ? 1 : 0), \ + (byte & 0x04 ? 1 : 0), \ + (byte & 0x02 ? 1 : 0), \ + (byte & 0x01 ? 1 : 0) + +static char lol[1024]; // we pollute this with printed vectors +static inline void test_rl(const struct bitvec *bv) +{ + bitvec_to_string_r(bv, lol); + printf("%s [%d] RL0=%d, RL1=%d\n", lol, bv->cur_bit, bitvec_rl(bv, false), bitvec_rl(bv, true)); +} + +static inline void test_shift(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + printf("%s << %d:\n", lol, n); + bitvec_shiftl(bv, n); + bitvec_to_string_r(bv, lol); + printf("%s\n", lol); +} + +static inline void test_get(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + printf("%s [%d]", lol, bv->cur_bit); + int16_t x = bitvec_get_int16_msb(bv, n); + uint8_t tmp[2]; + osmo_store16be(x, &tmp); + printf(" -> %d (%u bit) ["BIN_PATTERN" "BIN_PATTERN"]:\n", x, n, BIN(tmp[0]), BIN(tmp[1])); + bitvec_to_string_r(bv, lol); + printf("%s [%d]\n", lol, bv->cur_bit); +} + +static inline void test_fill(struct bitvec *bv, unsigned n, enum bit_value val) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int fi = bitvec_fill(bv, n, val); + printf("%c> FILL %s [%d] -%d-> [%d]:\n", bit_value_to_char(val), lol, bvlen, n, fi); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} + +static inline void test_spare(struct bitvec *bv, unsigned n) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int sp = bitvec_spare_padding(bv, n); + printf("%c> SPARE %s [%d] -%d-> [%d]:\n", bit_value_to_char(L), lol, bvlen, n, sp); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} + +static inline void test_set(struct bitvec *bv, enum bit_value bit) +{ + bitvec_to_string_r(bv, lol); + unsigned bvlen = bv->cur_bit; + int set = bitvec_set_bit(bv, bit); + printf("%c> SET %s [%d] ++> [%d]:\n", bit_value_to_char(bit), lol, bvlen, set); + bitvec_to_string_r(bv, lol); + printf(" %s [%d]\n\n", lol, bv->cur_bit); +} static void test_byte_ops() { @@ -33,7 +106,7 @@ static void test_byte_ops() rc = bitvec_set_uint(&bv, 0x7e, 8); OSMO_ASSERT(rc >= 0); - fprintf(stderr, "bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len)); + printf("bitvec: %s\n", osmo_hexdump(bv.data, bv.data_len)); /* Read from bitvec */ memset(out, 0xff, sizeof(out)); @@ -45,7 +118,7 @@ static void test_byte_ops() rc = bitvec_get_uint(&bv, 8); OSMO_ASSERT(rc == 0x7e); - fprintf(stderr, "out: %s\n", osmo_hexdump(out, sizeof(out))); + printf("out: %s\n", osmo_hexdump(out, sizeof(out))); OSMO_ASSERT(out[0] == 0xff); OSMO_ASSERT(out[in_size+1] == 0xff); @@ -72,11 +145,75 @@ static void test_unhex(const char *hex) int main(int argc, char **argv) { + struct bitvec bv; + uint8_t i = 8, test[i]; + + memset(test, 0, i); + bv.data_len = i; + bv.data = test; + bv.cur_bit = 0; + + printf("test shifting...\n"); + + bitvec_set_uint(&bv, 0x0E, 7); + test_shift(&bv, 3); + test_shift(&bv, 17); + bitvec_set_uint(&bv, 0, 32); + bitvec_set_uint(&bv, 0x0A, 7); + test_shift(&bv, 24); + + printf("checking RL functions...\n"); + + bitvec_zero(&bv); + test_rl(&bv); + bitvec_set_uint(&bv, 0x000F, 32); + test_rl(&bv); + bitvec_shiftl(&bv, 18); + test_rl(&bv); + bitvec_set_uint(&bv, 0x0F, 8); + test_rl(&bv); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xFF, 8); + test_rl(&bv); + bitvec_set_uint(&bv, 0xFE, 7); + test_rl(&bv); + bitvec_set_uint(&bv, 0, 17); + test_rl(&bv); + bitvec_shiftl(&bv, 18); + test_rl(&bv); + + printf("probing bit access...\n"); + + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0x3747817, 32); + bitvec_shiftl(&bv, 10); + + test_get(&bv, 2); + test_get(&bv, 7); + test_get(&bv, 9); + test_get(&bv, 13); + test_get(&bv, 16); + test_get(&bv, 42); + + printf("feeling bit fills...\n"); + + test_set(&bv, ONE); + test_fill(&bv, 3, ZERO); + test_spare(&bv, 38); + test_spare(&bv, 43); + test_spare(&bv, 1); + test_spare(&bv, 7); + test_fill(&bv, 5, ONE); + test_fill(&bv, 3, L); + + printf("byte me...\n"); + test_byte_ops(); test_unhex("48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("47240c00400000000000000079eb2ac9402b2b2b2b2b2b"); test_unhex("47283c367513ba333004242b2b2b2b2b2b2b2b2b2b2b2b"); test_unhex("DEADFACE000000000000000000000000000000BEEFFEED"); test_unhex("FFFFFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + return 0; } diff --git a/tests/bitvec/bitvec_test.ok b/tests/bitvec/bitvec_test.ok index 83328b2..1c993d3 100644 --- a/tests/bitvec/bitvec_test.ok +++ b/tests/bitvec/bitvec_test.ok @@ -1,4 +1,123 @@ +test shifting... + 0001110 << 3: + 1110 + 1110 << 17: + + 00000000 00000000 00000000 00000000 0001010 << 24: + 00000000 0001010 +checking RL functions... + [0] RL0=0, RL1=0 + 00000000 00000000 00000000 00001111 [32] RL0=28, RL1=0 + 00000000 001111 [14] RL0=10, RL1=0 + 00000000 00111100 001111 [22] RL0=10, RL1=0 + 11111111 [8] RL0=0, RL1=8 + 11111111 1111110 [15] RL0=0, RL1=14 + 11111111 11111100 00000000 00000000 [32] RL0=0, RL1=14 + 00000000 000000 [14] RL0=14, RL1=0 +probing bit access... + 11010001 11100000 010111 [22] -> 3 (2 bit) [00000000 00000011]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 104 (7 bit) [00000000 01101000]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 419 (9 bit) [00000001 10100011]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> 6716 (13 bit) [00011010 00111100]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> -22 (16 bit) [11111111 11101010]: + 11010001 11100000 010111 [22] + 11010001 11100000 010111 [22] -> -22 (42 bit) [11111111 11101010]: + 11010001 11100000 010111 [22] +feeling bit fills... +1> SET 11010001 11100000 010111 [22] ++> [0]: + 11010001 11100000 0101111 [23] + +0> FILL 11010001 11100000 0101111 [23] -3-> [0]: + 11010001 11100000 01011110 00 [26] + +L> SPARE 11010001 11100000 01011110 00 [26] -38-> [0]: + 11010001 11100000 01011110 00101011 0010101 [39] + +L> SPARE 11010001 11100000 01011110 00101011 0010101 [39] -43-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -1-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +L> SPARE 11010001 11100000 01011110 00101011 00101011 0010 [44] -7-> [0]: + 11010001 11100000 01011110 00101011 00101011 0010 [44] + +1> FILL 11010001 11100000 01011110 00101011 00101011 0010 [44] -5-> [0]: + 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] + +L> FILL 11010001 11100000 01011110 00101011 00101011 00101111 1 [49] -3-> [0]: + 11010001 11100000 01011110 00101011 00101011 00101111 1010 [52] + +byte me... === start test_byte_ops === +bitvec: 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 7e 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a 7e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 3f 20 a1 21 a2 22 a3 23 a4 24 a5 25 a6 26 a7 27 a8 28 a9 29 aa 2a ab 2b ac 2c ad 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 1f 90 50 90 d1 11 51 91 d2 12 52 92 d3 13 53 93 d4 14 54 94 d5 15 55 95 d6 16 56 9f 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 0f c8 28 48 68 88 a8 c8 e9 09 29 49 69 89 a9 c9 ea 0a 2a 4a 6a 8a aa ca eb 0b 2b 4f c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 07 e4 14 24 34 44 54 64 74 84 94 a4 b4 c4 d4 e4 f5 05 15 25 35 45 55 65 75 85 95 a7 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 03 f2 0a 12 1a 22 2a 32 3a 42 4a 52 5a 62 6a 72 7a 82 8a 92 9a a2 aa b2 ba c2 ca d3 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 01 f9 05 09 0d 11 15 19 1d 21 25 29 2d 31 35 39 3d 41 45 49 4d 51 55 59 5d 61 65 69 f8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff +bitvec: 00 00 00 00 fc 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +out: ff 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a ff === end test_byte_ops === 1 -=> cur_bit=184 48282407a6a074227201000b2b2b2b2b2b2b2b2b2b2b2b0000000000000000000000000000000000000000000000000000000000000000000000000000000000 -- 2.5.0 From suraev at alumni.ntnu.no Fri Feb 5 12:55:38 2016 From: suraev at alumni.ntnu.no (suraev at alumni.ntnu.no) Date: Fri, 5 Feb 2016 13:55:38 +0100 Subject: [PATCH 2/2] Add T4 bit map compression routines In-Reply-To: <1454676938-6783-1-git-send-email-suraev@alumni.ntnu.no> References: <1454676938-6783-1-git-send-email-suraev@alumni.ntnu.no> Message-ID: <1454676938-6783-2-git-send-email-suraev@alumni.ntnu.no> From: Max Add bit map encoder and decoder functions: decoder is fully functional while encoder is good enough for testing - no backtracking to find the best possible compression is implemented. If somebody is willing to implement MS side of EDGE than this has to be expanded. Add corresponding tests. N. B: the encoding is implemented according to ETSI TS 44.060 which is slightly different from T4 used for fax according to CCITT G31D (RFC 804). Ticket: OW#2407 Sponsored-by: On-Waves ehf Signed-off-by: Max --- .gitignore | 1 + include/Makefile.am | 1 + include/osmocom/core/bitcomp.h | 42 ++++ src/Makefile.am | 2 +- src/bitcomp.c | 480 +++++++++++++++++++++++++++++++++++++++++ tests/Makefile.am | 7 +- tests/bits/bitcomp_test.c | 66 ++++++ tests/bits/bitcomp_test.ok | 29 +++ tests/testsuite.at | 6 + 9 files changed, 631 insertions(+), 3 deletions(-) create mode 100644 include/osmocom/core/bitcomp.h create mode 100644 src/bitcomp.c create mode 100644 tests/bits/bitcomp_test.c create mode 100644 tests/bits/bitcomp_test.ok diff --git a/.gitignore b/.gitignore index 955634e..8904938 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ tests/vty/vty_test tests/gb/gprs_bssgp_test tests/smscb/gsm0341_test tests/bitvec/bitvec_test +tests/bits/bitcomp_test tests/gprs/gprs_test tests/msgb/msgb_test diff --git a/include/Makefile.am b/include/Makefile.am index 07d6c00..a965fb9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -7,6 +7,7 @@ nobase_include_HEADERS = \ osmocom/core/bit64gen.h \ osmocom/core/bits.h \ osmocom/core/bitvec.h \ + osmocom/core/bitcomp.h \ osmocom/core/conv.h \ osmocom/core/crc16.h \ osmocom/core/crc16gen.h \ diff --git a/include/osmocom/core/bitcomp.h b/include/osmocom/core/bitcomp.h new file mode 100644 index 0000000..89eccbc --- /dev/null +++ b/include/osmocom/core/bitcomp.h @@ -0,0 +1,42 @@ +#pragma once + +/* bit compression routines */ + +/* (C) 2016 sysmocom s.f.m.c. GmbH by Max Suraev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \defgroup bitcomp Bit compression + * @{ + */ + +/*! \file bitcomp.h + * \brief Osmocom bit compression routines + */ + +#include +#include + +#include + + +int osmo_t4_encode(struct bitvec *bv); +int osmo_t4_decode(const struct bitvec *in, bool cc, struct bitvec *out); + +/*! @} */ diff --git a/src/Makefile.am b/src/Makefile.am index c46cddf..45a77e3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ lib_LTLIBRARIES = libosmocore.la libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS) libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ - bitvec.c statistics.c \ + bitvec.c bitcomp.c statistics.c \ write_queue.c utils.c socket.c \ logging.c logging_syslog.c rate_ctr.c \ gsmtap_util.c crc16.c panic.c backtrace.c \ diff --git a/src/bitcomp.c b/src/bitcomp.c new file mode 100644 index 0000000..bf35927 --- /dev/null +++ b/src/bitcomp.c @@ -0,0 +1,480 @@ +/* bit compression routines */ + +/* (C) 2016 sysmocom s.f.m.c. GmbH by Max Suraev + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/*! \defgroup bitcomp Bit compression + * @{ + */ + +/*! \file bitcomp.c + * \brief Osmocom bit compression routines + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Terminating codes for uninterrupted sequences of 0 and 1 up to 64 bit length + * according to TS 44.060 9.1.10 + */ +static const unsigned t4_term[2][64] = { + { + 0b0000110111, + 0b10, + 0b11, + 0b010, + 0b011, + 0b0011, + 0b0010, + 0b00011, + 0b000101, + 0b000100, + 0b0000100, + 0b0000101, + 0b0000111, + 0b00000100, + 0b00000111, + 0b000011000, + 0b0000010111, + 0b0000011000, + 0b0000001000, + 0b00001100111, + 0b00001101000, + 0b00001101100, + 0b00000110111, + 0b00000101000, + 0b00000010111, + 0b00000011000, + 0b000011001010, + 0b000011001011, + 0b000011001100, + 0b000011001101, + 0b000001101000, + 0b000001101001, + 0b000001101010, + 0b000001101011, + 0b000011010010, + 0b000011010011, + 0b000011010100, + 0b000011010101, + 0b000011010110, + 0b000011010111, + 0b000001101100, + 0b000001101101, + 0b000011011010, + 0b000011011011, + 0b000001010100, + 0b000001010101, + 0b000001010110, + 0b000001010111, + 0b000001100100, + 0b000001100101, + 0b000001010010, + 0b000001010011, + 0b000000100100, + 0b000000110111, + 0b000000111000, + 0b000000100111, + 0b000000101000, + 0b000001011000, + 0b000001011001, + 0b000000101011, + 0b000000101100, + 0b000001011010, + 0b000001100110, + 0b000001100111 + }, + { + 0b00110101, + 0b000111, + 0b0111, + 0b1000, + 0b1011, + 0b1100, + 0b1110, + 0b1111, + 0b10011, + 0b10100, + 0b00111, + 0b01000, + 0b001000, + 0b000011, + 0b110100, + 0b110101, + 0b101010, + 0b101011, + 0b0100111, + 0b0001100, + 0b0001000, + 0b0010111, + 0b0000011, + 0b0000100, + 0b0101000, + 0b0101011, + 0b0010011, + 0b0100100, + 0b0011000, + 0b00000010, + 0b00000011, + 0b00011010, + 0b00011011, + 0b00010010, + 0b00010011, + 0b00010100, + 0b00010101, + 0b00010110, + 0b00010111, + 0b00101000, + 0b00101001, + 0b00101010, + 0b00101011, + 0b00101100, + 0b00101101, + 0b00000100, + 0b00000101, + 0b00001010, + 0b00001011, + 0b01010010, + 0b01010011, + 0b01010100, + 0b01010101, + 0b00100100, + 0b00100101, + 0b01011000, + 0b01011001, + 0b01011010, + 0b01011011, + 0b01001010, + 0b01001011, + 0b00110010, + 0b00110011, + 0b00110100 + } +}; + +static const unsigned t4_term_length[2][64] = { + {10, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12}, + {8, 6, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8} +}; + +static const unsigned t4_min_term_length[] = {2, 4}; +static const unsigned t4_min_make_up_length[] = {10, 5}; + +static const unsigned t4_max_term_length[] = {12, 8}; +static const unsigned t4_max_make_up_length[] = {13, 9}; + +static const unsigned t4_make_up_length[2][15] = { + {10, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13}, + {5, 5, 6, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9} +}; + +static const unsigned t4_make_up_ind[15] = {64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960}; + +static const unsigned t4_make_up[2][15] = { + { + 0b0000001111, + 0b000011001000, + 0b000011001001, + 0b000001011011, + 0b000000110011, + 0b000000110100, + 0b000000110101, + 0b0000001101100, + 0b0000001101101, + 0b0000001001010, + 0b0000001001011, + 0b0000001001100, + 0b0000001001101, + 0b0000001110010, + 0b0000001110011 + }, + { + 0b11011, + 0b10010, + 0b010111, + 0b0110111, + 0b00110110, + 0b00110111, + 0b01100100, + 0b01100101, + 0b01101000, + 0b01100111, + 0b011001100, + 0b011001101, + 0b011010010, + 0b011010011, + 0b011010100 + } +}; + +/*! \brief Attempt to decode compressed bit vector + * + * Return length of RLE according to modified ITU-T T.4 from TS 44.060 Table 9.1.10.2 + * or -1 if no applicable RLE found + * N. B: we need explicit bit length to make decoding unambiguous +*/ +static inline int t4_rle_term(unsigned w, bool b, unsigned bits) +{ + unsigned i; + for (i = 0; i < 64; i++) + if (w == t4_term[b][i] && bits == t4_term_length[b][i]) + return i; + return -1; +} + +static inline int t4_rle_makeup(unsigned w, bool b, unsigned bits) +{ + unsigned i; + for (i = 0; i < 15; i++) + if (w == t4_make_up[b][i] && bits == t4_make_up_length[b][i]) + return t4_make_up_ind[i]; + return -1; +} + +/*! \brief Make-up codes for a given length + * + * Return proper make-up code word for an uninterrupted sequence of b bits + * of length len according to modified ITU-T T.4 from TS 44.060 Table 9.1.10.2 */ +static inline int t4_rle(struct bitvec *bv, unsigned len, bool b) +{ + if (len >= 960) { + bitvec_set_uint(bv, t4_make_up[b][14], t4_make_up_length[b][14]); + return bitvec_set_uint(bv, t4_term[b][len - 960], t4_term_length[b][len - 960]); + } + + if (len >= 896) { + bitvec_set_uint(bv, t4_make_up[b][13], t4_make_up_length[b][13]); + return bitvec_set_uint(bv, t4_term[b][len - 896], t4_term_length[b][len - 896]); + } + + if (len >= 832) { + bitvec_set_uint(bv, t4_make_up[b][12], t4_make_up_length[b][12]); + return bitvec_set_uint(bv, t4_term[b][len - 832], t4_term_length[b][len - 832]); + } + + if (len >= 768) { + bitvec_set_uint(bv, t4_make_up[b][11], t4_make_up_length[b][11]); + return bitvec_set_uint(bv, t4_term[b][len - 768], t4_term_length[b][len - 768]); + } + + if (len >= 704) { + bitvec_set_uint(bv, t4_make_up[b][10], t4_make_up_length[b][10]); + return bitvec_set_uint(bv, t4_term[b][len - 704], t4_term_length[b][len - 704]); + } + + if (len >= 640) { + bitvec_set_uint(bv, t4_make_up[b][9], t4_make_up_length[b][9]); + return bitvec_set_uint(bv, t4_term[b][len - 640], t4_term_length[b][len - 640]); + } + + if (len >= 576) { + bitvec_set_uint(bv, t4_make_up[b][8], t4_make_up_length[b][8]); + return bitvec_set_uint(bv, t4_term[b][len - 576], t4_term_length[b][len - 576]); + } + + if (len >= 512) { + bitvec_set_uint(bv, t4_make_up[b][7], t4_make_up_length[b][7]); + return bitvec_set_uint(bv, t4_term[b][len - 512], t4_term_length[b][len - 512]); + } + + if (len >= 448) { + bitvec_set_uint(bv, t4_make_up[b][6], t4_make_up_length[b][6]); + return bitvec_set_uint(bv, t4_term[b][len - 448], t4_term_length[b][len - 448]); + } + + if (len >= 384) { + bitvec_set_uint(bv, t4_make_up[b][5], t4_make_up_length[b][5]); + return bitvec_set_uint(bv, t4_term[b][len - 384], t4_term_length[b][len - 384]); + } + + if (len >= 320) { + bitvec_set_uint(bv, t4_make_up[b][4], t4_make_up_length[b][4]); + return bitvec_set_uint(bv, t4_term[b][len - 320], t4_term_length[b][len - 320]); + } + + if (len >= 256) { + bitvec_set_uint(bv, t4_make_up[b][3], t4_make_up_length[b][3]); + return bitvec_set_uint(bv, t4_term[b][len - 256], t4_term_length[b][len - 256]); + } + + if (len >= 192) { + bitvec_set_uint(bv, t4_make_up[b][2], t4_make_up_length[b][2]); + return bitvec_set_uint(bv, t4_term[b][len - 192], t4_term_length[b][len - 192]); + } + + if (len >= 128) { + bitvec_set_uint(bv, t4_make_up[b][1], t4_make_up_length[b][1]); + return bitvec_set_uint(bv, t4_term[b][len - 128], t4_term_length[b][len - 128]); + } + + if (len >= 64) { + bitvec_set_uint(bv, t4_make_up[b][0], t4_make_up_length[b][0]); + return bitvec_set_uint(bv, t4_term[b][len - 64], t4_term_length[b][len - 64]); + } + + return bitvec_set_uint(bv, t4_term[b][len], t4_term_length[b][len]); +} + +enum dec_state { + EXPECT_TERM, + TOO_LONG, + NEED_MORE_BITS, + CORRUPT, + OK +}; + +static inline enum dec_state _t4_step(struct bitvec *v, uint16_t w, bool b, unsigned bits, bool term_only) +{ + if (bits > t4_max_make_up_length[b]) + return TOO_LONG; + if (bits < t4_min_term_length[b]) + return NEED_MORE_BITS; + + if (term_only) { + if (bits > t4_max_term_length[b]) + return CORRUPT; + int t = t4_rle_term(w, b, bits); + if (-1 != t) { + bitvec_fill(v, t, b ? ONE : ZERO); + return OK; + } + return NEED_MORE_BITS; + } + + int m = t4_rle_makeup(w, b, bits); + if (-1 != m) { + bitvec_fill(v, m, b ? ONE : ZERO); + return EXPECT_TERM; + } + + m = t4_rle_term(w, b, bits); + if (-1 != m) { + bitvec_fill(v, m, b ? ONE : ZERO); + return OK; + } + + return NEED_MORE_BITS; +} + +/*! \brief decode T4-encoded bit vector + * Assumes MSB first encoding. + * \param[in] in bit vector with encoded data + * \param[in] cc color code (whether decoding should start with 1 or 0) + * \param[out] out the bit vector to store result into + * returns 0 on success, negative value otherwise + */ +int osmo_t4_decode(const struct bitvec *in, bool cc, struct bitvec *out) +{ + uint8_t orig[in->data_len]; + struct bitvec vec; + vec.data = orig; + vec.data_len = in->data_len; + bitvec_zero(&vec); + memcpy(vec.data, in->data, in->data_len); + vec.cur_bit = in->cur_bit; + + /* init decoder using known color code: */ + unsigned bits = t4_min_term_length[cc]; + enum dec_state d; + int16_t w = bitvec_get_int16_msb(&vec, bits); + bool b = cc; + bool term_only = false; + + while (vec.cur_bit > 0) { + d = _t4_step(out, w, b, bits, term_only); + + switch (d) { + case EXPECT_TERM: + bitvec_shiftl(&vec, bits); + bits = t4_min_term_length[b]; + w = bitvec_get_int16_msb(&vec, bits); + term_only = true; + break; + case OK: + bitvec_shiftl(&vec, bits); + bits = t4_min_term_length[!b]; + w = bitvec_get_int16_msb(&vec, bits); + b = !b; + term_only = false; + break; + case NEED_MORE_BITS: + bits++; + w = bitvec_get_int16_msb(&vec, bits); + break; + case TOO_LONG: + return -E2BIG; + case CORRUPT: + return -EINVAL; + } + } + + return 0; +} + +/*! \brief encode bit vector in-place using T4 encoding + * Assumes MSB first encoding. + * \param[in] bv bit vector to be encoded + * returns color code (if the encoding started with 0 or 1) or -1 on failure (encoded is bigger than original) + */ +int osmo_t4_encode(struct bitvec *bv) +{ + unsigned rl0 = bitvec_rl(bv, false), rl1 = bitvec_rl(bv, true); + int r = (rl0 > rl1) ? 0 : 1; + uint8_t orig[bv->data_len], tmp[bv->data_len * 2]; /* FIXME: better estimate max possible encoding overhead */ + struct bitvec comp, vec; + comp.data = tmp; + comp.data_len = bv->data_len * 2; + bitvec_zero(&comp); + vec.data = orig; + vec.data_len = bv->data_len; + bitvec_zero(&vec); + memcpy(vec.data, bv->data, bv->data_len); + vec.cur_bit = bv->cur_bit; + + while (vec.cur_bit > 0) { + if (rl0 > rl1) { + bitvec_shiftl(&vec, rl0); + t4_rle(&comp, rl0, false); + } else { + bitvec_shiftl(&vec, rl1); + t4_rle(&comp, rl1, true); + } + /* + TODO: implement backtracking for optimal encoding + printf(" -> [%d/%d]", comp.cur_bit + vec.cur_bit, bv->cur_bit); + */ + rl0 = bitvec_rl(&vec, false); + rl1 = bitvec_rl(&vec, true); + } + if (comp.cur_bit < bv->cur_bit) { + memcpy(bv->data, tmp, bv->data_len); + bv->cur_bit = comp.cur_bit; + return r; + } + return -1; +} + + diff --git a/tests/Makefile.am b/tests/Makefile.am index a4a6b2e..571e87b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,7 +12,7 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \ loggingrb/loggingrb_test strrb/strrb_test \ vty/vty_test comp128/comp128_test utils/utils_test \ smscb/gsm0341_test stats/stats_test \ - bitvec/bitvec_test msgb/msgb_test + bitvec/bitvec_test msgb/msgb_test bits/bitcomp_test if ENABLE_MSGFILE check_PROGRAMS += msgfile/msgfile_test @@ -42,6 +42,9 @@ bits_bitrev_test_LDADD = $(top_builddir)/src/libosmocore.la bitvec_bitvec_test_SOURCES = bitvec/bitvec_test.c bitvec_bitvec_test_LDADD = $(top_builddir)/src/libosmocore.la +bits_bitcomp_test_SOURCES = bits/bitcomp_test.c +bits_bitcomp_test_LDADD = $(top_builddir)/src/libosmocore.la + conv_conv_test_SOURCES = conv/conv_test.c conv_conv_test_LDADD = $(top_builddir)/src/libosmocore.la @@ -136,7 +139,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \ loggingrb/logging_test.err strrb/strrb_test.ok \ vty/vty_test.ok comp128/comp128_test.ok \ utils/utils_test.ok stats/stats_test.ok \ - bitvec/bitvec_test.ok msgb/msgb_test.ok + bitvec/bitvec_test.ok msgb/msgb_test.ok bits/bitcomp_test.ok DISTCLEANFILES = atconfig diff --git a/tests/bits/bitcomp_test.c b/tests/bits/bitcomp_test.c new file mode 100644 index 0000000..f6895cf --- /dev/null +++ b/tests/bits/bitcomp_test.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static char lol[1024]; // for pretty-printing + +int main(int argc, char **argv) +{ + srand(time(NULL)); + + struct bitvec bv, out; + uint8_t i = 20, test[i], data[i]; + + bv.data_len = i; + bv.data = test; + out.data_len = i; + out.data = data; + bitvec_zero(&bv); + bitvec_zero(&out); + + printf("\nrunning static tests...\n"); + + printf("\nTEST1:\n 00110111 01000111 10000001 1111\n"); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0x374781F, 28); bitvec_to_string_r(&bv, lol); printf("%s", lol); + + printf("\nEncoded:\n%d", osmo_t4_encode(&bv)); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf(" [%d]\nExpected:\n0 11011110 10001000 01110101 01100101 100 [35]\n", bv.cur_bit); + + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xDE887565, 32); + bitvec_set_uint(&bv, 4, 3); + bitvec_to_string_r(&bv, lol); + printf(" %s [%d]\n", lol, bv.cur_bit); + int d = osmo_t4_decode(&bv, 0, &out); + printf("\nDecoded:\n%d", d); + bitvec_to_string_r(&out, lol); + printf("%s [%d]\n", lol, out.cur_bit); + printf("Expected:\n 00110111 01000111 10000001 1111 \n"); + + printf("\nTEST2:\n 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00\n"); + bitvec_zero(&bv); + bitvec_set_uint(&bv, 0xFFFFFFFF, 32); + bitvec_set_uint(&bv, 0xFFFFFFFF, 32); + bitvec_set_uint(&bv, 0xFFFFFC00, 26); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf("\nEncoded:\n%d", osmo_t4_encode(&bv)); bitvec_to_string_r(&bv, lol); printf("%s", lol); + printf(" [%d]\nExpected:\n1 11011101 01000001 00 [18]\n", bv.cur_bit); + + bitvec_zero(&out); + d = osmo_t4_decode(&bv, 1, &out); + printf("\nDecoded:\n%d", d); + bitvec_to_string_r(&out, lol); + printf("%s [%d]\n", lol, out.cur_bit); + printf("Expected:\n 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00\n"); + + return 0; +} diff --git a/tests/bits/bitcomp_test.ok b/tests/bits/bitcomp_test.ok new file mode 100644 index 0000000..238f3c4 --- /dev/null +++ b/tests/bits/bitcomp_test.ok @@ -0,0 +1,29 @@ + +running static tests... + +TEST1: + 00110111 01000111 10000001 1111 + 00110111 01000111 10000001 1111 +Encoded: +-1 00110111 01000111 10000001 1111 [28] +Expected: +0 11011110 10001000 01110101 01100101 100 [35] + 11011110 10001000 01110101 01100101 100 [35] + +Decoded: +0 00110111 01000111 10000001 1111 [28] +Expected: + 00110111 01000111 10000001 1111 + +TEST2: + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 +Encoded: +1 11011101 01000001 00 [18] +Expected: +1 11011101 01000001 00 [18] + +Decoded: +0 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 [90] +Expected: + 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 00000000 00 diff --git a/tests/testsuite.at b/tests/testsuite.at index 9cda1de..3d4d526 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -27,6 +27,12 @@ cat $abs_srcdir/bitvec/bitvec_test.ok > expout AT_CHECK([$abs_top_builddir/tests/bitvec/bitvec_test], [0], [expout], [ignore]) AT_CLEANUP +AT_SETUP([bitcomp]) +AT_KEYWORDS([bitcomp]) +cat $abs_srcdir/bits/bitcomp_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/bits/bitcomp_test], [0], [expout]) +AT_CLEANUP + AT_SETUP([conv]) AT_KEYWORDS([conv]) cat $abs_srcdir/conv/conv_test.ok > expout -- 2.5.0 From laforge at gnumonks.org Fri Feb 5 12:57:45 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 5 Feb 2016 13:57:45 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction In-Reply-To: <5608F327-0F8A-4027-BB71-6E43B8805833@freyther.de> References: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> <5608F327-0F8A-4027-BB71-6E43B8805833@freyther.de> Message-ID: <20160205125745.GP1150@nataraja> Hi Holger, On Fri, Feb 05, 2016 at 01:37:00PM +0100, Holger Freyther wrote: > small memleak. plink being assigned twice. thanks, fixed both now. > > + pcc->TrxId.byTrxId = pinst->u.octphy.trx_id; > > ah nice, is there another way we could check that all primitives have > all zero based indices set? I'm not sure what you mean here? AFAIK, the byTrxId can have arbitrary values from the PHY side, we just need to use the same value as used in the TRX-OPEN.req for all primitives belinging to that TRX. However, internally we use them with 0...n. > okay ran out of time here. The octphy change looked good, mechanical, > already fixing byTrxId assignment in case there will be more than one > phy. FYI: In the OCTPHY caes, we can actually have a single board (OCTBTS3500) which has two DSPs. To each of them we have pne PHY Link, and in each of them we can have multiple Software TRX, which then map to PHY instacnes on the OsmoBTS side. Let's say you have two Soft TRX in each DSP: * in terms of gsm_bts_trx numbers, we have TRX 0 .. 3 to match our data model (and the way how the GSM specs deal with multiple TRX) * in terms of byTrxId, we will have 0+1 on each of the PHY links Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Fri Feb 5 13:00:40 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 5 Feb 2016 14:00:40 +0100 Subject: [PATCH 1/3] Introduce new phy_link and phy_instance abstraction In-Reply-To: <20160205125745.GP1150@nataraja> References: <1454672483-15150-1-git-send-email-laforge@gnumonks.org> <5608F327-0F8A-4027-BB71-6E43B8805833@freyther.de> <20160205125745.GP1150@nataraja> Message-ID: <275C6314-9507-48D3-ACC7-B824C3445D72@freyther.de> > On 05 Feb 2016, at 13:57, Harald Welte wrote: > >> > > I'm not sure what you mean here? AFAIK, the byTrxId can have arbitrary > values from the PHY side, we just need to use the same value as used in > the TRX-OPEN.req for all primitives belinging to that TRX. However, > internally we use them with 0...n. I wondered which other fields we should have set and that work because talloc has used a memset on the msgb. For trx==0 there is no change but with trx != 0 there would be a fallout. From laforge at gnumonks.org Fri Feb 5 16:10:54 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 5 Feb 2016 17:10:54 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> Message-ID: <20160205161054.GE10932@nataraja> Hi Holger, On Thu, Feb 04, 2016 at 08:12:19AM +0100, Holger Freyther wrote: > I think some of us would like to move to redmine and start using > public tickets more frequently. So in case we move there are some > topics to be discussed and I would like to start with a couple of them > right now. Thanks for getting the public discussion about this started. To give some more background to the mailing list: * The trac installations at osmocom.org are pretty much underused/dormant. The only part that's used is the Wiki. * Osmocom started when a single project (OpenBSC) got a sister project (OsmocomBB) and has grown into many projects. Running a single trac instance for each project on a separate dns hostname is overkill. Also, as code is shifted around between libraries and programs, we'd appreciate some flexibility. * at sysmocom internally we have successfully used redmine for dozens of different projects. The project hierarchy can be changed as needed on the fly, and issues can relate to issues of other projects, shifted from project to project, etc. * Quite a bit of the work we do at sysmocom on the Osmocom software should have the issue tracker for bugs and features in the public, but as our internal redmine is so much easier than the public trac setup, we kept using the internal redmine. So my plan moving forward is to migrate all Osmocom projects (initially those related to GSM) to a public redmine, and then keep all issues updated there. This would give more visibility into the work we're doing, such as the EDGE PCU, the 3G NITB + SGSN, the HNB-GW, etc. > Redmine has a global linear sequence of ticket numbers. If we move > from many tracs to a single redmine we can either: > > * not import tickets > * only import from one project > * deal with changing ticket numbers I think not importing tickets or dealing wih changing numbers is the way to go. > In terms of installations the GMR trac is broken in regard to tickets, > there are some for SDR that are probably not being fixed anytime soon, > baseband might be relevant and OpenBSC is unlikely to be relevant. I > don't think we have ever used ticket reference in OpenBSC commit > messages so in terms of OpenBSC having changing ticket numbers would > not be a big deal. E.g. we could add a custom field with the old trac > number? If there is automatic import/conversion available, I'd prefer to import the OsmocomBB, SIMtrace, (non-spam) Security and OpenBSC tickets, even though most of them are probably stale and outdated for years. They're still part of the history. Changing the numbers doesn't matter, as we don't refer to them. > We have external references that should be redirected to the new > place. Is there any way besides maintaining a list in the > apache2/nginx configuration and making redirects as we find broken > references? Can we proactively manage this? Is anybody willing to come > up with a script and nginx configuration for doing this? I'm not aware of any tools that might be able to help here. Indeed, it would be great if anyone would volunteer to generate a script to generate the redirects. I guess the old format is e.g. http://openbsc.osmocom.org/trac/wiki/nanoBTS/Internals and the new URL would be something like http://projects.osmocom.org/redmine/openbsc/wiki/nanoBTS/Internals Or should we strip even the redmine from the URL? And should we have a rewrite for http://openbsc.osmocom.org/redmine to http://projects.osmocom.org/redmine/openbsc ? Any ideas? Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From 246tnt at gmail.com Fri Feb 5 20:57:12 2016 From: 246tnt at gmail.com (Sylvain Munaut) Date: Fri, 5 Feb 2016 21:57:12 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <20160205161054.GE10932@nataraja> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160205161054.GE10932@nataraja> Message-ID: Hi, >> I think some of us would like to move to redmine and start using >> public tickets more frequently. So in case we move there are some >> topics to be discussed and I would like to start with a couple of them >> right now. +1 for redmine. >> In terms of installations the GMR trac is broken in regard to tickets, >> there are some for SDR that are probably not being fixed anytime soon, >> baseband might be relevant and OpenBSC is unlikely to be relevant. I >> don't think we have ever used ticket reference in OpenBSC commit >> messages so in terms of OpenBSC having changing ticket numbers would >> not be a big deal. E.g. we could add a custom field with the old trac >> number? > > If there is automatic import/conversion available, I'd prefer to import > the OsmocomBB, SIMtrace, (non-spam) Security and OpenBSC tickets, even > though most of them are probably stale and outdated for years. They're > still part of the history. Changing the numbers doesn't matter, as we > don't refer to them. - OsmocomBB never used tickets AFAIK. - OsmocomGMR definitely never used them - OsmocomSDR ... don't think it's worth importing. - Security ... yeah maybe, although not really sure anyone is really using this. >> We have external references that should be redirected to the new >> place. Is there any way besides maintaining a list in the >> apache2/nginx configuration and making redirects as we find broken >> references? Can we proactively manage this? Is anybody willing to come >> up with a script and nginx configuration for doing this? > > I'm not aware of any tools that might be able to help here. > > Indeed, it would be great if anyone would volunteer to generate a script > to generate the redirects. script ? The page names should be the same, so it should pretty much be just a few redirects per project with regexp to redirect properly. Shouldn't be too hard once we settled for a URL scheme. Any reason not to go for just http://osmocom.org/ as a base ? We have nothing really in the front page and we could just let redmine handle it too. Then just http://osmocom.org/projectname/wiki/page/name looks good to me if doable. Cheers, Sylvain From laforge at gnumonks.org Fri Feb 5 23:54:33 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 6 Feb 2016 00:54:33 +0100 Subject: OsmoDevCon 2016 planning / wiki page In-Reply-To: <20160113133526.GO9964@nataraja> References: <20160112151200.GP1762@nataraja> <20160113133526.GO9964@nataraja> Message-ID: <20160205235433.GP10932@nataraja> Hi all, I've just created the template wiki page for OsmoDevCon2016 at http://openbsc.osmocom.org/trac/wiki/OsmoDevCon2016 please add your name to the list if you're interested to attend (and qualify as somebody who contributed to Osmocom projects). Please also add any talks or workshops that you'd like to either a) hold yourself, or b) would want somebody else to talk about Looking forward to meeting you all again. It will already be the fifth OsmoDevCon, so we might consider a small birthday celebration :) Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Mon Feb 8 12:07:58 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 8 Feb 2016 13:07:58 +0100 Subject: FIXME: TODO: do better In-Reply-To: References: <20160128133239.GD1755@dub6> Message-ID: <20160208120758.GA1249@dub6> On Thu, Feb 04, 2016 at 01:53:06PM +0100, Holger Freyther wrote: > > > On 28 Jan 2016, at 14:32, Neels Hofmeyr wrote: > > > > Would anyone like to prevent this commit from reaching master? ;) > > The silent_call handling doesn't fit from an architectural point of view. It is used to demonstrate a security implication of carrying a mobile phone. We simply open a channel and then don't do anything with it. At the same time one will receive measurement reports and could more easily triangulate or actively try to determine where the phone is. > > > As such this feature needs to always "accept" a new "Complete layer3 information" (as of GSM 08.08). The original todo is indeed not a good one as it has absolutely no meta information. Thinking about the code my goal was to define a more clear ownership of the "MSC" side of an operation. So instead of starting a generic "close soon" timer (or the loc operation timer) have something that takes ownership of the first message. This would mean we dispatch "complete layer3 information" differently than follow up messages. As with many parts this part of the architecture has never been fixed/implemented/corrected as the current is working good enough(tm). > > We can either remove the comment, leave it as such or fix the above text and put it into the code as a fixme/todo. Most helpful for me would be if you just fixed the todo comment, or handed me a text I can copy-paste without having to reflect on it myself... Thx :) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From suraev at alumni.ntnu.no Mon Feb 8 12:23:54 2016 From: suraev at alumni.ntnu.no (=?UTF-8?B?TWF4ICjimK0p?=) Date: Mon, 8 Feb 2016 13:23:54 +0100 Subject: statsd usage Message-ID: <56B888DA.7020606@alumni.ntnu.no> Hi. There are bunch of functions like osmo_counter_* and osmo_stats_reporter_* in libosmocore and other projects. I'm pretty much understand what they do, but what happens on the receiving end? There's nothing in our wiki regarding statsd. How do you guys use it? Any statsd config examples? Workflow hints? With such an elaborate functionality there got to be somebody who actually uses it. Please share your experience, configs, pretty screenshots and complaints :) cheers, Max. From nhofmeyr at sysmocom.de Mon Feb 8 13:29:35 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 8 Feb 2016 14:29:35 +0100 Subject: UE <--> CN connections in 3G Message-ID: <20160208132935.GB1249@dub6> Hi all, this is diverting a mail dialog that started off privately to this list, for the benefit of everyone. You may have noticed that Daniel is working on IuPS (3G/UMTS data conns) and I'm working on the OsmoCSCN, which is going to handle IuCS (3G/UMTS voice calls). There was still some puzzlement around connection IDs and how to reach a mobile device (aka UE). In particular, which ID or information do I store to identify the link to a UE, and how do I find a UE in case of paging? First off, we're so far implementing a special case where we're using a HNB-GW to demultiplex voice and data (IuCS and IuPS) from an hNodeB (femto-cell). ASCII art to illustrate, view in a monospaced font: UE 1 <--> |hNodeB 1| <-->|HNB-GW| <---> |CSCN or SGSN | 1 | | UE 2 <--> |hNodeB 2| <-->| | | UE 3 <--> | | | | | | UE 4 <--> |hNodeB 3| <-->|HNB-GW| <---> | | 2 | | UE 5 <--> |hNodeB 4| <-->| | | UE 6 <--> | | | | So, how does a CSCN know where to send a message for a given UE, and how does it reach that UE? Turns out the picture is more like this: . . . (hNodeB) . . . (HNB-GW) UE1 <--> | Cell <--1--> [RNC] <------------> [CSCN] UE2 <--> | Meaning that the hNodeB actually encloses an RNC (Radio Network Controller) and a single radio cell. The HNB-GW does pretty much "invisible" forwarding of the SCCP|SUA connection to the RNC. Each RNC has a global RNC ID, and can manage N radio cells. In the hNodeB case, there is exactly one cell behind the RNC, but the general case looks like this: UE1 <--> | Cell <-----> |RNC1 <------------> |CSCN UE2 <--> | | | | | UE3 <--> | Cell <-----> | | | | UE4 <--> | Cell <-----> |RNC2 <------------> | UE5 <--> | | | | | UE6 <--> | Cell <-----> | | When a UE calls, the CSCN receives a User SAP link with a conn_id, and simply routes the reply back to this link and conn_id. The reply goes right back to the RNC, and the RNC knows which cell the UE is at. The case where the CN contacts a UE is known as paging, i.e. the request by the CN that the UE shall please establish a connection to the CN. The CSCN may encounter different cases here: a User SAP link may have been established and is still present, or no link is available (e.g. a link has existed before but has been torn down due to a Reset by the RNC, etc.). If the link is still valid, this manifests as: the struct gsm_subscriber_connection still has a valid pointer to an osmo_sua_link, and iu_tx() feeds the conn_id to this link to reach the UE. (Note that the gsm_subscriber_connection struct does not yet have an osmo_sua_link pointer. I will move the ue_conn_ctx into the gsm_subscriber_connection struct in an upcoming commit.) If, e.g. due to a Reset, the osmo_sua_link pointer has been cleared, the CSCN or SGSN will ask the HLR: where has the last location update for this IMSI been registered? Each RNC can manage several location areas, further divided into several service areas, and once the HLR has identified the service area where the UE is expected, the CSCN or SGSN can identify the RNC by the global RNC ID and send the paging request in that direction. A bit of pseudo struct code: struct gsm_network { llist of struct gsm_subscriber_connection: { { struct gsm_subscriber subscr { char imsi[GSM_IMSI_LENGTH]; }; struct { struct osmo_sua_link *link; /* point into an rnc struct */ uint32_t conn_id; } iu; }, ... }; llist of struct rnc (does not exist yet) : { struct osmo_sua_link *link; /* upon link-down, clear the above */ ... }; }; So, IIUC, the global RNC ID resolved from the HLR info should identify the path to a particular UE. The CSCN knows which RNC is behind which of its local link endpoints. In our special case with an HNB-GW and when there are several hNodeB instances behind the HNB-GW, the HNB-GW knows which way to send a connection reply by the established SCCP|SUA link, or which way to send a paging request by the RNC ID. The finer code details here are not entirely known to me yet, but I hope that the answers will come naturally or have already been implemented by Daniel ;) If any questions, answers or comments emerge in your mind while reading this, please don't hesitate and share! Thanks, ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Tue Feb 9 11:06:04 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 9 Feb 2016 12:06:04 +0100 Subject: 2G vs 3G LACs Message-ID: <20160209110604.GB1189@dub6> Hi folks, to share a finding: the question was whether 2G and 3G cells may share location area codes. A glance at some (mostly anonymized) live data from GSM cell monitoring hardware, in use by one of our customers, answers that quite clearly: Network MCC MNC LAC CID Type Band FirstOperator 123 4 678 C669 GSM GSM900 FirstOperator 123 4 678 CF5A GSM GSM900 FirstOperator 123 4 678 CF2A GSM GSM900 FirstOperator 123 4 678 C695 GSM GSM900 FirstOperator 123 4 678 CF30 GSM GSM900 FirstOperator 123 4 678 CF58 GSM GSM900 FirstOperator 123 4 678 6869 UMTS UMTS2100 FirstOperator 123 4 678 C69B GSM GSM900 SecondOperator 123 5 9AB DEEF GSM DCS1800 SecondOperator 123 5 9AB E15D UMTS UMTS2100 SecondOperator 123 5 9AB E163 UMTS UMTS2100 SecondOperator 123 5 9AB E080 GSM DCS1800 LACs are shared across 2G ("GSM" here) and 3G ("UMTS") technologies, only the cell IDs are guaranteed to differ. Happy hacking, ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Tue Feb 9 11:09:19 2016 From: holger at freyther.de (Holger Freyther) Date: Tue, 9 Feb 2016 12:09:19 +0100 Subject: Smalltalk scalable SMSC project In-Reply-To: <9047F009-0798-4ED9-8211-BA5D515B9295@freyther.de> References: <9047F009-0798-4ED9-8211-BA5D515B9295@freyther.de> Message-ID: <47AB9864-CB30-4AEA-8FE5-45D484DF6002@freyther.de> > On 18 Jan 2016, at 16:56, Holger Freyther wrote: Good Morning, > If you are interested in specification, Smalltalk, testing, load testing, > SS7 or such please join me in the development. progress was a bit slower due having to handle administration topics at sysmocom but last weekend I completed most of the database interface. The biggest challenge was to enforce only one system will deliver to a specific destination at the same time, e.g. for multi-part SMS one should not send more than one fragment at a time. I currently solve this by using Compare-And-Swap (CAS) to lock a single SMS and then try to insert a unique lock for this destination into another collection. If that worked I will try to lock other SMS that are to be delivered (or in a couple of seconds). This way the SMS will look lock and no other node will try to use it (otherwise nodes would busy loop trying to lock a SMS that can not be delivered). All database operations have system tests and are executed on travis-ci with a recent mongodb. Right now I am completing the inserting of SubmitSM and DeliverSM into the database and the next stop is to work on delivery using SMPP and MAP. I will extract a lot of functionality from the HomeRouting SMS system, e.g. the SMPP<->MAP conversion, the dialogue handling for MAPv3/MAPv2. As usual anyone interested in playing with the system, contributing to it, writing system tests or load tests is more than welcome to participate. holger From nhofmeyr at sysmocom.de Tue Feb 9 21:30:15 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 9 Feb 2016 22:30:15 +0100 Subject: MSC split: is_siemens_bts() in libmsc/gsm_04_08.c / conn->bts vs. lchan->ts->trx->bts Message-ID: <20160209213015.GA5791@dub6> I'm trying to get rid of all BTS backpointers in libmsc. In libmsc/gsm_04_08.c, in gsm48_rx_mm_serv_req(), I find: if (is_siemens_bts(bts)) send_siemens_mrpci(msg->lchan, classmark2-1); My conclusion so far is that this "hook" should move to the BSC code, but I could use some comforting approval by more apt contenders... Some detail: send_siemens_mrpci() is found in libbsc/gsm_04_08_utils.c: int send_siemens_mrpci(struct gsm_lchan *lchan, uint8_t *classmark2_lv) { struct rsl_mrpci mrpci; if (classmark2_lv[0] < 2) return -EINVAL; mrpci.power_class = classmark2_lv[1] & 0x7; mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1); mrpci.vbs_capable = classmark2_lv[2] & (1 <<2); mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3; return rsl_siemens_mrpci(lchan, &mrpci); } IIUC the Siemens BS11 BTS needs to be tickled with a vendor-specific RSL message as soon as a CM service request (GSM48_MT_MM_CM_SERV_REQ) or a paging response is received from a subscriber. Only the BSC knows which BTS is involved, so I'd try to find some place in libbsc/ or osmo-bsc/ to move this away to. The same function is called from gsm48_handle_paging_resp() in libbsc. Any shortcuts / workarounds or could this also be dropped entirely? It does look like that particular case is indeed missing from osmo-bsc. Who is this Mister PCI anyway? ;) The gsm48_handle_paging_resp() function leads me to another, more general question: often, there are two bts pointers around, namely the gsm_subscriber_connection->bts as well as the lchan->ts->trx->bts Are these typically/always/never expected to be the same bts struct? (In this function, both bts pointers are used, and I'd like to understand why.) Thanks! ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From jerlbeck at sysmocom.de Tue Feb 9 22:28:24 2016 From: jerlbeck at sysmocom.de (Jacob Erlbeck) Date: Tue, 9 Feb 2016 23:28:24 +0100 Subject: EDGE over osmo-pcu In-Reply-To: <56B477F0.2030508@sysmocom.de> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> <56B477F0.2030508@sysmocom.de> Message-ID: <56BA6808.3050900@sysmocom.de> Hi Sipos, On 05.02.2016 11:22, Jacob Erlbeck wrote: > > On 04.02.2016 22:40, Sipos Csaba wrote: >> >> I hope I can do some testing on the weekend with a B200. I will also update the wiki article if needed. > > It is not in master yet and my development (wip) branch is still a mess > (GPRS is b0rken in the latter), but this should improve soon. I'll put > the revised commits to jerlbeck/master first. GPRS is fixed and jerlbeck/master is updated. Make sure to limit the MCS according to the HW/SW, so use the 'mcs max 4' command if the HW does not support 8PSK. Note that 8PSK is only supported for downlink yet, but the 'mcs max' command does not check this. So you should use 'mcs max 9 4' explicitely (this should be fixed by the additional commits (currently) in jerlbeck/testing/pcu, which adds that check and proper default values). Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From holger at freyther.de Wed Feb 10 10:09:17 2016 From: holger at freyther.de (Holger Freyther) Date: Wed, 10 Feb 2016 11:09:17 +0100 Subject: [PATCH 1/3] log: Add log_check_level function In-Reply-To: References: <1447757546-31341-1-git-send-email-jerlbeck@sysmocom.de> <5678090B.5060805@sysmocom.de> <0B6768C7-B56F-487E-ACEF-7B969F013ED3@freyther.de> <5678195F.9030204@sysmocom.de> Message-ID: <9B5CB0A9-8059-4A68-A512-AD2725BA269F@freyther.de> > On 28 Dec 2015, at 14:35, Pierre Baudry wrote: > > Hello list, Hi! > Is this patch still considered for a merge ? sure, I send an updated version to the list, feel free to review it and provide some comments. holger From holger at freyther.de Wed Feb 10 10:23:10 2016 From: holger at freyther.de (Holger Freyther) Date: Wed, 10 Feb 2016 11:23:10 +0100 Subject: MSC split: is_siemens_bts() in libmsc/gsm_04_08.c / conn->bts vs. lchan->ts->trx->bts In-Reply-To: <20160209213015.GA5791@dub6> References: <20160209213015.GA5791@dub6> Message-ID: <2CE1E208-ECA1-42BE-9BB1-B83872EE6D48@freyther.de> > On 09 Feb 2016, at 22:30, Neels Hofmeyr wrote: > > Hi! > Any shortcuts / workarounds or could this also be dropped entirely? > It does look like that particular case is indeed missing from osmo-bsc. > Who is this Mister PCI anyway? ;) Our trusty old BS11. I think some people might still use it. We need to move to the BSC layer and even if we repeat some code to check if this is a CM Service Request message. holger From ruben.undheim at gmail.com Wed Feb 10 18:22:50 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Wed, 10 Feb 2016 19:22:50 +0100 Subject: libosmocore does not build in Ubuntu Message-ID: <20160210182250.GA20778@macbookair> Hi, Can someone here help me debug the failing build of libosmocore in Ubuntu? See: https://launchpadlibrarian.net/235791225/buildlog_ubuntu-xenial-amd64.libosmocore_0.9.0-3_BUILDING.txt.gz The test case "gprs-bssgp" fails with following output: stderr: MESSAGE to 0x7f0000ff, msg length 12 02 00 81 01 01 82 0b 56 04 82 0b 55 All NS-VCs for NSEI 2901 are either dead or blocked! All NS-VCs for NSEI 2901 are either dead or blocked! BSSGP BVCI=0 Rx BVC STATUS, cause=Protocol error - unspecified BSSGP BVCI=1234 Rx BVC STATUS, cause=Unknown BVCI NSEI=2901/BVCI=2989 Cannot handle PDU type 34 for unknown BVCI, NS BVCI 2989 Unable to resolve NSEI 4660 to NS-VC! Assert failed rc >= 0 gb/gprs_bssgp_test.c:234 I think it is related to the hardening option "-D_FORTIFY_SOURCE=2". What is interesting is that it builds correctly in Debian, but not Ubuntu. The issue has apparently been observed before: http://comments.gmane.org/gmane.comp.mobile.osmocom.baseband.devel/4149 If this gets fixed quickly, it might go into the next Ubuntu LTS version which has import freeze Feb 18th. Cheers, Ruben From ruben.undheim at gmail.com Wed Feb 10 19:20:54 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Wed, 10 Feb 2016 20:20:54 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <20160210182250.GA20778@macbookair> References: <20160210182250.GA20778@macbookair> Message-ID: <20160210192054.GA22827@macbookair> I made a litle bit progress. The problem disappears if "-Wl,-Bsymbolic-functions" is removed from LDFLAGS. Any idea why? Ruben On Wed, Feb 10, 2016 at 07:22:50PM +0100, Ruben Undheim wrote: > Hi, > > Can someone here help me debug the failing build of libosmocore in Ubuntu? > > See: > https://launchpadlibrarian.net/235791225/buildlog_ubuntu-xenial-amd64.libosmocore_0.9.0-3_BUILDING.txt.gz > > The test case "gprs-bssgp" fails with following output: > > stderr: > MESSAGE to 0x7f0000ff, msg length 12 > 02 00 81 01 01 82 0b 56 04 82 0b 55 > All NS-VCs for NSEI 2901 are either dead or blocked! > All NS-VCs for NSEI 2901 are either dead or blocked! > BSSGP BVCI=0 Rx BVC STATUS, cause=Protocol error - unspecified > BSSGP BVCI=1234 Rx BVC STATUS, cause=Unknown BVCI > NSEI=2901/BVCI=2989 Cannot handle PDU type 34 for unknown BVCI, NS BVCI 2989 > Unable to resolve NSEI 4660 to NS-VC! > Assert failed rc >= 0 gb/gprs_bssgp_test.c:234 > > > I think it is related to the hardening option "-D_FORTIFY_SOURCE=2". What is > interesting is that it builds correctly in Debian, but not Ubuntu. > > The issue has apparently been observed before: > http://comments.gmane.org/gmane.comp.mobile.osmocom.baseband.devel/4149 > > If this gets fixed quickly, it might go into the next Ubuntu LTS version which > has import freeze Feb 18th. > > > Cheers, > Ruben From nhofmeyr at sysmocom.de Wed Feb 10 21:47:20 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 10 Feb 2016 22:47:20 +0100 Subject: hnbgw should reconnect to CN Message-ID: <20160210214720.GA9755@dub6> Hi list, during testing of OsmoCSCN, I find that osmo-hnbgw connects to the CN servers once, but when such a CN component restarts, no new connection is established. Sequence: - start hnbgw, which continuously tries to connect to CS and PS CN servers every five seconds (osmo-cscn and dummy-cn in my case). - start dummy-cn, hnbgw connects. - start osmo-cscn, hnbgw connects. - osmo-cscn segfaults ;) - hnbgw logs the disconnect - I restart osmo-cscn - but hnbgw never attempts to reconnect to osmo-cscn. - so I have to restart hnbgw, hnb-test and its VTY connection "all the time", which is cumbersome. I briefly tried to resolve the issue, but I'm losing patience. I tried to enable the DLINP debug logging but found that hnbgw's VTY doesn't allow me to manipulate logging levels, apparently. Next I'd have liked to set the hnbgw_log_info to indicate [DLINP] = { .loglevel = LOGL_DEBUG } but DLINP is negative. Does this really have to be as fiendish? I guess the INT2IDX() macro doesn't apply here, as it would cause index overlaps with the other D* constants. It can be really hard to find my way around the Osmo source code, with the little non-obvious things accumulating... I did find that much: the reconnect flag passed to osmo_stream_cli_open2() is effective only while state == STREAM_CLI_STATE_CONNECTING, i.e. until a first connection is established. Now, if upon disconnect, something were to set the state back to cli->state = STREAM_CLI_STATE_CONNECTING my guess is that the cli_timer_cb() would indeed attempt to reconnect as I intend. BTW, what does cli stand for? Not command-line interface, is it. If I stayed onto this I'd probably solve the issue. My focus should be on an IuCS Location Update though, so comments or help is appreciated :) So long I'll carry on with the workaround, restarting hnbgw "all the time". Thanks! ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Thu Feb 11 06:48:09 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 11 Feb 2016 07:48:09 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <20160210192054.GA22827@macbookair> References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> Message-ID: > On 10 Feb 2016, at 20:20, Ruben Undheim wrote: > > I made a litle bit progress. The problem disappears if > "-Wl,-Bsymbolic-functions" is removed from LDFLAGS. Please see this commit[1]. The GPRS NetworkService (NS) has two backends, one to use GRE and one to send using UDP. For the UDP case we try to override a symbol to see that it is called. With the -Bsymbolic-functions approach this call doesn't go through the symbol table so we will not see the call. [1] http://git.osmocom.org/libosmocore/commit/?id=e7c18dd59f4f91409e8d8854eee2d213165e0746 From holger at freyther.de Thu Feb 11 06:54:11 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 11 Feb 2016 07:54:11 +0100 Subject: hnbgw should reconnect to CN In-Reply-To: <20160210214720.GA9755@dub6> References: <20160210214720.GA9755@dub6> Message-ID: <7244A179-F5F7-4AE6-83DD-09DD51901B9A@freyther.de> > On 10 Feb 2016, at 22:47, Neels Hofmeyr wrote: > > Hi! > Next I'd have liked to set the hnbgw_log_info to indicate > [DLINP] = { .loglevel = LOGL_DEBUG } > but DLINP is negative. Does this really have to be as fiendish? > I guess the INT2IDX() macro doesn't apply here, as it would cause index > overlaps with the other D* constants. It can be really hard to find my way > around the Osmo source code, with the little non-obvious things > accumulating... well the default is defined where the entire log area is defined. With DL the indication is that it is one library, most likely libosmo-abis. To change the default for the application the config file is the right place. In the hnbgw somebody needs to call logging_vty_add_cmds. > I did find that much: the reconnect flag passed to > osmo_stream_cli_open2() > is effective only while state == STREAM_CLI_STATE_CONNECTING, i.e. until a > first connection is established. Now, if upon disconnect, something were > to set the state back to > cli->state = STREAM_CLI_STATE_CONNECTING > my guess is that the cli_timer_cb() would indeed attempt to reconnect as I > intend. Which library and which branch is this coming from? From nhofmeyr at sysmocom.de Thu Feb 11 15:35:01 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 11 Feb 2016 16:35:01 +0100 Subject: hnbgw should reconnect to CN In-Reply-To: <7244A179-F5F7-4AE6-83DD-09DD51901B9A@freyther.de> References: <20160210214720.GA9755@dub6> <7244A179-F5F7-4AE6-83DD-09DD51901B9A@freyther.de> Message-ID: <20160211153501.GA7081@dub6> On Thu, Feb 11, 2016 at 07:54:11AM +0100, Holger Freyther wrote: > In the hnbgw somebody needs to call logging_vty_add_cmds. sounds simple enough :) And it worked! thanks! > > I did find that much: the reconnect flag passed to > > osmo_stream_cli_open2() > > is effective only while state == STREAM_CLI_STATE_CONNECTING, i.e. until a > > first connection is established. Now, if upon disconnect, something were > > to set the state back to > > cli->state = STREAM_CLI_STATE_CONNECTING > > my guess is that the cli_timer_cb() would indeed attempt to reconnect as I > > intend. > > Which library and which branch is this coming from? Ah, sorry, it's on: libosmo-netif branch sysmocom/sctp src/stream.c hold on, weren't you supposed to do your tax reports today? ;) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 11 15:47:29 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 11 Feb 2016 16:47:29 +0100 Subject: hnbgw should reconnect to CN In-Reply-To: <20160210214720.GA9755@dub6> References: <20160210214720.GA9755@dub6> Message-ID: <20160211154729.GB7081@dub6> On Wed, Feb 10, 2016 at 10:47:20PM +0100, Neels Hofmeyr wrote: > BTW, what does cli stand for? Not command-line interface, is it. I guess stream_cli_ means "stream client" ... IMHO one of the less readable abbreviations ;) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From ruben.undheim at gmail.com Thu Feb 11 17:35:07 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Thu, 11 Feb 2016 18:35:07 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> Message-ID: <20160211173507.GA14916@macbookair> Perfect answer! Good to hear that it's not because of any code bug. I've removed the flag and now it has been built on Ubuntu. This also paves the way libosmo-abis, libosmo-netif, libosmo-sccp and openggsn which have been "dependency-waiting" on the servers. I notice that libosmo-sccp does not build correctly on powerpc architectures. It fails the sccp test.. Please see here: https://buildd.debian.org/status/fetch.php?pkg=libosmo-sccp&arch=powerpc&ver=0.7.0-1&stamp=1454910220 Maybe you have an idea? Is there maybe a struct problem again? Best regards, Ruben On Thu, Feb 11, 2016 at 07:48:09AM +0100, Holger Freyther wrote: > > > On 10 Feb 2016, at 20:20, Ruben Undheim wrote: > > > > I made a litle bit progress. The problem disappears if > > "-Wl,-Bsymbolic-functions" is removed from LDFLAGS. > > Please see this commit[1]. The GPRS NetworkService (NS) has two backends, one to use GRE and one to send using UDP. For the UDP case we try to override a symbol to see that it is called. With the -Bsymbolic-functions approach this call doesn't go through the symbol table so we will not see the call. > > > [1] http://git.osmocom.org/libosmocore/commit/?id=e7c18dd59f4f91409e8d8854eee2d213165e0746 From holger at freyther.de Thu Feb 11 17:38:52 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 11 Feb 2016 18:38:52 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <20160211173507.GA14916@macbookair> References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> <20160211173507.GA14916@macbookair> Message-ID: <5AB64556-354F-4FA2-82B1-DF3244887320@freyther.de> > On 11 Feb 2016, at 18:35, Ruben Undheim wrote: > > > > Please see here: > https://buildd.debian.org/status/fetch.php?pkg=libosmo-sccp&arch=powerpc&ver=0.7.0-1&stamp=1454910220 > > Maybe you have an idea? Is there maybe a struct problem again? Interesting. the first/second deployment of the SCCP code has been on 32bit PowerPC code. But most likely some 16bit is going wrong. If you have access to a PowerPC system through the debian project. Could you first look at the tests/testsuite.dir/*/testsuite.log? kind regards holger From ruben.undheim at gmail.com Thu Feb 11 20:15:31 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Thu, 11 Feb 2016 21:15:31 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <5AB64556-354F-4FA2-82B1-DF3244887320@freyther.de> References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> <20160211173507.GA14916@macbookair> <5AB64556-354F-4FA2-82B1-DF3244887320@freyther.de> Message-ID: <20160211201531.GA26650@macbookair> Hi, I don't have access to a PowerPC shell directly, but I can upload packages for a test build, and I've modified the build script to dump testsuite.log. See here: http://debomatic-powerpc.debian.net/distribution#unstable/libosmo-sccp/0.7.0-1/buildlog This is an extract from the log: - outgoing: dstref(196612) 1 -> 3 + outgoing: dstref(67109632) 1 -> 3 income: 0 -> 3 Writing test data2 incoming data: 4 Returning data3 - outgoing data: dstref(196612) 4 - outgoing: dstref(196612) 3 -> 4 - outgoing: dstref(196612) 4 -> 5 + outgoing data: dstref(67109632) 4 + outgoing: dstref(67109632) 3 -> 4 + outgoing: dstref(67109632) 4 -> 5 Ruben On Thu, Feb 11, 2016 at 06:38:52PM +0100, Holger Freyther wrote: > > > Interesting. the first/second deployment of the SCCP code has been on 32bit PowerPC code. But most likely some 16bit is going wrong. If you have access to a PowerPC system through the debian project. Could you first look at the tests/testsuite.dir/*/testsuite.log? > > kind regards > holger From holger at freyther.de Thu Feb 11 20:21:06 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 11 Feb 2016 21:21:06 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <20160211201531.GA26650@macbookair> References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> <20160211173507.GA14916@macbookair> <5AB64556-354F-4FA2-82B1-DF3244887320@freyther.de> <20160211201531.GA26650@macbookair> Message-ID: <695FAE83-E446-4C81-A28B-194775813977@freyther.de> > On 11 Feb 2016, at 21:15, Ruben Undheim wrote: > > Hi! I am off for today but.. > This is an extract from the log: > > - outgoing: dstref(196612) 1 -> 3 > + outgoing: dstref(67109632) 1 -> 3 uint32_t sccp_src_ref_to_int(struct sccp_source_reference *ref) struct sccp_source_reference sccp_src_ref_from_int(uint32_t int_ref); are the two candidates. You could have ntohl and htonl in them to make the format/result predictable on LE and BE machines. Or swap it on BE machines. holger From ruben.undheim at gmail.com Thu Feb 11 21:00:11 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Thu, 11 Feb 2016 22:00:11 +0100 Subject: libosmocore does not build in Ubuntu In-Reply-To: <695FAE83-E446-4C81-A28B-194775813977@freyther.de> References: <20160210182250.GA20778@macbookair> <20160210192054.GA22827@macbookair> <20160211173507.GA14916@macbookair> <5AB64556-354F-4FA2-82B1-DF3244887320@freyther.de> <20160211201531.GA26650@macbookair> <695FAE83-E446-4C81-A28B-194775813977@freyther.de> Message-ID: <20160211210011.GA4822@macbookair> Surely not elegant or efficient, but it makes the test pass...: Index: libosmo-sccp/src/sccp.c =================================================================== --- libosmo-sccp.orig/src/sccp.c 2016-02-05 16:56:35.845659264 +0100 +++ libosmo-sccp/src/sccp.c 2016-02-11 21:48:58.066093403 +0100 @@ -1392,14 +1392,26 @@ uint32_t sccp_src_ref_to_int(struct sccp_source_reference *ref) { uint32_t src_ref = 0; +#if OSMO_IS_LITTLE_ENDIAN memcpy(&src_ref, ref, sizeof(*ref)); +#elif OSMO_IS_BIG_ENDIAN + memcpy((((char*)(&src_ref))+3),&(ref->octet1),1); + memcpy((((char*)(&src_ref))+2),&(ref->octet2),1); + memcpy((((char*)(&src_ref))+1),&(ref->octet3),1); +#endif return src_ref; } struct sccp_source_reference sccp_src_ref_from_int(uint32_t int_ref) { struct sccp_source_reference ref; +#if OSMO_IS_LITTLE_ENDIAN memcpy(&ref, &int_ref, sizeof(ref)); +#elif OSMO_IS_BIG_ENDIAN + memcpy(&(ref.octet1),(((char*)(&int_ref))+3),1); + memcpy(&(ref.octet2),(((char*)(&int_ref))+2),1); + memcpy(&(ref.octet3),(((char*)(&int_ref))+1),1); +#endif return ref; } Cheers, Ruben On Thu, Feb 11, 2016 at 09:21:06PM +0100, Holger Freyther wrote: > > > On 11 Feb 2016, at 21:15, Ruben Undheim wrote: > > > > > > Hi! > > I am off for today but.. > > > This is an extract from the log: > > > > - outgoing: dstref(196612) 1 -> 3 > > + outgoing: dstref(67109632) 1 -> 3 > > uint32_t sccp_src_ref_to_int(struct sccp_source_reference *ref) > struct sccp_source_reference sccp_src_ref_from_int(uint32_t int_ref); > > are the two candidates. You could have ntohl and htonl in them to make the format/result predictable on LE and BE machines. Or swap it on BE machines. > > holger > From sipos.csaba at kvk.uni-obuda.hu Sat Feb 13 14:27:44 2016 From: sipos.csaba at kvk.uni-obuda.hu (Sipos Csaba) Date: Sat, 13 Feb 2016 15:27:44 +0100 (CET) Subject: EDGE over osmo-pcu In-Reply-To: <56BA6808.3050900@sysmocom.de> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> <56B477F0.2030508@sysmocom.de> <56BA6808.3050900@sysmocom.de> Message-ID: <1324311217.2742117.1455373664759.JavaMail.zimbra@kvk.uni-obuda.hu> Hi Jacob, Thanks for the information. Just wanted to test the new code, and I hit this problem: make[1]: Entering directory `/root/new_osmocom/osmo-pcu/src' CXX decoding.lo decoding.cpp:26:34: fatal error: osmocom/core/bitcomp.h: No such file or directory #include ^ compilation terminated. make[1]: *** [decoding.lo] Error 1 make[1]: Leaving directory `/root/new_osmocom/osmo-pcu/src' make: *** [all-recursive] Error 1 The libosmocore (master) is updated today, and the missing file is actually in /usr/local/include/osmocom/core/bitvec.h I tried both "jerlbeck/testing/pcu" and "jerlbeck/master" branches, the error is the same. Maybe I am missing something? Regards, Csaba ----- Eredeti ?zenet ----- Felad?: "Jacob Erlbeck" C?mzett: "Sipos Csaba" M?solatot kap: osmocom-net-gprs at lists.osmocom.org, openbsc at lists.osmocom.org Elk?ld?tt ?zenetek: Kedd, 2016. Febru?r 9. 23:28:24 T?rgy: Re: EDGE over osmo-pcu Hi Sipos, On 05.02.2016 11:22, Jacob Erlbeck wrote: > > On 04.02.2016 22:40, Sipos Csaba wrote: >> >> I hope I can do some testing on the weekend with a B200. I will also update the wiki article if needed. > > It is not in master yet and my development (wip) branch is still a mess > (GPRS is b0rken in the latter), but this should improve soon. I'll put > the revised commits to jerlbeck/master first. GPRS is fixed and jerlbeck/master is updated. Make sure to limit the MCS according to the HW/SW, so use the 'mcs max 4' command if the HW does not support 8PSK. Note that 8PSK is only supported for downlink yet, but the 'mcs max' command does not check this. So you should use 'mcs max 9 4' explicitely (this should be fixed by the additional commits (currently) in jerlbeck/testing/pcu, which adds that check and proper default values). Jacob -- - Jacob Erlbeck http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From holger at freyther.de Sat Feb 13 17:51:55 2016 From: holger at freyther.de (Holger Freyther) Date: Sat, 13 Feb 2016 18:51:55 +0100 Subject: EDGE over osmo-pcu In-Reply-To: <1324311217.2742117.1455373664759.JavaMail.zimbra@kvk.uni-obuda.hu> References: <56B39169.4050302@sysmocom.de> <56169256.1216377.1454622005188.JavaMail.zimbra@kvk.uni-obuda.hu> <56B477F0.2030508@sysmocom.de> <56BA6808.3050900@sysmocom.de> <1324311217.2742117.1455373664759.JavaMail.zimbra@kvk.uni-obuda.hu> Message-ID: <28DDF88A-101A-4C25-B334-1C516DD790A2@freyther.de> > On 13 Feb 2016, at 15:27, Sipos Csaba wrote: > > Hi Jacob, > > Thanks for the information. > > Just wanted to test the new code, and I hit this problem: > > make[1]: Entering directory `/root/new_osmocom/osmo-pcu/src' > CXX decoding.lo > decoding.cpp:26:34: fatal error: osmocom/core/bitcomp.h: No such file or directory > #include you need to grab the t4 patches Max from Sysmocom has posted. Due minor coding style issues these are not in master yet. From laforge at gnumonks.org Sun Feb 14 11:07:19 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sun, 14 Feb 2016 12:07:19 +0100 Subject: MSC split: is_siemens_bts() in libmsc/gsm_04_08.c / conn->bts vs. lchan->ts->trx->bts In-Reply-To: <20160209213015.GA5791@dub6> References: <20160209213015.GA5791@dub6> Message-ID: <20160214110719.GG9910@nataraja> Hi Neels, as Holger has indicated, we definitely need to keep BS-11 compatibility. On Tue, Feb 09, 2016 at 10:30:15PM +0100, Neels Hofmeyr wrote: > Who is this Mister PCI anyway? ;) I just Googled 'Siemens Abis MRPCI' and found an old question + response I posted some years ago: http://www.erlang.com/forum/erlang/thread.htx?thread=3168 I don't think it neccessarily needs to be sent at a very specific point in time, but it needs to be sent after dedicated channel establishment and before T_MSRFPCI expires. However, to put reasonable values into the message, we need to know the classmark of the MS. > The gsm48_handle_paging_resp() function leads me to another, more general > question: often, there are two bts pointers around, namely the > gsm_subscriber_connection->bts > as well as the > lchan->ts->trx->bts > Are these typically/always/never expected to be the same bts struct? I would assume that both pointers are the same in all cases. > (In this function, both bts pointers are used, and I'd like to understand why.) When I created OpenBSC, we only had the lchan->ts->trx->bts pointers, and we had the subscriber point directly to the lchan. IIRC, Holger later introduced the subscriber_connection when he created OsmoBSC. So there might be some cases where a field was not removed but could be removed? The lchan/ts/trx/bts hierarchy is always present when a dedicated channel is established. It is a very BSC-centric data structure. The subscriber/subscriber_conn is a MSC-centric data structure. And basically on the BSC side we have lchan's that are mapped over the A interface to a subscriber_conn on the MSC side. Thus, the MSC shouldn't referernce the lchan. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Sun Feb 14 16:51:24 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sun, 14 Feb 2016 17:51:24 +0100 Subject: MSC split: is_siemens_bts() in libmsc/gsm_04_08.c / conn->bts vs. lchan->ts->trx->bts In-Reply-To: <20160209213015.GA5791@dub6> References: <20160209213015.GA5791@dub6> Message-ID: <20160214165124.GA6692@nataraja> Hi Neels and others. FYI, I added a dot graph of the osmo-nitb data structures and their relations to openbsc.git in commit bafc1e4. The file is called openbsc/doc/osmo-nitb-data_structures.dot In general: * BTS/TRX/TS/LCHAN are BSC-side data structures * subscriber is a MSC-side data structures * subscriber_conn is sort of in between BSC and MSC, but mostly on the BSC side, too. Thus: * subscriber_conn should not point to gsm_bts. This is mostly used to resolve gsm_network. Replace conn->bts with a new conn->network * a 'network' will be required in both BSC and MSC * subscriber_group was an early idea that was never really used and could/should eventually be removed, and replaced with a direct subscriber->network reference. * nothing on the MSC/CSCN side should refer to lchan/ts/trx/bts subscriber_conn must be split between the BSC and the MSC/CSCN side. BSC side: * maintain the references to the lchans required for hand-over, assignment, etc. MSC/CSCN side: * remove the references to the lchans * instead refer to the Iu/A interface SCCP connection for this subscriber Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From ruben.undheim at gmail.com Sun Feb 14 20:35:45 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Sun, 14 Feb 2016 21:35:45 +0100 Subject: Status of osmocom libraries in Debian Message-ID: <20160214203545.GA16105@macbookair> Hi, First of all I would like to thank you guys for working on an awesome project and contributing so much nice code! I've been working on getting the Osmocom libraries into Debian. libosmocore has been there for some time now, but I recently also got libosmo-sccp, libosmo-abis, libosmo-netif, libsmpp34 (not directly osmocom) and openggsn in. This means that all dependencies for building openbsc, osmo-bts and osmo-pcu should be available in Debian. I would also like to thank you for keeping a quite well-maintained debian directory in the tar-balls, even with good state of SONAME-ing etc. I've used this as the starting point where possible, but also modified them to meet "Debian standard". It would be great if you could test the packages and also verify that the copyright files contain all the copyright holders. Let me know on this list or on private email if there is something missing or wrong. Here are links to all copyright files: https://tracker.debian.org/media/packages/libo/libosmo-abis/copyright-0.3.2%2B20151106git86fc3c8-1 https://tracker.debian.org/media/packages/libo/libosmo-netif/copyright-0.0.6-1 https://tracker.debian.org/media/packages/libo/libosmo-sccp/copyright-0.7.0-1 https://tracker.debian.org/media/packages/libo/libosmocore/copyright-0.9.0-4 https://tracker.debian.org/media/packages/libs/libsmpp34/copyright-1.10-1 https://tracker.debian.org/media/packages/o/openggsn/copyright-0.92-1 You will have to run Debian sid (unstable) to directly install the packages using "apt install", but you could also download the .deb-files manually from: https://packages.debian.org/unstable/[packagename] or for Ubuntu here: https://launchpad.net/ubuntu/xenial/+source/[packagename] I'm also aware of that the code is moving ahead rapidly and what is in Debian unstable now may quickly get out-of-date. But I will try to keep them up-to- date as much as possible, and also provide backport packages. Getting the packages in the first time is usually much more cumbersome than keeping them up-to-date. For those interested in Ubuntu, the current versions will most likely get into the next long-term support release (16.04), since its freeze date for package imports from Debian is already Feb 18th. So let me know quickly if there is something wrong so that I possibly may be able to fix it before the freeze (when it's much more straight forward). Cheers, Keep up the good work. Ruben From ruben.undheim at gmail.com Sun Feb 14 21:32:53 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Sun, 14 Feb 2016 22:32:53 +0100 Subject: Patch to make openbsc find libsmpp34 Message-ID: <20160214213253.GA32145@macbookair> Hi, This patch lets the build script for openbsc find the libsmpp34 installation with the help of pkg-config instead of assuming the header files are in /usr/include. diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 18bfa0c..5195890 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -1,6 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) + $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBSMPP34_CFLAGS) noinst_HEADERS = meas_feed.h diff --git a/openbsc/src/utils/Makefile.am b/openbsc/src/utils/Makefile.am index f6255a0..4521130 100644 --- a/openbsc/src/utils/Makefile.am +++ b/openbsc/src/utils/Makefile.am @@ -1,5 +1,6 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) \ + $(LIBSMPP34_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) noinst_HEADERS = meas_db.h diff --git a/openbsc/tests/smpp/Makefile.am b/openbsc/tests/smpp/Makefile.am index 06e7af6..9ab15c5 100644 --- a/openbsc/tests/smpp/Makefile.am +++ b/openbsc/tests/smpp/Makefile.am @@ -1,5 +1,5 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_srcdir)/src/libmsc -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBSMPP34_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) EXTRA_DIST = smpp_test.ok smpp_test.err It is needed if building with the debian package for libsmpp34. Best regards, Ruben From nhofmeyr at sysmocom.de Sun Feb 14 21:53:04 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sun, 14 Feb 2016 22:53:04 +0100 Subject: MSC split: is_siemens_bts() in libmsc/gsm_04_08.c / conn->bts vs. lchan->ts->trx->bts In-Reply-To: <20160214110719.GG9910@nataraja> References: <20160209213015.GA5791@dub6> <20160214110719.GG9910@nataraja> Message-ID: <20160214215304.GA11479@dub6> On Sun, Feb 14, 2016 at 12:07:19PM +0100, Harald Welte wrote: > > Who is this Mister PCI anyway? ;) > http://www.erlang.com/forum/erlang/thread.htx?thread=3168 heh, interesting > > question: often, there are two bts pointers around, namely the > > gsm_subscriber_connection->bts > > as well as the > > lchan->ts->trx->bts I should have said: there are often two bts pointers *in libbsc*, since in libmsc on my cscn branch, the gsm_subscriber_connection->bts as well as the ->lchan are already #ifdef'd away. > I would assume that both [bts] pointers are the same in all cases. > > When I created OpenBSC, we only had the lchan->ts->trx->bts pointers, > and we had the subscriber point directly to the lchan. IIRC, Holger > later introduced the subscriber_connection when he created OsmoBSC. ok, nice, I understand. That comment in gsm48_handle_paging_resp() (libbsc) sounds a bit like more than one BTS could be involved: /* Stop paging on the bts we received the paging response */ and it uses lchan->...bts first, but conn->bts at the bottom. (But nm, this function is not relevant for the MSC-split anyway.) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Mon Feb 15 20:08:06 2016 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 15 Feb 2016 21:08:06 +0100 Subject: Status of osmocom libraries in Debian In-Reply-To: <20160214203545.GA16105@macbookair> References: <20160214203545.GA16105@macbookair> Message-ID: <20160215200806.GO5868@nataraja> Hi Ruben, likewise, thanks a lot for your efforts in getting the official Debian packages going. Except the current work on libosmo-netif regarding UMTS/3G and the occasional EDGE related bit in libosmocore, I don't think there's that much constant new development happening in the libraries that would make them outdated soon. Would you also be interested in working on an official debian package for OpenBSC (particularly osmo-bsc, osmo-nitb, osmo-sgsn)? I think it would be a good idea and nothing less than the logical consequence of having the libraries in Debian. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From ruben.undheim at gmail.com Mon Feb 15 22:19:06 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Mon, 15 Feb 2016 23:19:06 +0100 Subject: Status of osmocom libraries in Debian In-Reply-To: <20160215200806.GO5868@nataraja> References: <20160214203545.GA16105@macbookair> <20160215200806.GO5868@nataraja> Message-ID: <20160215221906.GA495@macbookair> Hi, > Except the current work on libosmo-netif regarding UMTS/3G and the > occasional EDGE related bit in libosmocore, I don't think there's that > much constant new development happening in the libraries that would make > them outdated soon. Good to hear that things are nearly feature complete! > Would you also be interested in working on an official debian package > for OpenBSC (particularly osmo-bsc, osmo-nitb, osmo-sgsn)? I think it > would be a good idea and nothing less than the logical consequence of > having the libraries in Debian. Yes, this has been and is the ultimate goal. I have the packaging almost ready. There are just some copyright listings and lintian cleanup work left to do. I am also trying to find a clean way for osmo-bts to get the needed build files from the openbsc source directory. I think there's a need for a openbsc-source package or something similar which stores the necessary files and which osmo-bts can build-depend on. Cheers, Ruben From aschultz at tpip.net Tue Feb 16 08:22:30 2016 From: aschultz at tpip.net (Andreas Schultz) Date: Tue, 16 Feb 2016 09:22:30 +0100 Subject: Query regarding GTP-U code implementation in upstream linux kernel In-Reply-To: References: Message-ID: <56C2DC46.901@tpip.net> Hi Niti, On 02/16/2016 08:53 AM, Niti Rohilla wrote: > Hi All, > > I want to enable GTP-U in OpenVswitch. I have implemented the code for the GTP-U in ovs and submitted the same on ovs-dev. > > As currently, GTP-U support is not available in upstream linux kernel, so to create a GTP port in ovs we have to load the openvswitch kernel > module to linux kernel. > > I have received some review comments stating that first I have to implement the code for GTP-U in upstream linux kernel in netdev net-next > tree then it can be incorporated into ovs. > > I want to know the process of how to implement and get the code for GTP-U into upstream linux kernel. > > If anybody is working on the same how can I help them to get it in into the upstream linux kernel quickly. I'm a bit out of touch with OVS, so my idea on how this should work might be wrong. As far as I understand OVS, the way forward would be to use the lwtunnel infrastructure to enable OVS to use a kernel GTP module. Our current OVS module ([1], [2]) is not (yet) using lwtunnel, but we do plan on switching to that. So far, we have been coordinating the GTP kernel module development on the OpenBSC ML [3]. The goal is to upstream it as soon as all the basics are covered (smallish netlink API changes, final touches on IPv6 and maybe lwtunnel). On the OVS side, someone would then need to implement the necessary ops to handle GTP lwtunnel integration. Andreas [1]: http://git.osmocom.org/osmo-gtp-kernel [2]: https://github.com/RoadRunnr/osmo-ggsn [3]: https://lists.osmocom.org/mailman/listinfo/openbsc > > > Thanks & Regards > Niti Rohilla > > =====-----=====-----===== > Notice: The information contained in this e-mail > message and/or attachments to it may contain > confidential or privileged information. If you are > not the intended recipient, any dissemination, use, > review, distribution, printing or copying of the > information contained in this e-mail message > and/or attachments to it are strictly prohibited. If > you have received this communication in error, > please notify us by reply e-mail or telephone and > immediately and permanently delete the message > and any attachments. Thank you > From nhofmeyr at sysmocom.de Tue Feb 16 12:07:15 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 16 Feb 2016 13:07:15 +0100 Subject: libasn1c config.h Message-ID: <20160216120715.GA27266@dub6> Hi, you may be aware that the '#include "config.h"' in libasn1c's asn_system.h breaks builds with the out-of-the-box 'make install'. So far we go to the installed header and remove that line. This time I've removed the line from the source tree before building, and I can't find any effect really. My source tree has no config.h file to begin with. But I'm not sure what would be a point of failure there. When I commit this, will I break something I merely happen to not be using? Any autoconf guru here that could resolve this with a quick glance? http://git.osmocom.org/libasn1c/tree/configure.ac http://git.osmocom.org/libasn1c/tree/include/asn1c/asn_system.h Thanks, ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 17 10:51:56 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 17 Feb 2016 11:51:56 +0100 Subject: libasn1c config.h In-Reply-To: <20160216120715.GA27266@dub6> References: <20160216120715.GA27266@dub6> Message-ID: <20160217105155.GC1232@dub6> If no-one knows any better I'll just commit it and wait for complaints, if any. ~Neels On Tue, Feb 16, 2016 at 01:07:15PM +0100, Neels Hofmeyr wrote: > Hi, > > you may be aware that the '#include "config.h"' in libasn1c's asn_system.h > breaks builds with the out-of-the-box 'make install'. So far we go to the > installed header and remove that line. > > This time I've removed the line from the source tree before building, and > I can't find any effect really. My source tree has no config.h file to > begin with. > > But I'm not sure what would be a point of failure there. When I commit > this, will I break something I merely happen to not be using? Any autoconf > guru here that could resolve this with a quick glance? > > http://git.osmocom.org/libasn1c/tree/configure.ac > http://git.osmocom.org/libasn1c/tree/include/asn1c/asn_system.h > > Thanks, > ~Neels > > -- > - Neels Hofmeyr http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 17 10:55:27 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 17 Feb 2016 11:55:27 +0100 Subject: autoreconf v2.69 with subdir-objects: ./configure creates directory 'src/tests/\$(top_srcdir)' In-Reply-To: <20160114134038.GE1873@dub6> References: <20160114134038.GE1873@dub6> Message-ID: <20160217105527.GD1232@dub6> Dear autoconf, I have received no reply yet, so am taking the liberty to . BTW, is there a way to verify that this report has reached someone, besides waiting for an email reply? Thanks! ~Neels On Thu, Jan 14, 2016 at 02:40:38PM +0100, Neels Hofmeyr wrote: > Dear autoconf, > > I am observing a bug with `autoreconf -i`. > To my/our knowledge, this is not due to an error in > our configuration but a genuine bug from 'subdir-objects'. > > The symptom: after running ./configure, I find a directory > src/tests/\$(top_srcdir) > > (The string that looks like a variable that is to be expanded is written to the > file system in verbatim, as the directory name.) > > The weird dir contains only a .deps dir with dependency files for the src/* > files (not for src/tests/* files as one might expect). > > If I remove 'subdir-objects' from configure.ac, the weird dir is not created. > > > Reproduction recipe on debian stable: > > ? autoreconf --version > autoreconf (GNU Autoconf) 2.69 > Copyright (C) 2012 Free Software Foundation, Inc. > License GPLv3+/Autoconf: GNU GPL version 3 or later > , > This is free software: you are free to change and redistribute it. > There is NO WARRANTY, to the extent permitted by law. > > Written by David J. MacKenzie and Akim Demaille. > > > ? git clone git://git.osmocom.org/osmo-iuh > Cloning into 'osmo-iuh'... > remote: Counting objects: 5945, done. > remote: Compressing objects: 100% (2661/2661), done. > remote: Total 5945 (delta 4991), reused 3757 (delta 3228) > Receiving objects: 100% (5945/5945), 12.11 MiB | 8.97 MiB/s, done. > Resolving deltas: 100% (4991/4991), done. > Checking connectivity... done. > > ? cd osmo-iuh/ > > ? sed -i 's/^PKG_/dnl &/' configure.ac > > ? autoreconf -i > aclocal: warning: couldn't open directory 'm4': No such file or directory > libtoolize: putting auxiliary files in `.'. > libtoolize: copying file `./ltmain.sh' > libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'. > libtoolize: copying file `m4/libtool.m4' > libtoolize: copying file `m4/ltoptions.m4' > libtoolize: copying file `m4/ltsugar.m4' > libtoolize: copying file `m4/ltversion.m4' > libtoolize: copying file `m4/lt~obsolete.m4' > libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am. > configure.ac:5: installing './compile' > configure.ac:5: installing './config.guess' > configure.ac:5: installing './config.sub' > configure.ac:7: installing './install-sh' > configure.ac:7: installing './missing' > src/Makefile.am: installing './depcomp' > > ? ./configure > checking build system type... x86_64-unknown-linux-gnu > checking host system type... x86_64-unknown-linux-gnu > checking how to print strings... printf > checking for gcc... gcc > checking whether the C compiler works... yes > checking for C compiler default output file name... a.out > checking for suffix of executables... > checking whether we are cross compiling... no > checking for suffix of object files... o > checking whether we are using the GNU C compiler... yes > checking whether gcc accepts -g... yes > checking for gcc option to accept ISO C89... none needed > checking whether gcc understands -c and -o together... yes > checking for a sed that does not truncate output... /bin/sed > checking for grep that handles long lines and -e... /bin/grep > checking for egrep... /bin/grep -E > checking for fgrep... /bin/grep -F > checking for ld used by gcc... /usr/bin/ld > checking if the linker (/usr/bin/ld) is GNU ld... yes > checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B > checking the name lister (/usr/bin/nm -B) interface... BSD nm > checking whether ln -s works... yes > checking the maximum length of command line arguments... 1572864 > checking whether the shell understands some XSI constructs... yes > checking whether the shell understands "+="... yes > checking how to convert x86_64-unknown-linux-gnu file names to x86_64-unknown-linux-gnu format... func_convert_file_noop > checking how to convert x86_64-unknown-linux-gnu file names to toolchain format... func_convert_file_noop > checking for /usr/bin/ld option to reload object files... -r > checking for objdump... objdump > checking how to recognize dependent libraries... pass_all > checking for dlltool... no > checking how to associate runtime and link libraries... printf %s\n > checking for ar... ar > checking for archiver @FILE support... @ > checking for strip... strip > checking for ranlib... ranlib > checking for gawk... no > checking for mawk... mawk > checking command to parse /usr/bin/nm -B output from gcc object... ok > checking for sysroot... no > checking for mt... mt > checking if mt is a manifest tool... no > checking how to run the C preprocessor... gcc -E > checking for ANSI C header files... yes > checking for sys/types.h... yes > checking for sys/stat.h... yes > checking for stdlib.h... yes > checking for string.h... yes > checking for memory.h... yes > checking for strings.h... yes > checking for inttypes.h... yes > checking for stdint.h... yes > checking for unistd.h... yes > checking for dlfcn.h... yes > checking for objdir... .libs > checking if gcc supports -fno-rtti -fno-exceptions... no > checking for gcc option to produce PIC... -fPIC -DPIC > checking if gcc PIC flag -fPIC -DPIC works... yes > checking if gcc static flag -static works... yes > checking if gcc supports -c -o file.o... yes > checking if gcc supports -c -o file.o... (cached) yes > checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes > checking whether -lc should be explicitly linked in... no > checking dynamic linker characteristics... GNU/Linux ld.so > checking how to hardcode library paths into programs... immediate > checking whether stripping libraries is possible... yes > checking if libtool supports shared libraries... yes > checking whether to build shared libraries... yes > checking whether to build static libraries... yes > checking for a BSD-compatible install... /usr/bin/install -c > checking whether build environment is sane... yes > checking for a thread-safe mkdir -p... /bin/mkdir -p > checking whether make sets $(MAKE)... yes > checking for style of include used by make... GNU > checking whether make supports nested variables... yes > checking dependency style of gcc... gcc3 > checking whether make supports nested variables... (cached) yes > checking whether make sets $(MAKE)... (cached) yes > checking for gcc... (cached) gcc > checking whether we are using the GNU C compiler... (cached) yes > checking whether gcc accepts -g... (cached) yes > checking for gcc option to accept ISO C89... (cached) none needed > checking whether gcc understands -c and -o together... (cached) yes > checking for ANSI C header files... (cached) yes > checking that generated files are newer than configure... done > configure: creating ./config.status > config.status: creating libosmo-ranap.pc > config.status: creating src/Makefile > config.status: creating src/hnbap/Makefile > config.status: creating src/ranap/Makefile > config.status: creating src/rua/Makefile > config.status: creating src/tests/Makefile > config.status: creating Makefile > config.status: creating include/Makefile > config.status: creating include/osmocom/Makefile > config.status: creating include/osmocom/hnbap/Makefile > config.status: creating include/osmocom/ranap/Makefile > config.status: creating include/osmocom/rua/Makefile > config.status: executing libtool commands > config.status: executing depfiles commands > config.status: executing src/tests/atconfig commands > > ? ls -F src/tests/ > atconfig Makefile test_common.h test-hnbap.ok $(top_srcdir)/ > dummy_cn_sua.c Makefile.am test-helpers.c test-ranap.c > hnb-test.c Makefile.in test-helpers.ok test-ranap.ok > hnb-test.h test_common.c test-hnbap.c testsuite.at > > > Observe '$(top_srcdir)/' in file listing. > > > ? ls -aR src/tests/\$\(top_srcdir\)/ > src/tests/$(top_srcdir)/: > ./ ../ src/ > > src/tests/$(top_srcdir)/src: > ./ ../ .deps/ > > src/tests/$(top_srcdir)/src/.deps: > ./ hnbap_common.Po hnbap_encoder.Po rua_decoder.Po rua_msg_factory.Po > ../ hnbap_decoder.Po rua_common.Po rua_encoder.Po > > > > Please excuse my not trying to verify the bug with the latest sources. To my > knowledge, this bug applies to the latest released version (2.69) and I hope it > will not be an effort to you if the bug is already known to be fixed. > > Thank you for your time! > > ~Neels > > (I am not subscribed to any autoconf ML, hence a Cc to my sender address is > appreciated) -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Wed Feb 17 11:02:24 2016 From: holger at freyther.de (Holger Freyther) Date: Wed, 17 Feb 2016 12:02:24 +0100 Subject: libasn1c config.h In-Reply-To: <20160217105155.GC1232@dub6> References: <20160216120715.GA27266@dub6> <20160217105155.GC1232@dub6> Message-ID: <31B8E505-FF30-4983-802D-9800778F67CE@freyther.de> > On 17 Feb 2016, at 11:51, Neels Hofmeyr wrote: > > If no-one knows any better I'll just commit it and wait for complaints, if > any. nothing in the header should depend on config.h, what we don't know is what depends on an indirect include. Anyway. I believe a public header should not include config.h. holger From nhofmeyr at sysmocom.de Wed Feb 17 13:18:54 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 17 Feb 2016 14:18:54 +0100 Subject: hnb_cs_lu.msc Message-ID: <20160217131854.GA2106@dub6> Hi Harald, in osmo-iuh/doc/hnb_cs_lu.msc I find that after the location update request from the UE, an identity request "should" follow from the CN. Yesterday I made my first pcap using our hNodeB and that weighty black UE we use for testing, and saw that the MSC indeed sends out an identity request at that time [1], however, the UE simply never responds to it. My question: is the hnb_cs_lu.msc declarative and definitely correct, or could it be that in 3G, UEs in general expect authentication first, as the "osmo-iuh/pcap/UPP RANAP.pcap" suggests (starting at packet #335). Since my sources tell me (i.e. Daniel) that an identity request at that time is indeed kinda special practise by openbsc to collect all IMEIs we possibly can, I'm going for authentication first. Just wanted to make sure you agree that the hnb_cs_lu.msc may be erratic in that case. Thanks! ~Neels [1] near openbsc/src/libmsc/gsm_04_08.c:589 (thanks Daniel!) -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 17 14:44:35 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 17 Feb 2016 15:44:35 +0100 Subject: autoreconf v2.69 with subdir-objects: ./configure creates directory 'src/tests/\$(top_srcdir)' In-Reply-To: <56C4742E.7080406@redhat.com> References: <20160114134038.GE1873@dub6> <20160217105527.GD1232@dub6> <56C4742E.7080406@redhat.com> Message-ID: <20160217144435.GD2106@dub6> Eric, you've clarified just about all of my questions. Many thanks for your reply! ~Neels > https://lists.gnu.org/archive/html/automake/2015-12/msg00001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 17 14:47:10 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 17 Feb 2016 15:47:10 +0100 Subject: hnb_cs_lu.msc In-Reply-To: <20160217131854.GA2106@dub6> References: <20160217131854.GA2106@dub6> Message-ID: <20160217144710.GE2106@dub6> Update: it seems that for IuPS/SGSN, a quite identical Identity Request message is indeed answered upon by the UE, so the reason why I'm not receiving one for IuCS/CSCN is unclear. ~Neels On Wed, Feb 17, 2016 at 02:18:54PM +0100, Neels Hofmeyr wrote: > Hi Harald, > > in osmo-iuh/doc/hnb_cs_lu.msc I find that after the location update > request from the UE, an identity request "should" follow from the CN. > > Yesterday I made my first pcap using our hNodeB and that weighty black UE > we use for testing, and saw that the MSC indeed sends out an identity > request at that time [1], however, the UE simply never responds to it. > > My question: is the hnb_cs_lu.msc declarative and definitely correct, or > could it be that in 3G, UEs in general expect authentication first, as > the "osmo-iuh/pcap/UPP RANAP.pcap" suggests (starting at packet #335). > > Since my sources tell me (i.e. Daniel) that an identity request at that > time is indeed kinda special practise by openbsc to collect all IMEIs we > possibly can, I'm going for authentication first. > > Just wanted to make sure you agree that the hnb_cs_lu.msc may be erratic > in that case. Thanks! > > ~Neels > > [1] near openbsc/src/libmsc/gsm_04_08.c:589 (thanks Daniel!) > > -- > - Neels Hofmeyr http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From hwelte at sysmocom.de Wed Feb 17 16:26:52 2016 From: hwelte at sysmocom.de (Harald Welte) Date: Wed, 17 Feb 2016 17:26:52 +0100 Subject: hnb_cs_lu.msc In-Reply-To: <20160217131854.GA2106@dub6> References: <20160217131854.GA2106@dub6> Message-ID: <20160217162652.GU5868@nataraja> Hi Neels, On Wed, Feb 17, 2016 at 02:18:54PM +0100, Neels Hofmeyr wrote: > in osmo-iuh/doc/hnb_cs_lu.msc I find that after the location update > request from the UE, an identity request "should" follow from the CN. it is no 'should at all'. There are some "Common MM Procedures" that can be invoked by MM (on the network side) at any time. This includes, AFAIR: * IDENTITY REQ / RESP * AUTHENTICATION REQ / RESP * MM INFO So the network can at any point in time ask the MS/UE about any of its identities. > Yesterday I made my first pcap using our hNodeB and that weighty black UE > we use for testing, and saw that the MSC indeed sends out an identity > request at that time [1], however, the UE simply never responds to it. OsmoNITB was originally developed as part of security research, and thus we wanted to demonstrate the fact that we can query the IMSI and IMEI of every phone at a very early stage. This is why we always ask for the IMEI, and we ask for the IMSI if we don't already know it (because it was contained in the LU / CM SERV REQ, or because we know the TMSI and can use it to map to the IMSI). If there's no response from the phone, then it's likely something is going wrong somehwere in between. Do you see the request on the RUA interface towards the HNB? What does the HNB logging/tracing tell you about that message? What does a protocol trace on a UE with xgoldmon tell you? > My question: is the hnb_cs_lu.msc declarative and definitely correct, or > could it be that in 3G, UEs in general expect authentication first, as > the "osmo-iuh/pcap/UPP RANAP.pcap" suggests (starting at packet #335). No. There might still be situtaions where the IMSI is not known to the network at LU time, and the network must be able to obtain it via IDENTITY REQUEST before being able to obtain the auth quintuples and perform authentication. What else would you do if you'd get a LU with an unknown TMSI? -- - Harald Welte http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From nhofmeyr at sysmocom.de Thu Feb 18 11:56:20 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 18 Feb 2016 12:56:20 +0100 Subject: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; merging to master Message-ID: <20160218115512.GA2630@dub6> The openbsc branches to use for testing IuPS and IuCS have changed, because Daniel and I have merged the branches. They used to be daniel/gprs-iu (IIRC) and sysmocom/cscn. Both are now merged as: sysmocom/iu Holger, this is relevant to our coverity configuration. We are still using other branches that may or may not be merged to their respective masters. I'd like to publicly record here why or why not we should merge them now. Please add any reasons you know. We're using master for Iu[h|CS|PS] in: libasn1c: * master libosmo-abis: * master libosmocore: * master openggsn: * master osmo-python-tests: * master osmo-iuh: * master Reasons NOT to merge to master in: openbsc: * sysmocom/iu - hardcoded kc and sres for testing - NITB and most probably osmo-bsc are not operational - A-interface not implemented in CSCN asn1c: * aper-prefix - ? libosmo-netif: * sysmocom/sctp - ? libosmo-sccp: * laforge/wip - ? Thanks for any additions... ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Thu Feb 18 18:43:18 2016 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 18 Feb 2016 19:43:18 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> Message-ID: <20160218184318.GW4570@nataraja> Hi Holger, let's move ahead and start with the migration, I can't wait to put all the various tickets into a public redmine. Thanks! -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Thu Feb 18 18:52:55 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 18 Feb 2016 19:52:55 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <20160218184318.GW4570@nataraja> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> Message-ID: <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> > On 18 Feb 2016, at 19:43, Harald Welte wrote: > > Hi Holger, Hi all! > > let's move ahead and start with the migration, I can't wait to put all > the various tickets into a public redmine. last weekend I used the "stock" redmine trac->redmine converter and the result is on projects.osmocom.org. It is not perfect but I think good enough to start moving. We see that certain formating needs a post-import correction but that should be doable by all of us quickly. My plan/timeline (on short notice but I don't expect a major resistence so I hope it is fine): * Patch the redmine importer to not import tickets. This hopefully allows me to import other tracs at the same time (and re-add the security tickets by hand) * Friday evening set the tracs to read-only (I probably move the account file away) * Saturday/Sunday do the migration of the trac. * Make it available on osmocom.org (currently it is projects.osmocom.org) * Keep the trac as read-only version for now In the mid-term: * We need to post-process some pages and move them around to have a better structure * Add permanent redirects from the trac to osmocom.org for "approved" content. This way normal traffic will automatically move to the new page and then we can look at the access.log for which pages still need a re-direct. any objections? holger From holger at freyther.de Thu Feb 18 20:02:42 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 18 Feb 2016 21:02:42 +0100 Subject: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; merging to master In-Reply-To: <20160218115512.GA2630@dub6> References: <20160218115512.GA2630@dub6> Message-ID: > On 18 Feb 2016, at 12:56, Neels Hofmeyr wrote: > > The openbsc branches to use for testing IuPS and IuCS have changed, > because Daniel and I have merged the branches. > > They used to be daniel/gprs-iu (IIRC) and sysmocom/cscn. > Both are now merged as: > > sysmocom/iu > > Holger, this is relevant to our coverity configuration. and the build is broken. /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:126:1: warning: "ENHANCEDRELOCATIONCOMPLETEREQUESTIES_RANAP_EXTENDEDRNC_ID_PRESENT" redefined /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:125:1: warning: this is the location of the previous definition /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:436:1: warning: "RANAP_ENHANCEDRELOCATIONINFORMATIONREQUESTIES_RANAP_IUSIGNALLINGCONNECTIONIDENTIFIER_PRESENT" redefined /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:434:1: warning: this is the location of the previous definition /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:437:1: warning: "RANAP_ENHANCEDRELOCATIONINFORMATIONREQUESTIES_RANAP_GLOBALCN_ID_PRESENT" redefined /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:435:1: warning: this is the location of the previous definition In file included from /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_common.h:592, from /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:7, from iu.c:26: /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:856: error: redefinition of typedef 'RANAP_RAB_SetupOrModifiedItemIEs_t' ../../include/openbsc/iu.h:8: note: previous declaration of 'RANAP_RAB_SetupOrModifiedItemIEs_t' was here In file included from iu.c:31: /home/builder/coverity/install-iuh/include/asn1c/asn1helpers.h: In function 'OCTET_STRING_noalloc': /home/builder/coverity/install-iuh/include/asn1c/asn1helpers.h:26: warning: assignment discards qualifiers from pointer target type iu.c: In function 'ranap_handle_co_rab_ass_resp': iu.c:273: warning: implicit declaration of function 'ranap_free_rab_setupormodifieditemies' make[3]: *** [iu.o] Error 1 make[3]: Leaving directory `/home/builder/coverity/source-iuh/openbsc/openbsc/src/libiu' make[2]: *** [all-recursive] Error 1 make[2]: Leaving directory `/home/builder/coverity/source-iuh/openbsc/openbsc/src' make[1]: *** [all-recursive] Error 1 make[1]: Leaving directory `/home/builder/coverity/source-iuh/openbsc/openbsc' make: *** [all] Error 2 branches used: asn1c * aper-prefix layer1-api * master libasn1c * master libosmo-abis * master libosmo-dsp * master libosmo-netif * sysmocom/sctp libosmo-sccp * laforge/wip libosmocore * master libsmpp34 * master openbsc * sysmocom/iu openggsn * master osmo-bts * master osmo-gmr * master osmo-iuh * master osmo-pcu * master From nhofmeyr at sysmocom.de Thu Feb 18 22:45:44 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 18 Feb 2016 23:45:44 +0100 Subject: sysmocom/iu: your commits from today Message-ID: <20160218224544.GA18542@dub6> Moin Daniel :) (1) About ebd4d820b3b0d7ba5db3b25a14f407d0c7276044 "libiu: Use custom setupormodifieditemies function" It seems you forgot to commit the actual function definition of ranap_decode_rab_setupormodifieditemies_fromlist() I got the caller of it only and thus can't compile as-is. (2) About 38e2f1bca4e43414ed39a938d7c5d8bafe5e8533 " Revert "iu.c: avoid warning by declaring ranap_free_rab_setupormodifieditemies()" There should be no need to silence this warning, the ranap_free_* functions are declared in libranap headers. In any case this will only obscure any real issue. Maybe osmo-iuh was not rebuilt completely (including generation of the c files from the python script). This reverts commit 05ae5b1245f95bf765b42e49af7b2596e013f0a0. " I declared ranap_free_rab_setupormodifieditemies() like that because it is indeed not declared in a header that is installed. Also a grep tells me that no ranap_free_* is found in any osmo-iuh header file at all. I also did a 'make regen' in osmo-iuh/src/ to no avail. By 'libranap headers' I assume you mean libosmo-ranap, or is there a libranap I'm not aware of yet? If the ranap_free_* aren't in headers yet, I agree that they should be. I wanted to silence the warning without being sucked down the rabbit hole of autogenerated asn1 stuff. Any suggestions: more than welcome. (3) In general, I would welcome to see more of your WIP work in publicly visible private branches, maturing as you go and merged to sysmocom/iu once ready. For one, having a backup of your work-in-progress in the git repos makes it harder to lose it due to hardware failure. More important for me though is that I can see what you're up to, e.g. I could possibly find the ranap_..._fromlist() function defintion now. It's of course opening up your "most private" code developments to the outside world, possibly some stupid commits will be seen by one or two hacker peers, but I think it's a healthy premise that we all commit mostly bollocks and all needs refinement anyway... once again: push it! :) Ah, push it Push it good Ah, push it Pu-Push it real good -- Salt N Pepa (1987) As always I'm open to opinions and suggestions... ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 18 22:51:06 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 18 Feb 2016 23:51:06 +0100 Subject: osmo-iuh/src/regen-common-includes.sh Message-ID: <20160218225106.GB18542@dub6> I noticed that osmo-iuh/src/regen-common-includes.sh doesn't do anything useful (anymore). Should it be redirected towards osmo-iuh/include or can we drop it? osmo-iuh/src/regen-common-includes.sh: [[[ #!/bin/sh #for f in `(cd ../asn1/hnbap/asn1c && ls --color=none -1 *.h)`; do echo "#include \"$f\""; done for f in ranap/*.h; do echo "#include \"$f\""; done ]]] Thanks ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 18 23:16:01 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Fri, 19 Feb 2016 00:16:01 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> Message-ID: <20160218231601.GC18542@dub6> On Thu, Feb 18, 2016 at 07:52:55PM +0100, Holger Freyther wrote: > last weekend I used the "stock" redmine trac->redmine converter and the result is on projects.osmocom.org. It is not perfect but I think good enough to start moving. We see that certain formating needs a post-import correction but that should be doable by all of us quickly. I swiftly registered a 'neels' account and as soon as it's granted project memberships, I'd start off by making the overview png visible inline on the OpenBSC wiki page (unless we can automate those somehow). nitpick: I notice that in redmine, the project name "Openbsc" should probably be capitalized ("OpenBSC")? > * Saturday/Sunday do the migration of the trac. was I too quick then? I'll recreate my account again if necessary. > any objections? no problem, since we're all idling around all the time anyway ;) More seriously though, the wiki is on my todo list to explain gtphub and adjust that overview png, also to include Iu. Some day not too far I hope... ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Fri Feb 19 07:09:59 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 08:09:59 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <20160218231601.GC18542@dub6> References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> <20160218231601.GC18542@dub6> Message-ID: > On 19 Feb 2016, at 00:16, Neels Hofmeyr wrote: > > > nitpick: I notice that in redmine, the project name "Openbsc" should > probably be capitalized ("OpenBSC")? The redmine importer insists only works if I enter "openbsc" and then it apparently does "Openbsc" with it. But we can fix that after the import. >> * Saturday/Sunday do the migration of the trac. > > was I too quick then? I'll recreate my account again if necessary. I think we do not need to remove accounts. We might have to fix the email address of contributors that got their account automatically created as part of the import. > >> any objections? > > no problem, since we're all idling around all the time anyway ;) > More seriously though, the wiki is on my todo list to explain gtphub and > adjust that overview png, also to include Iu. Some day not too far I hope... The wiki conversion is not that great. We really have to do some work in post processing and making sure that all content has been migrated. E.g. "Software/Overview" and "SoftwareOverview" seem to confuse the importer: http://projects.osmocom.org/projects/baseband/wiki/SoftwareOverview vs. http://bb.osmocom.org/trac/wiki/Software/Overview vs. http://bb.osmocom.org/trac/wiki/SoftwareOverview So there will be some fallout but I think it still makes sense to move forward now. holger From hwelte at sysmocom.de Fri Feb 19 07:26:28 2016 From: hwelte at sysmocom.de (Harald Welte) Date: Fri, 19 Feb 2016 08:26:28 +0100 Subject: osmo-iuh/src/regen-common-includes.sh In-Reply-To: <20160218225106.GB18542@dub6> References: <20160218225106.GB18542@dub6> Message-ID: <20160219072628.GX4570@nataraja> On Thu, Feb 18, 2016 at 11:51:06PM +0100, Neels Hofmeyr wrote: > I noticed that osmo-iuh/src/regen-common-includes.sh doesn't do anything > useful (anymore). Should it be redirected towards osmo-iuh/include or can > we drop it? we certainly don't want to drop it. There could be reasons to modify the asn.1 source, or to update to a later version of it. -- - Harald Welte http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From axilirator at gmail.com Fri Feb 19 08:08:12 2016 From: axilirator at gmail.com (=?UTF-8?B?0JLQsNC00LjQvCDQr9C90LjRhtC60LjQuQ==?=) Date: Fri, 19 Feb 2016 14:08:12 +0600 Subject: Moving from trac to a single redmine Message-ID: Hi all! Moving all projects to a Redmine is a good way, I think. In connection with the event I would like to offer my help with post-processing some old pages (mostly OsmocomBB) and with improving the new wiki structure. So, my suggestions: - Create the main page that will describe all all of the child projects of Osmocom umbrella including recent news and plans. - Separate the libosmocore related pages from OsmocomBB into a new section named "Libraries", for example. - Separate both SIMTrace and softSIM into a new sections. It it would be nice to enable Strict-Transport-Security to avoid some traffic interception attempts. Also what about enabling SPF and DKIM for mailing lists? With best regards, Vadim Yanitskiy. 2016-02-19 4:46 GMT+06:00 : > Send OpenBSC mailing list submissions to > openbsc at lists.osmocom.org > > To subscribe or unsubscribe via the World Wide Web, visit > https://lists.osmocom.org/mailman/listinfo/openbsc > or, via email, send a message with subject or body 'help' to > openbsc-request at lists.osmocom.org > > You can reach the person managing the list at > openbsc-owner at lists.osmocom.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of OpenBSC digest..." > > > Today's Topics: > > 1. Re: autoreconf v2.69 with subdir-objects: ./configure creates > directory 'src/tests/\$(top_srcdir)' (Neels Hofmeyr) > 2. Re: hnb_cs_lu.msc (Neels Hofmeyr) > 3. Re: hnb_cs_lu.msc (Harald Welte) > 4. branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; > merging to master (Neels Hofmeyr) > 5. Re: Moving from trac to a single redmine (Harald Welte) > 6. Re: Moving from trac to a single redmine (Holger Freyther) > 7. Re: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; > merging to master (Holger Freyther) > 8. sysmocom/iu: your commits from today (Neels Hofmeyr) > > > ---------------------------------------------------------------------- > > Message: 1 > Date: Wed, 17 Feb 2016 15:44:35 +0100 > From: Neels Hofmeyr > To: Eric Blake > Cc: bug-autoconf at gnu.org, openbsc at lists.osmocom.org > Subject: Re: autoreconf v2.69 with subdir-objects: ./configure creates > directory 'src/tests/\$(top_srcdir)' > Message-ID: <20160217144435.GD2106 at dub6> > Content-Type: text/plain; charset="us-ascii" > > Eric, > > you've clarified just about all of my questions. > Many thanks for your reply! > > ~Neels > > > https://lists.gnu.org/archive/html/automake/2015-12/msg00001.html > -------------- next part -------------- > A non-text attachment was scrubbed... > Name: signature.asc > Type: application/pgp-signature > Size: 819 bytes > Desc: Digital signature > URL: < > http://lists.osmocom.org/pipermail/openbsc/attachments/20160217/8d3fdbf8/attachment-0001.bin > > > > ------------------------------ > > Message: 2 > Date: Wed, 17 Feb 2016 15:47:10 +0100 > From: Neels Hofmeyr > To: Harald Welte > Cc: openbsc at lists.osmocom.org > Subject: Re: hnb_cs_lu.msc > Message-ID: <20160217144710.GE2106 at dub6> > Content-Type: text/plain; charset="iso-8859-1" > > Update: it seems that for IuPS/SGSN, a quite identical Identity Request > message is indeed answered upon by the UE, so the reason why I'm not > receiving one for IuCS/CSCN is unclear. > > ~Neels > > On Wed, Feb 17, 2016 at 02:18:54PM +0100, Neels Hofmeyr wrote: > > Hi Harald, > > > > in osmo-iuh/doc/hnb_cs_lu.msc I find that after the location update > > request from the UE, an identity request "should" follow from the CN. > > > > Yesterday I made my first pcap using our hNodeB and that weighty black UE > > we use for testing, and saw that the MSC indeed sends out an identity > > request at that time [1], however, the UE simply never responds to it. > > > > My question: is the hnb_cs_lu.msc declarative and definitely correct, or > > could it be that in 3G, UEs in general expect authentication first, as > > the "osmo-iuh/pcap/UPP RANAP.pcap" suggests (starting at packet #335). > > > > Since my sources tell me (i.e. Daniel) that an identity request at that > > time is indeed kinda special practise by openbsc to collect all IMEIs we > > possibly can, I'm going for authentication first. > > > > Just wanted to make sure you agree that the hnb_cs_lu.msc may be erratic > > in that case. Thanks! > > > > ~Neels > > > > [1] near openbsc/src/libmsc/gsm_04_08.c:589 (thanks Daniel!) > > > > -- > > - Neels Hofmeyr http://www.sysmocom.de/ > > ======================================================================= > > * sysmocom - systems for mobile communications GmbH > > * Alt-Moabit 93 > > * 10559 Berlin, Germany > > * Sitz / Registered office: Berlin, HRB 134158 B > > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte > > > > -- > - Neels Hofmeyr http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte > -------------- next part -------------- > A non-text attachment was scrubbed... > Name: signature.asc > Type: application/pgp-signature > Size: 819 bytes > Desc: Digital signature > URL: < > http://lists.osmocom.org/pipermail/openbsc/attachments/20160217/7dbd36fd/attachment-0001.bin > > > > ------------------------------ > > Message: 3 > Date: Wed, 17 Feb 2016 17:26:52 +0100 > From: Harald Welte > To: Neels Hofmeyr > Cc: openbsc at lists.osmocom.org > Subject: Re: hnb_cs_lu.msc > Message-ID: <20160217162652.GU5868 at nataraja> > Content-Type: text/plain; charset=us-ascii > > Hi Neels, > > On Wed, Feb 17, 2016 at 02:18:54PM +0100, Neels Hofmeyr wrote: > > in osmo-iuh/doc/hnb_cs_lu.msc I find that after the location update > > request from the UE, an identity request "should" follow from the CN. > > it is no 'should at all'. There are some "Common MM Procedures" that > can be invoked by MM (on the network side) at any time. This includes, > AFAIR: > * IDENTITY REQ / RESP > * AUTHENTICATION REQ / RESP > * MM INFO > > So the network can at any point in time ask the MS/UE about any of its > identities. > > > Yesterday I made my first pcap using our hNodeB and that weighty black UE > > we use for testing, and saw that the MSC indeed sends out an identity > > request at that time [1], however, the UE simply never responds to it. > > OsmoNITB was originally developed as part of security research, and thus > we wanted to demonstrate the fact that we can query the IMSI and IMEI of > every phone at a very early stage. This is why we always ask for the > IMEI, and we ask for the IMSI if we don't already know it (because it > was contained in the LU / CM SERV REQ, or because we know the TMSI and > can use it to map to the IMSI). > > If there's no response from the phone, then it's likely something is > going wrong somehwere in between. Do you see the request on the RUA > interface towards the HNB? What does the HNB logging/tracing tell you > about that message? What does a protocol trace on a UE with xgoldmon > tell you? > > > My question: is the hnb_cs_lu.msc declarative and definitely correct, or > > could it be that in 3G, UEs in general expect authentication first, as > > the "osmo-iuh/pcap/UPP RANAP.pcap" suggests (starting at packet #335). > > No. There might still be situtaions where the IMSI is not known to the > network at LU time, and the network must be able to obtain it via > IDENTITY REQUEST before being able to obtain the auth quintuples and > perform authentication. > > What else would you do if you'd get a LU with an unknown TMSI? > > -- > - Harald Welte http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte > > > ------------------------------ > > Message: 4 > Date: Thu, 18 Feb 2016 12:56:20 +0100 > From: Neels Hofmeyr > To: openbsc at lists.osmocom.org > Subject: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; > merging to master > Message-ID: <20160218115512.GA2630 at dub6> > Content-Type: text/plain; charset="iso-8859-1" > > The openbsc branches to use for testing IuPS and IuCS have changed, > because Daniel and I have merged the branches. > > They used to be daniel/gprs-iu (IIRC) and sysmocom/cscn. > Both are now merged as: > > sysmocom/iu > > Holger, this is relevant to our coverity configuration. > > > We are still using other branches that may or may not be merged to their > respective masters. I'd like to publicly record here why or why not we > should merge them now. Please add any reasons you know. > > We're using master for Iu[h|CS|PS] in: > > libasn1c: * master > libosmo-abis: * master > libosmocore: * master > openggsn: * master > osmo-python-tests: * master > osmo-iuh: * master > > Reasons NOT to merge to master in: > > openbsc: * sysmocom/iu > - hardcoded kc and sres for testing > - NITB and most probably osmo-bsc are not operational > - A-interface not implemented in CSCN > > asn1c: * aper-prefix > - ? > > libosmo-netif: * sysmocom/sctp > - ? > > libosmo-sccp: * laforge/wip > - ? > > Thanks for any additions... > > ~Neels > > -- > - Neels Hofmeyr http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte > -------------- next part -------------- > A non-text attachment was scrubbed... > Name: signature.asc > Type: application/pgp-signature > Size: 819 bytes > Desc: Digital signature > URL: < > http://lists.osmocom.org/pipermail/openbsc/attachments/20160218/3f7a1c48/attachment-0001.bin > > > > ------------------------------ > > Message: 5 > Date: Thu, 18 Feb 2016 19:43:18 +0100 > From: Harald Welte > To: Holger Freyther > Cc: baseband-devel at lists.osmocom.org, OpenBSC Mailing List > , osmocom-sdr at lists.osmocom.org, > gmr at lists.osmocom.org > Subject: Re: Moving from trac to a single redmine > Message-ID: <20160218184318.GW4570 at nataraja> > Content-Type: text/plain; charset=us-ascii > > Hi Holger, > > let's move ahead and start with the migration, I can't wait to put all > the various tickets into a public redmine. > > Thanks! > -- > - Harald Welte > http://laforge.gnumonks.org/ > > ============================================================================ > "Privacy in residential applications is a desirable marketing option." > (ETSI EN 300 175-7 Ch. > A6) > > > ------------------------------ > > Message: 6 > Date: Thu, 18 Feb 2016 19:52:55 +0100 > From: Holger Freyther > To: baseband-devel at lists.osmocom.org, OpenBSC Mailing List > , osmocom-sdr at lists.osmocom.org, > gmr at lists.osmocom.org > Subject: Re: Moving from trac to a single redmine > Message-ID: <753DCDAF-0723-4EC5-8E3C-870B7D5959C5 at freyther.de> > Content-Type: text/plain; charset=us-ascii > > > > On 18 Feb 2016, at 19:43, Harald Welte wrote: > > > > Hi Holger, > > Hi all! > > > > > > let's move ahead and start with the migration, I can't wait to put all > > the various tickets into a public redmine. > > > last weekend I used the "stock" redmine trac->redmine converter and the > result is on projects.osmocom.org. It is not perfect but I think good > enough to start moving. We see that certain formating needs a post-import > correction but that should be doable by all of us quickly. > > My plan/timeline (on short notice but I don't expect a major resistence so > I hope it is fine): > > * Patch the redmine importer to not import tickets. This hopefully allows > me to import other tracs at the same time (and re-add the security tickets > by hand) > * Friday evening set the tracs to read-only (I probably move the account > file away) > * Saturday/Sunday do the migration of the trac. > * Make it available on osmocom.org (currently it is projects.osmocom.org) > * Keep the trac as read-only version for now > > In the mid-term: > > * We need to post-process some pages and move them around to have a better > structure > * Add permanent redirects from the trac to osmocom.org for "approved" > content. This way normal traffic will automatically move to the new page > and then we can look at the access.log for which pages still need a > re-direct. > > > > any objections? > > holger > > > > ------------------------------ > > Message: 7 > Date: Thu, 18 Feb 2016 21:02:42 +0100 > From: Holger Freyther > To: Neels Hofmeyr > Cc: openbsc at lists.osmocom.org > Subject: Re: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; > merging to master > Message-ID: > Content-Type: text/plain; charset=iso-8859-1 > > > > On 18 Feb 2016, at 12:56, Neels Hofmeyr wrote: > > > > The openbsc branches to use for testing IuPS and IuCS have changed, > > because Daniel and I have merged the branches. > > > > They used to be daniel/gprs-iu (IIRC) and sysmocom/cscn. > > Both are now merged as: > > > > sysmocom/iu > > > > Holger, this is relevant to our coverity configuration. > > and the build is broken. > > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:126:1: > warning: > "ENHANCEDRELOCATIONCOMPLETEREQUESTIES_RANAP_EXTENDEDRNC_ID_PRESENT" > redefined > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:125:1: > warning: this is the location of the previous definition > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:436:1: > warning: > "RANAP_ENHANCEDRELOCATIONINFORMATIONREQUESTIES_RANAP_IUSIGNALLINGCONNECTIONIDENTIFIER_PRESENT" > redefined > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:434:1: > warning: this is the location of the previous definition > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:437:1: > warning: > "RANAP_ENHANCEDRELOCATIONINFORMATIONREQUESTIES_RANAP_GLOBALCN_ID_PRESENT" > redefined > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:435:1: > warning: this is the location of the previous definition > In file included from > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_common.h:592, > from > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:7, > from iu.c:26: > /home/builder/coverity/install-iuh/include/osmocom/ranap/ranap_ies_defs.h:856: > error: redefinition of typedef 'RANAP_RAB_SetupOrModifiedItemIEs_t' > ../../include/openbsc/iu.h:8: note: previous declaration of > 'RANAP_RAB_SetupOrModifiedItemIEs_t' was here > In file included from iu.c:31: > /home/builder/coverity/install-iuh/include/asn1c/asn1helpers.h: In > function 'OCTET_STRING_noalloc': > /home/builder/coverity/install-iuh/include/asn1c/asn1helpers.h:26: > warning: assignment discards qualifiers from pointer target type > iu.c: In function 'ranap_handle_co_rab_ass_resp': > iu.c:273: warning: implicit declaration of function > 'ranap_free_rab_setupormodifieditemies' > make[3]: *** [iu.o] Error 1 > make[3]: Leaving directory > `/home/builder/coverity/source-iuh/openbsc/openbsc/src/libiu' > make[2]: *** [all-recursive] Error 1 > make[2]: Leaving directory > `/home/builder/coverity/source-iuh/openbsc/openbsc/src' > make[1]: *** [all-recursive] Error 1 > make[1]: Leaving directory > `/home/builder/coverity/source-iuh/openbsc/openbsc' > make: *** [all] Error 2 > > branches used: > > asn1c > * aper-prefix > layer1-api > * master > libasn1c > * master > libosmo-abis > * master > libosmo-dsp > * master > libosmo-netif > * sysmocom/sctp > libosmo-sccp > * laforge/wip > libosmocore > * master > libsmpp34 > * master > openbsc > * sysmocom/iu > openggsn > * master > osmo-bts > * master > osmo-gmr > * master > osmo-iuh > * master > osmo-pcu > * master > > ------------------------------ > > Message: 8 > Date: Thu, 18 Feb 2016 23:45:44 +0100 > From: Neels Hofmeyr > To: Daniel Willmann > Cc: openbsc at lists.osmocom.org > Subject: sysmocom/iu: your commits from today > Message-ID: <20160218224544.GA18542 at dub6> > Content-Type: text/plain; charset="iso-8859-1" > > Moin Daniel :) > > (1) > About ebd4d820b3b0d7ba5db3b25a14f407d0c7276044 > "libiu: Use custom setupormodifieditemies function" > > It seems you forgot to commit the actual function definition of > ranap_decode_rab_setupormodifieditemies_fromlist() > I got the caller of it only and thus can't compile as-is. > > > (2) > About 38e2f1bca4e43414ed39a938d7c5d8bafe5e8533 > " > Revert "iu.c: avoid warning by declaring > ranap_free_rab_setupormodifieditemies()" > > There should be no need to silence this warning, the ranap_free_* > functions are declared in libranap headers. In any case this will only > obscure any real issue. Maybe osmo-iuh was not rebuilt completely > (including generation of the c files from the python script). > > This reverts commit 05ae5b1245f95bf765b42e49af7b2596e013f0a0. > " > > I declared ranap_free_rab_setupormodifieditemies() like that because it is > indeed not declared in a header that is installed. Also a grep tells me > that no ranap_free_* is found in any osmo-iuh header file at all. > I also did a 'make regen' in osmo-iuh/src/ to no avail. > By 'libranap headers' I assume you mean libosmo-ranap, or is there a > libranap I'm not aware of yet? > > If the ranap_free_* aren't in headers yet, I agree that they should be. I > wanted to silence the warning without being sucked down the rabbit hole of > autogenerated asn1 stuff. Any suggestions: more than welcome. > > > (3) > In general, I would welcome to see more of your WIP work in publicly > visible private branches, maturing as you go and merged to sysmocom/iu > once ready. For one, having a backup of your work-in-progress in the git > repos makes it harder to lose it due to hardware failure. More important > for me though is that I can see what you're up to, e.g. I could possibly > find the ranap_..._fromlist() function defintion now. It's of course > opening up your "most private" code developments to the outside world, > possibly some stupid commits will be seen by one or two hacker peers, but > I think it's a healthy premise that we all commit mostly bollocks and all > needs refinement anyway... once again: push it! :) > > > Ah, push it > Push it good > Ah, push it > Pu-Push it real good > -- Salt N Pepa (1987) > > > As always I'm open to opinions and suggestions... > > ~Neels > > > -- > - Neels Hofmeyr http://www.sysmocom.de/ > ======================================================================= > * sysmocom - systems for mobile communications GmbH > * Alt-Moabit 93 > * 10559 Berlin, Germany > * Sitz / Registered office: Berlin, HRB 134158 B > * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte > -------------- next part -------------- > A non-text attachment was scrubbed... > Name: signature.asc > Type: application/pgp-signature > Size: 819 bytes > Desc: Digital signature > URL: < > http://lists.osmocom.org/pipermail/openbsc/attachments/20160218/e2656577/attachment.bin > > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > OpenBSC mailing list > OpenBSC at lists.osmocom.org > https://lists.osmocom.org/mailman/listinfo/openbsc > > > ------------------------------ > > End of OpenBSC Digest, Vol 16, Issue 19 > *************************************** > -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Fri Feb 19 08:16:05 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 19 Feb 2016 09:16:05 +0100 Subject: hnbgw should reconnect to CN In-Reply-To: <20160210214720.GA9755@dub6> References: <20160210214720.GA9755@dub6> Message-ID: <20160219081605.GZ4570@nataraja> Hi Neels, sorry for the late response, On Wed, Feb 10, 2016 at 10:47:20PM +0100, Neels Hofmeyr wrote: > I did find that much: the reconnect flag passed to > osmo_stream_cli_open2() > is effective only while state == STREAM_CLI_STATE_CONNECTING, i.e. until a > first connection is established. Now, if upon disconnect, something were > to set the state back to > cli->state = STREAM_CLI_STATE_CONNECTING > my guess is that the cli_timer_cb() would indeed attempt to reconnect as I > intend. the function osmo_stream_cli_reconnect() should be called in all cases where the connection is determined dead. It then re-starts the timer and re-sets the state to STREAM_CLI_STATE_CONNECTING, i.e. does exactly what you wrote above. It is called * if sctp_send() / send() returns a negative value * if getsockopt() return an error * if recv() returns a negative value * if recv() returns zero Which I would consider a comprehensive list of the cases where the connection is gone. A [sctp_]send() return value of zero would mean that the window is stalled and our local send buffer is exceeded. That's not equal to the connection beign lost or disconnected. In general, the bst way to debug this kind of issue is to use ltrace or strace to see what's happening in terms of the system calls on the SCTP client socket when provoking such a situation. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Fri Feb 19 08:35:19 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 19 Feb 2016 09:35:19 +0100 Subject: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; merging to master In-Reply-To: <20160218115512.GA2630@dub6> References: <20160218115512.GA2630@dub6> Message-ID: <20160219083519.GA4570@nataraja> Hi Neels, On Thu, Feb 18, 2016 at 12:56:20PM +0100, Neels Hofmeyr wrote: > Reasons NOT to merge to master in: > > asn1c: * aper-prefix > - ? If you look at the aper code I took from OpenAirInterface and re-based, you will see that it does not look 100% complete and would probably not yet qualify for submitting it to the upstream asn1c project. The situation is not made better by my hackish way to implement the type prefixing on top of it by means of an environment variable. Specifically, it * contains commented-out code which might just have been a work-around of some buggy code, rather than fit for removal in general * contains TODO comments like "/* TODO: act upon NOTE in #18.7 for canonical PER */" which hints that it is not properly implementing parts of the PER specification * contrary to the rest of asn1c, it does not come with a comprehensive test suiet for the APER encoding and decoding routines of all types Any help in cleaning this code up (it could be done for the type prefixing independent of the APER support) would be much appreciated. The goal is to get this merged in asn1c, after all. It might also be worth to contact the OpenAirInterface guys about their thoughts on moving this code forward. I fear there might be none, as they are using an ancient version of asn1c to begin with. But they are a much larger project and might be convinced to put some resources on doing this properly? Unless we think something is ready for pushing to upstream asn1c, we should keep it out of our local master, too. > libosmo-netif: * sysmocom/sctp > - ? I pushed one of the two commits to master. However, commit 89118114972d587f623305e410d45eb934900e81 basically just prints some messages to the log file in case there are association state changes like UP and LOST. This is clearly not the intended behavior. The application should be notified accordintly in such events, particularly in 'connection lost' events that can be communicated in the same way as they can for e.g. TCP sockets. Only after that is resolved, we can merge it to master. > libosmo-sccp: * laforge/wip > - ? My main problem with this patch set is naming. We are creating an 'SCCP User SAP' which should look the same no matter what the underlying transport protocol stacking is. Whether it's SUA/SCTP/IP or SCCP/M3UA/SCTP/IP or SCCP/MTP3/M2UA/SCTP/IP or SCCP/MTP3/MTP2/E1 or SCCP/MTP3/MTP2/M2PA/SCTP/IP should not matter to the application. The sccp_sap.h data structures still follow that rule. However the sua.h code (creating a SUA client or server, 'struct osmo_sua_user / struct osmo_sua_link' directly reference SUA. In terms of the function names I don't care really too much, as inevitably an application will somehow need to specify the protocol stacking it would like to use. Either explicitly or implicitly via system-level configuration of the signalling stack. However, the application should not have to keep an 'osmo_sua_user' pointer or an 'osmo_sua_link' pointer in its own data structures. It should be an opaque osmo_sccp_user / osmo_sccp_link structure, so once we change from one underlying stacking to another, the data structures of the application do not have to change. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Fri Feb 19 11:36:29 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 12:36:29 +0100 Subject: Moving from trac to a single redmine In-Reply-To: References: Message-ID: <80FDBDBD-2B0E-46EC-B751-AE47B3CF1F87@freyther.de> > On 19 Feb 2016, at 09:08, ????? ??????? wrote: > > Hi all! > > So, my suggestions: > - Create the main page that will describe all all of the child projects > of Osmocom umbrella including recent news and plans. > - Separate the libosmocore related pages from OsmocomBB > into a new section named "Libraries", for example. > - Separate both SIMTrace and softSIM into a new sections. yes, we can have separate projects for them now and should do it. I don't think we can move wiki pages from one project to another but we should be able to somehow add redirects. I intend to add one more wiki plugin to have table of contents and other features we are used to from trac. > It it would be nice to enable Strict-Transport-Security to avoid > some traffic interception attempts. Also what about enabling > SPF and DKIM for mailing lists? projects.osmocom.org is using "Let's encrypt". Do you have a guide HSTS with nginx? SPF/DKIM: The only SPF record I ever wrote was to allow everyone send mail for one of my domains to please outlook.com. What is improved by having only two systems that are allowed to send for lists.osmocom.org? From axilirator at gmail.com Fri Feb 19 13:18:15 2016 From: axilirator at gmail.com (=?UTF-8?B?0JLQsNC00LjQvCDQr9C90LjRhtC60LjQuQ==?=) Date: Fri, 19 Feb 2016 19:18:15 +0600 Subject: Moving from trac to a single redmine In-Reply-To: <80FDBDBD-2B0E-46EC-B751-AE47B3CF1F87@freyther.de> References: <80FDBDBD-2B0E-46EC-B751-AE47B3CF1F87@freyther.de> Message-ID: > > Do you have a guide HSTS with nginx? It can be easily enabled adding this string at the Nginx config in the server section: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; SPF/DKIM: The only SPF record I ever wrote was to allow everyone send mail > for one of my domains to please outlook.com. What is improved by having > only two systems that are allowed to send for lists.osmocom.org? I think that SPF record will no limit anybody to send mails for lists.osmocom.org, but vice versa. I wrote about that because sometimes the digests and subscription messages marked as spam. ? ?????????? ???????????, ??????? ?????. 2016-02-19 17:36 GMT+06:00 Holger Freyther : > > > On 19 Feb 2016, at 09:08, ????? ??????? wrote: > > > > Hi all! > > > > > > So, my suggestions: > > - Create the main page that will describe all all of the child projects > > of Osmocom umbrella including recent news and plans. > > - Separate the libosmocore related pages from OsmocomBB > > into a new section named "Libraries", for example. > > - Separate both SIMTrace and softSIM into a new sections. > > yes, we can have separate projects for them now and should do it. I don't > think we can move wiki pages from one project to another but we should be > able to somehow add redirects. > > I intend to add one more wiki plugin to have table of contents and other > features we are used to from trac. > > > > > It it would be nice to enable Strict-Transport-Security to avoid > > some traffic interception attempts. Also what about enabling > > SPF and DKIM for mailing lists? > > > projects.osmocom.org is using "Let's encrypt". Do you have a guide HSTS > with nginx? > > SPF/DKIM: The only SPF record I ever wrote was to allow everyone send mail > for one of my domains to please outlook.com. What is improved by having > only two systems that are allowed to send for lists.osmocom.org? > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dwillmann at sysmocom.de Fri Feb 19 16:03:41 2016 From: dwillmann at sysmocom.de (Daniel Willmann) Date: Fri, 19 Feb 2016 17:03:41 +0100 Subject: sysmocom/iu: your commits from today In-Reply-To: <20160218224544.GA18542@dub6> (sfid-20160218_234634_678316_2F2A7AD6) References: <20160218224544.GA18542@dub6> (sfid-20160218_234634_678316_2F2A7AD6) Message-ID: <1455897821.8409.12.camel@sysmocom.de> Hey Neels, On Thu, 2016-02-18 at 23:45 +0100, Neels Hofmeyr wrote: > Moin Daniel :) > > (1) > About ebd4d820b3b0d7ba5db3b25a14f407d0c7276044 > "libiu: Use custom setupormodifieditemies function" > > It seems you forgot to commit the actual function definition of > ranap_decode_rab_setupormodifieditemies_fromlist() > I got the caller of it only and thus can't compile as-is. osmo-iuh commit 635fac0c3eef has both the function and the declaration. > (2) > About 38e2f1bca4e43414ed39a938d7c5d8bafe5e8533 > " > Revert "iu.c: avoid warning by declaring ranap_free_rab_setupormodifieditemies()" > > There should be no need to silence this warning, the ranap_free_* > functions are declared in libranap headers. In any case this will only > obscure any real issue. Maybe osmo-iuh was not rebuilt completely > (including generation of the c files from the python script). > > This reverts commit 05ae5b1245f95bf765b42e49af7b2596e013f0a0. > " > > I declared ranap_free_rab_setupormodifieditemies() like that because it again) to add the function declarations to the ies_defs.h file.is > indeed not declared in a header that is installed. Also a grep tells me > that no ranap_free_* is found in any osmo-iuh header file at all. > I also did a 'make regen' in osmo-iuh/src/ to no avail. > By 'libranap headers' I assume you mean libosmo-ranap, or is there a > libranap I'm not aware of yet? > If the ranap_free_* aren't in headers yet, I agree that they should be. I > wanted to silence the warning without being sucked down the rabbit hole of > autogenerated asn1 stuff. Any suggestions: more than welcome. Bummer, you're right. It seems the script doesn't generate the free() declarations. I'll fix that. > (3) > I think it's a healthy premise that we all commit mostly bollocks and all > needs refinement anyway... once again: push it! :) Yeah, well, this time I did ;-) -- - Daniel Willmann http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From msuraev at sysmocom.de Fri Feb 19 18:17:54 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Fri, 19 Feb 2016 19:17:54 +0100 Subject: [PATCH] Extend L1SAP PH-DATA with presence information Message-ID: <1455905874-14883-1-git-send-email-msuraev@sysmocom.de> From: Max Previously the presence of header and data blocks were communicated in-band which decreases code readability and makes it unnecessary hard to add support for new hardware. Note: both OsmoBTS and OsmoPCU have to be modified to take advantage of extended ph_data_param structure. --- include/osmocom/gsm/l1sap.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/osmocom/gsm/l1sap.h b/include/osmocom/gsm/l1sap.h index 9f3fe98..1af8ba8 100644 --- a/include/osmocom/gsm/l1sap.h +++ b/include/osmocom/gsm/l1sap.h @@ -25,6 +25,16 @@ enum osmo_mph_info_type { PRIM_INFO_DEACT_CIPH, /*!< \brief Deactivation of ciphering */ }; +/*! \brief PH-DATA presence information */ +enum osmo_ph_pres_info_type { + PRES_INFO_INVALID = 0, /*!< \brief Data is invalid */ + PRES_INFO_HEADER = 1, /*!< \brief Only header is present and valid */ + PRES_INFO_FIRST = 3, /*!< \brief First half of data + header are valid (2nd half may be present but invalid) */ + PRES_INFO_SECOND = 5, /*!< \brief Second half of data + header are valid (1st halfmay be present but invalid) */ + PRES_INFO_BOTH = 7, /*!< \brief Both parts + header are present and valid */ + PRES_INFO_UNKNOWN +}; + /*! \brief for PH-RANDOM_ACCESS.req */ struct ph_rach_req_param { uint8_t ra; /*!< \brief Random Access */ @@ -48,6 +58,7 @@ struct ph_data_param { uint8_t chan_nr; /*!< \brief Channel Number (Like RSL) */ uint32_t fn; /*!< \brief GSM Frame Number */ int8_t rssi; /*!< \brief RSSI of receivedindication */ + enum osmo_ph_pres_info_type pdch_presence_info; /*!< \brief Info regarding presence/validity of header and data parts */ }; /*! \brief for TCH.{req,ind} | TCH-RTS.ind */ -- 2.7.1 From msuraev at sysmocom.de Fri Feb 19 18:20:13 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Fri, 19 Feb 2016 19:20:13 +0100 Subject: [PATCH 2/3] Introduce --gsmtap-ip/-i option In-Reply-To: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> References: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> Message-ID: <1455906014-14949-2-git-send-email-msuraev@sysmocom.de> From: Max his option allows user to use custom IP address instead of default "localhost". Correspondingly gsmtap init moved from sysmoBTS-specific code up to "bts" struct level. This way it can be easier reused by other implementations. Signed-off-by: Max --- src/bts.h | 2 ++ src/pcu_l1_if.cpp | 5 +++-- src/pcu_main.cpp | 20 ++++++++++++++++++-- src/sysmo_l1_if.c | 6 ++---- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/bts.h b/src/bts.h index 45432ea..2b69023 100644 --- a/src/bts.h +++ b/src/bts.h @@ -27,6 +27,7 @@ extern "C" { #include #include #include +#include } #include "poll_controller.h" @@ -168,6 +169,7 @@ struct gprs_rlcmac_bts { uint8_t n3101; uint8_t n3103; uint8_t n3105; + struct gsmtap_inst *gsmtap; struct gprs_rlcmac_trx trx[8]; int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 9d7dbee..e816e6f 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -42,7 +42,7 @@ extern "C" { // FIXME: move this, when changed from c++ to c. extern "C" { -void *l1if_open_pdch(void *priv, uint32_t hlayer1); +void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap); int l1if_connect_pdch(void *obj, uint8_t ts); int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); @@ -436,7 +436,8 @@ bssgp_failed: if (!bts->trx[trx].fl1h) bts->trx[trx].fl1h = l1if_open_pdch( (void *)trx, - info_ind->trx[trx].hlayer1); + info_ind->trx[trx].hlayer1, + bts->gsmtap); if (!bts->trx[trx].fl1h) { LOGP(DL1IF, LOGL_FATAL, "Failed to open direct " "DSP access for PDCH.\n"); diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 96dc6d7..4065d71 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -33,6 +33,8 @@ extern "C" { #include #include #include +#include +#include } extern struct gprs_nsvc *nsvc; @@ -44,6 +46,7 @@ void *tall_pcu_ctx; extern void *bv_tall_ctx; static int quit = 0; static int rt_prio = -1; +static char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead static void print_help() { @@ -58,10 +61,11 @@ static void print_help() " -V --version print version\n" " -r --realtime PRIO Use SCHED_RR with the specified " "priority\n" + " -i --gsmtap-ip The destination IP used for GSMTAP.\n" ); } -/* FIXME: finally get some option parsing code into libosmocore */ +/* FIXME: finally try using gengetopt */ static void handle_options(int argc, char **argv) { while (1) { @@ -74,10 +78,11 @@ static void handle_options(int argc, char **argv) { "version", 0, 0, 'V' }, { "realtime", 1, 0, 'r' }, { "exit", 0, 0, 'e' }, + { "gsmtap-ip", 1, 0, 'i' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "hc:m:n:Vr:e", + c = getopt_long(argc, argv, "hc:m:n:Vr:e:i:", long_options, &option_idx); if (c == -1) break; @@ -102,6 +107,9 @@ static void handle_options(int argc, char **argv) print_version(1); exit(0); break; + case 'i': + gsmtap_addr = optarg; + break; case 'r': rt_prio = atoi(optarg); break; @@ -212,6 +220,14 @@ int main(int argc, char *argv[]) exit(0); } + bts->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1); + + if (bts->gsmtap) { + gsmtap_source_add_sink(bts->gsmtap); + } else { + fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr); + } + rc = vty_read_config_file(config_file, NULL); if (rc < 0 && config_given) { fprintf(stderr, "Failed to parse the config file: '%s'\n", diff --git a/src/sysmo_l1_if.c b/src/sysmo_l1_if.c index 8572786..c7c54dd 100644 --- a/src/sysmo_l1_if.c +++ b/src/sysmo_l1_if.c @@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, return 0; } -void *l1if_open_pdch(void *priv, uint32_t hlayer1) +void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) { struct femtol1_hdl *fl1h; int rc; @@ -378,9 +378,7 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1) return NULL; } - fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1); - if (fl1h->gsmtap) - gsmtap_source_add_sink(fl1h->gsmtap); + fl1h->gsmtap = gsmtap; return fl1h; } -- 2.7.1 From msuraev at sysmocom.de Fri Feb 19 18:20:12 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Fri, 19 Feb 2016 19:20:12 +0100 Subject: [PATCH 1/3] Ignore files generated by cscope tool Message-ID: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> From: Max Signed-off-by: Max --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6cc9aa5..a22fd4f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ Makefile.in Makefile .deps +src/cscope* aclocal.m4 autom4te.cache -- 2.7.1 From msuraev at sysmocom.de Fri Feb 19 18:20:14 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Fri, 19 Feb 2016 19:20:14 +0100 Subject: [PATCH 3/3] Add gsmtap support to generic bts In-Reply-To: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> References: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> Message-ID: <1455906014-14949-3-git-send-email-msuraev@sysmocom.de> From: Max Instrument TX and RX functions dealing with regular BTS (without direct DSP access) to use GSMTAP. Previously only DSP-related functions were instrumented. Signed-off-by: Max --- src/pcu_l1_if.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index e816e6f..1b727a5 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -30,6 +30,8 @@ extern "C" { #include #include #include +#include +#include } #include @@ -93,7 +95,7 @@ static int pcu_tx_act_req(uint8_t trx, uint8_t ts, uint8_t activate) static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, uint16_t arfcn, uint32_t fn, uint8_t block_nr, uint8_t *data, - uint8_t len) + uint8_t len, struct gsmtap_inst *gsmtap) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -118,54 +120,58 @@ static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, memcpy(data_req->data, data, len); data_req->len = len; + gsmtap_send(gsmtap, arfcn, ts, GSMTAP_CHANNEL_PACCH, 0, fn, 0, 0, data, len); + return pcu_sock_send(msg); } void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP struct gprs_rlcmac_bts *bts = bts_main_data(); +#ifdef ENABLE_SYSMODSP if (bts->trx[trx].fl1h) l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr, msg->data, msg->len); else #endif pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr, - msg->data, msg->len); + msg->data, msg->len, bts->gsmtap); msgb_free(msg); } void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP struct gprs_rlcmac_bts *bts = bts_main_data(); +#ifdef ENABLE_SYSMODSP if (bts->trx[trx].fl1h) l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, msg->data, msg->len); else #endif pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, - msg->data, msg->len); + msg->data, msg->len, bts->gsmtap); msgb_free(msg); } void pcu_l1if_tx_agch(bitvec * block, int plen) { uint8_t data[23]; /* prefix PLEN */ - + struct gprs_rlcmac_bts *bts = bts_main_data(); + /* FIXME: why does OpenBTS has no PLEN and no fill in message? */ bitvec_pack(block, data + 1); data[0] = (plen << 2) | 0x01; - pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23); + pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23, bts->gsmtap); } void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi) { uint8_t data[23+3]; /* prefix PLEN */ + struct gprs_rlcmac_bts *bts = bts_main_data(); /* paging group */ if (!imsi || strlen(imsi) < 3) @@ -177,7 +183,7 @@ void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi) bitvec_pack(block, data + 3+1); data[3] = (plen << 2) | 0x01; - pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3); + pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3, bts->gsmtap); } extern "C" void pcu_rx_block_time(uint16_t arfcn, uint32_t fn, uint8_t ts_no) @@ -200,7 +206,7 @@ extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *dat return pdch->rcv_block(data, len, fn, meas); } -static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) +static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind, struct gsmtap_inst *gsmtap) { int rc = 0; pcu_l1_meas meas; @@ -223,6 +229,15 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) rc = -EINVAL; } + if (rc < 0) + return rc; + + int r = gsmtap_send(gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr, + GSMTAP_CHANNEL_PACCH, 0, data_ind->fn, 0, 0, data_ind->data, data_ind->len); + if (r < 0) { + LOGP(DL1IF, LOGL_ERROR, "Sending RX data via GSMTAP failed: %d\n", r); + } + return rc; } @@ -508,10 +523,11 @@ static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req) int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) { int rc = 0; + struct gprs_rlcmac_bts *bts = bts_main_data(); switch (msg_type) { case PCU_IF_MSG_DATA_IND: - rc = pcu_rx_data_ind(&pcu_prim->u.data_ind); + rc = pcu_rx_data_ind(&pcu_prim->u.data_ind, bts->gsmtap); break; case PCU_IF_MSG_DATA_CNF: rc = pcu_rx_data_cnf(&pcu_prim->u.data_cnf); -- 2.7.1 From msuraev at sysmocom.de Fri Feb 19 18:21:20 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Fri, 19 Feb 2016 19:21:20 +0100 Subject: [PATCH] Fix OsmoPCU integration Message-ID: <1455906080-15007-1-git-send-email-msuraev@sysmocom.de> From: Max Add support for explicitly passing PH-DATA presence info. Remove in-band passing of presence information and replace corresponding check. This also fixes integration between Octasic BTS hw and OsmoPCU: previously osmo-bts-octphy have not provided in-band presence information which cause off-by-one errors and misinterpretation of ph_data_ind by PCU. Note: this requires libosmocore version with osmo_ph_pres_info_type support integrated. --- include/osmo-bts/scheduler_backend.h | 2 +- src/common/l1sap.c | 5 +++-- src/common/scheduler.c | 3 ++- src/osmo-bts-octphy/l1_if.c | 1 + src/osmo-bts-trx/scheduler_trx.c | 16 +++++++--------- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/include/osmo-bts/scheduler_backend.h b/include/osmo-bts/scheduler_backend.h index 9f663cd..1614250 100644 --- a/include/osmo-bts/scheduler_backend.h +++ b/include/osmo-bts/scheduler_backend.h @@ -42,7 +42,7 @@ struct msgb *_sched_dequeue_prim(struct l1sched_trx *l1t, int8_t tn, uint32_t fn enum trx_chan_type chan); int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi); + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info); int _sched_compose_tch_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, enum trx_chan_type chan, uint8_t *tch, uint8_t tch_len); diff --git a/src/common/l1sap.c b/src/common/l1sap.c index 8056034..ac398d3 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -744,6 +744,7 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, uint8_t tn; uint32_t fn; int8_t rssi; + enum osmo_ph_pres_info_type pr_info = data_ind->pdch_presence_info; rssi = data_ind->rssi; chan_nr = data_ind->chan_nr; @@ -767,11 +768,11 @@ static int l1sap_ph_data_ind(struct gsm_bts_trx *trx, return 0; } /* drop incomplete UL block */ - if (data[0] != 7) + if (pr_info != PRES_INFO_BOTH) return 0; /* PDTCH / PACCH frame handling */ pcu_tx_data_ind(&trx->ts[tn], 0, fn, 0 /* ARFCN */, - L1SAP_FN2MACBLOCK(fn), data + 1, len - 1, rssi); + L1SAP_FN2MACBLOCK(fn), data, len, rssi); return 0; } diff --git a/src/common/scheduler.c b/src/common/scheduler.c index e9d2423..07c2e12 100644 --- a/src/common/scheduler.c +++ b/src/common/scheduler.c @@ -268,7 +268,7 @@ found_msg: } int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, - enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi) + enum trx_chan_type chan, uint8_t *l2, uint8_t l2_len, float rssi, enum osmo_ph_pres_info_type presence_info) { struct msgb *msg; struct osmo_phsap_prim *l1sap; @@ -284,6 +284,7 @@ int _sched_compose_ph_data_ind(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, l1sap->u.data.link_id = trx_chan_desc[chan].link_id; l1sap->u.data.fn = fn; l1sap->u.data.rssi = (int8_t) (rssi); + l1sap->u.data.pdch_presence_info = presence_info; msg->l2h = msgb_put(msg, l2_len); if (l2_len) memcpy(msg->l2h, l2, l2_len); diff --git a/src/osmo-bts-octphy/l1_if.c b/src/osmo-bts-octphy/l1_if.c index 3215aa1..781d589 100644 --- a/src/osmo-bts-octphy/l1_if.c +++ b/src/osmo-bts-octphy/l1_if.c @@ -1032,6 +1032,7 @@ static int handle_ph_data_ind(struct octphy_hdl *fl1, l1sap->u.data.chan_nr = chan_nr; l1sap->u.data.fn = fn; l1sap->u.data.rssi = rssi; + l1sap->u.data.pdch_presence_info = PRES_INFO_BOTH; /* FIXME: consider EDGE support */ l1sap_up(trx, l1sap); diff --git a/src/osmo-bts-trx/scheduler_trx.c b/src/osmo-bts-trx/scheduler_trx.c index 15c05e8..243539d 100644 --- a/src/osmo-bts-trx/scheduler_trx.c +++ b/src/osmo-bts-trx/scheduler_trx.c @@ -190,7 +190,7 @@ got_msg: l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, 456, 456, -110, 0); - _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110); + _sched_compose_ph_data_ind(l1t, tn, 0, chan, NULL, 0, -110, PRES_INFO_INVALID); } } @@ -841,7 +841,7 @@ int rx_data_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, n_errors, n_bits_total, *rssi_sum / *rssi_num, *toa_sum / *toa_num); - return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num); + return _sched_compose_ph_data_ind(l1t, tn, *first_fn, chan, l2, l2_len, *rssi_sum / *rssi_num, PRES_INFO_UNKNOWN); } int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -856,7 +856,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, uint8_t *rssi_num = &chan_state->rssi_num; float *toa_sum = &chan_state->toa_sum; uint8_t *toa_num = &chan_state->toa_num; - uint8_t l2[54+1]; + uint8_t l2[54]; int n_errors, n_bits_total; int rc; @@ -906,7 +906,7 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, *mask = 0x0; /* decode */ - rc = pdtch_decode(l2 + 1, *bursts_p, NULL, &n_errors, &n_bits_total); + rc = pdtch_decode(l2, *bursts_p, NULL, &n_errors, &n_bits_total); /* Send uplnk measurement information to L2 */ l1if_process_meas_res(l1t->trx, tn, fn, trx_chan_desc[chan].chan_nr | tn, @@ -919,10 +919,8 @@ int rx_pdtch_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, return 0; } - l2[0] = 7; /* valid frame */ - return _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 3) % GSM_HYPERFRAME, chan, - l2, rc + 1, *rssi_sum / *rssi_num); + l2, rc + 1, *rssi_sum / *rssi_num, PRES_INFO_BOTH); } int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, @@ -1038,7 +1036,7 @@ int rx_tchf_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, /* FACCH */ if (rc == GSM_MACBLOCK_LEN) { _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 7) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ @@ -1204,7 +1202,7 @@ int rx_tchh_fn(struct l1sched_trx *l1t, uint8_t tn, uint32_t fn, chan_state->ul_ongoing_facch = 1; _sched_compose_ph_data_ind(l1t, tn, (fn + GSM_HYPERFRAME - 10 - ((fn % 26) >= 19)) % GSM_HYPERFRAME, chan, - tch_data + amr, GSM_MACBLOCK_LEN, rssi); + tch_data + amr, GSM_MACBLOCK_LEN, rssi, PRES_INFO_UNKNOWN); bfi: if (rsl_cmode == RSL_CMOD_SPD_SPEECH) { /* indicate bad frame */ -- 2.7.1 From holger at freyther.de Fri Feb 19 18:47:36 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 19:47:36 +0100 Subject: [PATCH] Extend L1SAP PH-DATA with presence information In-Reply-To: <1455905874-14883-1-git-send-email-msuraev@sysmocom.de> References: <1455905874-14883-1-git-send-email-msuraev@sysmocom.de> Message-ID: <61DCDA0E-BCFC-480F-9ACA-1D06E4134385@freyther.de> > On 19 Feb 2016, at 19:17, msuraev at sysmocom.de wrote: > > good! > > +/*! \brief PH-DATA presence information */ > +enum osmo_ph_pres_info_type { > + PRES_INFO_INVALID = 0, /*!< \brief Data is invalid */ > + PRES_INFO_HEADER = 1, /*!< \brief Only header is present and valid */ > + PRES_INFO_FIRST = 3, /*!< \brief First half of data + header are valid (2nd half may be present but invalid) */ > + PRES_INFO_SECOND = 5, /*!< \brief Second half of data + header are valid (1st halfmay be present but invalid) */ > + PRES_INFO_BOTH = 7, /*!< \brief Both parts + header are present and valid */ do you intend to use it as a bit mask or why the b101 and b111? > + PRES_INFO_UNKNOWN > +}; > + > /*! \brief for PH-RANDOM_ACCESS.req */ > struct ph_rach_req_param { > > + enum osmo_ph_pres_info_type pdch_presence_info; /*!< \brief Info regarding presence/validity of header and data parts */ > }; This might or might not change the size of the struct osmo_phsap_prim and then we have an ABI issue. For such cases we have created the TODO-RELEASE file to indicate that we need to bump the SOVERSION on the next release. holger From holger at freyther.de Fri Feb 19 18:50:36 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 19:50:36 +0100 Subject: [PATCH 2/3] Introduce --gsmtap-ip/-i option In-Reply-To: <1455906014-14949-2-git-send-email-msuraev@sysmocom.de> References: <1455906014-14949-1-git-send-email-msuraev@sysmocom.de> <1455906014-14949-2-git-send-email-msuraev@sysmocom.de> Message-ID: <1781CEB8-450B-4EA2-BCF2-941B9C4EC71C@freyther.de> > On 19 Feb 2016, at 19:20, msuraev at sysmocom.de wrote: > > From: Max > > his option allows user to use custom IP address instead of default "localhost". > Correspondingly gsmtap init moved from sysmoBTS-specific code up to "bts" struct > level. This way it can be easier reused by other implementations. great. Have you checked that the osmo-pcu for the sysmoBTS behaves as before? > -/* FIXME: finally get some option parsing code into libosmocore */ > +/* FIXME: finally try using gengetopt */ this is a different question. What I have seen in the OpenGGSN did not impress me. Now your patch is blocked by something that has nothing to do with gsmtap. ;) > static void handle_options(int argc, char **argv) > { > while (1) { > @@ -74,10 +78,11 @@ static void handle_options(int argc, char **argv) > { "version", 0, 0, 'V' }, > { "realtime", 1, 0, 'r' }, > { "exit", 0, 0, 'e' }, > + { "gsmtap-ip", 1, 0, 'i' }, > { 0, 0, 0, 0 } > }; > > - c = getopt_long(argc, argv, "hc:m:n:Vr:e", > + c = getopt_long(argc, argv, "hc:m:n:Vr:e:i:", > long_options, &option_idx); > if (c == -1) > break; > @@ -102,6 +107,9 @@ static void handle_options(int argc, char **argv) > print_version(1); > exit(0); > break; > + case 'i': > + gsmtap_addr = optarg; > + break; > case 'r': > rt_prio = atoi(optarg); > break; > @@ -212,6 +220,14 @@ int main(int argc, char *argv[]) > exit(0); > } > > + bts->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1); > + > + if (bts->gsmtap) { > + gsmtap_source_add_sink(bts->gsmtap); > + } else { > + fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr); > + } coding style, please drop the curly braces. The rest does look fine. From msuraev at sysmocom.de Fri Feb 19 18:51:37 2016 From: msuraev at sysmocom.de (Max) Date: Fri, 19 Feb 2016 19:51:37 +0100 Subject: [PATCH] Extend L1SAP PH-DATA with presence information In-Reply-To: <61DCDA0E-BCFC-480F-9ACA-1D06E4134385@freyther.de> References: <1455905874-14883-1-git-send-email-msuraev@sysmocom.de> <61DCDA0E-BCFC-480F-9ACA-1D06E4134385@freyther.de> Message-ID: <56C76439.90409@sysmocom.de> Good point, totally forgot about TODO-RELEASE. As for values - I've took them directly from off-list comment by Harald. I suspect there might be other places where hardcoded values are used. cheers, Max. From ruben.undheim at gmail.com Fri Feb 19 18:54:10 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Fri, 19 Feb 2016 19:54:10 +0100 Subject: License exception for OpenSSL Message-ID: <20160219185410.GA15737@macbookair> Hi, When running lintian on openbsc, I get the following error: E: osmocom-bsc-nat: possible-gpl-code-linked-with-openssl E: osmocom-nitb: possible-gpl-code-linked-with-openssl It seems like openbsc is being linked with libcrypto from OpenSSL, but I cannot find any statement of OpenSSL exception for the AGPL. Debian policy requires this. Can you look into this? You can have a look at wget if you need an example. Ruben From holger at freyther.de Fri Feb 19 19:00:55 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 20:00:55 +0100 Subject: Status of osmocom libraries in Debian In-Reply-To: <20160214203545.GA16105@macbookair> References: <20160214203545.GA16105@macbookair> Message-ID: <9A2E93CB-F36C-45AC-8405-AF6C0FD23200@freyther.de> > On 14 Feb 2016, at 21:35, Ruben Undheim wrote: > > https://tracker.debian.org/media/packages/libo/libosmocore/copyright-0.9.0-4 Files: tests/fr/fr_test.c tests/logging/logging_test.c tests/loggingrb/loggingrb_test.c Copyright: 2008,2009,2012 Holger Hans Peter Freyther 2012-2013 Katerina Barone-Adesi License: AGPL-3+ I need to update the license to GPL-3+. It has been a mistake to use AGPL here. Files: src/gsm/milenage/aes-internal.c src/gsm/milenage/aes-encblock.c src/gsm/milenage/aes.h src/gsm/milenage/milenage.c src/gsm/milenage/aes_wrap.h src/gsm/milenage/aes-internal-enc.c src/gsm/milenage/aes_i.h Copyright: 2003-2007 Jouni Malinen License: GPL-2 Comment: Most of the file aes-internal.c is public_domain That would be problematic. The code is dual-licensed to be GPLv2 and BSD licensed. To be compatible in the "great" scheme this code should be used under BSD license. In fact the upstream code has now switched to only use BSD for this code. holger From holger at freyther.de Fri Feb 19 19:21:32 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 20:21:32 +0100 Subject: License exception for OpenSSL In-Reply-To: <20160219185410.GA15737@macbookair> References: <20160219185410.GA15737@macbookair> Message-ID: <1D30431E-0CF5-4EF5-9C36-FF72D659A979@freyther.de> > On 19 Feb 2016, at 19:54, Ruben Undheim wrote: > > Hi, Dear Ruben, > > When running lintian on openbsc, I get the following error: > > E: osmocom-bsc-nat: possible-gpl-code-linked-with-openssl > E: osmocom-nitb: possible-gpl-code-linked-with-openssl > > It seems like openbsc is being linked with libcrypto from OpenSSL, but I cannot > find any statement of OpenSSL exception for the AGPL. Debian policy requires > this. > > Can you look into this? You can have a look at wget if you need an example. if you are debian developer maybe you know someone working on lintian. What always triggers me is that it (and specially lintian.debian.org) say what is wrong but they don't point to a solution, e.g. they also link to other broken packages but never to an example how this specific program has fixed the issue. It is a bit like writing E: blub. When picking libcrypto I considered it a system library (FreeBSD, OSX, etc. ship it in the base system). I think instead of changing the license it is easier to change the calls. From my point of view there are several options: 1.) You link against libgnutls-openssl-dev which provides a wrapper for RAND_bytes. 2.) We move to GNUtls (or gcrypt?) to call the function that RAND_bytes is wrapped around (after reading the documentation) 3.) We use GNU nettle and their yarrow-256 implementation (assuming that is a smart move)? I think from a packaging point of view 1st might be the easiest and just means patching one line in configure.ac? holger From holger at freyther.de Fri Feb 19 19:23:15 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 20:23:15 +0100 Subject: sysmocom/iu: your commits from today In-Reply-To: <1455897821.8409.12.camel@sysmocom.de> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> Message-ID: <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> > On 19 Feb 2016, at 17:03, Daniel Willmann wrote: > > Hey Neels, > > Yeah, well, this time I did ;-) gsm_04_11.c: In function 'sms_route_mt_sms': gsm_04_11.c:318: error: 'struct gsm_subscriber_connection' has no member named 'bts' make[3]: *** [gsm_04_11.o] Error 1 progress.. new error.. whoever makes the build blue/green for a week.. will get some homemade chocolate cookies... From holger at freyther.de Fri Feb 19 19:34:17 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 20:34:17 +0100 Subject: Smalltalk scalable SMSC project In-Reply-To: <47AB9864-CB30-4AEA-8FE5-45D484DF6002@freyther.de> References: <9047F009-0798-4ED9-8211-BA5D515B9295@freyther.de> <47AB9864-CB30-4AEA-8FE5-45D484DF6002@freyther.de> Message-ID: > On 09 Feb 2016, at 12:09, Holger Freyther wrote: > > >> On 18 Jan 2016, at 16:56, Holger Freyther wrote: > > > Good Morning, Hi! > As usual anyone interested in playing with the system, contributing to it, writing system tests or load tests is more than welcome to participate. progress has continued but several administration topics has delayed me a bit. We now have a complete REST interface for managing SMPP and SS7 links in the inserter and delivery part of the system. The delivery part can now lock SMS, lock the destination and select messages to be sent. There is also the first system test that tests the REST interface and we are working on a system test that brings up the inserter and inserts SMPP messages into the DB. I have worked on configuring delivery routes through REST. One can define a route that matches: * by default * a destination address prefix * a destination + source address prefix * a destination + source address prefix and the link the message arrived Each route defines 0-N delivery methods. A delivery method refers a SMPP or SS7 link and some parameters. E.g. for SS7 the to be used MAP version is configured, the source GT, the SMSC number, the GT translation flags for SCCP. As usual the source code and all intermediate versions is free software (still on my private github repo as the travis-ci system integration is quite neat but that will change). kind regards holger From ruben.undheim at gmail.com Fri Feb 19 19:54:07 2016 From: ruben.undheim at gmail.com (Ruben Undheim) Date: Fri, 19 Feb 2016 20:54:07 +0100 Subject: License exception for OpenSSL In-Reply-To: <1D30431E-0CF5-4EF5-9C36-FF72D659A979@freyther.de> References: <20160219185410.GA15737@macbookair> <1D30431E-0CF5-4EF5-9C36-FF72D659A979@freyther.de> Message-ID: <20160219195407.GA7366@macbookair> > 1.) You link against libgnutls-openssl-dev which provides a wrapper for RAND_bytes. > > 2.) We move to GNUtls (or gcrypt?) to call the function that RAND_bytes is wrapped around (after reading the documentation) > > 3.) We use GNU nettle and their yarrow-256 implementation (assuming that is a smart move)? Thanks. I did #1. Here's the patch: Index: openbsc/openbsc/configure.ac =================================================================== --- openbsc.orig/openbsc/configure.ac 2016-02-19 20:39:10.824145024 +0100 +++ openbsc/openbsc/configure.ac 2016-02-19 20:39:10.820145095 +0100 @@ -27,7 +27,8 @@ PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0) PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4) PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1) -PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5) +#PKG_CHECK_MODULES(LIBCRYPTO, gnutls) +AC_SUBST(LIBCRYPTO_LIBS, -lgnutls-openssl) # Enabke/disable the NAT? AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])], Index: openbsc/openbsc/src/libmsc/auth.c =================================================================== --- openbsc.orig/openbsc/src/libmsc/auth.c 2016-02-19 20:13:19.417462737 +0100 +++ openbsc/openbsc/src/libmsc/auth.c 2016-02-19 20:40:13.607032169 +0100 @@ -27,7 +27,7 @@ #include -#include +#include #include Index: openbsc/openbsc/src/libmsc/db.c =================================================================== --- openbsc.orig/openbsc/src/libmsc/db.c 2016-02-19 20:13:19.421462672 +0100 +++ openbsc/openbsc/src/libmsc/db.c 2016-02-19 20:40:27.318789122 +0100 @@ -38,7 +38,7 @@ #include #include -#include +#include /* Semi-Private-Interface (SPI) for the subscriber code */ void subscr_direct_free(struct gsm_subscriber *subscr); Index: openbsc/openbsc/src/osmo-bsc_nat/bsc_nat.c =================================================================== --- openbsc.orig/openbsc/src/osmo-bsc_nat/bsc_nat.c 2016-02-19 20:13:19.433462478 +0100 +++ openbsc/openbsc/src/osmo-bsc_nat/bsc_nat.c 2016-02-19 20:39:58.791294787 +0100 @@ -69,7 +69,7 @@ #include -#include +#include #include "../../bscconfig.h" It seems to work. Luckily the SSL library isn't used for anything advanced. Cool if you also figure out a way to solve this upstream! Cheers Ruben From holger at freyther.de Fri Feb 19 20:00:42 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 21:00:42 +0100 Subject: Moving from trac to a single redmine In-Reply-To: References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> <20160218231601.GC18542@dub6> Message-ID: > On 19 Feb 2016, at 08:09, Holger Freyther wrote: > > > The wiki conversion is not that great. We really have to do some work in post processing and making sure that all content has been migrated. E.g. "Software/Overview" and "SoftwareOverview" seem to confuse the importer: > > http://projects.osmocom.org/projects/baseband/wiki/SoftwareOverview vs. http://bb.osmocom.org/trac/wiki/Software/Overview vs. http://bb.osmocom.org/trac/wiki/SoftwareOverview I am fixing this but if somebody wants to help with some code/regexp it would be nice too. In trac we have: [[Image(motorola_filter_replacement_step_1_low.jpg, 250px)]] For redmine we need: {{thumbnail(motorola_filter_replacement_step_1_low.jpg, size=250)}} Anyone wants to try his luck with a regexp to do this automatically? Or a bit of ruby code to split and manipulate if it is matching [[Image? From elofssonjens at gmail.com Fri Feb 19 22:01:14 2016 From: elofssonjens at gmail.com (Jens Elofsson) Date: Fri, 19 Feb 2016 23:01:14 +0100 Subject: Moving from trac to a single redmine In-Reply-To: References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> <20160218231601.GC18542@dub6> Message-ID: According to Google, this should do the trick perl -p -i -e 's/\[\[Image\((.+?)\)\]\]/\{\{thumbnail\($1\)\}\}/g' filename.txt (note that it replaces [[Image...]] with {{thumbnail...}} in the file without creating a backup)). /Jens E 2016-02-19 21:00 GMT+01:00 Holger Freyther : > > > On 19 Feb 2016, at 08:09, Holger Freyther wrote: > > > > > > The wiki conversion is not that great. We really have to do some work in > post processing and making sure that all content has been migrated. E.g. > "Software/Overview" and "SoftwareOverview" seem to confuse the importer: > > > > http://projects.osmocom.org/projects/baseband/wiki/SoftwareOverview vs. > http://bb.osmocom.org/trac/wiki/Software/Overview vs. > http://bb.osmocom.org/trac/wiki/SoftwareOverview > > I am fixing this but if somebody wants to help with some code/regexp it > would be nice too. > > In trac we have: > > [[Image(motorola_filter_replacement_step_1_low.jpg, 250px)]] > > For redmine we need: > > {{thumbnail(motorola_filter_replacement_step_1_low.jpg, size=250)}} > > Anyone wants to try his luck with a regexp to do this automatically? Or a > bit of ruby code to split and manipulate if it is matching [[Image? > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From holger at freyther.de Fri Feb 19 22:03:10 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 19 Feb 2016 23:03:10 +0100 Subject: Moving from trac to a single redmine In-Reply-To: References: <29DF7E51-8366-40A3-8EF1-F4705D3A0E6D@freyther.de> <20160218184318.GW4570@nataraja> <753DCDAF-0723-4EC5-8E3C-870B7D5959C5@freyther.de> <20160218231601.GC18542@dub6> Message-ID: <5E9E5F4C-658A-491F-9AD7-9B7418238A5C@freyther.de> > On 19 Feb 2016, at 08:09, Holger Freyther wrote: > > > The wiki conversion is not that great. We really have to do some work in post processing and making sure that all content has been migrated. E.g. "Software/Overview" and "SoftwareOverview" seem to confuse the importer: > > http://projects.osmocom.org/projects/baseband/wiki/SoftwareOverview vs. http://bb.osmocom.org/trac/wiki/Software/Overview vs. http://bb.osmocom.org/trac/wiki/SoftwareOverview > > So there will be some fallout but I think it still makes sense to move forward now. This post is Sponsored by the Ministry of Stuff you Didn't want to know. Trac has a "flat" wiki model. The hierarchy is added by the notion of adding / into the path. This means that SoftwareOverview is a top-level page and Software/Overview is a child of software. In Redmine there is the concept of "parent" pages but the name is a flat namespace. So by convention the page would be called "Overview" but be a child of "Software". Redmine will normalize a pagetitle like Software/Overview to SoftwareOverview. To avoid having "SoftwareOverview" and "Software/Overview" clash I am expanding the later to SoftwareSoftwareOverview and this gives us funny names and broken links (*sigh*) but with reasonable effort this seems to be as good as I can get it. This means our manual fix-up step will so far include: * Fix general format issue (e.g.
 but no 
) * Remove custom html I created to have a multi-column view. * Fix the [[Image unless I get the regexp to work in ruby * Rename SoftwareSoftwareOverview and other pages (and delete the old one) kind regards holger From holger at freyther.de Sat Feb 20 10:58:07 2016 From: holger at freyther.de (Holger Freyther) Date: Sat, 20 Feb 2016 11:58:07 +0100 Subject: Progress of trac->redmine migration Message-ID: <7BA392B9-A3E6-41E6-98ED-10F7F4B699DD@freyther.de> Hi all, I think we are close to the point of no return. All tickets and wikis have been imported. Please have a quick look if there is something obviously broken and if not I will proceed with post-processing and renaming tonight. kind regards holger From 246tnt at gmail.com Sat Feb 20 11:43:41 2016 From: 246tnt at gmail.com (Sylvain Munaut) Date: Sat, 20 Feb 2016 12:43:41 +0100 Subject: Progress of trac->redmine migration In-Reply-To: <7BA392B9-A3E6-41E6-98ED-10F7F4B699DD@freyther.de> References: <7BA392B9-A3E6-41E6-98ED-10F7F4B699DD@freyther.de> Message-ID: Hi Holger, Just had a quick look at the GMR one and it looks OK. Images and Tables and PRE blocks are randomly screwed up in the wiki but I can just post fix that manually once you're done. Also had a look at the osmocom-BB one, wiki is also going to need a review of each page, but at least the content is there. The issues in the osmocom-bb project are the issues for SimTrace, I did find that a bit weird. Is that expected ? Finally, for the OsmoSDR project I'm wondering if we shouldn't change it to just "SDR" since it ends up hosting pretty much everything SDR ( rtl-sdr gr-osmosdr sdrangelove fosphor ) rather than just the "OsmoSDR" project itself. Each of them only has a single wikipage so I don't think it's worth splitting them in individual projects in redmine. Cheers, Sylvain From nhofmeyr at sysmocom.de Sat Feb 20 14:43:34 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 20 Feb 2016 15:43:34 +0100 Subject: sysmocom/iu: your commits from today In-Reply-To: <1455897821.8409.12.camel@sysmocom.de> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> Message-ID: <20160220144334.GA1953@dub6> whoever got what wrong and when, I did get it all working now, thanks :) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Sat Feb 20 15:16:55 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 20 Feb 2016 16:16:55 +0100 Subject: warnings Message-ID: <20160220151655.GB1953@dub6> Hi list, I tend to use vim's :make command so that it takes me to the positions of warnings and errors automatically. However, when hacking on osmo-iuh, I sometimes get dozens of these irritating warning chunks: [[[ ../../include/osmocom/hnbap/CriticalityDiagnostics-IE-List.h:35:10: warning: ?struct Member? declared inside parameter list struct IE_Extensions *iE_Extensions /* OPTIONAL */; ^ /usr/local/include/asn1c/asn_SET_OF.h:17:16: note: in definition of macro ?A_SET_OF? void (*free)(type *); \ ^ ../../include/osmocom/hnbap/CriticalityDiagnostics-IE-List.h:31:2: note: in expansion of macro ?A_SEQUENCE_OF? A_SEQUENCE_OF(struct Member { ^ ../../include/osmocom/hnbap/CriticalityDiagnostics-IE-List.h:35:10: warning: its scope is only this definition or declaration, which is probably not what you want struct IE_Extensions *iE_Extensions /* OPTIONAL */; ^ /usr/local/include/asn1c/asn_SET_OF.h:17:16: note: in definition of macro ?A_SET_OF? void (*free)(type *); \ ^ ../../include/osmocom/hnbap/CriticalityDiagnostics-IE-List.h:31:2: note: in expansion of macro ?A_SEQUENCE_OF? A_SEQUENCE_OF(struct Member { ^ ]]] The cause are numerous instances of code like: [[[ /* CriticalityDiagnostics-IE-List */ typedef struct CriticalityDiagnostics_IE_List { A_SEQUENCE_OF(struct Member { Criticality_t iECriticality; ProtocolIE_ID_t iE_ID; TypeOfError_t typeOfError; struct IE_Extensions *iE_Extensions /* OPTIONAL */; /* * This type is extensible, * possible extensions are below. */ /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } ) list; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; } CriticalityDiagnostics_IE_List_t; ]]] "...which is probably not what you want". Turns out it kinda is what I want, I just don't want these warnings :P Filtering proper error messages from this mess is hard. Any idea to get rid of these warnings would speed up my dev cycle dramatically... Short of refactoring the way these A_SEQUENCE_OF() get generated. I guess the struct should rather be first declared with a unique name and then only the type name should be used in A_SEQUENCE_OF(). i.e. not like osmo-iuh/include/osmocom/rua/RUA_CriticalityDiagnostics-IE-List.h: A_SEQUENCE_OF(struct Member {... but like: osmo-iuh/include/osmocom/rua/RUA_Disconnect.h: A_SEQUENCE_OF(RUA_IE_t) list; Doesn't seem to come from the asn1tostruct.py... Thanks!! ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Sat Feb 20 15:31:04 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 20 Feb 2016 16:31:04 +0100 Subject: branches: daniel/gprs-iu + sysmocom/cscn = sysmocom/iu; merging to master In-Reply-To: <20160219083519.GA4570@nataraja> References: <20160218115512.GA2630@dub6> <20160219083519.GA4570@nataraja> Message-ID: <20160220153104.GC1953@dub6> Thanks for the detailed reasoning! ~Neels On Fri, Feb 19, 2016 at 09:35:19AM +0100, Harald Welte wrote: [...] -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Sat Feb 20 15:39:48 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sat, 20 Feb 2016 16:39:48 +0100 Subject: no member named 'bts' -- was: sysmocom/iu: your commits from today In-Reply-To: <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> Message-ID: <20160220153948.GD1953@dub6> On Fri, Feb 19, 2016 at 08:23:15PM +0100, Holger Freyther wrote: > gsm_04_11.c: In function 'sms_route_mt_sms': > gsm_04_11.c:318: error: 'struct gsm_subscriber_connection' has no member named 'bts' > make[3]: *** [gsm_04_11.o] Error 1 Interesting, I don't see any reference to 'bts' anywhere in that file. My line 318 looks like: osmo_counter_inc(conn->network->stats.sms.no_receiver); And I changed it in d03faa4bacd4d2a8b9155faf5219a948b73f481c - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + osmo_counter_inc(conn->network->stats.sms.no_receiver); which is part of the sysmocom/iu branch. Does that help?? (BTW I also fixed a test expectation in osmo-iuh today, maybe that's worth half a chocolate cookie?) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Sat Feb 20 17:38:09 2016 From: holger at freyther.de (Holger Freyther) Date: Sat, 20 Feb 2016 18:38:09 +0100 Subject: Progress of trac->redmine migration In-Reply-To: References: <7BA392B9-A3E6-41E6-98ED-10F7F4B699DD@freyther.de> Message-ID: > On 20 Feb 2016, at 12:43, Sylvain Munaut <246tnt at gmail.com> wrote: > > Hi Holger, Dear Sylvain! > Just had a quick look at the GMR one and it looks OK. Images and > Tables and PRE blocks are randomly screwed up in the wiki but I can > just post fix that manually once you're done. yes, we will need to have this post fix run but it should be fairly quick. > Also had a look at the osmocom-BB one, wiki is also going to need a > review of each page, but at least the content is there. The issues in > the osmocom-bb project are the issues for SimTrace, I did find that a > bit weird. Is that expected ? I don't understand. simtrace.osmocom.org was actually only a redirect into the OsmocomBB trac so the content (and issues) will be in this project. We can and should move it to a separate project in the near future. But it sounds like you are referring something more specific? > > Finally, for the OsmoSDR project I'm wondering if we shouldn't change > it to just "SDR" since it ends up hosting pretty much everything SDR ( > rtl-sdr gr-osmosdr sdrangelove fosphor ) rather than just the > "OsmoSDR" project itself. Each of them only has a single wikipage so I > don't think it's worth splitting them in individual projects in > redmine. The url is "sdr" but the name says "OsmoSDR". Feel free to update the project information as you wish (okay, I probably need to help you to reset/fix the auto-created account to be useful for you). holger From holger at freyther.de Sat Feb 20 18:17:00 2016 From: holger at freyther.de (Holger Freyther) Date: Sat, 20 Feb 2016 19:17:00 +0100 Subject: License exception for OpenSSL In-Reply-To: <20160219195407.GA7366@macbookair> References: <20160219185410.GA15737@macbookair> <1D30431E-0CF5-4EF5-9C36-FF72D659A979@freyther.de> <20160219195407.GA7366@macbookair> Message-ID: > On 19 Feb 2016, at 20:54, Ruben Undheim wrote: > >> 1.) You link against libgnutls-openssl-dev which provides a wrapper for RAND_bytes. >> >> 2.) We move to GNUtls (or gcrypt?) to call the function that RAND_bytes is wrapped around (after reading the documentation) >> >> 3.) We use GNU nettle and their yarrow-256 implementation (assuming that is a smart move)? > > Thanks. > I did #1. Here's the patch: > I explored 2nd and gnutls calls gcrypt so I looked at gcry_randomize[1]. In comparison to the OpenSSL RNAD_bytes documentation I feel a lot is missing. RAND_bytes will fail if the RNG is not seeded, I don't see anything like this in gcry_randomize documentation. Do I really need to call gcry_check_version or is it okay to not call it? I will not do this weekend, but please ping me if there is not progress in the weeks to come. I think we roughly need to do: * Call gcry_check_version in the main routine of apps using it * Switch to use gcry_randomize holger [1] https://gnupg.org/documentation/manuals/gcrypt/Retrieving-random-numbers.html#Retrieving-random-numbers [2] https://www.openssl.org/docs/manmaster/crypto/RAND_bytes.html From laforge at gnumonks.org Sat Feb 20 18:27:08 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 20 Feb 2016 19:27:08 +0100 Subject: warnings In-Reply-To: <20160220151655.GB1953@dub6> References: <20160220151655.GB1953@dub6> Message-ID: <20160220182708.GI4570@nataraja> Hi Neels, the topic you're raising is one of asn1c's code generation, and it should probably be discussed in the mailing list / forum / ... of asn1c. I did some research in the past and not find a way to disable those specific warnings in gcc (without recompiling gcc). -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Sat Feb 20 18:25:46 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 20 Feb 2016 19:25:46 +0100 Subject: Progress of trac->redmine migration In-Reply-To: References: <7BA392B9-A3E6-41E6-98ED-10F7F4B699DD@freyther.de> Message-ID: <20160220182546.GH4570@nataraja> Hi Holger, Sylvain, On Sat, Feb 20, 2016 at 06:38:09PM +0100, Holger Freyther wrote: > > Also had a look at the osmocom-BB one, wiki is also going to need a > > review of each page, but at least the content is there. The issues in > > the osmocom-bb project are the issues for SimTrace, I did find that a > > bit weird. Is that expected ? > > I don't understand. simtrace.osmocom.org was actually only a redirect > into the OsmocomBB trac so the content (and issues) will be in this > project. We can and should move it to a separate project in the near > future. But it sounds like you are referring something more specific? I simply suppose that sylvain simply didn't remember this ugly hack (the redirect). I will create a SIMtrace project and move the issues. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Sat Feb 20 18:54:11 2016 From: holger at freyther.de (Holger Freyther) Date: Sat, 20 Feb 2016 19:54:11 +0100 Subject: no member named 'bts' -- was: sysmocom/iu: your commits from today In-Reply-To: <20160220153948.GD1953@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> Message-ID: > On 20 Feb 2016, at 16:39, Neels Hofmeyr wrote: > > > which is part of the sysmocom/iu branch. > > Does that help?? go left, pick up compiler-error smpp_openbsc.c: In function 'deliver_to_esme': smpp_openbsc.c:536: error: 'struct gsm_subscriber_connection' has no member named 'lchan' smpp_openbsc.c:537: error: 'struct gsm_subscriber_connection' has no member named 'lchan' this is an interesting case. We want to annotate the SMPP message with extra values of from where the SMS came from. This is possible in the osmo-nitb and should probably remain possible. Do you see a way to make this work? I am really late with this but as part of the bsc_api, I envisioned that we would have a msc_subscriber_connection if we ever split things up :} holger From nhofmeyr at sysmocom.de Sun Feb 21 10:16:45 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sun, 21 Feb 2016 11:16:45 +0100 Subject: no member named 'bts' -- was: sysmocom/iu: your commits from today In-Reply-To: References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> Message-ID: <20160221101645.GA1884@dub6> On Sat, Feb 20, 2016 at 07:54:11PM +0100, Holger Freyther wrote: > go left, pick up compiler-error > > smpp_openbsc.c: In function 'deliver_to_esme': > smpp_openbsc.c:536: error: 'struct gsm_subscriber_connection' has no member named 'lchan' > smpp_openbsc.c:537: error: 'struct gsm_subscriber_connection' has no member named 'lchan' Argh, my own build excludes SMPP for some reason, so I didn't catch that one with my "guaranteed to catch all" method. Anyway: > this is an interesting case. We want to annotate the SMPP message with extra values of from where the SMS came from. This is possible in the osmo-nitb and should probably remain possible. Do you see a way to make this work? I haven't really investigated at all about plugging osmo-bsc back to osmo-cscn with an A-interface, because the focus is so far firmly on IuCS. Worst case we could introduce a "vendor specific" DTAP message sent to the MSC, possibly a feature enabled by a vendor specific BSSMAP message sent by the MSC fist?? (wildly guessing) But I'll start off by enabling SMPP in my build ... :/ > I am really late with this but as part of the bsc_api, I envisioned that we > would have a msc_subscriber_connection if we ever split things up :} Not that late really, I looked at bsc_api briefly but saw that it wasn't helping for IuCS, so I postponed dissecting the (numerous) details of it to another day. It should come naturally when the A-interface is created. But in fact my foggy vision so far is that the struct bsc_api will not actually survive, since the A-interface rx, like IuCS rx, will call functions directly instead of keeping a struct of function pointers... IMHO A clearly structured header file would do a nicer job at highlighting the MSC<->BSC entry points. I am also presuming that we will drop osmo-nitb as such and replace it with "please run osmo-bsc plugged into osmo-cscn", BTW. Thoughts welcome. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Sun Feb 21 11:11:10 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sun, 21 Feb 2016 12:11:10 +0100 Subject: warnings In-Reply-To: <20160220182708.GI4570@nataraja> References: <20160220151655.GB1953@dub6> <20160220182708.GI4570@nataraja> Message-ID: <20160221111110.GB1884@dub6> On Sat, Feb 20, 2016 at 07:27:08PM +0100, Harald Welte wrote: > Hi Neels, > > the topic you're raising is one of asn1c's code generation, and it > should probably be discussed in the mailing list / forum / ... of asn1c. > > I did some research in the past and not find a way to disable those > specific warnings in gcc (without recompiling gcc). Ok, thanks! I'm glad I didn't investigate further than I did into gcc, then. I'll see if/when I get time to talk to asn1c's list... ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Sun Feb 21 11:26:10 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Sun, 21 Feb 2016 12:26:10 +0100 Subject: no member named 'bts' In-Reply-To: <20160221101645.GA1884@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> Message-ID: <20160221112610.GC1884@dub6> On Sun, Feb 21, 2016 at 11:16:45AM +0100, Neels Hofmeyr wrote: > But I'll start off by enabling SMPP in my build ... :/ I've pushed a commit that disables the Osmocom SMPP TLVs for now. The build should work now. Maybe this time it actually will ;) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Sun Feb 21 11:29:48 2016 From: holger at freyther.de (Holger Freyther) Date: Sun, 21 Feb 2016 12:29:48 +0100 Subject: no member named 'bts' In-Reply-To: <20160221112610.GC1884@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> <20160221112610.GC1884@dub6> Message-ID: <614F008B-AC06-44F8-AF33-3759792D24C5@freyther.de> > On 21 Feb 2016, at 12:26, Neels Hofmeyr wrote: > > On Sun, Feb 21, 2016 at 11:16:45AM +0100, Neels Hofmeyr wrote: >> But I'll start off by enabling SMPP in my build ... :/ > > I've pushed a commit that disables the Osmocom SMPP TLVs for now. > The build should work now. Maybe this time it actually will ;) i triggered the coverity build.. we will see in a couple of minutes. From holger at freyther.de Sun Feb 21 12:57:27 2016 From: holger at freyther.de (Holger Freyther) Date: Sun, 21 Feb 2016 13:57:27 +0100 Subject: no member named 'bts' In-Reply-To: <20160221112610.GC1884@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> <20160221112610.GC1884@dub6> Message-ID: <24702181-0653-4A1D-9F8C-7B33D6D34B74@freyther.de> > On 21 Feb 2016, at 12:26, Neels Hofmeyr wrote: > > On Sun, Feb 21, 2016 at 11:16:45AM +0100, Neels Hofmeyr wrote: >> But I'll start off by enabling SMPP in my build ... :/ > > I've pushed a commit that disables the Osmocom SMPP TLVs for now. > The build should work now. Maybe this time it actually will ;) osmo_bsc_main.c: In function 'main': osmo_bsc_main.c:206: error: too few arguments to function 'bsc_vty_init' osmo_bsc_main.c:221: warning: implicit declaration of function 'bsc_bootstrap_network' then maybe disable the osmo-bsc right now? From holger at freyther.de Sun Feb 21 13:10:32 2016 From: holger at freyther.de (Holger Freyther) Date: Sun, 21 Feb 2016 14:10:32 +0100 Subject: no member named 'bts' -- was: sysmocom/iu: your commits from today In-Reply-To: <20160221101645.GA1884@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> Message-ID: > On 21 Feb 2016, at 11:16, Neels Hofmeyr wrote: > > Not that late really, I looked at bsc_api briefly but saw that it wasn't > helping for IuCS, so I postponed dissecting the (numerous) details of it > to another day. It should come naturally when the A-interface is created. > But in fact my foggy vision so far is that the struct bsc_api will not > actually survive, since the A-interface rx, like IuCS rx, will call > functions directly instead of keeping a struct of function pointers... > IMHO A clearly structured header file would do a nicer job at highlighting > the MSC<->BSC entry points. I am also presuming that we will drop > osmo-nitb as such and replace it with "please run osmo-bsc plugged into > osmo-cscn", BTW. The initial idea was that at the "MSC" the "Complete Layer3 message" (the initial message) would arrive. The MSC would then create an instance of a msc_subscriber_connection (and add a backpointer to the gsm_subscriber_connection which then probably should be called bsc_subscriber_connection). The MM, CC and other code should then refer to the msc_subscriber_connection. In case of osmo-cscn the msc_subscriber_conn would point to the "Iu" definition and for osmo-nitb it would still have the gsm_subscriber_conn backpointer. The other part was that there should be something like msc_api inside the MM/CC code that either directly maps to the BSC code or in case of osmo-cscn send it to the HNBGW. anyway, you will come up with something that makes sense too holger From laforge at gnumonks.org Sun Feb 21 16:31:15 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sun, 21 Feb 2016 17:31:15 +0100 Subject: Moving from trac to a single redmine In-Reply-To: <80FDBDBD-2B0E-46EC-B751-AE47B3CF1F87@freyther.de> References: <80FDBDBD-2B0E-46EC-B751-AE47B3CF1F87@freyther.de> Message-ID: <20160221163115.GO4570@nataraja> Hi all, On Fri, Feb 19, 2016 at 12:36:29PM +0100, Holger Freyther wrote: > > So, my suggestions: > > - Create the main page that will describe all all of the child projects > > of Osmocom umbrella including recent news and plans. in progress. > > - Separate the libosmocore related pages from OsmocomBB > > into a new section named "Libraries", for example. Libaries has libosmocore / libosmo-netif / libosmo-abis as sub-projects, related wiki pages have been moved. > > - Separate both SIMTrace and softSIM into a new sections. SIMtrace is a new project. > I don't think we can move wiki pages from one project to another but > we should be able to somehow add redirects. Luckily one can move wiki pages (including their attachments and any child wiki pages) between projects, that's what I've been doing most parts of today. > I intend to add one more wiki plugin to have table of contents and > other features we are used to from trac. You can play with the tree-like structure of wiki pages and use constructs like {{child_pages(BTS_Hardwware,depth=1)}} to automaticall get an automatic list/tree of child pages into another page. There most likely are more advanced tools avaiailable, but I find that already quite powerful. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Mon Feb 22 09:46:35 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 10:46:35 +0100 Subject: no member named 'bts' -- was: sysmocom/iu: your commits from today In-Reply-To: References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> Message-ID: <20160222094635.GA15564@dub6> On Sun, Feb 21, 2016 at 02:10:32PM +0100, Holger Freyther wrote: > The initial idea was that at the "MSC" the "Complete Layer3 message" (the initial message) would arrive. The MSC would then create an instance of a msc_subscriber_connection (and add a backpointer to the gsm_subscriber_connection which then probably should be called bsc_subscriber_connection). The MM, CC and other code should then refer to the msc_subscriber_connection. In case of osmo-cscn the msc_subscriber_conn would point to the "Iu" definition and for osmo-nitb it would still have the gsm_subscriber_conn backpointer. > > > The other part was that there should be something like msc_api inside the MM/CC code that either directly maps to the BSC code or in case of osmo-cscn send it to the HNBGW. The thing is, I need to get to know most of the code first. And I'm so far just trying "to reach the other side" and would like to look at the rackety bridge I built in a second iteration. I presume the basic building blocks will be useful to rearrange them in a bigger picture, which I'm in my head still busy enriching with the details. So I would first like to see IuCS do something useful and then let's look at the hopefully limited madness I created to obtain that. Today I'm going to hunt segfaults in hnbgw so I can continue testing. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Feb 22 09:48:10 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 10:48:10 +0100 Subject: no member named 'bts' In-Reply-To: <24702181-0653-4A1D-9F8C-7B33D6D34B74@freyther.de> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> <20160221112610.GC1884@dub6> <24702181-0653-4A1D-9F8C-7B33D6D34B74@freyther.de> Message-ID: <20160222094810.GB15564@dub6> On Sun, Feb 21, 2016 at 01:57:27PM +0100, Holger Freyther wrote: > then maybe disable the osmo-bsc right now? Yeah in fact that's also disabled in my build. I'm looking at it now for a few minutes, but why not disable it until we got it back on its feet... ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From msuraev at sysmocom.de Mon Feb 22 10:03:26 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Mon, 22 Feb 2016 11:03:26 +0100 Subject: [PATCH] Extend L1SAP PH-DATA with presence information Message-ID: <1456135406-24049-1-git-send-email-msuraev@sysmocom.de> From: Max Previously the presence of header and data blocks were communicated in-band which decreases code readability and makes it unnecessary hard to add support for new hardware. Note: OsmoBTS have to be modified to take advantage of extended ph_data_param structure. --- TODO-RELEASE | 1 + include/osmocom/gsm/l1sap.h | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/TODO-RELEASE b/TODO-RELEASE index edf1099..0939336 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1,2 +1,3 @@ #library what description / commit summary line libosmocore change major external talloc dependency / internal talloc removal +libosmocore change major size of ph_data_param struct changed / Extend L1SAP PH-DATA with presence information \ No newline at end of file diff --git a/include/osmocom/gsm/l1sap.h b/include/osmocom/gsm/l1sap.h index 9f3fe98..1af8ba8 100644 --- a/include/osmocom/gsm/l1sap.h +++ b/include/osmocom/gsm/l1sap.h @@ -25,6 +25,16 @@ enum osmo_mph_info_type { PRIM_INFO_DEACT_CIPH, /*!< \brief Deactivation of ciphering */ }; +/*! \brief PH-DATA presence information */ +enum osmo_ph_pres_info_type { + PRES_INFO_INVALID = 0, /*!< \brief Data is invalid */ + PRES_INFO_HEADER = 1, /*!< \brief Only header is present and valid */ + PRES_INFO_FIRST = 3, /*!< \brief First half of data + header are valid (2nd half may be present but invalid) */ + PRES_INFO_SECOND = 5, /*!< \brief Second half of data + header are valid (1st halfmay be present but invalid) */ + PRES_INFO_BOTH = 7, /*!< \brief Both parts + header are present and valid */ + PRES_INFO_UNKNOWN +}; + /*! \brief for PH-RANDOM_ACCESS.req */ struct ph_rach_req_param { uint8_t ra; /*!< \brief Random Access */ @@ -48,6 +58,7 @@ struct ph_data_param { uint8_t chan_nr; /*!< \brief Channel Number (Like RSL) */ uint32_t fn; /*!< \brief GSM Frame Number */ int8_t rssi; /*!< \brief RSSI of receivedindication */ + enum osmo_ph_pres_info_type pdch_presence_info; /*!< \brief Info regarding presence/validity of header and data parts */ }; /*! \brief for TCH.{req,ind} | TCH-RTS.ind */ -- 2.7.1 From nhofmeyr at sysmocom.de Mon Feb 22 10:39:06 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 11:39:06 +0100 Subject: osmo-nitb configurable Message-ID: <20160222103906.GA11457@dub6> Hi Harald, Holger has just refreshed my memory on a conversation we've had on running multiple NITB instances on the same box: Linux Network Namespaces vs. making NITB configurable. Kindly remind me of the immediate plans, should we make osmo-nitb configurable to bind on only specific IP addresses, like, now? IIUC that would be a VTY item for osmo-nitb and a parameter into libosmo-abis. Concerning the VTY, the port could be configurable, or the IP address, thinking of 127.0.0.42. I guess relying on `ip netns` would be quicker for now, and I'd have slightly more time for IuCS. Is there anyone else out there that would love to configure osmo-nitb to bind on specific IP addresses only? Thanks, ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From msuraev at sysmocom.de Mon Feb 22 10:58:43 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Mon, 22 Feb 2016 11:58:43 +0100 Subject: [PATCH 1/3] Ignore files generated by cscope tool Message-ID: <1456138725-28145-1-git-send-email-msuraev@sysmocom.de> From: Max Signed-off-by: Max --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6cc9aa5..a22fd4f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ Makefile.in Makefile .deps +src/cscope* aclocal.m4 autom4te.cache -- 2.7.1 From msuraev at sysmocom.de Mon Feb 22 10:58:44 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Mon, 22 Feb 2016 11:58:44 +0100 Subject: [PATCH 2/3] Introduce --gsmtap-ip/-i option In-Reply-To: <1456138725-28145-1-git-send-email-msuraev@sysmocom.de> References: <1456138725-28145-1-git-send-email-msuraev@sysmocom.de> Message-ID: <1456138725-28145-2-git-send-email-msuraev@sysmocom.de> From: Max This option allows user to use custom IP address instead of default "localhost". Correspondingly gsmtap init moved from sysmoBTS-specific code up to "bts" struct level. This way it can be easier reused by other implementations. The lack of regressions was verified by checking following command on sysmoBTS: "./osmo-pcu -c osmo-pcu.cfg -r 1 -i 192.168.10.1" where 192.168.10.1 is the host which was running wireshark and netcat: "nc -u -l 192.168.10.1 -p 4729" to accept gsmtap flow. --- src/bts.h | 2 ++ src/pcu_l1_if.cpp | 5 +++-- src/pcu_main.cpp | 17 ++++++++++++++++- src/sysmo_l1_if.c | 6 ++---- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/bts.h b/src/bts.h index 119f6b2..c975304 100644 --- a/src/bts.h +++ b/src/bts.h @@ -27,6 +27,7 @@ extern "C" { #include #include #include +#include } #include "poll_controller.h" @@ -172,6 +173,7 @@ struct gprs_rlcmac_bts { uint8_t n3101; uint8_t n3103; uint8_t n3105; + struct gsmtap_inst *gsmtap; struct gprs_rlcmac_trx trx[8]; int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts, struct GprsMs *ms, diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index 9d7dbee..e816e6f 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -42,7 +42,7 @@ extern "C" { // FIXME: move this, when changed from c++ to c. extern "C" { -void *l1if_open_pdch(void *priv, uint32_t hlayer1); +void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap); int l1if_connect_pdch(void *obj, uint8_t ts); int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, uint16_t arfcn, uint8_t block_nr, uint8_t *data, uint8_t len); @@ -436,7 +436,8 @@ bssgp_failed: if (!bts->trx[trx].fl1h) bts->trx[trx].fl1h = l1if_open_pdch( (void *)trx, - info_ind->trx[trx].hlayer1); + info_ind->trx[trx].hlayer1, + bts->gsmtap); if (!bts->trx[trx].fl1h) { LOGP(DL1IF, LOGL_FATAL, "Failed to open direct " "DSP access for PDCH.\n"); diff --git a/src/pcu_main.cpp b/src/pcu_main.cpp index 8eb7441..4126d06 100644 --- a/src/pcu_main.cpp +++ b/src/pcu_main.cpp @@ -33,6 +33,8 @@ extern "C" { #include #include #include +#include +#include } extern struct gprs_nsvc *nsvc; @@ -44,6 +46,7 @@ void *tall_pcu_ctx; extern void *bv_tall_ctx; static int quit = 0; static int rt_prio = -1; +static char *gsmtap_addr = "localhost"; // FIXME: use gengetopt's default value instead static void print_help() { @@ -58,6 +61,7 @@ static void print_help() " -V --version print version\n" " -r --realtime PRIO Use SCHED_RR with the specified " "priority\n" + " -i --gsmtap-ip The destination IP used for GSMTAP.\n" ); } @@ -74,10 +78,11 @@ static void handle_options(int argc, char **argv) { "version", 0, 0, 'V' }, { "realtime", 1, 0, 'r' }, { "exit", 0, 0, 'e' }, + { "gsmtap-ip", 1, 0, 'i' }, { 0, 0, 0, 0 } }; - c = getopt_long(argc, argv, "hc:m:n:Vr:e", + c = getopt_long(argc, argv, "hc:m:n:Vr:e:i:", long_options, &option_idx); if (c == -1) break; @@ -102,6 +107,9 @@ static void handle_options(int argc, char **argv) print_version(1); exit(0); break; + case 'i': + gsmtap_addr = optarg; + break; case 'r': rt_prio = atoi(optarg); break; @@ -219,6 +227,13 @@ int main(int argc, char *argv[]) exit(0); } + bts->gsmtap = gsmtap_source_init(gsmtap_addr, GSMTAP_UDP_PORT, 1); + + if (bts->gsmtap) + gsmtap_source_add_sink(bts->gsmtap); + else + fprintf(stderr, "Failed to initialize GSMTAP for %s\n", gsmtap_addr); + rc = vty_read_config_file(config_file, NULL); if (rc < 0 && config_given) { fprintf(stderr, "Failed to parse the config file: '%s'\n", diff --git a/src/sysmo_l1_if.c b/src/sysmo_l1_if.c index 8572786..c7c54dd 100644 --- a/src/sysmo_l1_if.c +++ b/src/sysmo_l1_if.c @@ -357,7 +357,7 @@ int l1if_pdch_req(void *obj, uint8_t ts, int is_ptcch, uint32_t fn, return 0; } -void *l1if_open_pdch(void *priv, uint32_t hlayer1) +void *l1if_open_pdch(void *priv, uint32_t hlayer1, struct gsmtap_inst *gsmtap) { struct femtol1_hdl *fl1h; int rc; @@ -378,9 +378,7 @@ void *l1if_open_pdch(void *priv, uint32_t hlayer1) return NULL; } - fl1h->gsmtap = gsmtap_source_init("localhost", GSMTAP_UDP_PORT, 1); - if (fl1h->gsmtap) - gsmtap_source_add_sink(fl1h->gsmtap); + fl1h->gsmtap = gsmtap; return fl1h; } -- 2.7.1 From msuraev at sysmocom.de Mon Feb 22 10:58:45 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Mon, 22 Feb 2016 11:58:45 +0100 Subject: [PATCH 3/3] Add gsmtap support to generic bts In-Reply-To: <1456138725-28145-1-git-send-email-msuraev@sysmocom.de> References: <1456138725-28145-1-git-send-email-msuraev@sysmocom.de> Message-ID: <1456138725-28145-3-git-send-email-msuraev@sysmocom.de> From: Max Instrument TX and RX functions dealing with regular BTS (without direct DSP access) to use GSMTAP. Previously only DSP-related functions were instrumented. --- src/pcu_l1_if.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index e816e6f..1b727a5 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -30,6 +30,8 @@ extern "C" { #include #include #include +#include +#include } #include @@ -93,7 +95,7 @@ static int pcu_tx_act_req(uint8_t trx, uint8_t ts, uint8_t activate) static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, uint16_t arfcn, uint32_t fn, uint8_t block_nr, uint8_t *data, - uint8_t len) + uint8_t len, struct gsmtap_inst *gsmtap) { struct msgb *msg; struct gsm_pcu_if *pcu_prim; @@ -118,54 +120,58 @@ static int pcu_tx_data_req(uint8_t trx, uint8_t ts, uint8_t sapi, memcpy(data_req->data, data, len); data_req->len = len; + gsmtap_send(gsmtap, arfcn, ts, GSMTAP_CHANNEL_PACCH, 0, fn, 0, 0, data, len); + return pcu_sock_send(msg); } void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP struct gprs_rlcmac_bts *bts = bts_main_data(); +#ifdef ENABLE_SYSMODSP if (bts->trx[trx].fl1h) l1if_pdch_req(bts->trx[trx].fl1h, ts, 0, fn, arfcn, block_nr, msg->data, msg->len); else #endif pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PDTCH, arfcn, fn, block_nr, - msg->data, msg->len); + msg->data, msg->len, bts->gsmtap); msgb_free(msg); } void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, uint32_t fn, uint8_t block_nr) { -#ifdef ENABLE_SYSMODSP struct gprs_rlcmac_bts *bts = bts_main_data(); +#ifdef ENABLE_SYSMODSP if (bts->trx[trx].fl1h) l1if_pdch_req(bts->trx[trx].fl1h, ts, 1, fn, arfcn, block_nr, msg->data, msg->len); else #endif pcu_tx_data_req(trx, ts, PCU_IF_SAPI_PTCCH, arfcn, fn, block_nr, - msg->data, msg->len); + msg->data, msg->len, bts->gsmtap); msgb_free(msg); } void pcu_l1if_tx_agch(bitvec * block, int plen) { uint8_t data[23]; /* prefix PLEN */ - + struct gprs_rlcmac_bts *bts = bts_main_data(); + /* FIXME: why does OpenBTS has no PLEN and no fill in message? */ bitvec_pack(block, data + 1); data[0] = (plen << 2) | 0x01; - pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23); + pcu_tx_data_req(0, 0, PCU_IF_SAPI_AGCH, 0, 0, 0, data, 23, bts->gsmtap); } void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi) { uint8_t data[23+3]; /* prefix PLEN */ + struct gprs_rlcmac_bts *bts = bts_main_data(); /* paging group */ if (!imsi || strlen(imsi) < 3) @@ -177,7 +183,7 @@ void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi) bitvec_pack(block, data + 3+1); data[3] = (plen << 2) | 0x01; - pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3); + pcu_tx_data_req(0, 0, PCU_IF_SAPI_PCH, 0, 0, 0, data, 23+3, bts->gsmtap); } extern "C" void pcu_rx_block_time(uint16_t arfcn, uint32_t fn, uint8_t ts_no) @@ -200,7 +206,7 @@ extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *dat return pdch->rcv_block(data, len, fn, meas); } -static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) +static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind, struct gsmtap_inst *gsmtap) { int rc = 0; pcu_l1_meas meas; @@ -223,6 +229,15 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind) rc = -EINVAL; } + if (rc < 0) + return rc; + + int r = gsmtap_send(gsmtap, data_ind->arfcn | GSMTAP_ARFCN_F_UPLINK, data_ind->ts_nr, + GSMTAP_CHANNEL_PACCH, 0, data_ind->fn, 0, 0, data_ind->data, data_ind->len); + if (r < 0) { + LOGP(DL1IF, LOGL_ERROR, "Sending RX data via GSMTAP failed: %d\n", r); + } + return rc; } @@ -508,10 +523,11 @@ static int pcu_rx_pag_req(struct gsm_pcu_if_pag_req *pag_req) int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim) { int rc = 0; + struct gprs_rlcmac_bts *bts = bts_main_data(); switch (msg_type) { case PCU_IF_MSG_DATA_IND: - rc = pcu_rx_data_ind(&pcu_prim->u.data_ind); + rc = pcu_rx_data_ind(&pcu_prim->u.data_ind, bts->gsmtap); break; case PCU_IF_MSG_DATA_CNF: rc = pcu_rx_data_cnf(&pcu_prim->u.data_cnf); -- 2.7.1 From laforge at gnumonks.org Mon Feb 22 11:11:27 2016 From: laforge at gnumonks.org (Harald Welte) Date: Mon, 22 Feb 2016 12:11:27 +0100 Subject: osmo-nitb configurable In-Reply-To: <20160222103906.GA11457@dub6> References: <20160222103906.GA11457@dub6> Message-ID: <20160222111127.GT5883@nataraja> Hi Neels, On Mon, Feb 22, 2016 at 11:39:06AM +0100, Neels Hofmeyr wrote: > Holger has just refreshed my memory on a conversation we've had on running > multiple NITB instances on the same box: Linux Network Namespaces vs. > making NITB configurable. > > Kindly remind me of the immediate plans, should we make osmo-nitb > configurable to bind on only specific IP addresses, like, now? yes, I think that would be very useful. > IIUC that would be a VTY item for osmo-nitb and a parameter into > libosmo-abis. Concerning the VTY, the port could be configurable, or the > IP address, thinking of 127.0.0.42. also don't forget the control interface. Furthermore, the unix domain sockets for rf_control and for MNCC need to be configurable, too. Ah, I just see it already is by means of the '-r' command line argument. In general I prefer things being configured via VTY paramters over command line arguments. > I guess relying on `ip netns` would be quicker for now, and I'd have > slightly more time for IuCS. I'm not sure this solves the general problem, and it is of course highly Linux-specific. For an all-IP NITB there currently is no strict Linux dependency. I would say maing the addresses configurable seems reasonably straight-forward to do it right now. It shouldn't take much time, or am I missing something? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Mon Feb 22 11:20:52 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 12:20:52 +0100 Subject: no member named 'bts' In-Reply-To: <20160222094810.GB15564@dub6> References: <20160218224544.GA18542@dub6> <1455897821.8409.12.camel@sysmocom.de> <99A95E9A-A5D5-46A7-80BB-045A7A42A3B6@freyther.de> <20160220153948.GD1953@dub6> <20160221101645.GA1884@dub6> <20160221112610.GC1884@dub6> <24702181-0653-4A1D-9F8C-7B33D6D34B74@freyther.de> <20160222094810.GB15564@dub6> Message-ID: <20160222112052.GB11457@dub6> On Mon, Feb 22, 2016 at 10:48:10AM +0100, Neels Hofmeyr wrote: > On Sun, Feb 21, 2016 at 01:57:27PM +0100, Holger Freyther wrote: > > then maybe disable the osmo-bsc right now? > > Yeah in fact that's also disabled in my build. I'm looking at it now for a > few minutes, but why not disable it until we got it back on its feet... sysmocom-iu's osmo-bsc is compiling now. At least for me :P verbose comments in c01abec. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Feb 22 11:28:44 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 12:28:44 +0100 Subject: osmo-nitb configurable In-Reply-To: <20160222111127.GT5883@nataraja> References: <20160222103906.GA11457@dub6> <20160222111127.GT5883@nataraja> Message-ID: <20160222112844.GC11457@dub6> On Mon, Feb 22, 2016 at 12:11:27PM +0100, Harald Welte wrote: > I would say maing the addresses configurable seems reasonably > straight-forward to do it right now. It shouldn't take much time, or am > I missing something? No, I think we've mentioned all items, thanks for the ctrl iface reminder. The only counter argument is that I'm constantly doing things that don't take much time instead of moving ahead on IuCS :P But indeed, it makes sense to do it now so that we can employ it in our test setup, saving reconfiguration time later. I'll do that, then. (before hunting the hnbgw segfaults mentioned in another mail) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Feb 22 11:55:06 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 12:55:06 +0100 Subject: rebase sysmocom-iu? branch 'jerlbeck/fixes/sgsn' merged to master Message-ID: <20160222115506.GD11457@dub6> Hi Daniel, the 'jerlbeck/fixes/sgsn' branch has been merged to master. sysmocom-iu has some merge conflicts in the SGSN, so I assume it's better if you do the rebase of sysmocom-iu onto master. Agree? It would also be nice if we did the merge together ... maybe ping me when you do the rebase and I'll see if I join you. I would like to stay as close to master as possible to avoid conflict build up. If you could do the rebase sooner rather than later, that would be great. Thanks! (I could have told you in person but it's good to let the list know, too) ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Tue Feb 23 10:09:49 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 23 Feb 2016 11:09:49 +0100 Subject: [PATCH] ipa driver: make bind address vty configurable In-Reply-To: <1456222189-13203-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456222189-13203-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456222189-13203-2-git-send-email-nhofmeyr@sysmocom.de> Add VTY function to set the ipa bind address: e1_input ipa bind (A.B.C.D|any) Add a priv pointer to struct e1inp_driver in order to communicate the bind address parameter to ipaccess_line_update(). Add two "internal.h" functions to get/set it in the ipa driver struct. Add static ip_bind_addr() to use the IP address set from the VTY or, if none, use "0.0.0.0". Apply in ipaccess_line_update(). --- include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 27 +++++++++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/include/internal.h b/include/internal.h index 7f6e31a..740a86d 100644 --- a/include/internal.h +++ b/include/internal.h @@ -13,6 +13,9 @@ extern void *libosmo_abis_ctx; /* use libosmo_abis_init, this is only for internal use. */ void e1inp_init(void); +void e1inp_ipaccess_set_bind(const char *ip_bind_addr); +const char *e1inp_ipaccess_get_bind(void); + /* ipaccess.c requires these functions defined here */ struct msgb; struct msgb *ipa_msg_alloc(int headroom); diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index e5d2991..4d00e03 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -139,6 +139,7 @@ struct e1inp_driver { void (*vty_show)(struct vty *vty, struct e1inp_line *line); int default_delay; int has_keepalive; + void *priv; }; struct e1inp_line_ops { diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index 0b4adb2..130c9bb 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -168,6 +168,25 @@ DEFUN(cfg_e1inp, cfg_e1inp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ipa_bind, + cfg_ipa_bind_cmd, + "ipa bind (A.B.C.D|any)", + "ipa driver config\n" + "Set ipa local bind address\n" + "Listen only on this IP address\n" + "Listen on any local interface\n") +{ + const char *want_bind; + if (strcmp(argv[0], "any") == 0) + want_bind = NULL; + else + want_bind = argv[0]; + e1inp_ipaccess_set_bind(want_bind); + + return CMD_SUCCESS; +} + + static int e1inp_config_write(struct vty *vty) { struct e1inp_line *line; @@ -202,6 +221,12 @@ static int e1inp_config_write(struct vty *vty) VTY_NEWLINE); } + + const char *ipa_bind = e1inp_ipaccess_get_bind(); + if (ipa_bind) + vty_out(vty, " ipa bind %s%s", + ipa_bind, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -351,6 +376,8 @@ int e1inp_vty_init(void) install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); + install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); install_element_ve(&show_e1ts_cmd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ffdb19..d645e24 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -804,6 +804,13 @@ struct ipaccess_line { int line_already_initialized; }; +static const char *ip_bind_addr() +{ + return ipaccess_driver.priv? + ((const char*)ipaccess_driver.priv) + : "0.0.0.0"; +} + static int ipaccess_line_update(struct e1inp_line *line) { int ret = -ENOENT; @@ -831,7 +838,7 @@ static int ipaccess_line_update(struct e1inp_line *line) LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode\n"); oml_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_OML, + ip_bind_addr(), IPA_TCP_PORT_OML, ipaccess_bsc_oml_cb, NULL); if (oml_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create OML " @@ -845,7 +852,7 @@ static int ipaccess_line_update(struct e1inp_line *line) return -EIO; } rsl_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_RSL, + ip_bind_addr(), IPA_TCP_PORT_RSL, ipaccess_bsc_rsl_cb, NULL); if (rsl_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL " @@ -944,3 +951,20 @@ void e1inp_ipaccess_init(void) tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa"); e1inp_driver_register(&ipaccess_driver); } + +void e1inp_ipaccess_set_bind(const char *ip_bind_addr) +{ + if (ipaccess_driver.priv) { + talloc_free(ipaccess_driver.priv); + ipaccess_driver.priv = NULL; + } + + if (ip_bind_addr) + ipaccess_driver.priv = (void*)talloc_strdup(tall_ipa_ctx, + ip_bind_addr); +} + +const char *e1inp_ipaccess_get_bind(void) +{ + return (const char*)ipaccess_driver.priv; +} -- 2.1.4 From nhofmeyr at sysmocom.de Tue Feb 23 10:09:48 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Tue, 23 Feb 2016 11:09:48 +0100 Subject: [PATCH] configure Abis/IP bind address Message-ID: <1456222189-13203-1-git-send-email-nhofmeyr@sysmocom.de> This patch allows Abis/IP bind address config for osmo-nitb as well as the osmo-bscs, without touching openbsc.git. This is the libosmo-abis part of making osmo-nitb's IP addresses configurable instead of always listening on 'any'. This will allow running more than one on the same box. Ctrl interface and vty are to follow, though not in this repo. I did sink a bit of time until the penny dropped that all I need to do is add a VTY command in libosmo-abis, but I did find out eventually. Neels Hofmeyr (1): ipa driver: make bind address vty configurable include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 27 +++++++++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 57 insertions(+), 2 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:34:55 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:34:55 +0100Wed, 24 Feb 2016 03:33:17 +0100 Subject: [PATCH] v2 of: configure Abis/IP bind address Message-ID: <201602240235.u1O2ZiqP027049@einhorn.in-berlin.de> I decided to drop the 'any' keyword from the Abis bind address config, to ensure that the written config is always identical to the parsed config. Neels Hofmeyr (1): ipa driver: make bind address vty configurable include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 2 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:34:57 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:34:57 +0100Mon, 22 Feb 2016 13:29:09 +0100 Subject: [PATCH] ipa driver: make bind address vty configurable Message-ID: <201602240235.u1O2Zjxb027056@einhorn.in-berlin.de> Add VTY function to set the ipa bind address: e1_input ipa bind A.B.C.D Add a priv pointer to struct e1inp_driver in order to communicate the bind address parameter to ipaccess_line_update(). Add two "internal.h" functions to get/set it in the ipa driver struct. Add static ip_bind_addr() to use the IP address set from the VTY or, if NULL, use "0.0.0.0". Apply in ipaccess_line_update(). --- include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/internal.h b/include/internal.h index 7f6e31a..740a86d 100644 --- a/include/internal.h +++ b/include/internal.h @@ -13,6 +13,9 @@ extern void *libosmo_abis_ctx; /* use libosmo_abis_init, this is only for internal use. */ void e1inp_init(void); +void e1inp_ipaccess_set_bind(const char *ip_bind_addr); +const char *e1inp_ipaccess_get_bind(void); + /* ipaccess.c requires these functions defined here */ struct msgb; struct msgb *ipa_msg_alloc(int headroom); diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index e5d2991..4d00e03 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -139,6 +139,7 @@ struct e1inp_driver { void (*vty_show)(struct vty *vty, struct e1inp_line *line); int default_delay; int has_keepalive; + void *priv; }; struct e1inp_line_ops { diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index 0b4adb2..71747f0 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -168,6 +168,18 @@ DEFUN(cfg_e1inp, cfg_e1inp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ipa_bind, + cfg_ipa_bind_cmd, + "ipa bind A.B.C.D", + "ipa driver config\n" + "Set ipa local bind address\n" + "Listen on this IP address (default 0.0.0.0)\n") +{ + e1inp_ipaccess_set_bind(argv[0]); + return CMD_SUCCESS; +} + + static int e1inp_config_write(struct vty *vty) { struct e1inp_line *line; @@ -202,6 +214,12 @@ static int e1inp_config_write(struct vty *vty) VTY_NEWLINE); } + + const char *ipa_bind = e1inp_ipaccess_get_bind(); + if (ipa_bind) + vty_out(vty, " ipa bind %s%s", + ipa_bind, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -351,6 +369,8 @@ int e1inp_vty_init(void) install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); + install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); install_element_ve(&show_e1ts_cmd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ffdb19..d645e24 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -804,6 +804,13 @@ struct ipaccess_line { int line_already_initialized; }; +static const char *ip_bind_addr() +{ + return ipaccess_driver.priv? + ((const char*)ipaccess_driver.priv) + : "0.0.0.0"; +} + static int ipaccess_line_update(struct e1inp_line *line) { int ret = -ENOENT; @@ -831,7 +838,7 @@ static int ipaccess_line_update(struct e1inp_line *line) LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode\n"); oml_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_OML, + ip_bind_addr(), IPA_TCP_PORT_OML, ipaccess_bsc_oml_cb, NULL); if (oml_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create OML " @@ -845,7 +852,7 @@ static int ipaccess_line_update(struct e1inp_line *line) return -EIO; } rsl_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_RSL, + ip_bind_addr(), IPA_TCP_PORT_RSL, ipaccess_bsc_rsl_cb, NULL); if (rsl_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL " @@ -944,3 +951,20 @@ void e1inp_ipaccess_init(void) tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa"); e1inp_driver_register(&ipaccess_driver); } + +void e1inp_ipaccess_set_bind(const char *ip_bind_addr) +{ + if (ipaccess_driver.priv) { + talloc_free(ipaccess_driver.priv); + ipaccess_driver.priv = NULL; + } + + if (ip_bind_addr) + ipaccess_driver.priv = (void*)talloc_strdup(tall_ipa_ctx, + ip_bind_addr); +} + +const char *e1inp_ipaccess_get_bind(void) +{ + return (const char*)ipaccess_driver.priv; +} -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:39:33 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:39:33 +0100Wed, 24 Feb 2016 03:36:57 +0100 Subject: [PATCH 0/3] prepare configuration of vty-telnet and ctrl binds Message-ID: <201602240240.u1O2eL5d030417@einhorn.in-berlin.de> Patch sets for openbsc and osmo-iuh will follow. Neels Hofmeyr (3): vty: add bind command for telnet vty line add bind address parameter to ctrl_interface_setup() Add VTY section for Control interface bind address include/Makefile.am | 3 +- include/osmocom/ctrl/control_if.h | 4 +- include/osmocom/ctrl/control_vty.h | 9 ++++ include/osmocom/vty/command.h | 3 +- include/osmocom/vty/vty.h | 3 ++ src/ctrl/Makefile.am | 4 ++ src/ctrl/control_if.c | 6 +-- src/ctrl/control_vty.c | 90 ++++++++++++++++++++++++++++++++++++++ src/vty/vty.c | 32 ++++++++++++++ 9 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 include/osmocom/ctrl/control_vty.h create mode 100644 src/ctrl/control_vty.c -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:39:35 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:39:35 +0100Tue, 23 Feb 2016 14:01:41 +0100 Subject: [PATCH 1/3] vty: add bind command for telnet vty line Message-ID: <201602240240.u1O2eNDc030422@einhorn.in-berlin.de> Add VTY command line vty bind A.B.C.D The command merely stores the configured IP-address, which can then be used by the calling main program to set the telnet port of the VTY line. (Commits in openbsc and osmo-iuh will follow up on this.) Add function vty_get_bind_addr() to publish the address in the vty.h API. Add static vty_bind_addr to store. For allocation/freeing reasons, a NULL address defaults to 127.0.0.1. BTW, I decided against allowing keywords 'any' and 'localhost' in place of an actual IP address to make sure a written config is always identical to the parsed config. --- include/osmocom/vty/vty.h | 3 +++ src/vty/vty.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/osmocom/vty/vty.h b/include/osmocom/vty/vty.h index 3684397..43cb0cf 100644 --- a/include/osmocom/vty/vty.h +++ b/include/osmocom/vty/vty.h @@ -186,6 +186,9 @@ void *vty_current_index(struct vty *); int vty_current_node(struct vty *vty); int vty_go_parent(struct vty *vty); +/* Return IP address passed to the 'line vty'/'bind' command, or "127.0.0.1" */ +const char *vty_get_bind_addr(void); + extern void *tall_vty_ctx; extern struct cmd_element cfg_description_cmd; diff --git a/src/vty/vty.c b/src/vty/vty.c index 5bcbe4a..7e27d7e 100644 --- a/src/vty/vty.c +++ b/src/vty/vty.c @@ -75,6 +75,10 @@ vector Vvty_serv_thread; char *vty_cwd = NULL; +/* IP address passed to the 'line vty'/'bind' command */ +static const char *vty_bind_addr = NULL; +#define VTY_BIND_ADDR_DEFAULT "127.0.0.1" + /* Configure lock. */ static int vty_config; @@ -1585,6 +1589,29 @@ DEFUN(no_vty_login, return CMD_SUCCESS; } +/* vty bind */ +DEFUN(vty_bind, vty_bind_cmd, "bind A.B.C.D", + "Accept VTY telnet connections on local interface\n" + "Local interface IP address (default: " VTY_BIND_ADDR_DEFAULT ")\n") +{ + /* Avoid (small) mem leak: initially, vty_bind_addr is NULL. Whenever + * this gets called, it is set to a strdup. So whenever it is non-NULL, + * free it first. See also vty_get_bind_addr() for the NULL default. */ + if (vty_bind_addr) { + talloc_free((void*)vty_bind_addr); + vty_bind_addr = NULL; + } + vty_bind_addr = talloc_strdup(tall_vty_ctx, argv[0]); + return CMD_SUCCESS; +} + +const char *vty_get_bind_addr(void) +{ + if (!vty_bind_addr) + return VTY_BIND_ADDR_DEFAULT; + return vty_bind_addr; +} + DEFUN(service_advanced_vty, service_advanced_vty_cmd, "service advanced-vty", @@ -1654,6 +1681,10 @@ static int vty_config_write(struct vty *vty) if (!password_check) vty_out(vty, " no login%s", VTY_NEWLINE); + /* bind */ + if (vty_bind_addr) + vty_out(vty, " bind %s%s", vty_bind_addr, VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -1757,6 +1788,7 @@ void vty_init(struct vty_app_info *app_info) vty_install_default(VTY_NODE); install_element(VTY_NODE, &vty_login_cmd); install_element(VTY_NODE, &no_vty_login_cmd); + install_element(VTY_NODE, &vty_bind_cmd); } /*! \brief Read the configuration file using the VTY code -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:39:37 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:39:37 +0100Wed, 24 Feb 2016 00:09:40 +0100 Subject: [PATCH 2/3] add bind address parameter to ctrl_interface_setup() Message-ID: <201602240240.u1O2ePec030429@einhorn.in-berlin.de> Make the ctrl interface bind address configurable, so that it may be made available on other addresses than 127.0.0.1. The specific aim is to allow running multiple osmo-nitbs alongside each other (commits in openbsc follow). --- include/osmocom/ctrl/control_if.h | 4 ++-- src/ctrl/control_if.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/osmocom/ctrl/control_if.h b/include/osmocom/ctrl/control_if.h index 00caacc..2f327c1 100644 --- a/include/osmocom/ctrl/control_if.h +++ b/include/osmocom/ctrl/control_if.h @@ -20,7 +20,7 @@ struct ctrl_handle { int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd); -struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, - ctrl_cmd_lookup lookup); +struct ctrl_handle *ctrl_interface_setup(void *data, const char *bind_addr, + uint16_t port, ctrl_cmd_lookup lookup); int ctrl_cmd_handle(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data); diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c index 18e695d..74c84c9 100644 --- a/src/ctrl/control_if.c +++ b/src/ctrl/control_if.c @@ -670,8 +670,8 @@ static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data) return 0; } -struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, - ctrl_cmd_lookup lookup) +struct ctrl_handle *ctrl_interface_setup(void *data, const char *bind_addr, + uint16_t port, ctrl_cmd_lookup lookup) { int ret; struct ctrl_handle *ctrl; @@ -693,7 +693,7 @@ struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl->listen_fd.cb = listen_fd_cb; ctrl->listen_fd.data = ctrl; ret = osmo_sock_init_ofd(&ctrl->listen_fd, AF_INET, SOCK_STREAM, IPPROTO_TCP, - "127.0.0.1", port, OSMO_SOCK_F_BIND); + bind_addr, port, OSMO_SOCK_F_BIND); if (ret < 0) goto err_vec; -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:39:39 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:39:39 +0100Wed, 24 Feb 2016 00:10:41 +0100 Subject: [PATCH 3/3] Add VTY section for Control interface bind address Message-ID: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> This may seem like overkill for a mere const char * config item, but it makes the Control interface VTY commands reusable in any main() scope (inspired by libosmo-abis' VTY config). Add API functions ctrl_vty_init() and ctrl_vty_get_bind_addr(), in new files src/ctrl/control_vty.c and include/osmocom/ctrl/control_vty.h, compiled and/or installed dependent on ENABLE_VTY. Using these functions allows configuring a static const char* with the VTY commands ctrl bind A.B.C.D which callers shall subsequently use to bind the Control interface to a specific local interface address, by passing the return value of ctrl_vty_get_bind_addr() to control_interface_setup(). Add CTRL_NODE to enum node_type, "eating" RESERVED4_NODE to heed that comment on avoiding ABI changes. --- include/Makefile.am | 3 +- include/osmocom/ctrl/control_vty.h | 9 ++++ include/osmocom/vty/command.h | 3 +- src/ctrl/Makefile.am | 4 ++ src/ctrl/control_vty.c | 90 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 include/osmocom/ctrl/control_vty.h create mode 100644 src/ctrl/control_vty.c diff --git a/include/Makefile.am b/include/Makefile.am index a965fb9..ac22ee6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -117,7 +117,8 @@ nobase_include_HEADERS += \ osmocom/vty/telnet_interface.h \ osmocom/vty/vector.h \ osmocom/vty/vty.h \ - osmocom/vty/ports.h + osmocom/vty/ports.h \ + osmocom/ctrl/control_vty.h endif noinst_HEADERS = \ diff --git a/include/osmocom/ctrl/control_vty.h b/include/osmocom/ctrl/control_vty.h new file mode 100644 index 0000000..d0ef69f --- /dev/null +++ b/include/osmocom/ctrl/control_vty.h @@ -0,0 +1,9 @@ +#pragma once + +/* Add the 'ctrl' section to VTY, containing the 'bind' command. */ +int ctrl_vty_init(void *ctx); + +/* Obtain the IP address configured by the 'ctrl'/'bind A.B.C.D' VTY command. + * This should be fed to ctrl_interface_setup() once the configuration has been + * read. */ +const char *ctrl_vty_get_bind_addr(void); diff --git a/include/osmocom/vty/command.h b/include/osmocom/vty/command.h index 2078e1b..937d2f8 100644 --- a/include/osmocom/vty/command.h +++ b/include/osmocom/vty/command.h @@ -84,6 +84,8 @@ enum node_type { L_NS_NODE, /*!< \brief NS node in libosmo-gb. */ L_BSSGP_NODE, /*!< \brief BSSGP node in libosmo-gb. */ + CTRL_NODE, /*!< \brief Control interface node. */ + /* * When adding new nodes to the libosmocore project, these nodes can be * used to avoid ABI changes for unrelated projects. @@ -91,7 +93,6 @@ enum node_type { RESERVED1_NODE, /*!< \brief Reserved for later extensions */ RESERVED2_NODE, /*!< \brief Reserved for later extensions */ RESERVED3_NODE, /*!< \brief Reserved for later extensions */ - RESERVED4_NODE, /*!< \brief Reserved for later extensions */ _LAST_OSMOVTY_NODE }; diff --git a/src/ctrl/Makefile.am b/src/ctrl/Makefile.am index e6ccafb..b4a3da4 100644 --- a/src/ctrl/Makefile.am +++ b/src/ctrl/Makefile.am @@ -13,3 +13,7 @@ libosmoctrl_la_LIBADD = \ $(top_builddir)/src/libosmocore.la \ $(top_builddir)/src/gsm/libosmogsm.la \ $(top_builddir)/src/vty/libosmovty.la + +if ENABLE_VTY +libosmoctrl_la_SOURCES += control_vty.c +endif diff --git a/src/ctrl/control_vty.c b/src/ctrl/control_vty.c new file mode 100644 index 0000000..7df53b8 --- /dev/null +++ b/src/ctrl/control_vty.c @@ -0,0 +1,90 @@ +/* VTY configuration for Control interface + * + * (C) 2016 by sysmocom s.m.f.c GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include + +static void *ctrl_vty_ctx = NULL; +static const char *ctrl_vty_bind_addr = NULL; + +DEFUN(cfg_ctrl_bind_addr, + cfg_ctrl_bind_addr_cmd, + "bind A.B.C.D", + "Set bind address to listen for Control connections\n" + "Local IP address (default 127.0.0.1)\n") +{ + if (ctrl_vty_bind_addr) { + talloc_free((void*)ctrl_vty_bind_addr); + ctrl_vty_bind_addr = NULL; + } + ctrl_vty_bind_addr = talloc_strdup(ctrl_vty_ctx, argv[0]); + return CMD_SUCCESS; +} + +const char *ctrl_vty_get_bind_addr(void) +{ + if (!ctrl_vty_bind_addr) + return "127.0.0.1"; + return ctrl_vty_bind_addr; +} + +struct cmd_node ctrl_node = { + CTRL_NODE, + "%s(config-ctrl)# ", + 1, +}; + +DEFUN(cfg_ctrl, + cfg_ctrl_cmd, + "ctrl", "Configure the Control Interface") +{ + vty->index = NULL; + vty->node = CTRL_NODE; + + return CMD_SUCCESS; +} + +static int config_write_ctrl(struct vty *vty) +{ + /* So far there's only one element. Omit the entire section if the bind + * element is omitted. */ + if (!ctrl_vty_bind_addr) + return CMD_SUCCESS; + + vty_out(vty, "ctrl%s", VTY_NEWLINE); + vty_out(vty, " bind %s%s", ctrl_vty_bind_addr, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +int ctrl_vty_init(void *ctx) +{ + ctrl_vty_ctx = ctx; + install_element(CONFIG_NODE, &cfg_ctrl_cmd); + install_node(&ctrl_node, config_write_ctrl); + + install_element(CTRL_NODE, &cfg_ctrl_bind_addr_cmd); + return 0; +} + -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:51 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:51 +0100Wed, 24 Feb 2016 03:41:57 +0100 Subject: [PATCH 0/6] Allow osmo-nitb bind config (and others) Message-ID: <201602240257.u1O2vexC010412@einhorn.in-berlin.de> Following the previous patch sets for libosmo-abis and libosmocore, this patch set allows configuring almost all of the osmo-nitb IP addresses. The goal is to allow several osmo-nitb processes to run alongside each other. (1) Abis/IP (from the libosmo-abis patch) in the config file, have: e1_input ipa bind 10.9.8.7 (2) telnet VTY (prepared by libosmocore patch set) in the config file, have: line vty bind 127.0.0.99 (3) ctrl interface (prepared by libosmocore patch set) in the config file, have: ctrl bind 127.0.0.99 (4) MNCC socket In addition to the old -m option with a fixed socket path, you may now supply a cmdline argument with explicit path: -M /path/to/socket/file (5) still TODO: SMPP SMSC libsmpp34 is still listening on 0.0.0.0:2775, requires a change in libsmpp34. Will follow in a subsequent patch. Neels Hofmeyr (6): enable telnet VTY bind address config for various programs osmo-nitb: add -M to pass specific MNCC socket path osmo-nitb: cosmetic: rename to rf_ctrl_path, following mncc_sock_path osmo-nitb: be strict about cmdline args enable ctrl bind config for various programs bsc_nat: fail if VTY telnet port cannot be bound openbsc/include/openbsc/bsc_nat.h | 3 ++- openbsc/include/openbsc/ctrl.h | 3 ++- openbsc/include/openbsc/gprs_sgsn.h | 3 ++- openbsc/include/openbsc/mncc.h | 2 +- openbsc/src/gprs/gb_proxy_main.c | 12 ++++++---- openbsc/src/gprs/gtphub_main.c | 11 ++++++--- openbsc/src/gprs/sgsn_ctrl.c | 5 ++-- openbsc/src/gprs/sgsn_main.c | 42 ++++++++++++++++++++++----------- openbsc/src/libbsc/bsc_ctrl_lookup.c | 6 +++-- openbsc/src/libbsc/bsc_init.c | 6 ++++- openbsc/src/libmsc/mncc_sock.c | 9 +++---- openbsc/src/osmo-bsc/osmo_bsc_main.c | 10 +++++++- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 6 ++++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 21 ++++++++++++++--- openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c | 5 ++-- openbsc/src/osmo-nitb/bsc_hack.c | 39 ++++++++++++++++++++---------- 16 files changed, 130 insertions(+), 53 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:53 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:53 +0100Tue, 23 Feb 2016 14:09:38 +0100 Subject: [PATCH 1/6] enable telnet VTY bind address config for various programs Message-ID: <201602240257.u1O2vfQd010420@einhorn.in-berlin.de> Following the 'line vty'/'bind A.B.C.D' command added in libosmocore, use the configured address to set the telnet bind for the VTY line. It is now possible to publish the VTY on a specific local interface (including 0.0.0.0 aka "any"). Implement in all of: osmo-gbproxy osmo-gtphub osmo-sgsn osmo-bsc osmo-bsc_nat osmo-bsc_mgcp osmo-nitb In some of these main programs, move the telnet initialization below the configuration parsing. Historically, this was not a good idea for programs using bsc_init.c (aka bsc_bootstrap_network()), since they expected a gsm_network struct pointer in ((struct telnet_connection*)vty->priv)->priv, so that telnet had to be either initialized or replaced by a dummy struct. In the meantime, the gsm_network struct is not actually looked up in a priv pointer but in the static bsc_vty.c scope (bsc_gsmnet), so this limitation is mere legacy (even though said legacy is still there in an "#if 0" chunk). In the other binaries I have briefly looked at the init sequence dependencies and found no reason to initialize telnet above the config file parsing. In any case, I have tested every single one of abovementioned binaries to verify that they still parse the example config successfully and launch, allowing VTY connections on the configured address(es). I hope this suffices. In all of the above, log VTY address and port. LOGL_INFO is disabled by default in some of the logging scopes, and since it is a single log message right at program launch, I decided for the slightly more aggressive LOGL_NOTICE. --- openbsc/src/gprs/gb_proxy_main.c | 12 ++++++++---- openbsc/src/gprs/gtphub_main.c | 11 ++++++++--- openbsc/src/gprs/sgsn_main.c | 11 ++++++++--- openbsc/src/libbsc/bsc_init.c | 6 +++++- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 6 +++++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 7 ++++++- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index f82fb5b..0c3cfbe 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -252,10 +252,6 @@ int main(int argc, char **argv) rate_ctr_init(tall_bsc_ctx); osmo_stats_init(tall_bsc_ctx); - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_GBPROXY); - if (rc < 0) - exit(1); - bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_bsc_ctx); if (!bssgp_nsi) { LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); @@ -274,6 +270,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY); + if (rc < 0) + exit(1); + if (!gprs_nsvc_by_nsei(gbcfg.nsi, gbcfg.nsip_sgsn_nsei)) { LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u " "without creating that NSEI before\n", diff --git a/openbsc/src/gprs/gtphub_main.c b/openbsc/src/gprs/gtphub_main.c index f18710d..89582b1 100644 --- a/openbsc/src/gprs/gtphub_main.c +++ b/openbsc/src/gprs/gtphub_main.c @@ -314,9 +314,6 @@ int main(int argc, char **argv) gtphub_vty_init(hub, cfg); rate_ctr_init(osmo_gtphub_ctx); - rc = telnet_init(osmo_gtphub_ctx, 0, OSMO_VTY_PORT_GTPHUB); - if (rc < 0) - exit(1); handle_options(ccfg, argc, argv); @@ -327,6 +324,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGTPHUB, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_GTPHUB); + rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(), + OSMO_VTY_PORT_GTPHUB); + if (rc < 0) + exit(1); + if (gtphub_start(hub, cfg, next_restart_count(ccfg->restart_counter_file)) != 0) diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 2d3a0e4..b10b0b3 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -315,9 +315,6 @@ int main(int argc, char **argv) handle_options(argc, argv); rate_ctr_init(tall_bsc_ctx); - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_SGSN); - if (rc < 0) - exit(1); ctrl = sgsn_controlif_setup(NULL, OSMO_CTRL_PORT_SGSN); if (!ctrl) { @@ -357,6 +354,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_SGSN); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_SGSN); + if (rc < 0) + exit(1); + rc = sgsn_gtp_init(&sgsn_inst); if (rc) { LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n"); diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 743f4c1..859d999 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -495,7 +495,11 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *), return rc; } - rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, OSMO_VTY_PORT_NITB_BSC); + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_NITB_BSC); + rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(), + OSMO_VTY_PORT_NITB_BSC); if (rc < 0) return rc; diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index d755c90..e226b02 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -232,7 +232,11 @@ int main(int argc, char **argv) if (rc < 0) return rc; - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_BSC_MGCP); + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DMGCP, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP); if (rc < 0) return rc; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 41291d9..e3dc10e 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -1628,12 +1628,17 @@ int main(int argc, char **argv) osmo_stats_init(tall_bsc_ctx); /* init vty and parse */ - telnet_init(tall_bsc_ctx, NULL, OSMO_VTY_PORT_BSC_NAT); if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) { fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); return -3; } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DNAT, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_NAT); + telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), + OSMO_VTY_PORT_BSC_NAT); + /* over rule the VTY config */ if (msc_ip) bsc_nat_set_msc_ip(nat, msc_ip); -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:54 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:54 +0100Tue, 23 Feb 2016 14:55:17 +0100 Subject: [PATCH 2/6] osmo-nitb: add -M to pass specific MNCC socket path Message-ID: <201602240257.u1O2vhAD010427@einhorn.in-berlin.de> The old -m option without argument is still available and marked deprecated, to not make users' lives more difficult than necessary. --- openbsc/include/openbsc/mncc.h | 2 +- openbsc/src/libmsc/mncc_sock.c | 9 +++++---- openbsc/src/osmo-nitb/bsc_hack.c | 17 +++++++++++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 10192ad..49f0c8b 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -206,7 +206,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg); /* input from CC code into mncc_sock */ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg); -int mncc_sock_init(struct gsm_network *gsmnet); +int mncc_sock_init(struct gsm_network *net, const char *sock_path); #define mncc_is_data_frame(msg_type) \ (msg_type == GSM_TCHF_FRAME \ diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c index dd0a44f..6da1c56 100644 --- a/openbsc/src/libmsc/mncc_sock.c +++ b/openbsc/src/libmsc/mncc_sock.c @@ -277,7 +277,7 @@ static int mncc_sock_accept(struct osmo_fd *bfd, unsigned int flags) } -int mncc_sock_init(struct gsm_network *net) +int mncc_sock_init(struct gsm_network *net, const char *sock_path) { struct mncc_sock_state *state; struct osmo_fd *bfd; @@ -292,10 +292,10 @@ int mncc_sock_init(struct gsm_network *net) bfd = &state->listen_bfd; - rc = osmo_unixsock_listen(bfd, SOCK_SEQPACKET, "/tmp/bsc_mncc"); + rc = osmo_unixsock_listen(bfd, SOCK_SEQPACKET, sock_path); if (rc < 0) { - LOGP(DMNCC, LOGL_ERROR, "Could not create unix socket: %s\n", - strerror(errno)); + LOGP(DMNCC, LOGL_ERROR, "Could not create unix socket: %s: %s\n", + sock_path, strerror(errno)); talloc_free(state); return rc; } @@ -314,6 +314,7 @@ int mncc_sock_init(struct gsm_network *net) net->mncc_state = state; + LOGP(DMNCC, LOGL_NOTICE, "MNCC socket at %s\n", sock_path); return 0; } diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 8b074f1..3c878a6 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -62,7 +62,7 @@ static const char *config_file = "openbsc.cfg"; static const char *rf_ctrl_name = NULL; extern const char *openbsc_copyright; static int daemonize = 0; -static int use_mncc_sock = 0; +static const char *mncc_sock_path = NULL; static int use_db_counter = 1; /* timer to store statistics */ @@ -103,7 +103,8 @@ static void print_help() printf(" -V --version Print the version of OpenBSC.\n"); printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC.\n"); printf(" -e --log-level number Set a global loglevel.\n"); - printf(" -m --mncc-sock Disable built-in MNCC handler and offer socket.\n"); + printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n"); + printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n"); printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n"); printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n"); } @@ -126,12 +127,13 @@ static void handle_options(int argc, char **argv) {"rtp-proxy", 0, 0, 'P'}, {"log-level", 1, 0, 'e'}, {"mncc-sock", 0, 0, 'm'}, + {"mncc-sock-path", 1, 0, 'M'}, {"no-dbcounter", 0, 0, 'C'}, {"rf-ctl", 1, 0, 'r'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:Dsl:ar:p:TPVc:e:mCr:", + c = getopt_long(argc, argv, "hd:Dsl:ar:p:TPVc:e:mCr:M:", long_options, &option_index); if (c == -1) break; @@ -168,8 +170,11 @@ static void handle_options(int argc, char **argv) case 'e': log_set_log_level(osmo_stderr_target, atoi(optarg)); break; + case 'M': + mncc_sock_path = optarg; + break; case 'm': - use_mncc_sock = 1; + mncc_sock_path = "/tmp/bsc_mncc"; break; case 'C': use_db_counter = 0; @@ -275,10 +280,10 @@ int main(int argc, char **argv) handle_options(argc, argv); /* internal MNCC handler or MNCC socket? */ - if (use_mncc_sock) { + if (mncc_sock_path) { rc = bsc_bootstrap_network(mncc_sock_from_cc, config_file); if (rc >= 0) - mncc_sock_init(bsc_gsmnet); + mncc_sock_init(bsc_gsmnet, mncc_sock_path); } else rc = bsc_bootstrap_network(int_mncc_recv, config_file); if (rc < 0) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:56 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:56 +0100Tue, 23 Feb 2016 14:57:22 +0100 Subject: [PATCH 3/6] osmo-nitb: cosmetic: rename to rf_ctrl_path, following mncc_sock_path Message-ID: <201602240257.u1O2viHN010430@einhorn.in-berlin.de> Strictly speaking, the unix domain socket location is not a name but a path. The MNCC socket is called path, so it is confusing to call the ctrl socket a 'name'. --- openbsc/src/osmo-nitb/bsc_hack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 3c878a6..a89300a 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -59,7 +59,7 @@ struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; -static const char *rf_ctrl_name = NULL; +static const char *rf_ctrl_path = NULL; extern const char *openbsc_copyright; static int daemonize = 0; static const char *mncc_sock_path = NULL; @@ -106,7 +106,7 @@ static void print_help() printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n"); printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n"); printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n"); - printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n"); + printf(" -r --rf-ctl PATH A unix domain socket to listen for cmds.\n"); } static void handle_options(int argc, char **argv) @@ -184,7 +184,7 @@ static void handle_options(int argc, char **argv) exit(0); break; case 'r': - rf_ctrl_name = optarg; + rf_ctrl_path = optarg; break; default: /* ignore */ @@ -312,7 +312,7 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); - bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_name, bsc_gsmnet); + bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_path, bsc_gsmnet); if (!bsc_gsmnet->bsc_data->rf_ctrl) { fprintf(stderr, "Failed to create the RF service.\n"); exit(1); -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:58 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:58 +0100Tue, 23 Feb 2016 14:59:43 +0100 Subject: [PATCH 4/6] osmo-nitb: be strict about cmdline args Message-ID: <201602240257.u1O2vkCt010443@einhorn.in-berlin.de> Abort upon unknown options and missing option arguments. This came to my attention while rewiring the -m and -M options: passing -M without argument would launch nitb with wrong configuration. So, rather exit immediately. If there are legacy options that should be ignored, they deserve an own 'case:' in the option switch. There are none that I'm aware of though. --- openbsc/src/osmo-nitb/bsc_hack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index a89300a..6f8da98 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -187,7 +187,9 @@ static void handle_options(int argc, char **argv) rf_ctrl_path = optarg; break; default: - /* ignore */ + /* catch unknown options *as well as* missing arguments. */ + fprintf(stderr, "Error in command line options. Abort.\n"); + exit(-1); break; } } -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:56:59 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:56:59 +0100Tue, 23 Feb 2016 15:10:33 +0100 Subject: [PATCH 5/6] enable ctrl bind config for various programs Message-ID: <201602240257.u1O2vlWk010453@einhorn.in-berlin.de> Add ctrl_vty_init() calls and feed the ctrl_vty_get_bind_addr() return value to ctrl_interface_setup() in the following programs: osmo-bsc osmo-bsc_nat osmo-nitb osmo-sgsn For osmo-sgsn, move the control interface setup invocation below the config parsing, so that the ctrl_vty_get_bind_addr() can return the configured address. --- openbsc/include/openbsc/bsc_nat.h | 3 ++- openbsc/include/openbsc/ctrl.h | 3 ++- openbsc/include/openbsc/gprs_sgsn.h | 3 ++- openbsc/src/gprs/sgsn_ctrl.c | 5 +++-- openbsc/src/gprs/sgsn_main.c | 31 ++++++++++++++++++++----------- openbsc/src/libbsc/bsc_ctrl_lookup.c | 6 ++++-- openbsc/src/osmo-bsc/osmo_bsc_main.c | 10 +++++++++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 9 ++++++++- openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c | 5 +++-- openbsc/src/osmo-nitb/bsc_hack.c | 10 +++++++++- 10 files changed, 62 insertions(+), 23 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 027b6de..309adb1 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -423,7 +423,8 @@ void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const stru void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port); +struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, + const char *bind_addr, int port); void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending); int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); diff --git a/openbsc/include/openbsc/ctrl.h b/openbsc/include/openbsc/ctrl.h index 38fa054..c5ac210 100644 --- a/openbsc/include/openbsc/ctrl.h +++ b/openbsc/include/openbsc/ctrl.h @@ -1,3 +1,4 @@ #pragma once -struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port); +struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 74f0735..49d5407 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -315,7 +315,8 @@ int sgsn_force_reattach_oldmsg(struct msgb *oldmsg); * ctrl interface related work */ struct gsm_network; -struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, uint16_t port); +struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, + const char *bind_addr, uint16_t port); int sgsn_ctrl_cmds_install(void); /* diff --git a/openbsc/src/gprs/sgsn_ctrl.c b/openbsc/src/gprs/sgsn_ctrl.c index eff94e0..0b40703 100644 --- a/openbsc/src/gprs/sgsn_ctrl.c +++ b/openbsc/src/gprs/sgsn_ctrl.c @@ -73,7 +73,8 @@ int sgsn_ctrl_cmds_install(void) return rc; } -struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *net, uint16_t port) +struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port) { - return ctrl_interface_setup(net, port, NULL); + return ctrl_interface_setup(net, bind_addr, port, NULL); } diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index b10b0b3..cb762b7 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -47,6 +47,8 @@ #include #include +#include + #include #include #include @@ -311,22 +313,12 @@ int main(int argc, char **argv) logging_vty_add_cmds(&gprs_log_info); osmo_stats_vty_add_cmds(&gprs_log_info); sgsn_vty_init(); + ctrl_vty_init(tall_bsc_ctx); handle_options(argc, argv); rate_ctr_init(tall_bsc_ctx); - ctrl = sgsn_controlif_setup(NULL, OSMO_CTRL_PORT_SGSN); - if (!ctrl) { - LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); - exit(1); - } - - if (sgsn_ctrl_cmds_install() != 0) { - LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); - exit(1); - } - gprs_ns_set_log_ss(DNS); bssgp_set_log_ss(DBSSGP); @@ -362,6 +354,23 @@ int main(int argc, char **argv) if (rc < 0) exit(1); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_SGSN); + ctrl = sgsn_controlif_setup(NULL, ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_SGSN); + if (!ctrl) { + LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); + exit(1); + } + + if (sgsn_ctrl_cmds_install() != 0) { + LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); + exit(1); + } + + rc = sgsn_gtp_init(&sgsn_inst); if (rc) { LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n"); diff --git a/openbsc/src/libbsc/bsc_ctrl_lookup.c b/openbsc/src/libbsc/bsc_ctrl_lookup.c index b504ccc..2a41c71 100644 --- a/openbsc/src/libbsc/bsc_ctrl_lookup.c +++ b/openbsc/src/libbsc/bsc_ctrl_lookup.c @@ -99,7 +99,9 @@ err_index: return -ERANGE; } -struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port) +struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port) { - return ctrl_interface_setup(net, port, bsc_ctrl_node_lookup); + return ctrl_interface_setup(net, bind_addr, port, + bsc_ctrl_node_lookup); } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_main.c b/openbsc/src/osmo-bsc/osmo_bsc_main.c index 3806b24..3594a5b 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_main.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -205,6 +206,7 @@ int main(int argc, char **argv) vty_init(&vty_info); bsc_vty_init(&log_info); bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE); + ctrl_vty_init(tall_bsc_ctx); INIT_LLIST_HEAD(&access_lists); @@ -225,7 +227,13 @@ int main(int argc, char **argv) } bsc_api_init(bsc_gsmnet, osmo_bsc_api()); - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC); + bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, + ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_NITB_BSC); if (!bsc_gsmnet->ctrl) { fprintf(stderr, "Failed to init the control interface. Exiting.\n"); exit(1); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index e3dc10e..8404e41 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -1618,6 +1619,7 @@ int main(int argc, char **argv) logging_vty_add_cmds(&log_info); osmo_stats_vty_add_cmds(&log_info); bsc_nat_vty_init(nat); + ctrl_vty_init(tall_bsc_ctx); /* parse options */ @@ -1661,7 +1663,12 @@ int main(int argc, char **argv) exit(1); } - nat->ctrl = bsc_nat_controlif_setup(nat, OSMO_CTRL_PORT_BSC_NAT); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNAT, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_BSC_NAT); + nat->ctrl = bsc_nat_controlif_setup(nat, ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_BSC_NAT); if (!nat->ctrl) { fprintf(stderr, "Creating the control interface failed.\n"); exit(1); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c index f3ca924..ec4243e 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c @@ -470,13 +470,14 @@ static int get_net_save_cmd(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_ERROR; } -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port) +struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, + const char *bind_addr, int port) { struct ctrl_handle *ctrl; int rc; - ctrl = bsc_controlif_setup(NULL, OSMO_CTRL_PORT_BSC_NAT); + ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT); if (!ctrl) { fprintf(stderr, "Failed to initialize the control interface. Exiting.\n"); return NULL; diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 6f8da98..4bd03fc 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +273,7 @@ int main(int argc, char **argv) /* This needs to precede handle_options() */ vty_init(&vty_info); bsc_vty_init(&log_info); + ctrl_vty_init(tall_bsc_ctx); #ifdef BUILD_SMPP if (smpp_openbsc_init(tall_bsc_ctx, 0) < 0) @@ -295,7 +297,13 @@ int main(int argc, char **argv) #endif bsc_api_init(bsc_gsmnet, msc_bsc_api()); - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC); + bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, + ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_NITB_BSC); if (!bsc_gsmnet->ctrl) { printf("Failed to initialize control interface. Exiting.\n"); return -1; -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 03:57:01 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 03:57:01 +0100Wed, 24 Feb 2016 03:12:44 +0100 Subject: [PATCH 6/6] bsc_nat: fail if VTY telnet port cannot be bound Message-ID: <201602240257.u1O2vnjV010464@einhorn.in-berlin.de> --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 8404e41..cdab406 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -1638,10 +1638,13 @@ int main(int argc, char **argv) /* start telnet after reading config for vty_get_bind_addr() */ LOGP(DNAT, LOGL_NOTICE, "VTY at %s %d\n", vty_get_bind_addr(), OSMO_VTY_PORT_BSC_NAT); - telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), - OSMO_VTY_PORT_BSC_NAT); + if (telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), + OSMO_VTY_PORT_BSC_NAT)) { + fprintf(stderr, "Creating VTY telnet line failed\n"); + return -5; + } - /* over rule the VTY config */ + /* over rule the VTY config for MSC IP */ if (msc_ip) bsc_nat_set_msc_ip(nat, msc_ip); -- 2.1.4 From eblake at redhat.com Wed Feb 17 13:22:54 2016 From: eblake at redhat.com (Eric Blake) Date: Wed, 17 Feb 2016 06:22:54 -0700 Subject: autoreconf v2.69 with subdir-objects: ./configure creates directory 'src/tests/\$(top_srcdir)' In-Reply-To: <20160217105527.GD1232@dub6> References: <20160114134038.GE1873@dub6> <20160217105527.GD1232@dub6> Message-ID: <56C4742E.7080406@redhat.com> On 02/17/2016 03:55 AM, Neels Hofmeyr wrote: > Dear autoconf, > > I have received no reply yet, so am taking the liberty to . > > BTW, is there a way to verify that this report has reached someone, > besides waiting for an email reply? You can check the list archives online, to see that it was delivered: https://lists.gnu.org/archive/html/bug-autoconf/2016-01/index.html > > Thanks! > > ~Neels > > On Thu, Jan 14, 2016 at 02:40:38PM +0100, Neels Hofmeyr wrote: >> Dear autoconf, >> >> I am observing a bug with `autoreconf -i`. >> To my/our knowledge, this is not due to an error in >> our configuration but a genuine bug from 'subdir-objects'. >> >> The symptom: after running ./configure, I find a directory >> src/tests/\$(top_srcdir) This is a known automake bug, not caused by autoconf; that may explain why you haven't seen much response on the autoconf list, but I don't know if there are any active maintainers on the automake list that have suggestions on how to work around it, or on when a fixed automake will be available (or if it is already available). A quick search found this, though: https://lists.gnu.org/archive/html/automake/2015-12/msg00001.html >> (I am not subscribed to any autoconf ML, hence a Cc to my sender address is >> appreciated) Reply-to-all is general policy on GNU lists, for precisely that reason. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 604 bytes Desc: OpenPGP digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 24 00:55:49 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 01:55:49 +0100 Subject: [PATCH] v2 of: configure Abis/IP bind address Message-ID: <201602240200.u1O20bIv001892@einhorn.in-berlin.de> I decided to drop the 'any' keyword from the Abis bind address config, to ensure that the written config is always identical to the parsed config. Neels Hofmeyr (1): ipa driver: make bind address vty configurable include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 2 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Mon Feb 22 12:29:09 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 22 Feb 2016 13:29:09 +0100 Subject: [PATCH] ipa driver: make bind address vty configurable Message-ID: <201602240200.u1O20c7G001895@einhorn.in-berlin.de> Add VTY function to set the ipa bind address: e1_input ipa bind A.B.C.D Add a priv pointer to struct e1inp_driver in order to communicate the bind address parameter to ipaccess_line_update(). Add two "internal.h" functions to get/set it in the ipa driver struct. Add static ip_bind_addr() to use the IP address set from the VTY or, if NULL, use "0.0.0.0". Apply in ipaccess_line_update(). --- include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 28 ++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/internal.h b/include/internal.h index 7f6e31a..740a86d 100644 --- a/include/internal.h +++ b/include/internal.h @@ -13,6 +13,9 @@ extern void *libosmo_abis_ctx; /* use libosmo_abis_init, this is only for internal use. */ void e1inp_init(void); +void e1inp_ipaccess_set_bind(const char *ip_bind_addr); +const char *e1inp_ipaccess_get_bind(void); + /* ipaccess.c requires these functions defined here */ struct msgb; struct msgb *ipa_msg_alloc(int headroom); diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index e5d2991..4d00e03 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -139,6 +139,7 @@ struct e1inp_driver { void (*vty_show)(struct vty *vty, struct e1inp_line *line); int default_delay; int has_keepalive; + void *priv; }; struct e1inp_line_ops { diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index 0b4adb2..71747f0 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -168,6 +168,18 @@ DEFUN(cfg_e1inp, cfg_e1inp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ipa_bind, + cfg_ipa_bind_cmd, + "ipa bind A.B.C.D", + "ipa driver config\n" + "Set ipa local bind address\n" + "Listen on this IP address (default 0.0.0.0)\n") +{ + e1inp_ipaccess_set_bind(argv[0]); + return CMD_SUCCESS; +} + + static int e1inp_config_write(struct vty *vty) { struct e1inp_line *line; @@ -202,6 +214,12 @@ static int e1inp_config_write(struct vty *vty) VTY_NEWLINE); } + + const char *ipa_bind = e1inp_ipaccess_get_bind(); + if (ipa_bind) + vty_out(vty, " ipa bind %s%s", + ipa_bind, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -351,6 +369,8 @@ int e1inp_vty_init(void) install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); + install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); install_element_ve(&show_e1ts_cmd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ffdb19..d645e24 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -804,6 +804,13 @@ struct ipaccess_line { int line_already_initialized; }; +static const char *ip_bind_addr() +{ + return ipaccess_driver.priv? + ((const char*)ipaccess_driver.priv) + : "0.0.0.0"; +} + static int ipaccess_line_update(struct e1inp_line *line) { int ret = -ENOENT; @@ -831,7 +838,7 @@ static int ipaccess_line_update(struct e1inp_line *line) LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode\n"); oml_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_OML, + ip_bind_addr(), IPA_TCP_PORT_OML, ipaccess_bsc_oml_cb, NULL); if (oml_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create OML " @@ -845,7 +852,7 @@ static int ipaccess_line_update(struct e1inp_line *line) return -EIO; } rsl_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_RSL, + ip_bind_addr(), IPA_TCP_PORT_RSL, ipaccess_bsc_rsl_cb, NULL); if (rsl_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL " @@ -944,3 +951,20 @@ void e1inp_ipaccess_init(void) tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa"); e1inp_driver_register(&ipaccess_driver); } + +void e1inp_ipaccess_set_bind(const char *ip_bind_addr) +{ + if (ipaccess_driver.priv) { + talloc_free(ipaccess_driver.priv); + ipaccess_driver.priv = NULL; + } + + if (ip_bind_addr) + ipaccess_driver.priv = (void*)talloc_strdup(tall_ipa_ctx, + ip_bind_addr); +} + +const char *e1inp_ipaccess_get_bind(void) +{ + return (const char*)ipaccess_driver.priv; +} -- 2.1.4 From laforge at gnumonks.org Wed Feb 24 09:08:35 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 10:08:35 +0100 Subject: [PATCH 3/3] Add VTY section for Control interface bind address In-Reply-To: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> References: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> Message-ID: <20160224090835.GS18382@nataraja> Hi Neels, On Wed, Feb 24, 2016 at 03:39:39AM +0100, Neels Hofmeyr wrote: > L_NS_NODE, /*!< \brief NS node in libosmo-gb. */ > L_BSSGP_NODE, /*!< \brief BSSGP node in libosmo-gb. */ > > + CTRL_NODE, /*!< \brief Control interface node. */ > + the existing nodes are pre-fixed with L_ to indicate they are part of a library, as opposed to those without prefix (from the main application). -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Wed Feb 24 09:04:40 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 10:04:40 +0100 Subject: [PATCH 1/3] vty: add bind command for telnet vty line In-Reply-To: <201602240240.u1O2eNDc030422@einhorn.in-berlin.de> References: <201602240240.u1O2eNDc030422@einhorn.in-berlin.de> Message-ID: <20160224090440.GQ18382@nataraja> On Wed, Feb 24, 2016 at 03:39:35AM +0100, Neels Hofmeyr wrote: > + /* Avoid (small) mem leak: initially, vty_bind_addr is NULL. Whenever > + * this gets called, it is set to a strdup. So whenever it is non-NULL, > + * free it first. See also vty_get_bind_addr() for the NULL default. */ > + if (vty_bind_addr) { > + talloc_free((void*)vty_bind_addr); > + vty_bind_addr = NULL; > + } free() on NULL is very well-defined and valid, so is talloc_free(). So maybe just unconditionally talloc_free it and avoid three lines of code and three lines of comments? You can keep it the way it is, but I fond it unusually verbose. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Wed Feb 24 09:06:48 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 10:06:48 +0100 Subject: [PATCH 2/3] add bind address parameter to ctrl_interface_setup() In-Reply-To: <201602240240.u1O2ePec030429@einhorn.in-berlin.de> References: <201602240240.u1O2ePec030429@einhorn.in-berlin.de> Message-ID: <20160224090648.GR18382@nataraja> Hi Neels, On Wed, Feb 24, 2016 at 03:39:37AM +0100, Neels Hofmeyr wrote: > -struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, > - ctrl_cmd_lookup lookup); > +struct ctrl_handle *ctrl_interface_setup(void *data, const char *bind_addr, > + uint16_t port, ctrl_cmd_lookup lookup); we generally don't beak interfaces of our libraries like this. Pleaes add a second/new function like (ctrl_interface_setup2 or ctrl_interface_setup_nonlocal, ctrl_interface_setup_bind, ...) with the new argument. This way old and new code works. See telnet_init_dynif() vs. telnet_init() in libosmovty. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From msuraev at sysmocom.de Wed Feb 24 11:57:33 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Wed, 24 Feb 2016 12:57:33 +0100 Subject: [PATCH] Refactor coding scheme assignment code Message-ID: <1456315053-16934-1-git-send-email-msuraev@sysmocom.de> From: Max Previously this code used too much copy-paste of boilerplate code which is error-prone and hard to read. Factor out actual (M)CS assignment into separate function and use it for both DL and UL cases in respective mode. Fixes: Coverity: CID 1351733 --- src/gprs_ms.cpp | 65 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/gprs_ms.cpp b/src/gprs_ms.cpp index 78f03f8..c10c735 100644 --- a/src/gprs_ms.cpp +++ b/src/gprs_ms.cpp @@ -209,45 +209,46 @@ void GprsMs::stop_timer() unref(); } +inline static GprsCodingScheme assign_cs(GprsCodingScheme current, BTS *bts, bool uplink, GprsCodingScheme::Mode mode) +{ + GprsCodingScheme tmp = GprsCodingScheme::UNKNOWN; + struct gprs_rlcmac_bts * b = bts->bts_data(); + + if (GprsCodingScheme::GPRS == mode) { + if (!current.isGprs()) { + tmp = GprsCodingScheme::getGprsByNum(uplink ? b->initial_cs_ul : b->initial_cs_dl); + if (!tmp.isValid()) + return GprsCodingScheme::CS1; + } + } else { + if (!current.isEgprs()) { + tmp = GprsCodingScheme::getEgprsByNum(uplink ? b->initial_mcs_ul : b->initial_mcs_dl); + if (!tmp.isValid()) + return GprsCodingScheme::MCS1; + } + } + + return tmp; +} + void GprsMs::set_mode(GprsCodingScheme::Mode mode) { + GprsCodingScheme tmp; m_mode = mode; if (!m_bts) return; - switch (m_mode) { - case GprsCodingScheme::GPRS: - if (!m_current_cs_ul.isGprs()) { - m_current_cs_ul = GprsCodingScheme::getGprsByNum( - m_bts->bts_data()->initial_cs_ul); - if (!m_current_cs_ul.isValid()) - m_current_cs_ul = GprsCodingScheme::CS1; - } - if (!m_current_cs_dl.isGprs()) { - m_current_cs_dl = GprsCodingScheme::getGprsByNum( - m_bts->bts_data()->initial_cs_dl); - if (!m_current_cs_dl.isValid()) - m_current_cs_dl = GprsCodingScheme::CS1; - } - break; - - case GprsCodingScheme::EGPRS_GMSK: - case GprsCodingScheme::EGPRS: - if (!m_current_cs_ul.isEgprs()) { - m_current_cs_ul = GprsCodingScheme::getEgprsByNum( - m_bts->bts_data()->initial_mcs_ul); - if (!m_current_cs_dl.isValid()) - m_current_cs_ul = GprsCodingScheme::MCS1; - } - if (!m_current_cs_dl.isEgprs()) { - m_current_cs_dl = GprsCodingScheme::getEgprsByNum( - m_bts->bts_data()->initial_mcs_dl); - if (!m_current_cs_dl.isValid()) - m_current_cs_dl = GprsCodingScheme::MCS1; - } - break; - } + tmp = assign_cs(m_current_cs_ul, m_bts, true, mode); + if (tmp) + m_current_cs_ul = tmp; + + tmp = assign_cs(m_current_cs_dl, m_bts, false, mode); + if (tmp) + m_current_cs_dl = tmp; + + LOGP(DRLCMAC, LOGL_DEBUG, "MS IMSI=%s mode set to %s: UL=%s, DL=%s\n", + imsi(), tmp.modeName(mode), m_current_cs_ul.name(), m_current_cs_dl.name()); } void GprsMs::attach_tbf(struct gprs_rlcmac_tbf *tbf) -- 2.7.1 From nhofmeyr at sysmocom.de Wed Feb 24 13:36:03 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 14:36:03 +0100 Subject: [PATCH 1/3] vty: add bind command for telnet vty line In-Reply-To: <20160224090440.GQ18382@nataraja> References: <201602240240.u1O2eNDc030422@einhorn.in-berlin.de> <20160224090440.GQ18382@nataraja> Message-ID: <20160224133603.GB1601@dub6> On Wed, Feb 24, 2016 at 10:04:40AM +0100, Harald Welte wrote: > On Wed, Feb 24, 2016 at 03:39:35AM +0100, Neels Hofmeyr wrote: > > + /* Avoid (small) mem leak: initially, vty_bind_addr is NULL. Whenever > > + * this gets called, it is set to a strdup. So whenever it is non-NULL, > > + * free it first. See also vty_get_bind_addr() for the NULL default. */ > > + if (vty_bind_addr) { > > + talloc_free((void*)vty_bind_addr); > > + vty_bind_addr = NULL; > > + } > > free() on NULL is very well-defined and valid, so is talloc_free(). Really? Wasn't aware of that, indeed. Away with the ifs then. I felt the comment should explain why I treat NULL as some default string -- if I set vty_bind_addr = "127.0.0.1" then I can't free that string, thus NULL. Hmm the comment sucks, yes. Thanks! ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 24 13:38:26 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 14:38:26 +0100 Subject: [PATCH 2/3] add bind address parameter to ctrl_interface_setup() In-Reply-To: <20160224090648.GR18382@nataraja> References: <201602240240.u1O2ePec030429@einhorn.in-berlin.de> <20160224090648.GR18382@nataraja> Message-ID: <20160224133826.GC1601@dub6> On Wed, Feb 24, 2016 at 10:06:48AM +0100, Harald Welte wrote: > Hi Neels, > > On Wed, Feb 24, 2016 at 03:39:37AM +0100, Neels Hofmeyr wrote: > > -struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, > > - ctrl_cmd_lookup lookup); > > +struct ctrl_handle *ctrl_interface_setup(void *data, const char *bind_addr, > > + uint16_t port, ctrl_cmd_lookup lookup); > > we generally don't beak interfaces of our libraries like this. Pleaes I was suspecting so. "Just checking if you're paying attention" ;) > See telnet_init_dynif() vs. telnet_init() in libosmovty. exactly what I had in mind. _dynif is a good suffix to reuse then, I assume. Thanks! ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 24 13:47:15 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 14:47:15 +0100 Subject: [PATCH 3/3] Add VTY section for Control interface bind address In-Reply-To: <20160224090835.GS18382@nataraja> References: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> <20160224090835.GS18382@nataraja> Message-ID: <20160224134715.GD1601@dub6> On Wed, Feb 24, 2016 at 10:08:35AM +0100, Harald Welte wrote: > Hi Neels, > > On Wed, Feb 24, 2016 at 03:39:39AM +0100, Neels Hofmeyr wrote: > > L_NS_NODE, /*!< \brief NS node in libosmo-gb. */ > > L_BSSGP_NODE, /*!< \brief BSSGP node in libosmo-gb. */ > > > > + CTRL_NODE, /*!< \brief Control interface node. */ > > + > > the existing nodes are pre-fixed with L_ to indicate they are part of a > library, as opposed to those without prefix (from the main application). AFAICT it is used only in openbsc, but still the control interface itself is part of libosmocore. That's why I put its vty there in the first place. libosmocore/src/ctrl/* -- Am I missing something? While we're at it: I'd have put CTRL_NODE above but that would shift the numbers of the L_* items. I find the name CTRL_NODE a bit too general. e.g. we also have Ctrl in GTP. First I had CTRLIFACE_NODE, but most other control interface code uses the ctrl_ prefix and that looks ugly too. Any opinions? ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From laforge at gnumonks.org Wed Feb 24 14:59:55 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 15:59:55 +0100 Subject: [PATCH 3/3] Add VTY section for Control interface bind address In-Reply-To: <20160224134715.GD1601@dub6> References: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> <20160224090835.GS18382@nataraja> <20160224134715.GD1601@dub6> Message-ID: <20160224145955.GG23371@nataraja> On Wed, Feb 24, 2016 at 02:47:15PM +0100, Neels Hofmeyr wrote: > On Wed, Feb 24, 2016 at 10:08:35AM +0100, Harald Welte wrote: > > Hi Neels, > > > > On Wed, Feb 24, 2016 at 03:39:39AM +0100, Neels Hofmeyr wrote: > > > L_NS_NODE, /*!< \brief NS node in libosmo-gb. */ > > > L_BSSGP_NODE, /*!< \brief BSSGP node in libosmo-gb. */ > > > > > > + CTRL_NODE, /*!< \brief Control interface node. */ > > > + > > > > the existing nodes are pre-fixed with L_ to indicate they are part of a > > library, as opposed to those without prefix (from the main application). > > AFAICT it is used only in openbsc, not true. osmo-bts is the first counter-example. > but still the control interface itself is part of libosmocore. That's > why I put its vty there in the first place. libosmocore/src/ctrl/* > -- Am I missing something? It's fine that you add it there .but it should be called L_CTRL_NODE, not CTRL_NODE. > I find the name CTRL_NODE a bit too general. e.g. we also have Ctrl in > GTP. First I had CTRLIFACE_NODE, but most other control interface code > uses the ctrl_ prefix and that looks ugly too. Any opinions? I don't care as long as it has an L_ prefix if it is implemented in a library. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From msuraev at sysmocom.de Wed Feb 24 15:05:48 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Wed, 24 Feb 2016 16:05:48 +0100 Subject: [PATCH] Add byte printing macros Message-ID: <1456326348-8754-1-git-send-email-msuraev@sysmocom.de> From: Max It's sometimes handy for debugging to be able to immediately see which bits are set in a given byte. Generalize macro used for that in bitvec tests and make it available for the rest of the library. --- include/osmocom/core/bits.h | 21 +++++++++++++++++++++ tests/bitvec/bitvec_test.c | 13 +------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h index 1587b05..46f0c8b 100644 --- a/include/osmocom/core/bits.h +++ b/include/osmocom/core/bits.h @@ -50,6 +50,27 @@ int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs, const pbit_t *in, unsigned int in_ofs, unsigned int num_bits, int lsb_mode); +#define OSMO_BIN_SPEC "%d%d%d%d%d%d%d%d" +#define OSMO_BIN_PRINT(byte) \ + (byte & 0x80 ? 1 : 0), \ + (byte & 0x40 ? 1 : 0), \ + (byte & 0x20 ? 1 : 0), \ + (byte & 0x10 ? 1 : 0), \ + (byte & 0x08 ? 1 : 0), \ + (byte & 0x04 ? 1 : 0), \ + (byte & 0x02 ? 1 : 0), \ + (byte & 0x01 ? 1 : 0) + +#define OSMO_BIT_SPEC "%c%c%c%c%c%c%c%c" +#define OSMO_BIT_PRINT(byte) \ + (byte & 0x80 ? '1' : '.'), \ + (byte & 0x40 ? '1' : '.'), \ + (byte & 0x20 ? '1' : '.'), \ + (byte & 0x10 ? '1' : '.'), \ + (byte & 0x08 ? '1' : '.'), \ + (byte & 0x04 ? '1' : '.'), \ + (byte & 0x02 ? '1' : '.'), \ + (byte & 0x01 ? '1' : '.') /* BIT REVERSAL */ diff --git a/tests/bitvec/bitvec_test.c b/tests/bitvec/bitvec_test.c index 800a040..76d6773 100644 --- a/tests/bitvec/bitvec_test.c +++ b/tests/bitvec/bitvec_test.c @@ -11,17 +11,6 @@ #include #include -#define BIN_PATTERN "%d%d%d%d%d%d%d%d" -#define BIN(byte) \ - (byte & 0x80 ? 1 : 0), \ - (byte & 0x40 ? 1 : 0), \ - (byte & 0x20 ? 1 : 0), \ - (byte & 0x10 ? 1 : 0), \ - (byte & 0x08 ? 1 : 0), \ - (byte & 0x04 ? 1 : 0), \ - (byte & 0x02 ? 1 : 0), \ - (byte & 0x01 ? 1 : 0) - static char lol[1024]; // we pollute this with printed vectors static inline void test_rl(const struct bitvec *bv) { @@ -45,7 +34,7 @@ static inline void test_get(struct bitvec *bv, unsigned n) int16_t x = bitvec_get_int16_msb(bv, n); uint8_t tmp[2]; osmo_store16be(x, &tmp); - printf(" -> %d (%u bit) ["BIN_PATTERN" "BIN_PATTERN"]:\n", x, n, BIN(tmp[0]), BIN(tmp[1])); + printf(" -> %d (%u bit) ["OSMO_BIN_SPEC" "OSMO_BIN_SPEC"]:\n", x, n, OSMO_BIN_PRINT(tmp[0]), OSMO_BIN_PRINT(tmp[1])); bitvec_to_string_r(bv, lol); printf("%s [%d]\n", lol, bv->cur_bit); } -- 2.7.1 From msuraev at sysmocom.de Wed Feb 24 15:39:57 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Wed, 24 Feb 2016 16:39:57 +0100 Subject: [PATCH] Expand RLCMAC diagnostics output Message-ID: <1456328397-11800-1-git-send-email-msuraev@sysmocom.de> From: Max When smth bad happens (e. g. we hit timeout in RLCMAC) on TBF - obtain corresponding MS object and print extended information about it and its TBFs to aid troubleshooting. Diagnostic function should not change state hence make it const with no return value. --- src/tbf.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/tbf.h | 2 +- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/tbf.cpp b/src/tbf.cpp index 69b9e3a..18205fd 100644 --- a/src/tbf.cpp +++ b/src/tbf.cpp @@ -490,7 +490,7 @@ void gprs_rlcmac_tbf::poll_timeout() if (!(state_flags & (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK))) { LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " "PACKET CONTROL ACK for PACKET UPLINK ACK\n"); - rlcmac_diag(); + rlcmac_diag("POLL TIMEOUT for PACKET CONTROL ACK for PACKET UPLINK ACK"); state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ACK); } ul_ack_state = GPRS_RLCMAC_UL_ACK_NONE; @@ -514,7 +514,7 @@ void gprs_rlcmac_tbf::poll_timeout() LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " "PACKET CONTROL ACK for PACKET UPLINK " "ASSIGNMENT.\n"); - rlcmac_diag(); + rlcmac_diag("POLL TIMEOUT for PACKET CONTROL ACK for PACKET UPLINK ASSIGNMENT"); state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_UL_ASS); } ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE; @@ -534,7 +534,7 @@ void gprs_rlcmac_tbf::poll_timeout() LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " "PACKET CONTROL ACK for PACKET DOWNLINK " "ASSIGNMENT.\n"); - rlcmac_diag(); + rlcmac_diag("POLL TIMEOUT for PACKET CONTROL ACK for PACKET DOWNLINK ASSIGNMENT"); state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ASS); } dl_ass_state = GPRS_RLCMAC_DL_ASS_NONE; @@ -555,7 +555,7 @@ void gprs_rlcmac_tbf::poll_timeout() if (!(dl_tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK))) { LOGP(DRLCMAC, LOGL_NOTICE, "- Timeout for polling " "PACKET DOWNLINK ACK.\n"); - dl_tbf->rlcmac_diag(); + dl_tbf->rlcmac_diag("POLL TIMEOUT for PACKET DOWNLINK ACK"); dl_tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_TO_DL_ACK); } dl_tbf->n3105++; @@ -872,7 +872,7 @@ void gprs_rlcmac_tbf::handle_timeout() case 3195: LOGP(DRLCMAC, LOGL_NOTICE, "%s T%d timeout during " "transsmission\n", tbf_name(this), T); - rlcmac_diag(); + rlcmac_diag("TRANSMISSION TIMEOUT"); /* fall through */ case 3193: LOGP(DRLCMAC, LOGL_DEBUG, @@ -887,8 +887,26 @@ void gprs_rlcmac_tbf::handle_timeout() } } -int gprs_rlcmac_tbf::rlcmac_diag() +static inline void print_tbf_diag(const struct gprs_rlcmac_tbf * t, bool uplink) { + const char * d = uplink ? "UL" : "DL"; + + LOGP(DRLCMAC, LOGL_NOTICE, "- MS %s %s\n", d, t->name()); + LOGP(DRLCMAC, LOGL_NOTICE, "- MS %s TBF 1st TS = %d, 1st common TS = %d, ctrl TS = %d\n", + d, t->first_ts, t->first_common_ts, t->control_ts); + LOGP(DRLCMAC, LOGL_NOTICE, "- MS %s TBF TSC = %d, DL: "OSMO_BIT_SPEC", UL: "OSMO_BIT_SPEC"\n", + d, t->tsc(), OSMO_BIT_PRINT(t->dl_slots()), OSMO_BIT_PRINT(t->ul_slots())); + + if (GPRS_RLCMAC_POLL_SCHED == t->poll_state) + LOGP(DRLCMAC, LOGL_NOTICE, "- MS %s TBF poll. scheduled: FN = %d, TS = %d\n", d, t->poll_fn, t->poll_ts); + else + LOGP(DRLCMAC, LOGL_NOTICE, "- MS %s TBF no polling\n", d); +} + +void gprs_rlcmac_tbf::rlcmac_diag(const char * context) const +{ + GprsMs * m = ms(); + LOGP(DRLCMAC, LOGL_NOTICE, "- RLCMAC diag. report for %s:\n", context); if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on CCCH\n"); if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) @@ -902,7 +920,57 @@ int gprs_rlcmac_tbf::rlcmac_diag() else if (direction == GPRS_RLCMAC_DL_TBF) LOGP(DRLCMAC, LOGL_NOTICE, "- No downlink ACK received yet\n"); - return 0; + if (is_tfi_assigned()) + LOGP(DRLCMAC, LOGL_NOTICE, "- TBF's TFI = %d\n", tfi()); + else + LOGP(DRLCMAC, LOGL_NOTICE, "- No TFI is assigned to this TBF yet\n"); + + if (is_tlli_valid()) + LOGP(DRLCMAC, LOGL_NOTICE, "- TBF's TLLI = 0x%x\n", tlli()); + else + LOGP(DRLCMAC, LOGL_NOTICE, "- No TLLI is assigned to this TBF yet\n"); + + LOGP(DRLCMAC, LOGL_NOTICE, "- MS IMSI = %s, GPRS class = %d, EGPRS class = %d, TA = %d, TLLI = 0x%x\n", + m->imsi(), m->ms_class(), m->egprs_ms_class(), m->ta(), m->tlli()); + LOGP(DRLCMAC, LOGL_NOTICE, "- MS 1st common TS = %d, current PACCH = %d\n", + m->first_common_ts(), m->current_pacch_slots()); + LOGP(DRLCMAC, LOGL_NOTICE, "- MS DL: "OSMO_BIT_SPEC" (RSRVD: "OSMO_BIT_SPEC"), UL: "OSMO_BIT_SPEC" (RSRVD: "OSMO_BIT_SPEC")\n", + OSMO_BIT_PRINT(m->dl_slots()), OSMO_BIT_PRINT(m->reserved_dl_slots()), OSMO_BIT_PRINT(m->ul_slots()), OSMO_BIT_PRINT(m->reserved_ul_slots())); + + if (m->is_idle()) + LOGP(DRLCMAC, LOGL_NOTICE, "- MS id idle\n"); + if (m->need_dl_tbf()) + LOGP(DRLCMAC, LOGL_NOTICE, "- MS needs DL TBF\n"); + + if (m->dl_tbf()) { + struct gprs_rlcmac_dl_tbf * dl = m->dl_tbf(); + print_tbf_diag(dl, false); + + if (m->dl_tbf()->need_control_ts()) + LOGP(DRLCMAC, LOGL_NOTICE, "- MS DL TBF needs ctrl TS\n"); + + if (m->dl_tbf()->have_data()) + LOGP(DRLCMAC, LOGL_NOTICE, "- MS DL TBF have data\n"); + } else + LOGP(DRLCMAC, LOGL_NOTICE, "- MS have no DL TBF\n"); + + if (m->ul_tbf()) { + struct gprs_rlcmac_ul_tbf * ul = m->ul_tbf(); + print_tbf_diag(ul, true); + + LOGP(DRLCMAC, LOGL_NOTICE, "- MS UL TBF USF: %d %d %d %d %d %d %d %d\n", + m->ul_tbf()->m_usf[0], + m->ul_tbf()->m_usf[1], + m->ul_tbf()->m_usf[2], + m->ul_tbf()->m_usf[3], + m->ul_tbf()->m_usf[4], + m->ul_tbf()->m_usf[5], + m->ul_tbf()->m_usf[6], + m->ul_tbf()->m_usf[7]); + } else + LOGP(DRLCMAC, LOGL_NOTICE, "- MS have no UL TBF\n"); + + LOGP(DRLCMAC, LOGL_NOTICE, "- RLCMAC diag. report complete\n\n"); } struct msgb *gprs_rlcmac_tbf::create_dl_ass(uint32_t fn, uint8_t ts) diff --git a/src/tbf.h b/src/tbf.h index ad8ad4c..b556e0c 100644 --- a/src/tbf.h +++ b/src/tbf.h @@ -112,7 +112,7 @@ struct gprs_rlcmac_tbf { uint8_t tsc() const; - int rlcmac_diag(); + void rlcmac_diag(const char * context) const; int update(); void handle_timeout(); -- 2.7.1 From msuraev at sysmocom.de Wed Feb 24 16:40:18 2016 From: msuraev at sysmocom.de (msuraev at sysmocom.de) Date: Wed, 24 Feb 2016 17:40:18 +0100 Subject: [PATCH] Explicitly initialize m_v_n and m_v_b Message-ID: <1456332018-30709-1-git-send-email-msuraev@sysmocom.de> From: Max Call reset() to initialize m_v_b in gprs_rlc_dl_window() and m_v_n in gprs_rlc_ul_window() constructors. Fixes: Coverity: CID 1351738, 1351737 --- src/rlc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rlc.h b/src/rlc.h index 54f28df..c3c03e0 100644 --- a/src/rlc.h +++ b/src/rlc.h @@ -448,6 +448,7 @@ inline gprs_rlc_dl_window::gprs_rlc_dl_window() : m_v_s(0) , m_v_a(0) { + m_v_b.reset(); } inline const uint16_t gprs_rlc_dl_window::v_s() const @@ -494,6 +495,7 @@ inline gprs_rlc_ul_window::gprs_rlc_ul_window() : m_v_r(0) , m_v_q(0) { + m_v_n.reset(); } inline bool gprs_rlc_ul_window::is_in_window(uint16_t bsn) const -- 2.7.1 From laforge at gnumonks.org Wed Feb 24 17:03:17 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 18:03:17 +0100 Subject: more CCAN gems Message-ID: <20160224170317.GK23371@nataraja> structeq looks like a great candidate to have type-aware memmp() of two structures: https://github.com/rustyrussell/ccan/tree/master/ccan/structeq type-safe callbacks rather than 'void *' pointers: https://github.com/rustyrussell/ccan/blob/master/ccan/typesafe_cb/_info assert at build time: https://github.com/rustyrussell/ccan/blob/master/ccan/build_assert/_info fast pseudo-random generator. Too sas that we want real random numbres for authentication challenges in GSUP/OAP? https://github.com/rustyrussell/ccan/blob/master/ccan/isaac/_info -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Wed Feb 24 16:30:02 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 17:30:02 +0100 Subject: more comfortable Option parsing? (CCAN) Message-ID: <20160224163002.GJ23371@nataraja> FYI, Rusty's CCAN contains some interesting option parsing code released under GPLv2+, i.e. compatible to libosmocore: Usage is explained in https://github.com/rustyrussell/ccan/blob/master/ccan/opt/_info It seems rather small and simple, and permits the subsequent addition of options, i.e. some shared code can register options, and other parts of the code can register even more options to it (like our libraries, or bts-specific code in osmo-bts, ...) I have more pressing things on my todo list than convert this now, but as there was some discussion regarding gengetopt here recently, I thought I might point out an alternative. We might also look into the LGPL 2.1+ CCAN htable https://github.com/rustyrussell/ccan/blob/master/ccan/htable/_info as a possible replacement for those areas where our linear llist iterations should turn out to be problematic. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Wed Feb 24 17:54:50 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 18:54:50 +0100 Subject: [PATCH 0/6] Allow osmo-nitb bind config (and others) In-Reply-To: <201602240257.u1O2vexC010412@einhorn.in-berlin.de> References: <201602240257.u1O2vexC010412@einhorn.in-berlin.de> Message-ID: <20160224175450.GA3029@dub6> On Wed, Feb 24, 2016 at 03:56:51AM +0100, Neels Hofmeyr wrote: > (5) still TODO: SMPP SMSC > libsmpp34 is still listening on 0.0.0.0:2775, requires a change in libsmpp34. Actually not. I mistook the test app headers for library headers, instead those in openbsc are used, and no libsmpp34 change is needed. Patch coming up. libsmpp34/test_apps/smpp_smsc.h vs. openbsc/openbsc/src/libmsc/smpp_smsc.h ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 24 17:59:29 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 18:59:29 +0100 Subject: [PATCH 0/3] v2 of: prepare configuration of vty-telnet and ctrl binds Message-ID: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> incorporated all comments. * improved comment * just talloc_free(NULL) * don't break ctrl_interface_setup() API * L_CTRL_NODE Neels Hofmeyr (3): vty: add bind command for telnet vty line add ctrl_interface_setup_dynip() for bind address vty: add ctrl section for Control interface bind address include/Makefile.am | 3 +- include/osmocom/ctrl/control_if.h | 4 ++ include/osmocom/ctrl/control_vty.h | 9 ++++ include/osmocom/vty/command.h | 2 +- include/osmocom/vty/vty.h | 3 ++ src/ctrl/Makefile.am | 4 ++ src/ctrl/control_if.c | 10 ++++- src/ctrl/control_vty.c | 90 ++++++++++++++++++++++++++++++++++++++ src/vty/vty.c | 28 ++++++++++++ 9 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 include/osmocom/ctrl/control_vty.h create mode 100644 src/ctrl/control_vty.c -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 17:59:30 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 18:59:30 +0100 Subject: [PATCH 1/3] vty: add bind command for telnet vty line In-Reply-To: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456336772-8538-2-git-send-email-nhofmeyr@sysmocom.de> Add VTY command line vty bind A.B.C.D The command merely stores the configured IP-address, which can then be used by the calling main program to set the telnet port of the VTY line. (Commits in openbsc and osmo-iuh will follow up on this.) Add function vty_get_bind_addr() to publish the address in the vty.h API. Add static vty_bind_addr to store. For allocation/freeing reasons, a NULL address defaults to 127.0.0.1. BTW, I decided against allowing keywords 'any' and 'localhost' in place of an actual IP address to make sure a written config is always identical to the parsed config. --- include/osmocom/vty/vty.h | 3 +++ src/vty/vty.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/osmocom/vty/vty.h b/include/osmocom/vty/vty.h index 3684397..43cb0cf 100644 --- a/include/osmocom/vty/vty.h +++ b/include/osmocom/vty/vty.h @@ -186,6 +186,9 @@ void *vty_current_index(struct vty *); int vty_current_node(struct vty *vty); int vty_go_parent(struct vty *vty); +/* Return IP address passed to the 'line vty'/'bind' command, or "127.0.0.1" */ +const char *vty_get_bind_addr(void); + extern void *tall_vty_ctx; extern struct cmd_element cfg_description_cmd; diff --git a/src/vty/vty.c b/src/vty/vty.c index 5bcbe4a..a4630fb 100644 --- a/src/vty/vty.c +++ b/src/vty/vty.c @@ -75,6 +75,12 @@ vector Vvty_serv_thread; char *vty_cwd = NULL; +/* IP address passed to the 'line vty'/'bind' command. + * Setting the default as vty_bind_addr = "127.0.0.1" doesn't allow freeing, so + * use NULL and VTY_BIND_ADDR_DEFAULT instead. */ +static const char *vty_bind_addr = NULL; +#define VTY_BIND_ADDR_DEFAULT "127.0.0.1" + /* Configure lock. */ static int vty_config; @@ -1585,6 +1591,23 @@ DEFUN(no_vty_login, return CMD_SUCCESS; } +/* vty bind */ +DEFUN(vty_bind, vty_bind_cmd, "bind A.B.C.D", + "Accept VTY telnet connections on local interface\n" + "Local interface IP address (default: " VTY_BIND_ADDR_DEFAULT ")\n") +{ + talloc_free((void*)vty_bind_addr); + vty_bind_addr = talloc_strdup(tall_vty_ctx, argv[0]); + return CMD_SUCCESS; +} + +const char *vty_get_bind_addr(void) +{ + if (!vty_bind_addr) + return VTY_BIND_ADDR_DEFAULT; + return vty_bind_addr; +} + DEFUN(service_advanced_vty, service_advanced_vty_cmd, "service advanced-vty", @@ -1654,6 +1677,10 @@ static int vty_config_write(struct vty *vty) if (!password_check) vty_out(vty, " no login%s", VTY_NEWLINE); + /* bind */ + if (vty_bind_addr) + vty_out(vty, " bind %s%s", vty_bind_addr, VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -1757,6 +1784,7 @@ void vty_init(struct vty_app_info *app_info) vty_install_default(VTY_NODE); install_element(VTY_NODE, &vty_login_cmd); install_element(VTY_NODE, &no_vty_login_cmd); + install_element(VTY_NODE, &vty_bind_cmd); } /*! \brief Read the configuration file using the VTY code -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 17:59:31 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 18:59:31 +0100 Subject: [PATCH 2/3] add ctrl_interface_setup_dynip() for bind address In-Reply-To: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456336772-8538-3-git-send-email-nhofmeyr@sysmocom.de> Make the ctrl interface bind address configurable, so that it may be made available on other addresses than 127.0.0.1. The specific aim is to allow running multiple osmo-nitbs alongside each other (commits in openbsc follow). --- include/osmocom/ctrl/control_if.h | 4 ++++ src/ctrl/control_if.c | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/osmocom/ctrl/control_if.h b/include/osmocom/ctrl/control_if.h index 00caacc..181c60a 100644 --- a/include/osmocom/ctrl/control_if.h +++ b/include/osmocom/ctrl/control_if.h @@ -22,5 +22,9 @@ struct ctrl_handle { int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd); struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl_cmd_lookup lookup); +struct ctrl_handle *ctrl_interface_setup_dynip(void *data, + const char *bind_addr, + uint16_t port, + ctrl_cmd_lookup lookup); int ctrl_cmd_handle(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data); diff --git a/src/ctrl/control_if.c b/src/ctrl/control_if.c index 18e695d..bde245d 100644 --- a/src/ctrl/control_if.c +++ b/src/ctrl/control_if.c @@ -673,6 +673,14 @@ static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data) struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl_cmd_lookup lookup) { + return ctrl_interface_setup_dynip(data, "127.0.0.1", port, lookup); +} + +struct ctrl_handle *ctrl_interface_setup_dynip(void *data, + const char *bind_addr, + uint16_t port, + ctrl_cmd_lookup lookup) +{ int ret; struct ctrl_handle *ctrl; @@ -693,7 +701,7 @@ struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl->listen_fd.cb = listen_fd_cb; ctrl->listen_fd.data = ctrl; ret = osmo_sock_init_ofd(&ctrl->listen_fd, AF_INET, SOCK_STREAM, IPPROTO_TCP, - "127.0.0.1", port, OSMO_SOCK_F_BIND); + bind_addr, port, OSMO_SOCK_F_BIND); if (ret < 0) goto err_vec; -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 17:59:32 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 18:59:32 +0100 Subject: [PATCH 3/3] vty: add ctrl section for Control interface bind address In-Reply-To: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456336772-8538-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456336772-8538-4-git-send-email-nhofmeyr@sysmocom.de> This may seem like overkill for a mere const char * config item, but it makes the Control interface VTY commands reusable in any main() scope (inspired by libosmo-abis' VTY config). Add API functions ctrl_vty_init() and ctrl_vty_get_bind_addr(), in new files src/ctrl/control_vty.c and include/osmocom/ctrl/control_vty.h, compiled and/or installed dependent on ENABLE_VTY. Using these functions allows configuring a static const char* with the VTY commands ctrl bind A.B.C.D which callers shall subsequently use to bind the Control interface to a specific local interface address, by passing the return value of ctrl_vty_get_bind_addr() to control_interface_setup(). Add CTRL_NODE to enum node_type, "eating" RESERVED4_NODE to heed that comment on avoiding ABI changes. --- include/Makefile.am | 3 +- include/osmocom/ctrl/control_vty.h | 9 ++++ include/osmocom/vty/command.h | 2 +- src/ctrl/Makefile.am | 4 ++ src/ctrl/control_vty.c | 90 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 include/osmocom/ctrl/control_vty.h create mode 100644 src/ctrl/control_vty.c diff --git a/include/Makefile.am b/include/Makefile.am index a965fb9..ac22ee6 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -117,7 +117,8 @@ nobase_include_HEADERS += \ osmocom/vty/telnet_interface.h \ osmocom/vty/vector.h \ osmocom/vty/vty.h \ - osmocom/vty/ports.h + osmocom/vty/ports.h \ + osmocom/ctrl/control_vty.h endif noinst_HEADERS = \ diff --git a/include/osmocom/ctrl/control_vty.h b/include/osmocom/ctrl/control_vty.h new file mode 100644 index 0000000..d0ef69f --- /dev/null +++ b/include/osmocom/ctrl/control_vty.h @@ -0,0 +1,9 @@ +#pragma once + +/* Add the 'ctrl' section to VTY, containing the 'bind' command. */ +int ctrl_vty_init(void *ctx); + +/* Obtain the IP address configured by the 'ctrl'/'bind A.B.C.D' VTY command. + * This should be fed to ctrl_interface_setup() once the configuration has been + * read. */ +const char *ctrl_vty_get_bind_addr(void); diff --git a/include/osmocom/vty/command.h b/include/osmocom/vty/command.h index 2078e1b..9a02575 100644 --- a/include/osmocom/vty/command.h +++ b/include/osmocom/vty/command.h @@ -83,6 +83,7 @@ enum node_type { L_IPA_NODE, /*!< \brief IPA proxying commands in libosmo-abis. */ L_NS_NODE, /*!< \brief NS node in libosmo-gb. */ L_BSSGP_NODE, /*!< \brief BSSGP node in libosmo-gb. */ + L_CTRL_NODE, /*!< \brief Control interface node. */ /* * When adding new nodes to the libosmocore project, these nodes can be @@ -91,7 +92,6 @@ enum node_type { RESERVED1_NODE, /*!< \brief Reserved for later extensions */ RESERVED2_NODE, /*!< \brief Reserved for later extensions */ RESERVED3_NODE, /*!< \brief Reserved for later extensions */ - RESERVED4_NODE, /*!< \brief Reserved for later extensions */ _LAST_OSMOVTY_NODE }; diff --git a/src/ctrl/Makefile.am b/src/ctrl/Makefile.am index e6ccafb..b4a3da4 100644 --- a/src/ctrl/Makefile.am +++ b/src/ctrl/Makefile.am @@ -13,3 +13,7 @@ libosmoctrl_la_LIBADD = \ $(top_builddir)/src/libosmocore.la \ $(top_builddir)/src/gsm/libosmogsm.la \ $(top_builddir)/src/vty/libosmovty.la + +if ENABLE_VTY +libosmoctrl_la_SOURCES += control_vty.c +endif diff --git a/src/ctrl/control_vty.c b/src/ctrl/control_vty.c new file mode 100644 index 0000000..ca1cbd9 --- /dev/null +++ b/src/ctrl/control_vty.c @@ -0,0 +1,90 @@ +/* VTY configuration for Control interface + * + * (C) 2016 by sysmocom s.m.f.c GmbH + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include + +static void *ctrl_vty_ctx = NULL; +static const char *ctrl_vty_bind_addr = NULL; + +DEFUN(cfg_ctrl_bind_addr, + cfg_ctrl_bind_addr_cmd, + "bind A.B.C.D", + "Set bind address to listen for Control connections\n" + "Local IP address (default 127.0.0.1)\n") +{ + if (ctrl_vty_bind_addr) { + talloc_free((void*)ctrl_vty_bind_addr); + ctrl_vty_bind_addr = NULL; + } + ctrl_vty_bind_addr = talloc_strdup(ctrl_vty_ctx, argv[0]); + return CMD_SUCCESS; +} + +const char *ctrl_vty_get_bind_addr(void) +{ + if (!ctrl_vty_bind_addr) + return "127.0.0.1"; + return ctrl_vty_bind_addr; +} + +struct cmd_node ctrl_node = { + L_CTRL_NODE, + "%s(config-ctrl)# ", + 1, +}; + +DEFUN(cfg_ctrl, + cfg_ctrl_cmd, + "ctrl", "Configure the Control Interface") +{ + vty->index = NULL; + vty->node = L_CTRL_NODE; + + return CMD_SUCCESS; +} + +static int config_write_ctrl(struct vty *vty) +{ + /* So far there's only one element. Omit the entire section if the bind + * element is omitted. */ + if (!ctrl_vty_bind_addr) + return CMD_SUCCESS; + + vty_out(vty, "ctrl%s", VTY_NEWLINE); + vty_out(vty, " bind %s%s", ctrl_vty_bind_addr, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +int ctrl_vty_init(void *ctx) +{ + ctrl_vty_ctx = ctx; + install_element(CONFIG_NODE, &cfg_ctrl_cmd); + install_node(&ctrl_node, config_write_ctrl); + + install_element(L_CTRL_NODE, &cfg_ctrl_bind_addr_cmd); + return 0; +} + -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 18:06:52 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 19:06:52 +0100 Subject: [PATCH] v3 of: configure Abis/IP bind address Message-ID: <1456337213-8846-1-git-send-email-nhofmeyr@sysmocom.de> Like in the vty/ctrl patch set, just talloc_free(NULL) and save two lines of code. Neels Hofmeyr (1): ipa driver: make bind address vty configurable include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 26 ++++++++++++++++++++++++-- 4 files changed, 48 insertions(+), 2 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 18:06:53 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 19:06:53 +0100 Subject: [PATCH] ipa driver: make bind address vty configurable In-Reply-To: <1456337213-8846-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456337213-8846-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456337213-8846-2-git-send-email-nhofmeyr@sysmocom.de> Add VTY function to set the ipa bind address: e1_input ipa bind A.B.C.D Add a priv pointer to struct e1inp_driver in order to communicate the bind address parameter to ipaccess_line_update(). Add two "internal.h" functions to get/set it in the ipa driver struct. Add static ip_bind_addr() to use the IP address set from the VTY or, if NULL, use "0.0.0.0". Apply in ipaccess_line_update(). --- include/internal.h | 3 +++ include/osmocom/abis/e1_input.h | 1 + src/e1_input_vty.c | 20 ++++++++++++++++++++ src/input/ipaccess.c | 26 ++++++++++++++++++++++++-- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/internal.h b/include/internal.h index 7f6e31a..740a86d 100644 --- a/include/internal.h +++ b/include/internal.h @@ -13,6 +13,9 @@ extern void *libosmo_abis_ctx; /* use libosmo_abis_init, this is only for internal use. */ void e1inp_init(void); +void e1inp_ipaccess_set_bind(const char *ip_bind_addr); +const char *e1inp_ipaccess_get_bind(void); + /* ipaccess.c requires these functions defined here */ struct msgb; struct msgb *ipa_msg_alloc(int headroom); diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index e5d2991..4d00e03 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -139,6 +139,7 @@ struct e1inp_driver { void (*vty_show)(struct vty *vty, struct e1inp_line *line); int default_delay; int has_keepalive; + void *priv; }; struct e1inp_line_ops { diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index 0b4adb2..71747f0 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -168,6 +168,18 @@ DEFUN(cfg_e1inp, cfg_e1inp_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ipa_bind, + cfg_ipa_bind_cmd, + "ipa bind A.B.C.D", + "ipa driver config\n" + "Set ipa local bind address\n" + "Listen on this IP address (default 0.0.0.0)\n") +{ + e1inp_ipaccess_set_bind(argv[0]); + return CMD_SUCCESS; +} + + static int e1inp_config_write(struct vty *vty) { struct e1inp_line *line; @@ -202,6 +214,12 @@ static int e1inp_config_write(struct vty *vty) VTY_NEWLINE); } + + const char *ipa_bind = e1inp_ipaccess_get_bind(); + if (ipa_bind) + vty_out(vty, " ipa bind %s%s", + ipa_bind, VTY_NEWLINE); + return CMD_SUCCESS; } @@ -351,6 +369,8 @@ int e1inp_vty_init(void) install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd); install_element(L_E1INP_NODE, &cfg_e1_line_no_keepalive_cmd); + install_element(L_E1INP_NODE, &cfg_ipa_bind_cmd); + install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); install_element_ve(&show_e1ts_cmd); diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ffdb19..8f4f027 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -804,6 +804,13 @@ struct ipaccess_line { int line_already_initialized; }; +static const char *ip_bind_addr() +{ + return ipaccess_driver.priv? + ((const char*)ipaccess_driver.priv) + : "0.0.0.0"; +} + static int ipaccess_line_update(struct e1inp_line *line) { int ret = -ENOENT; @@ -831,7 +838,7 @@ static int ipaccess_line_update(struct e1inp_line *line) LOGP(DLINP, LOGL_NOTICE, "enabling ipaccess BSC mode\n"); oml_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_OML, + ip_bind_addr(), IPA_TCP_PORT_OML, ipaccess_bsc_oml_cb, NULL); if (oml_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create OML " @@ -845,7 +852,7 @@ static int ipaccess_line_update(struct e1inp_line *line) return -EIO; } rsl_link = ipa_server_link_create(tall_ipa_ctx, line, - "0.0.0.0", IPA_TCP_PORT_RSL, + ip_bind_addr(), IPA_TCP_PORT_RSL, ipaccess_bsc_rsl_cb, NULL); if (rsl_link == NULL) { LOGP(DLINP, LOGL_ERROR, "cannot create RSL " @@ -944,3 +951,18 @@ void e1inp_ipaccess_init(void) tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa"); e1inp_driver_register(&ipaccess_driver); } + +void e1inp_ipaccess_set_bind(const char *ip_bind_addr) +{ + talloc_free(ipaccess_driver.priv); + ipaccess_driver.priv = NULL; + + if (ip_bind_addr) + ipaccess_driver.priv = (void*)talloc_strdup(tall_ipa_ctx, + ip_bind_addr); +} + +const char *e1inp_ipaccess_get_bind(void) +{ + return (const char*)ipaccess_driver.priv; +} -- 2.1.4 From laforge at gnumonks.org Wed Feb 24 17:19:04 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 18:19:04 +0100 Subject: Move PCU/SGSN/GGSN discussions to osmocom-net-gprs Message-ID: <20160224171904.GN23371@nataraja> Hi all, several years ago at an OsmoDevCon, we decided to rename the PCU mailinglist into osmocom-net-grps to expand it to cover all parts of the GPRS/packet-switched systm, and then continue to discuss circuit-switched stuff in openbsc. Over the years it seems the list was more and more forgotten, and all patches were posted here. I would like to propose to move all GPRS / PS related discussion to the osmo-net-gprs mailing list again. Now you can argue that osmo-sgsn, osmo-gbproxy and gtphub are all built inside the openbsc repository. The presence of osmo-sgsn, osmo-gbproxy etc. inside one single OpenBSC git reposiory is a historic legacy, and one that I'm not very proud of. Rather than having more of that overlap/confusion we should probably aim for less and more separation. However, let's wait for the Iu-CS / Iu-PS integration and osmo-cscn (nitb without integrated bsc) first, and then look at how to lay out the source code repositories. Meanwhile, let's please aim at discussing GPRS related topics + patches (particularly PCU bits) on the osmocom-net-gprs list. Thanks for your attention! I think there are a lot of people on the openbsc lists who are primarily interested in OsmoNITB and who are not neccessarily interested in the low-level-bits of the GPRS/EGPRS RLC/MAC layers .... Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Wed Feb 24 19:07:21 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:07:21 +0100 Subject: (int)(void*)(int) 64 vs 32 Message-ID: <20160224190642.GB3029@dub6> On my 64bit system, I get warnings about casting int to pointer of different size and vice versa. However, below patch only shifts the warnings to 32bit systems, right? Should we encapsulate in some #ifdef __i386__ or is there an always-native int type? Thanks ~Neels From f25f8cebb58ad1f5241a33d9bac76654cd2a68a2 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Wed, 24 Feb 2016 19:31:33 +0100 Subject: [PATCH] remove warning on 64bit, add warning on i386? --- openbsc/src/osmo-bsc/osmo_bsc_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c index d871f01..1e4e6ee 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c @@ -43,7 +43,7 @@ static struct osmo_bsc_data *osmo_bsc_data(struct vty *vty) static struct osmo_msc_data *osmo_msc_data(struct vty *vty) { - return osmo_msc_data_find(bsc_gsmnet, (int) vty->index); + return osmo_msc_data_find(bsc_gsmnet, (int)(long int) vty->index); } static struct cmd_node bsc_node = { @@ -70,7 +70,7 @@ DEFUN(cfg_net_msc, cfg_net_msc_cmd, return CMD_WARNING; } - vty->index = (void *) index; + vty->index = (void *)(long int) index; vty->node = MSC_NODE; return CMD_SUCCESS; } -- 2.1.4 -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From suraev at alumni.ntnu.no Wed Feb 24 19:10:45 2016 From: suraev at alumni.ntnu.no (=?UTF-8?B?TWF4ICjimK0p?=) Date: Wed, 24 Feb 2016 20:10:45 +0100 Subject: Move PCU/SGSN/GGSN discussions to osmocom-net-gprs In-Reply-To: <20160224171904.GN23371@nataraja> References: <20160224171904.GN23371@nataraja> Message-ID: <56CE0035.1090600@alumni.ntnu.no> Would it be possible to point patchwork to osmocom-net-grps as well? cheers, Max. From nhofmeyr at sysmocom.de Wed Feb 24 19:16:04 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:16:04 +0100 Subject: [PATCH 0/3] eliminate some compiler warnings Message-ID: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> These patches eradicate some of the easier-to-fix compiler warnings I keep seeing in almost every dev cycle. I'd be glad to have them on master. One of them is an actual error, ignoring return values. Neels Hofmeyr (3): bsc_nat: fail if VTY telnet port cannot be bound, clarify comment ipaccess_rcvmsg: fix returncode, add partial write warning gsm340_rx_tpdu: comment-out two unused vars openbsc/src/ipaccess/ipaccess-proxy.c | 8 +++++++- openbsc/src/libmsc/gsm_04_11.c | 7 +++++-- openbsc/src/osmo-bsc_nat/bsc_nat.c | 7 +++++-- 3 files changed, 17 insertions(+), 5 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:16:05 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:16:05 +0100 Subject: [PATCH 1/3] bsc_nat: fail if VTY telnet port cannot be bound, clarify comment In-Reply-To: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456341367-15394-2-git-send-email-nhofmeyr@sysmocom.de> --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 41291d9..2d4f2a8 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -1628,13 +1628,16 @@ int main(int argc, char **argv) osmo_stats_init(tall_bsc_ctx); /* init vty and parse */ - telnet_init(tall_bsc_ctx, NULL, OSMO_VTY_PORT_BSC_NAT); + if (telnet_init(tall_bsc_ctx, NULL, OSMO_VTY_PORT_BSC_NAT)) { + fprintf(stderr, "Creating VTY telnet line failed\n"); + return -5; + } if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) { fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); return -3; } - /* over rule the VTY config */ + /* over rule the VTY config for MSC IP */ if (msc_ip) bsc_nat_set_msc_ip(nat, msc_ip); -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:16:06 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:16:06 +0100 Subject: [PATCH 2/3] ipaccess_rcvmsg: fix returncode, add partial write warning In-Reply-To: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456341367-15394-3-git-send-email-nhofmeyr@sysmocom.de> Kills a compiler warning. --- openbsc/src/ipaccess/ipaccess-proxy.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c index ab43b9e..3dfaeca 100644 --- a/openbsc/src/ipaccess/ipaccess-proxy.c +++ b/openbsc/src/ipaccess/ipaccess-proxy.c @@ -527,6 +527,12 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg, return -EIO; } ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len); + if (ret != ipbc->id_resp_len) { + LOGP(DLINP, LOGL_ERROR, "Partial write: %d of %d\n", + ret, ipbc->id_resp_len); + ret = -EIO; + } + else ret = 0; break; case IPAC_MSGT_ID_ACK: DEBUGP(DLMI, "ID_ACK? -> ACK!\n"); @@ -537,7 +543,7 @@ static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg, return 1; break; } - return 0; + return ret; } struct msgb *ipaccess_proxy_read_msg(struct osmo_fd *bfd, int *error) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:16:07 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:16:07 +0100 Subject: [PATCH 3/3] gsm340_rx_tpdu: comment-out two unused vars In-Reply-To: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456341367-15394-4-git-send-email-nhofmeyr@sysmocom.de> Kills two compiler warnings. --- openbsc/src/libmsc/gsm_04_11.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 266cd4d..e3d261e 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -357,7 +357,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m uint8_t *smsp = msgb_sms(msg); struct gsm_sms *gsms; unsigned int sms_alphabet; - uint8_t sms_mti, sms_mms, sms_vpf, sms_rp; + uint8_t sms_mti, sms_vpf; uint8_t *sms_vp; uint8_t da_len_bytes; uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ @@ -371,11 +371,14 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m /* invert those fields where 0 means active/present */ sms_mti = *smsp & 0x03; - sms_mms = !!(*smsp & 0x04); sms_vpf = (*smsp & 0x18) >> 3; gsms->status_rep_req = (*smsp & 0x20); gsms->ud_hdr_ind = (*smsp & 0x40); + /* This used to be unused code, avoid a recurring compiler warning: + uint8_t sms_mms, sms_rp; + sms_mms = !!(*smsp & 0x04); sms_rp = (*smsp & 0x80); + */ smsp++; gsms->msg_ref = *smsp++; -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:34 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:34 +0100 Subject: [PATCH 1/6] enable telnet VTY bind address config for various programs In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-2-git-send-email-nhofmeyr@sysmocom.de> Following the 'line vty'/'bind A.B.C.D' command added in libosmocore, use the configured address to set the telnet bind for the VTY line. It is now possible to publish the VTY on a specific local interface (including 0.0.0.0 aka "any"). Implement in all of: osmo-gbproxy osmo-gtphub osmo-sgsn osmo-bsc osmo-bsc_nat osmo-bsc_mgcp osmo-nitb In some of these main programs, move the telnet initialization below the configuration parsing. Historically, this was not a good idea for programs using bsc_init.c (aka bsc_bootstrap_network()), since they expected a gsm_network struct pointer in ((struct telnet_connection*)vty->priv)->priv, so that telnet had to be either initialized or replaced by a dummy struct. In the meantime, the gsm_network struct is not actually looked up in a priv pointer but in the static bsc_vty.c scope (bsc_gsmnet), so this limitation is mere legacy (even though said legacy is still there in an "#if 0" chunk). In the other binaries I have briefly looked at the init sequence dependencies and found no reason to initialize telnet above the config file parsing. In any case, I have tested every single one of abovementioned binaries to verify that they still parse the example config successfully and launch, allowing VTY connections on the configured address(es). I hope this suffices. In all of the above, log VTY address and port. LOGL_INFO is disabled by default in some of the logging scopes, and since it is a single log message right at program launch, I decided for the slightly more aggressive LOGL_NOTICE. --- openbsc/src/gprs/gb_proxy_main.c | 12 ++++++++---- openbsc/src/gprs/gtphub_main.c | 11 ++++++++--- openbsc/src/gprs/sgsn_main.c | 11 ++++++++--- openbsc/src/libbsc/bsc_init.c | 6 +++++- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 6 +++++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 13 +++++++++---- 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index f82fb5b..0c3cfbe 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -252,10 +252,6 @@ int main(int argc, char **argv) rate_ctr_init(tall_bsc_ctx); osmo_stats_init(tall_bsc_ctx); - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_GBPROXY); - if (rc < 0) - exit(1); - bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb, tall_bsc_ctx); if (!bssgp_nsi) { LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); @@ -274,6 +270,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY); + if (rc < 0) + exit(1); + if (!gprs_nsvc_by_nsei(gbcfg.nsi, gbcfg.nsip_sgsn_nsei)) { LOGP(DGPRS, LOGL_FATAL, "You cannot proxy to NSEI %u " "without creating that NSEI before\n", diff --git a/openbsc/src/gprs/gtphub_main.c b/openbsc/src/gprs/gtphub_main.c index f18710d..89582b1 100644 --- a/openbsc/src/gprs/gtphub_main.c +++ b/openbsc/src/gprs/gtphub_main.c @@ -314,9 +314,6 @@ int main(int argc, char **argv) gtphub_vty_init(hub, cfg); rate_ctr_init(osmo_gtphub_ctx); - rc = telnet_init(osmo_gtphub_ctx, 0, OSMO_VTY_PORT_GTPHUB); - if (rc < 0) - exit(1); handle_options(ccfg, argc, argv); @@ -327,6 +324,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGTPHUB, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_GTPHUB); + rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(), + OSMO_VTY_PORT_GTPHUB); + if (rc < 0) + exit(1); + if (gtphub_start(hub, cfg, next_restart_count(ccfg->restart_counter_file)) != 0) diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 2d3a0e4..b10b0b3 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -315,9 +315,6 @@ int main(int argc, char **argv) handle_options(argc, argv); rate_ctr_init(tall_bsc_ctx); - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_SGSN); - if (rc < 0) - exit(1); ctrl = sgsn_controlif_setup(NULL, OSMO_CTRL_PORT_SGSN); if (!ctrl) { @@ -357,6 +354,14 @@ int main(int argc, char **argv) exit(2); } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_SGSN); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_SGSN); + if (rc < 0) + exit(1); + rc = sgsn_gtp_init(&sgsn_inst); if (rc) { LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n"); diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 743f4c1..859d999 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -495,7 +495,11 @@ int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *), return rc; } - rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, OSMO_VTY_PORT_NITB_BSC); + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_NITB_BSC); + rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(), + OSMO_VTY_PORT_NITB_BSC); if (rc < 0) return rc; diff --git a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c index d755c90..e226b02 100644 --- a/openbsc/src/osmo-bsc_mgcp/mgcp_main.c +++ b/openbsc/src/osmo-bsc_mgcp/mgcp_main.c @@ -232,7 +232,11 @@ int main(int argc, char **argv) if (rc < 0) return rc; - rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_BSC_MGCP); + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DMGCP, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP); + rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network, + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_MGCP); if (rc < 0) return rc; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 2d4f2a8..04c12e3 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -1628,15 +1628,20 @@ int main(int argc, char **argv) osmo_stats_init(tall_bsc_ctx); /* init vty and parse */ - if (telnet_init(tall_bsc_ctx, NULL, OSMO_VTY_PORT_BSC_NAT)) { - fprintf(stderr, "Creating VTY telnet line failed\n"); - return -5; - } if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) { fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); return -3; } + /* start telnet after reading config for vty_get_bind_addr() */ + LOGP(DNAT, LOGL_NOTICE, "VTY at %s %d\n", + vty_get_bind_addr(), OSMO_VTY_PORT_BSC_NAT); + if (telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), + OSMO_VTY_PORT_BSC_NAT)) { + fprintf(stderr, "Creating VTY telnet line failed\n"); + return -5; + } + /* over rule the VTY config for MSC IP */ if (msc_ip) bsc_nat_set_msc_ip(nat, msc_ip); -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:33 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:33 +0100 Subject: [PATCH 0/6] v2: Allow osmo-nitb bind config (and others) Message-ID: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> This time SMPP is included. Here is the abridged complete overview: Following the previous patch sets for libosmo-abis and libosmocore, this patch set allows configuring ALL of osmo-nitb's local IP addresses and makes it possible to run several osmo-nitb processes alongside each other. (1) Abis/IP (from the libosmo-abis patch) In the config file, have: e1_input ipa bind 10.9.8.7 (2) telnet VTY (prepared by libosmocore patch set) In the config file, have: line vty bind 10.9.8.7 (3) ctrl interface (prepared by libosmocore patch set) In the config file, have: ctrl bind 10.9.8.7 (4) MNCC socket In addition to the old -m option with a fixed socket path, you may now supply a cmdline argument with explicit path: -M /path/to/socket/file (5) SMPP SMSC In the config file, have: smpp local-tcp 10.9.8.7 2775 Neels Hofmeyr (6): enable telnet VTY bind address config for various programs osmo-nitb: add -M to pass specific MNCC socket path osmo-nitb: cosmetic: rename to rf_ctrl_path, following mncc_sock_path osmo-nitb: be strict about cmdline args enable ctrl bind config for various programs smpp: refactor initialization, add bind address openbsc/include/openbsc/bsc_nat.h | 3 +- openbsc/include/openbsc/ctrl.h | 3 +- openbsc/include/openbsc/gprs_sgsn.h | 3 +- openbsc/include/openbsc/mncc.h | 2 +- openbsc/include/openbsc/smpp.h | 4 +- openbsc/src/gprs/gb_proxy_main.c | 12 +++-- openbsc/src/gprs/gtphub_main.c | 11 ++-- openbsc/src/gprs/sgsn_ctrl.c | 5 +- openbsc/src/gprs/sgsn_main.c | 42 ++++++++++----- openbsc/src/libbsc/bsc_ctrl_lookup.c | 6 ++- openbsc/src/libbsc/bsc_init.c | 6 ++- openbsc/src/libmsc/mncc_sock.c | 9 ++-- openbsc/src/libmsc/smpp_openbsc.c | 43 +++++++++------ openbsc/src/libmsc/smpp_smsc.c | 93 ++++++++++++++++++++++++--------- openbsc/src/libmsc/smpp_smsc.h | 7 ++- openbsc/src/libmsc/smpp_vty.c | 75 +++++++++++++++++++++----- openbsc/src/osmo-bsc/osmo_bsc_main.c | 10 +++- openbsc/src/osmo-bsc_mgcp/mgcp_main.c | 6 ++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 22 ++++++-- openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c | 5 +- openbsc/src/osmo-nitb/bsc_hack.c | 43 ++++++++++----- 21 files changed, 298 insertions(+), 112 deletions(-) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:35 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:35 +0100 Subject: [PATCH 2/6] osmo-nitb: add -M to pass specific MNCC socket path In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-3-git-send-email-nhofmeyr@sysmocom.de> The old -m option without argument is still available and marked deprecated, to not make users' lives more difficult than necessary. --- openbsc/include/openbsc/mncc.h | 2 +- openbsc/src/libmsc/mncc_sock.c | 9 +++++---- openbsc/src/osmo-nitb/bsc_hack.c | 17 +++++++++++------ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 10192ad..49f0c8b 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -206,7 +206,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg); /* input from CC code into mncc_sock */ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg); -int mncc_sock_init(struct gsm_network *gsmnet); +int mncc_sock_init(struct gsm_network *net, const char *sock_path); #define mncc_is_data_frame(msg_type) \ (msg_type == GSM_TCHF_FRAME \ diff --git a/openbsc/src/libmsc/mncc_sock.c b/openbsc/src/libmsc/mncc_sock.c index dd0a44f..6da1c56 100644 --- a/openbsc/src/libmsc/mncc_sock.c +++ b/openbsc/src/libmsc/mncc_sock.c @@ -277,7 +277,7 @@ static int mncc_sock_accept(struct osmo_fd *bfd, unsigned int flags) } -int mncc_sock_init(struct gsm_network *net) +int mncc_sock_init(struct gsm_network *net, const char *sock_path) { struct mncc_sock_state *state; struct osmo_fd *bfd; @@ -292,10 +292,10 @@ int mncc_sock_init(struct gsm_network *net) bfd = &state->listen_bfd; - rc = osmo_unixsock_listen(bfd, SOCK_SEQPACKET, "/tmp/bsc_mncc"); + rc = osmo_unixsock_listen(bfd, SOCK_SEQPACKET, sock_path); if (rc < 0) { - LOGP(DMNCC, LOGL_ERROR, "Could not create unix socket: %s\n", - strerror(errno)); + LOGP(DMNCC, LOGL_ERROR, "Could not create unix socket: %s: %s\n", + sock_path, strerror(errno)); talloc_free(state); return rc; } @@ -314,6 +314,7 @@ int mncc_sock_init(struct gsm_network *net) net->mncc_state = state; + LOGP(DMNCC, LOGL_NOTICE, "MNCC socket at %s\n", sock_path); return 0; } diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 8b074f1..3c878a6 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -62,7 +62,7 @@ static const char *config_file = "openbsc.cfg"; static const char *rf_ctrl_name = NULL; extern const char *openbsc_copyright; static int daemonize = 0; -static int use_mncc_sock = 0; +static const char *mncc_sock_path = NULL; static int use_db_counter = 1; /* timer to store statistics */ @@ -103,7 +103,8 @@ static void print_help() printf(" -V --version Print the version of OpenBSC.\n"); printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC.\n"); printf(" -e --log-level number Set a global loglevel.\n"); - printf(" -m --mncc-sock Disable built-in MNCC handler and offer socket.\n"); + printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n"); + printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n"); printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n"); printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n"); } @@ -126,12 +127,13 @@ static void handle_options(int argc, char **argv) {"rtp-proxy", 0, 0, 'P'}, {"log-level", 1, 0, 'e'}, {"mncc-sock", 0, 0, 'm'}, + {"mncc-sock-path", 1, 0, 'M'}, {"no-dbcounter", 0, 0, 'C'}, {"rf-ctl", 1, 0, 'r'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:Dsl:ar:p:TPVc:e:mCr:", + c = getopt_long(argc, argv, "hd:Dsl:ar:p:TPVc:e:mCr:M:", long_options, &option_index); if (c == -1) break; @@ -168,8 +170,11 @@ static void handle_options(int argc, char **argv) case 'e': log_set_log_level(osmo_stderr_target, atoi(optarg)); break; + case 'M': + mncc_sock_path = optarg; + break; case 'm': - use_mncc_sock = 1; + mncc_sock_path = "/tmp/bsc_mncc"; break; case 'C': use_db_counter = 0; @@ -275,10 +280,10 @@ int main(int argc, char **argv) handle_options(argc, argv); /* internal MNCC handler or MNCC socket? */ - if (use_mncc_sock) { + if (mncc_sock_path) { rc = bsc_bootstrap_network(mncc_sock_from_cc, config_file); if (rc >= 0) - mncc_sock_init(bsc_gsmnet); + mncc_sock_init(bsc_gsmnet, mncc_sock_path); } else rc = bsc_bootstrap_network(int_mncc_recv, config_file); if (rc < 0) -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:36 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:36 +0100 Subject: [PATCH 3/6] osmo-nitb: cosmetic: rename to rf_ctrl_path, following mncc_sock_path In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-4-git-send-email-nhofmeyr@sysmocom.de> Strictly speaking, the unix domain socket location is not a name but a path. The MNCC socket is called path, so it is confusing to call the ctrl socket a 'name'. --- openbsc/src/osmo-nitb/bsc_hack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 3c878a6..a89300a 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -59,7 +59,7 @@ struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; -static const char *rf_ctrl_name = NULL; +static const char *rf_ctrl_path = NULL; extern const char *openbsc_copyright; static int daemonize = 0; static const char *mncc_sock_path = NULL; @@ -106,7 +106,7 @@ static void print_help() printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n"); printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n"); printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n"); - printf(" -r --rf-ctl NAME A unix domain socket to listen for cmds.\n"); + printf(" -r --rf-ctl PATH A unix domain socket to listen for cmds.\n"); } static void handle_options(int argc, char **argv) @@ -184,7 +184,7 @@ static void handle_options(int argc, char **argv) exit(0); break; case 'r': - rf_ctrl_name = optarg; + rf_ctrl_path = optarg; break; default: /* ignore */ @@ -312,7 +312,7 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); - bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_name, bsc_gsmnet); + bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_path, bsc_gsmnet); if (!bsc_gsmnet->bsc_data->rf_ctrl) { fprintf(stderr, "Failed to create the RF service.\n"); exit(1); -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:37 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:37 +0100 Subject: [PATCH 4/6] osmo-nitb: be strict about cmdline args In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-5-git-send-email-nhofmeyr@sysmocom.de> Abort upon unknown options and missing option arguments. This came to my attention while rewiring the -m and -M options: passing -M without argument would launch nitb with wrong configuration. So, rather exit immediately. If there are legacy options that should be ignored, they deserve an own 'case:' in the option switch. There are none that I'm aware of though. --- openbsc/src/osmo-nitb/bsc_hack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index a89300a..6f8da98 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -187,7 +187,9 @@ static void handle_options(int argc, char **argv) rf_ctrl_path = optarg; break; default: - /* ignore */ + /* catch unknown options *as well as* missing arguments. */ + fprintf(stderr, "Error in command line options. Abort.\n"); + exit(-1); break; } } -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:38 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:38 +0100 Subject: [PATCH 5/6] enable ctrl bind config for various programs In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-6-git-send-email-nhofmeyr@sysmocom.de> Add ctrl_vty_init() calls and feed the ctrl_vty_get_bind_addr() return value to ctrl_interface_setup() in the following programs: osmo-bsc osmo-bsc_nat osmo-nitb osmo-sgsn For osmo-sgsn, move the control interface setup invocation below the config parsing, so that the ctrl_vty_get_bind_addr() can return the configured address. --- openbsc/include/openbsc/bsc_nat.h | 3 ++- openbsc/include/openbsc/ctrl.h | 3 ++- openbsc/include/openbsc/gprs_sgsn.h | 3 ++- openbsc/src/gprs/sgsn_ctrl.c | 5 +++-- openbsc/src/gprs/sgsn_main.c | 31 ++++++++++++++++++++----------- openbsc/src/libbsc/bsc_ctrl_lookup.c | 6 ++++-- openbsc/src/osmo-bsc/osmo_bsc_main.c | 10 +++++++++- openbsc/src/osmo-bsc_nat/bsc_nat.c | 9 ++++++++- openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c | 5 +++-- openbsc/src/osmo-nitb/bsc_hack.c | 10 +++++++++- 10 files changed, 62 insertions(+), 23 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 027b6de..309adb1 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -423,7 +423,8 @@ void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const stru void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port); +struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, + const char *bind_addr, int port); void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending); int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); diff --git a/openbsc/include/openbsc/ctrl.h b/openbsc/include/openbsc/ctrl.h index 38fa054..c5ac210 100644 --- a/openbsc/include/openbsc/ctrl.h +++ b/openbsc/include/openbsc/ctrl.h @@ -1,3 +1,4 @@ #pragma once -struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port); +struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 74f0735..49d5407 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -315,7 +315,8 @@ int sgsn_force_reattach_oldmsg(struct msgb *oldmsg); * ctrl interface related work */ struct gsm_network; -struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, uint16_t port); +struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, + const char *bind_addr, uint16_t port); int sgsn_ctrl_cmds_install(void); /* diff --git a/openbsc/src/gprs/sgsn_ctrl.c b/openbsc/src/gprs/sgsn_ctrl.c index eff94e0..ccf5076 100644 --- a/openbsc/src/gprs/sgsn_ctrl.c +++ b/openbsc/src/gprs/sgsn_ctrl.c @@ -73,7 +73,8 @@ int sgsn_ctrl_cmds_install(void) return rc; } -struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *net, uint16_t port) +struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port) { - return ctrl_interface_setup(net, port, NULL); + return ctrl_interface_setup_dynip(net, bind_addr, port, NULL); } diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index b10b0b3..cb762b7 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -47,6 +47,8 @@ #include #include +#include + #include #include #include @@ -311,22 +313,12 @@ int main(int argc, char **argv) logging_vty_add_cmds(&gprs_log_info); osmo_stats_vty_add_cmds(&gprs_log_info); sgsn_vty_init(); + ctrl_vty_init(tall_bsc_ctx); handle_options(argc, argv); rate_ctr_init(tall_bsc_ctx); - ctrl = sgsn_controlif_setup(NULL, OSMO_CTRL_PORT_SGSN); - if (!ctrl) { - LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); - exit(1); - } - - if (sgsn_ctrl_cmds_install() != 0) { - LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); - exit(1); - } - gprs_ns_set_log_ss(DNS); bssgp_set_log_ss(DBSSGP); @@ -362,6 +354,23 @@ int main(int argc, char **argv) if (rc < 0) exit(1); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DGPRS, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_SGSN); + ctrl = sgsn_controlif_setup(NULL, ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_SGSN); + if (!ctrl) { + LOGP(DGPRS, LOGL_ERROR, "Failed to create CTRL interface.\n"); + exit(1); + } + + if (sgsn_ctrl_cmds_install() != 0) { + LOGP(DGPRS, LOGL_ERROR, "Failed to install CTRL commands.\n"); + exit(1); + } + + rc = sgsn_gtp_init(&sgsn_inst); if (rc) { LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on GTP socket\n"); diff --git a/openbsc/src/libbsc/bsc_ctrl_lookup.c b/openbsc/src/libbsc/bsc_ctrl_lookup.c index b504ccc..a8a8cf5 100644 --- a/openbsc/src/libbsc/bsc_ctrl_lookup.c +++ b/openbsc/src/libbsc/bsc_ctrl_lookup.c @@ -99,7 +99,9 @@ err_index: return -ERANGE; } -struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port) +struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, + const char *bind_addr, uint16_t port) { - return ctrl_interface_setup(net, port, bsc_ctrl_node_lookup); + return ctrl_interface_setup_dynip(net, bind_addr, port, + bsc_ctrl_node_lookup); } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_main.c b/openbsc/src/osmo-bsc/osmo_bsc_main.c index 3806b24..3594a5b 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_main.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -205,6 +206,7 @@ int main(int argc, char **argv) vty_init(&vty_info); bsc_vty_init(&log_info); bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE); + ctrl_vty_init(tall_bsc_ctx); INIT_LLIST_HEAD(&access_lists); @@ -225,7 +227,13 @@ int main(int argc, char **argv) } bsc_api_init(bsc_gsmnet, osmo_bsc_api()); - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC); + bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, + ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_NITB_BSC); if (!bsc_gsmnet->ctrl) { fprintf(stderr, "Failed to init the control interface. Exiting.\n"); exit(1); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 04c12e3..cdab406 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -1618,6 +1619,7 @@ int main(int argc, char **argv) logging_vty_add_cmds(&log_info); osmo_stats_vty_add_cmds(&log_info); bsc_nat_vty_init(nat); + ctrl_vty_init(tall_bsc_ctx); /* parse options */ @@ -1664,7 +1666,12 @@ int main(int argc, char **argv) exit(1); } - nat->ctrl = bsc_nat_controlif_setup(nat, OSMO_CTRL_PORT_BSC_NAT); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNAT, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_BSC_NAT); + nat->ctrl = bsc_nat_controlif_setup(nat, ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_BSC_NAT); if (!nat->ctrl) { fprintf(stderr, "Creating the control interface failed.\n"); exit(1); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c index f3ca924..ec4243e 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c @@ -470,13 +470,14 @@ static int get_net_save_cmd(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_ERROR; } -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port) +struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, + const char *bind_addr, int port) { struct ctrl_handle *ctrl; int rc; - ctrl = bsc_controlif_setup(NULL, OSMO_CTRL_PORT_BSC_NAT); + ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT); if (!ctrl) { fprintf(stderr, "Failed to initialize the control interface. Exiting.\n"); return NULL; diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 6f8da98..4bd03fc 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +273,7 @@ int main(int argc, char **argv) /* This needs to precede handle_options() */ vty_init(&vty_info); bsc_vty_init(&log_info); + ctrl_vty_init(tall_bsc_ctx); #ifdef BUILD_SMPP if (smpp_openbsc_init(tall_bsc_ctx, 0) < 0) @@ -295,7 +297,13 @@ int main(int argc, char **argv) #endif bsc_api_init(bsc_gsmnet, msc_bsc_api()); - bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, OSMO_CTRL_PORT_NITB_BSC); + /* start control interface after reading config for + * ctrl_vty_get_bind_addr() */ + LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n", + ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC); + bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet, + ctrl_vty_get_bind_addr(), + OSMO_CTRL_PORT_NITB_BSC); if (!bsc_gsmnet->ctrl) { printf("Failed to initialize control interface. Exiting.\n"); return -1; -- 2.1.4 From nhofmeyr at sysmocom.de Wed Feb 24 19:48:39 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:48:39 +0100 Subject: [PATCH 6/6] smpp: refactor initialization, add bind address In-Reply-To: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456343319-572-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <1456343319-572-7-git-send-email-nhofmeyr@sysmocom.de> Make the SMPP bind address configurable (used to be harcoded as "0.0.0.0"). Add VTY command smpp local-tcp A.B.C.D <1-65535> while keeping the old command 'local-tcp-port <1-65535>'. Both the old and the new command immediately change the SMPP listening address and port. Add a LOGL_NOTICE log when the SMPP listening address and/or port change. However, to be useful, this patch has to go somewhat further: refactor the initialization procedure, because it was impossible to run the VTY commands without an already established connection. The SMPP initialization procedure was weird. It would first open a connection on the default port, and a subsequent VTY port reconfiguration while reading the config file would try to re-establish a connection on a different port. If that failed, smpp would switch back to the default port instead of failing the program launch as the user would expect. If anything else ran on port 2775, SMPP would thus refuse to launch despite the config file having a different port: the first bind would always happen on 0.0.0.0:2775. Change that. In the VTY commands, merely store address and port if no fd is established yet. Introduce several SMPP initialization stages: * allocate struct and initialize pointers, * then read config file without immediately starting to listen, * and once the main program is ready, start listening. After that, the VTY command behaves as before: try to re-establish the old connection if the newly supplied address and port don't work out. I'm not actually sure why this switch-back behavior is needed, but fair enough. In detail, replace the function smpp_smsc_init() with the various steps smpp_smsc_alloc_init() -- prepare struct for VTY commands smpp_smsc_conf() -- set addr an port only, for reading the config file smpp_smsc_start() -- establish a first connection, for main() smpp_smsc_restart() -- switch running connection, for telnet VTY smpp_smsc_stop() -- tear down connection, used by _start() twice And replace smpp_openbsc_init() smpp_openbsc_set_net() with smpp_openbsc_alloc_init() smpp_openbsc_start() I'd have picked function names like "_bind"/"_unbind", but in the SMPP protocol there is also a bind/unbind process, so instead I chose the names "_start", "_restart" and "_stop". The smsc struct used to be talloc'd outside of smpp_smsc_init(). Since the smsc code internally uses talloc anyway and employs the smsc struct as talloc context, I decided to enforce talloc allocation within smpp_smsc_alloc_init(). Be stricter about osmo_signal_register_handler() return codes. --- openbsc/include/openbsc/smpp.h | 4 +- openbsc/src/libmsc/smpp_openbsc.c | 43 +++++++++++------- openbsc/src/libmsc/smpp_smsc.c | 93 +++++++++++++++++++++++++++++---------- openbsc/src/libmsc/smpp_smsc.h | 7 ++- openbsc/src/libmsc/smpp_vty.c | 75 ++++++++++++++++++++++++++----- openbsc/src/osmo-nitb/bsc_hack.c | 4 +- 6 files changed, 169 insertions(+), 57 deletions(-) diff --git a/openbsc/include/openbsc/smpp.h b/openbsc/include/openbsc/smpp.h index 9941cee..bcdac8f 100644 --- a/openbsc/include/openbsc/smpp.h +++ b/openbsc/include/openbsc/smpp.h @@ -1,4 +1,4 @@ #pragma once -int smpp_openbsc_init(void *ctx, uint16_t port); -void smpp_openbsc_set_net(struct gsm_network *net); +int smpp_openbsc_alloc_init(void *ctx); +int smpp_openbsc_start(struct gsm_network *net); diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index a2fa0f4..0269f4b 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -569,27 +569,38 @@ struct smsc *smsc_from_vty(struct vty *v) return g_smsc; } -/*! \brief Initialize the OpenBSC SMPP interface */ -int smpp_openbsc_init(void *ctx, uint16_t port) +/*! \brief Allocate the OpenBSC SMPP interface struct and init VTY. */ +int smpp_openbsc_alloc_init(void *ctx) +{ + g_smsc = smpp_smsc_alloc_init(ctx); + if (!g_smsc) { + LOGP(DSMPP, LOGL_FATAL, "Cannot allocate smsc struct\n"); + return -1; + } + return smpp_vty_init(); +} + +/*! \brief Launch the OpenBSC SMPP interface with the parameters set from VTY. + */ +int smpp_openbsc_start(struct gsm_network *net) { - struct smsc *smsc = talloc_zero(ctx, struct smsc); int rc; + g_smsc->priv = net; - rc = smpp_smsc_init(smsc, port); + /* If a VTY configuration has taken place, the values have been stored + * in the smsc struct. Otherwise, use the defaults (NULL -> any, 0 -> + * default SMPP port, see smpp_smsc_bind()). */ + rc = smpp_smsc_start(g_smsc, g_smsc->bind_addr, g_smsc->listen_port); if (rc < 0) - talloc_free(smsc); - - osmo_signal_register_handler(SS_SMS, smpp_sms_cb, smsc); - osmo_signal_register_handler(SS_SUBSCR, smpp_subscr_cb, smsc); + return rc; - g_smsc = smsc; - - smpp_vty_init(); + rc = osmo_signal_register_handler(SS_SMS, smpp_sms_cb, g_smsc); + if (rc < 0) + return rc; + rc = osmo_signal_register_handler(SS_SUBSCR, smpp_subscr_cb, g_smsc); + if (rc < 0) + return rc; - return rc; + return 0; } -void smpp_openbsc_set_net(struct gsm_network *net) -{ - g_smsc->priv = net; -} diff --git a/openbsc/src/libmsc/smpp_smsc.c b/openbsc/src/libmsc/smpp_smsc.c index c1ec22f..ef4277a 100644 --- a/openbsc/src/libmsc/smpp_smsc.c +++ b/openbsc/src/libmsc/smpp_smsc.c @@ -931,39 +931,84 @@ static int smsc_fd_cb(struct osmo_fd *ofd, unsigned int what) return link_accept_cb(ofd->data, rc, &sa, sa_len); } -/*! \brief Initialize the SMSC-side SMPP implementation */ -int smpp_smsc_init(struct smsc *smsc, uint16_t port) +/*! \brief allocate and initialize an smsc struct from talloc context ctx. */ +struct smsc *smpp_smsc_alloc_init(void *ctx) +{ + struct smsc *smsc = talloc_zero(ctx, struct smsc); + + INIT_LLIST_HEAD(&smsc->esme_list); + INIT_LLIST_HEAD(&smsc->acl_list); + INIT_LLIST_HEAD(&smsc->route_list); + + smsc->listen_ofd.data = smsc; + smsc->listen_ofd.cb = smsc_fd_cb; + + return smsc; +} + +/*! \brief Set the SMPP address and port without binding. */ +int smpp_smsc_conf(struct smsc *smsc, const char *bind_addr, uint16_t port) +{ + talloc_free((void*)smsc->bind_addr); + smsc->bind_addr = NULL; + if (bind_addr) { + smsc->bind_addr = talloc_strdup(smsc, bind_addr); + if (!smsc->bind_addr) + return -ENOMEM; + } + smsc->listen_port = port; + return 0; +} + +/*! \brief Bind to given address and port and accept connections. + * \param[in] bind_addr Local IP address, may be NULL for any. + * \param[in] port TCP port number, may be 0 for default SMPP (2775). + */ +int smpp_smsc_start(struct smsc *smsc, const char *bind_addr, uint16_t port) { int rc; /* default port for SMPP */ - if (port == 0) + if (!port) port = 2775; - /* This will not work if we were to actually ever use FD 0 - * (stdin) for this ... */ - if (smsc->listen_ofd.fd <= 0) { - INIT_LLIST_HEAD(&smsc->esme_list); - INIT_LLIST_HEAD(&smsc->acl_list); - INIT_LLIST_HEAD(&smsc->route_list); - smsc->listen_ofd.data = smsc; - smsc->listen_ofd.cb = smsc_fd_cb; - } else { - close(smsc->listen_ofd.fd); - osmo_fd_unregister(&smsc->listen_ofd); - } + smpp_smsc_stop(smsc); + + LOGP(DSMPP, LOGL_NOTICE, "SMPP at %s %d\n", + bind_addr? bind_addr : "0.0.0.0", port); rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, SOCK_STREAM, - IPPROTO_TCP, NULL, port, + IPPROTO_TCP, bind_addr, port, OSMO_SOCK_F_BIND); + if (rc < 0) + return rc; - /* if there is an error, try to re-bind to the old port */ - if (rc < 0) { - rc = osmo_sock_init_ofd(&smsc->listen_ofd, AF_UNSPEC, - SOCK_STREAM, IPPROTO_TCP, NULL, - smsc->listen_port, OSMO_SOCK_F_BIND); - } else - smsc->listen_port = port; - + /* store new address and port */ + rc = smpp_smsc_conf(smsc, bind_addr, port); + if (rc) + smpp_smsc_stop(smsc); return rc; } + +/*! \brief Change a running connection to a different address/port, and upon + * error switch back to the running configuration. */ +int smpp_smsc_restart(struct smsc *smsc, const char *bind_addr, uint16_t port) +{ + int rc; + + rc = smpp_smsc_start(smsc, bind_addr, port); + if (rc) + /* if there is an error, try to re-bind to the old port */ + return smpp_smsc_start(smsc, smsc->bind_addr, smsc->listen_port); + return 0; +} + +/*! /brief Close SMPP connection. */ +void smpp_smsc_stop(struct smsc *smsc) +{ + if (smsc->listen_ofd.fd > 0) { + close(smsc->listen_ofd.fd); + smsc->listen_ofd.fd = 0; + osmo_fd_unregister(&smsc->listen_ofd); + } +} diff --git a/openbsc/src/libmsc/smpp_smsc.h b/openbsc/src/libmsc/smpp_smsc.h index 3dd6562..bd20137 100644 --- a/openbsc/src/libmsc/smpp_smsc.h +++ b/openbsc/src/libmsc/smpp_smsc.h @@ -89,6 +89,7 @@ struct smsc { struct llist_head esme_list; struct llist_head acl_list; struct llist_head route_list; + const char *bind_addr; uint16_t listen_port; char system_id[SMPP_SYS_ID_LEN+1]; int accept_all; @@ -100,7 +101,11 @@ struct smsc { int smpp_addr_eq(const struct osmo_smpp_addr *a, const struct osmo_smpp_addr *b); -int smpp_smsc_init(struct smsc *smsc, uint16_t port); +struct smsc *smpp_smsc_alloc_init(void *ctx); +int smpp_smsc_conf(struct smsc *smsc, const char *bind_addr, uint16_t port); +int smpp_smsc_start(struct smsc *smsc, const char *bind_addr, uint16_t port); +int smpp_smsc_restart(struct smsc *smsc, const char *bind_addr, uint16_t port); +void smpp_smsc_stop(struct smsc *smsc); void smpp_esme_get(struct osmo_esme *esme); void smpp_esme_put(struct osmo_esme *esme); diff --git a/openbsc/src/libmsc/smpp_vty.c b/openbsc/src/libmsc/smpp_vty.c index c0695fe..5ab632f 100644 --- a/openbsc/src/libmsc/smpp_vty.c +++ b/openbsc/src/libmsc/smpp_vty.c @@ -76,31 +76,76 @@ DEFUN(cfg_no_smpp_first, cfg_no_smpp_first_cmd, return CMD_SUCCESS; } -DEFUN(cfg_smpp_port, cfg_smpp_port_cmd, - "local-tcp-port <1-65535>", - "Set the local TCP port on which we listen for SMPP\n" - "TCP port number") +static int smpp_local_tcp(struct vty *vty, + const char *bind_addr, uint16_t port) { struct smsc *smsc = smsc_from_vty(vty); - uint16_t port = atoi(argv[0]); + int is_running = smsc->listen_ofd.fd > 0; + int same_bind_addr; int rc; - rc = smpp_smsc_init(smsc, port); + /* If it is not up yet, don't rebind, just set values. */ + if (!is_running) { + rc = smpp_smsc_conf(smsc, bind_addr, port); + if (rc < 0) { + vty_out(vty, "%% Cannot configure new address:port%s", + VTY_NEWLINE); + return CMD_WARNING; + } + return CMD_SUCCESS; + } + + rc = smpp_smsc_restart(smsc, bind_addr, port); if (rc < 0) { - vty_out(vty, "%% Cannot bind to new port %u nor to " - "old port %u%s", port, smsc->listen_port, VTY_NEWLINE); + vty_out(vty, "%% Cannot bind to new port %s:%u nor to" + " old port %s:%u%s", + bind_addr? bind_addr : "0.0.0.0", + port, + smsc->bind_addr? smsc->bind_addr : "0.0.0.0", + smsc->listen_port, + VTY_NEWLINE); return CMD_WARNING; } - if (port != smsc->listen_port) { - vty_out(vty, "%% Cannot bind to new port %u, staying on old" - "port %u%s", port, smsc->listen_port, VTY_NEWLINE); + same_bind_addr = (bind_addr == smsc->bind_addr) + || (bind_addr && smsc->bind_addr + && (strcmp(bind_addr, smsc->bind_addr) == 0)); + + if (!same_bind_addr || port != smsc->listen_port) { + vty_out(vty, "%% Cannot bind to new port %s:%u, staying on" + " old port %s:%u%s", + bind_addr? bind_addr : "0.0.0.0", + port, + smsc->bind_addr? smsc->bind_addr : "0.0.0.0", + smsc->listen_port, + VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } +DEFUN(cfg_smpp_port, cfg_smpp_port_cmd, + "local-tcp-port <1-65535>", + "Set the local TCP port on which we listen for SMPP\n" + "TCP port number") +{ + struct smsc *smsc = smsc_from_vty(vty); + uint16_t port = atoi(argv[0]); + return smpp_local_tcp(vty, smsc->bind_addr, port); +} + +DEFUN(cfg_smpp_addr_port, cfg_smpp_addr_port_cmd, + "local-tcp A.B.C.D <1-65535>", + "Set the local IP address and TCP port on which we listen for SMPP\n" + "Local IP address\n" + "TCP port number") +{ + const char *bind_addr = argv[0]; + uint16_t port = atoi(argv[1]); + return smpp_local_tcp(vty, bind_addr, port); +} + DEFUN(cfg_smpp_sys_id, cfg_smpp_sys_id_cmd, "system-id ID", "Set the System ID of this SMSC\n" @@ -138,7 +183,12 @@ static int config_write_smpp(struct vty *vty) struct smsc *smsc = smsc_from_vty(vty); vty_out(vty, "smpp%s", VTY_NEWLINE); - vty_out(vty, " local-tcp-port %u%s", smsc->listen_port, VTY_NEWLINE); + if (smsc->bind_addr) + vty_out(vty, " local-tcp %s %u%s", smsc->bind_addr, + smsc->listen_port, VTY_NEWLINE); + else + vty_out(vty, " local-tcp-port %u%s", smsc->listen_port, + VTY_NEWLINE); if (strlen(smsc->system_id) > 0) vty_out(vty, " system-id %s%s", smsc->system_id, VTY_NEWLINE); vty_out(vty, " policy %s%s", @@ -535,6 +585,7 @@ int smpp_vty_init(void) install_element(SMPP_NODE, &cfg_smpp_first_cmd); install_element(SMPP_NODE, &cfg_no_smpp_first_cmd); install_element(SMPP_NODE, &cfg_smpp_port_cmd); + install_element(SMPP_NODE, &cfg_smpp_addr_port_cmd); install_element(SMPP_NODE, &cfg_smpp_sys_id_cmd); install_element(SMPP_NODE, &cfg_smpp_policy_cmd); install_element(SMPP_NODE, &cfg_esme_cmd); diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index 4bd03fc..3bd73f4 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -276,7 +276,7 @@ int main(int argc, char **argv) ctrl_vty_init(tall_bsc_ctx); #ifdef BUILD_SMPP - if (smpp_openbsc_init(tall_bsc_ctx, 0) < 0) + if (smpp_openbsc_alloc_init(tall_bsc_ctx) < 0) return -1; #endif @@ -293,7 +293,7 @@ int main(int argc, char **argv) if (rc < 0) exit(1); #ifdef BUILD_SMPP - smpp_openbsc_set_net(bsc_gsmnet); + smpp_openbsc_start(bsc_gsmnet); #endif bsc_api_init(bsc_gsmnet, msc_bsc_api()); -- 2.1.4 From laforge at gnumonks.org Wed Feb 24 19:46:05 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 20:46:05 +0100 Subject: Move PCU/SGSN/GGSN discussions to osmocom-net-gprs In-Reply-To: <56CE0035.1090600@alumni.ntnu.no> References: <20160224171904.GN23371@nataraja> <56CE0035.1090600@alumni.ntnu.no> Message-ID: <20160224194605.GQ23371@nataraja> On Wed, Feb 24, 2016 at 08:10:45PM +0100, Max (?) wrote: > Would it be possible to point patchwork to osmocom-net-grps as well? I'll ask Jeremy for that, thanks. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From nhofmeyr at sysmocom.de Wed Feb 24 19:56:23 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:56:23 +0100 Subject: [PATCH 0/3] eliminate some compiler warnings In-Reply-To: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> References: <1456341367-15394-1-git-send-email-nhofmeyr@sysmocom.de> Message-ID: <20160224195623.GC3029@dub6> On Wed, Feb 24, 2016 at 08:16:04PM +0100, Neels Hofmeyr wrote: > These patches eradicate some of the easier-to-fix compiler warnings I keep sorry, the first one is not actually a compiler warning eradication, but a mere initialization "buglet". ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Wed Feb 24 19:58:56 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Wed, 24 Feb 2016 20:58:56 +0100 Subject: [PATCH 3/3] Add VTY section for Control interface bind address In-Reply-To: <20160224145955.GG23371@nataraja> References: <201602240240.u1O2eRvN030435@einhorn.in-berlin.de> <20160224090835.GS18382@nataraja> <20160224134715.GD1601@dub6> <20160224145955.GG23371@nataraja> Message-ID: <20160224195856.GD3029@dub6> On Wed, Feb 24, 2016 at 03:59:55PM +0100, Harald Welte wrote: > I don't care as long as it has an L_ prefix if it is implemented in a > library. I finally grokked that it's part of libosmoctrl, which is part of libosmocore, hence the L_; not some other "external" library. ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Wed Feb 24 21:22:29 2016 From: holger at freyther.de (Holger Freyther) Date: Wed, 24 Feb 2016 22:22:29 +0100 Subject: Smalltalk scalable SMSC project In-Reply-To: References: <9047F009-0798-4ED9-8211-BA5D515B9295@freyther.de> <47AB9864-CB30-4AEA-8FE5-45D484DF6002@freyther.de> Message-ID: <188C6BD2-0176-4F18-BCA6-6EEEB2500536@freyther.de> > On 19 Feb 2016, at 20:34, Holger Freyther wrote: > Hi! > > As usual the source code and all intermediate versions is free software (still on my private github repo as the travis-ci system integration is quite neat but that will change). I have now finished the delivery code for SMPP and SS7/MAP (forwardSM/mt-ForwardSM). The code is missing some unit tests and might not work yet but the structure for it is there. The next steps will be: * Continue on packaging and system-tests * Add (unit) tests for simulating the various failures on SMPP and SS7 delivery * Use the "write-concern" of mongo for writing * Deploy and measure performance of the system. holger From laforge at gnumonks.org Wed Feb 24 22:38:36 2016 From: laforge at gnumonks.org (Harald Welte) Date: Wed, 24 Feb 2016 23:38:36 +0100 Subject: (int)(void*)(int) 64 vs 32 In-Reply-To: <20160224190642.GB3029@dub6> References: <20160224190642.GB3029@dub6> Message-ID: <20160224223836.GU23371@nataraja> On Wed, Feb 24, 2016 at 08:07:21PM +0100, Neels Hofmeyr wrote: > On my 64bit system, I get warnings about casting int to pointer of > different size and vice versa. However, below patch only shifts the > warnings to 32bit systems, right? I don't think so. 'long' typically corresponds to the pointer size, at least based on my experience. Of course the C standard doesn't give you any guarantees and just states that it should be at least the size of a signed 32bit integer. according to page 6 of http://www.agner.org/optimize/calling_conventions.pdf the only practical exception seems to be windows, where on 64bit even a 'long' is only 32bit ;) The more interesting question is probably why is vty->index not pointing to 'struct osmo_msc_data' in the first place? That's what we typically use, rather than storing integers in the pointer and then perfomring lookups on that. Holger? -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From jacob01 at gmx.net Thu Feb 25 09:03:21 2016 From: jacob01 at gmx.net (Jacob) Date: Thu, 25 Feb 2016 10:03:21 +0100 Subject: (int)(void*)(int) 64 vs 32 In-Reply-To: <20160224190642.GB3029@dub6> References: <20160224190642.GB3029@dub6> Message-ID: <56CEC359.5090908@gmx.net> Hi On 24.02.2016 20:07, Neels Hofmeyr wrote: > On my 64bit system, I get warnings about casting int to pointer of > different size and vice versa. However, below patch only shifts the > warnings to 32bit systems, right? > > Should we encapsulate in some #ifdef __i386__ or is there an always-native > int type? What about using uintptr_t from stdint.h ? Jacob From nhofmeyr at sysmocom.de Thu Feb 25 11:25:54 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 25 Feb 2016 12:25:54 +0100 Subject: (int)(void*)(int) 64 vs 32 In-Reply-To: <56CEC359.5090908@gmx.net> References: <20160224190642.GB3029@dub6> <56CEC359.5090908@gmx.net> Message-ID: <20160225112554.GA1285@dub6> On Wed, Feb 24, 2016 at 11:38:36PM +0100, Harald Welte wrote: > On Wed, Feb 24, 2016 at 08:07:21PM +0100, Neels Hofmeyr wrote: > > On my 64bit system, I get warnings about casting int to pointer of > > different size and vice versa. However, below patch only shifts the > > warnings to 32bit systems, right? >? > I don't think so. 'long' typically corresponds to the pointer size, at > least based on my experience. Of course the C standard doesn't give you > any guarantees and just states that it should be at least the size of a > signed 32bit integer. >? > according to page 6 of > http://www.agner.org/optimize/calling_conventions.pdf the only practical > exception seems to be windows, where on 64bit even a 'long' is only > 32bit ;) can't do that then, can we ;) On Thu, Feb 25, 2016 at 10:03:21AM +0100, Jacob wrote: > What about using uintptr_t from stdint.h ? stdint.h:typedef unsigned long int uintptr_t; So that would work indeed. I'd have interpreted the name to mean unsigned int* but it seems to be made for this specific case. But I agree that the case per se is still odd: On Wed, Feb 24, 2016 at 11:38:36PM +0100, Harald Welte wrote: > The more interesting question is probably why is vty->index not pointing > to 'struct osmo_msc_data' in the first place? That's what we typically > use, rather than storing integers in the pointer and then perfomring > lookups on that. Holger? /me escalating to hfreyther ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 25 11:37:38 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 25 Feb 2016 12:37:38 +0100 Subject: fyi, my recent patch sets Message-ID: <20160225113738.GB1285@dub6> This is just to say that all my currently waiting patch sets have been merged to the respective master branches, after due nitpicking by Holger in person (thanks!) with various style/simplicity modifications applied. (The one still open is the int/void* thing, not intended as a patch anyway but more as a question.) So the road is clear now for configuring osmo-nitb with its entire set of own IP addresses, and as a side effect various other osmo-programs also have configurable telnet-VTY, Ctrl-interface and Abis addresses now. To summarize the final result: (1) Abis/IP e1_input ipa bind 10.9.8.7 (2) telnet VTY line vty bind 10.9.8.7 (3) ctrl interface ctrl bind 10.9.8.7 (4) MNCC unix domain socket -M /path/to/socket/file (5) SMPP SMSC smpp local-tcp-ip 10.9.8.7 2775 Is this worth a Wiki entry? ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 25 11:49:47 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 25 Feb 2016 12:49:47 +0100 Subject: more CCAN gems In-Reply-To: <20160224170317.GK23371@nataraja> References: <20160224170317.GK23371@nataraja> Message-ID: <20160225114947.GC1285@dub6> On Wed, Feb 24, 2016 at 06:03:17PM +0100, Harald Welte wrote: > fast pseudo-random generator. Too sas that we want real random numbres > for authentication challenges in GSUP/OAP? > https://github.com/rustyrussell/ccan/blob/master/ccan/isaac/_info This makes me think of openbsc/src/osmo-bsc_mgcp/mgcp_main.c: srand(time(NULL)); openbsc/src/osmo-bsc/osmo_bsc_main.c: srand(time(NULL)); openbsc/src/osmo-bsc_nat/bsc_nat.c: srand(time(NULL)); openbsc/src/osmo-nitb/bsc_hack.c: srand(time(NULL)); Crypto nightmare. Are we using those for challenges, actually? ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Thu Feb 25 11:52:43 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Thu, 25 Feb 2016 12:52:43 +0100 Subject: Move PCU/SGSN/GGSN discussions to osmocom-net-gprs In-Reply-To: <20160224171904.GN23371@nataraja> References: <20160224171904.GN23371@nataraja> Message-ID: <20160225115243.GD1285@dub6> On Wed, Feb 24, 2016 at 06:19:04PM +0100, Harald Welte wrote: > However, let's wait for the Iu-CS / Iu-PS integration and osmo-cscn > (nitb without integrated bsc) first, and then look at how to lay out the > source code repositories. Thanks for this ... unless we want to create another list for 3G (named 3G because it would be a list for three Germans). ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Thu Feb 25 13:00:09 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 25 Feb 2016 14:00:09 +0100 Subject: more CCAN gems In-Reply-To: <20160225114947.GC1285@dub6> References: <20160224170317.GK23371@nataraja> <20160225114947.GC1285@dub6> Message-ID: > On 25 Feb 2016, at 12:49, Neels Hofmeyr wrote: > > > Are we using those for challenges, actually? We are using RAND_bytes for at least TMSI, P-TMSI (thus TLLI) and challenge response on the NAT. From holger at freyther.de Thu Feb 25 13:01:00 2016 From: holger at freyther.de (Holger Freyther) Date: Thu, 25 Feb 2016 14:01:00 +0100 Subject: (int)(void*)(int) 64 vs 32 In-Reply-To: <20160224223836.GU23371@nataraja> References: <20160224190642.GB3029@dub6> <20160224223836.GU23371@nataraja> Message-ID: <103DA54D-DE0C-48F5-85AF-A86EA0B26FE9@freyther.de> > On 24 Feb 2016, at 23:38, Harald Welte wrote: > > > The more interesting question is probably why is vty->index not pointing > to 'struct osmo_msc_data' in the first place? That's what we typically > use, rather than storing integers in the pointer and then perfomring > lookups on that. Holger? I don't remember why I wanted to work with numbers. We can use the pointer to the struct. holger From wei at issohandso.me Thu Feb 25 19:29:42 2016 From: wei at issohandso.me (Wei) Date: Thu, 25 Feb 2016 14:29:42 -0500 Subject: Fail in using pySIM to set authentication algorithm Message-ID: Hi, I'm having a trouble when using pySIM to change the authentication algorithm in a USIM-SJS1 card. Basically I want disable the 3G authentication on the card, and only use 2G authentication regardless of the network type. Anyway, here's my procedure. In the beginning, I didn't realize there's a zecke/tmp2 branch. So i modified the the cards.py by myself. I added data, sw = self._scc.update_binary('6F00', '03') in the this line http://cgit.osmocom.org/pysim/tree/pySim/cards.py?h=master#n461 I learned the values '6F00' and '03' from this osmocom webpage . One thing to mention that is I also commented out the self._scc.verify_chv() and update KI/IMSI statements in above. Because it always fails in the self._scc.verify_chv() step (apdu response 69xx), though I provided the adm-1 key in the CLI. After it's done, unfortunately I found that when use ./pySim-read.py to read SIM again, it fails with apdu response 6b00. Also, the attempt to updating authentication algorithm didn't work when test in the phone. Did I already mess up this SIM card at this point? Then, I found there's a zecke/tmp2 branch. Tried it. Still not working either in reading (apdu response 6b00); or writing (still ails in self._scc.verify_chv() with apdu response 6983) Please give suggestion on what I should do. Thank you. -------------- next part -------------- An HTML attachment was scrubbed... URL: From laforge at gnumonks.org Thu Feb 25 19:48:05 2016 From: laforge at gnumonks.org (Harald Welte) Date: Thu, 25 Feb 2016 20:48:05 +0100 Subject: Fail in using pySIM to set authentication algorithm In-Reply-To: References: Message-ID: <20160225194805.GV23371@nataraja> On Thu, Feb 25, 2016 at 02:29:42PM -0500, Wei wrote: > I'm having a trouble when using pySIM to change the authentication > algorithm in a USIM-SJS1 card. Basically I want disable the 3G authentication > on the card, and only use 2G authentication regardless of the network type. This is not a valid operation. The card is a combined SIM + UICC + USIM card. A USIM application by definition must support an UMTS authentication context. You can change the UMTS authentication algoritmh from MILENAGE to XOR, but even the specs for USIM don't allow any COMP128v1/v2/v3 algorithms. Please read the relevant specs. So in fact what you need is a pure old 2G SIM card (like the magic SIM, sysmoSIM-GR1), not a SIM + USIM + UICC. -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Fri Feb 26 16:41:38 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 26 Feb 2016 17:41:38 +0100 Subject: RFC MNCC to SIP bridge Message-ID: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> Hi, I am looking into building a very simple MNCC to SIP bridge to be used with the NITB (and later the CSCN). This will be based on what was learned from adding the RTP bridge which means the audio will not flow through the bridge (eventually later there will be a UDP proxy for NAT traversal) The primary design points are: * Being able to select TCH/F or TCH/H * Decide on the codec very late * Support for AMR parameters through MNCC I just look at MO and MT Call establishment from a high-level point of view: MO-Call: * NITB will send the SETUP indication * MNCC GW will do screening and decide if to proceed * MNCC GW will make TCH/F or TCH/H decision and ask for a source IP, source port * Based on bearer caps (to be handled by MNCC GW?) and TCH/F, TCH/H MNCC GW can offer a SDP file with multiple codecs to the PBX. ... * PBX will decide on a codec (ringing or 200 connect) * MNCC GW will ask NITB to reconfigure and audio will flow * (TODO: check ringtone, check default, check codec change) MT-Call: * MNCC GW will be presented with a list of codecs already * Depending on that TCH/F or TCH/H can/must be chosen (e.g. for AMR even the codec rate can be in the SDP file that decides which TCH/F or TCH/H to use) * Can decide bearer caps once paging has succeeded and call is progressing * Sets audio codec and waits for call to connect Handover support: * IP/port (and then SSRC and timestamp in RTP) will change * MNCC GW could try SIP re-invite with changed parameters * MMCC GW could hope PBX implements RTP annex and re-learns the connection Do you have comments or remarks? The above will lead to a version update, probably a dedicated assignment command in MNCC, and separating socket creation and codec change. Anyone wants to have a go at that? have a nice weekend holger From laforge at gnumonks.org Fri Feb 26 18:45:04 2016 From: laforge at gnumonks.org (Harald Welte) Date: Fri, 26 Feb 2016 19:45:04 +0100 Subject: RFC MNCC to SIP bridge In-Reply-To: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> References: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> Message-ID: <20160226184504.GM23371@nataraja> Hi Holger, On Fri, Feb 26, 2016 at 05:41:38PM +0100, Holger Freyther wrote: > This will be based on what was learned from adding the RTP bridge > which means the audio will not flow through the bridge (eventually > later there will be a UDP proxy for NAT traversal) It might be good to have at last have a plan what to do with legacy BTSs with E1 intrface. I know it's not the primary goal right now, but we do have all the code to convert from TRAU frames to RTP and vice-versa, and we use that with the classic non-rtp-bridge MNCC towards LCR. However, we can currently only have one MNCC app registered to the MNCC socket, so if you register the new SIP-to-MNCC gateway, then the codec frames will end up there. Any ideas on that? Split MNCC into separate signalling and user plane sockets? That way an external future gateway could actually do that conversion without any change to the SIP converter? Or get rid of trau frame handling in the NITB when transitioning to CSCN, and move all that to the BSC / BSC-mgcp? Then at least from that point upwards it would all be A-over-IP and RTP, even for E1 based BTSs? > * Being able to select TCH/F or TCH/H Who would do the selection? The remote SIP PBX? Also, what about the BSC autonomously handing-over from a TCH/H to a TCH/F, in cases where the BTS gets more loaded, or in case there's a hand-over and the new target BTS has no slots of the same type available? > * Based on bearer caps (to be handled by MNCC GW?) and TCH/F, > TCH/H MNCC GW can offer a SDP file with multiple codecs to the > PBX. What do you mean by the question 'to be handled by MNCC GW?' I think the MNCC interface today already exposes the full MS originated bearer capabilities as sent in CC, in a decoded form. MNCC-SIP-GW then needs to translate that into SDP, as you point out. Sorry for making things more complex, but this might also be the right point to look at the 3GPP LCLS (local call local switch) feature, and how they have implemented the short-circuit of keeping BTs-local or BSC-local calls local without passing the user plane all the way into the core network. I think in many cases one would also want this in a MNCC-SIP kind of situation, and it's better to understand all constraints now before designign something new that falls short of something required for the latter... > * IP/port (and then SSRC and timestamp in RTP) will change see above, also the codec and even the TCH type could change. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Fri Feb 26 20:07:01 2016 From: holger at freyther.de (Holger Freyther) Date: Fri, 26 Feb 2016 21:07:01 +0100 Subject: RFC MNCC to SIP bridge In-Reply-To: <20160226184504.GM23371@nataraja> References: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> <20160226184504.GM23371@nataraja> Message-ID: <4538D1DD-C949-4A1A-B896-D8FC8B69F9DE@freyther.de> > On 26 Feb 2016, at 19:45, Harald Welte wrote: > > It might be good to have at last have a plan what to do with legacy BTSs > with E1 intrface. I know it's not the primary goal right now, but we do > have all the code to convert from TRAU frames to RTP and vice-versa, and > we use that with the classic non-rtp-bridge MNCC towards LCR. However, > we can currently only have one MNCC app registered to the MNCC socket, > so if you register the new SIP-to-MNCC gateway, then the codec frames > will end up there. Any ideas on that? Split MNCC into separate > signalling and user plane sockets? That way an external future gateway > could actually do that conversion without any change to the SIP > converter? > > Or get rid of trau frame handling in the NITB when transitioning to > CSCN, and move all that to the BSC / BSC-mgcp? Then at least from that > point upwards it would all be A-over-IP and RTP, even for E1 based BTSs? Codec frames will not end up at the new GW because the new RTP bridge command will fail and this leads to the call being dropped/not proceeding. Now it is good to have a plan to move forward and not let the conversion code just rot. a.) We can do the TRAU/RTP conversion inside the NITB. The RTP bridge code would then not ask the BTS to open a socket but open it itself and the SIP-to-MNCC gateway would not have to know the difference. b.) The SIP-to-MNCC gw can know the difference and we could use some funny Unix feature to send a fd to the timeslot that carries TRAU to the application and the TRAU/RTP code is done in the gateway? Doing a.) is probably very easy but I don't think anyone used the BS11 in the CCCB for a long time and I don't know any other BS11 (or Nokia or Ericsson) setup right now. >> * Being able to select TCH/F or TCH/H > > Who would do the selection? The remote SIP PBX? The MO-Call could select anything it wants or pick "any" and for the MT-Call the GW would ask the NITB to pick something that matches the offered codecs. So if AMR5.9 and HR are offered by the PBX the MT-Call should be using TCH/H (and start to page for this kind of channel and then look for the bearer capabilities to make the decision). So I think it is feasible but the issue will be with the PBX we are trying to use. > Also, what about the BSC autonomously handing-over from a TCH/H to a > TCH/F, in cases where the BTS gets more loaded, or in case there's a > hand-over and the new target BTS has no slots of the same type > available? This is getting hardcore. I know of SIP 're-invite' but this is mostly a measure to check that the other party is still active. In theory one could re-negotiate the codec but I doubt that it will work with proprietary SIP PBXs and even with the FOSS ones it will most likely end up with the requirement to patch it. > >> * Based on bearer caps (to be handled by MNCC GW?) and TCH/F, >> TCH/H MNCC GW can offer a SDP file with multiple codecs to the >> PBX. > > What do you mean by the question 'to be handled by MNCC GW?' I think > the MNCC interface today already exposes the full MS originated bearer > capabilities as sent in CC, in a decoded form. MNCC-SIP-GW then needs > to translate that into SDP, as you point out. Yes, I just wondered if bearer capability handling is best done in the MNCC GW or if we want to extend the MNCC interface to just list the possible codecs (already reduced by the traffic channel in use?) > Sorry for making things more complex, but this might also be the right > point to look at the 3GPP LCLS (local call local switch) feature, and > how they have implemented the short-circuit of keeping BTs-local or > BSC-local calls local without passing the user plane all the way into > the core network. I think in many cases one would also want this in a > MNCC-SIP kind of situation, and it's better to understand all > constraints now before designign something new that falls short of > something required for the latter... Can you point me to the right number for it? From laforge at gnumonks.org Sat Feb 27 09:21:56 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 27 Feb 2016 10:21:56 +0100 Subject: RFC MNCC to SIP bridge In-Reply-To: <4538D1DD-C949-4A1A-B896-D8FC8B69F9DE@freyther.de> References: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> <20160226184504.GM23371@nataraja> <4538D1DD-C949-4A1A-B896-D8FC8B69F9DE@freyther.de> Message-ID: <20160227092156.GN23371@nataraja> Hi Holger, On Fri, Feb 26, 2016 at 09:07:01PM +0100, Holger Freyther wrote: > > On 26 Feb 2016, at 19:45, Harald Welte wrote: > > Or get rid of trau frame handling in the NITB when transitioning to > > CSCN, and move all that to the BSC / BSC-mgcp? Then at least from that > > point upwards it would all be A-over-IP and RTP, even for E1 based BTSs? > > a.) We can do the TRAU/RTP conversion inside the NITB. The RTP bridge > code would then not ask the BTS to open a socket but open it itself > and the SIP-to-MNCC gateway would not have to know the difference. I like that approach. This functionality would be at the OsmoBSC level, once we start to use OsmoCSCN + OsmoBSC as replacement for OsmoNITB. So the functional split in the code could already be prepared for that, rather tuan introducing more TCH/lchan dependencies to the "MSC side" of the code, which Neels is trying to remoove at this point. > b.) The SIP-to-MNCC gw can know the difference and we could use some > funny Unix feature to send a fd to the timeslot that carries TRAU to > the application and the TRAU/RTP code is done in the gateway? I don't really like that idea. The gateway shouldn't have to know the differences. > Doing a.) is probably very easy but I don't think anyone used the BS11 > in the CCCB for a long time and I don't know any other BS11 (or Nokia > or Ericsson) setup right now. I have a fully wired setup with BS-11, Ericsson RBS2307 and a Nokia InSite at my home. Haven't used it in a long time, but it is still there. We could also move that to sysmocom and make it part of the regression testing setup, once that setup is more complete. > > Who would do the selection? The remote SIP PBX? > > The MO-Call could select anything it wants or pick "any" my question was where exactly would that selection happen? In the remote SIP PBX? > and for the MT-Call the GW would ask the NITB to pick something that > matches the offered codecs. So if AMR5.9 and HR are offered by the PBX > the MT-Call should be using TCH/H (and start to page for this kind of > channel and then look for the bearer capabilities to make the > decision). understood. What's also required is that the supported codecs of the BTS segment are understood. We have the list of codecs supported by the MS inside the CC message, but we don't know the list of codecs supported by the BTS by this. Or the reduced set of codecs as per administrative means (configuration). I think MNCC should be extended to include that as part of the SETUP message towards the external MNCC handler, rather than messing around with the CC level message. > > Also, what about the BSC autonomously handing-over from a TCH/H to a > > TCH/F, in cases where the BTS gets more loaded, or in case there's a > > hand-over and the new target BTS has no slots of the same type > > available? > > This is getting hardcore. yes, but a unfortunately perfectly normal case in all bu the simplest networks :/ > I know of SIP 're-invite' but this is mostly a measure to check that > the other party is still active. In theory one could re-negotiate the > codec but I doubt that it will work with proprietary SIP PBXs and even > with the FOSS ones it will most likely end up with the requirement to > patch it. One might want to have a look on how this is done on the SIP side in LTE/IMS to 2G/3G hand-over cases. They should have the same problem. > Yes, I just wondered if bearer capability handling is best done in the > MNCC GW or if we want to extend the MNCC interface to just list the > possible codecs (already reduced by the traffic channel in use?) see above, I think it's better to pass through the "raw" information rather than messing with the Layer3 bearer capability IE content. > > Sorry for making things more complex, but this might also be the right > > point to look at the 3GPP LCLS (local call local switch) feature, and > > how they have implemented the short-circuit of keeping BTs-local or > > BSC-local calls local without passing the user plane all the way into > > the core network. > > Can you point me to the right number for it? A high-level description seems to be offered in TS 23.284 (http://www.etsi.org/deliver/etsi_ts/123200_123299/123284/13.00.00_60/ts_123284v130000p.pdf) http://www.3gpp.org/DynaReport/WiCr--430001.htm contains a list of changes made to other 3GPP specs for LCLS support. Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From laforge at gnumonks.org Sat Feb 27 11:29:15 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sat, 27 Feb 2016 12:29:15 +0100 Subject: RFC MNCC to SIP bridge In-Reply-To: <20160227092156.GN23371@nataraja> References: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> <20160226184504.GM23371@nataraja> <4538D1DD-C949-4A1A-B896-D8FC8B69F9DE@freyther.de> <20160227092156.GN23371@nataraja> Message-ID: <20160227112915.GO23371@nataraja> Hi Holger, I'm sorry for again making this more complex than neccessary. It's up to you whether you would like to go down that route, of course :) I found the following specifications that relate to how existing classic GSM/3GPP call control is mapped to SIP and vice versa (unfortunately typically over BICC as intermediate, but BICC is closer to 04.08 CC). In the context of interoperability with IMS this might be worth investigating: * 3GPP CS interworking with BICC/ISUP and SIP-I networks http://www.3gpp.org/DynaReport/29164.htm http://www.3gpp.org/DynaReport/WiCr--13033.htm heavily based on ITU-T Q.1912.5: SIP <-> BICC/ISUP interworking https://www.itu.int/rec/T-REC-Q.1912.5-200403-I/en (and as a side-note, ITU-T has actually specified conformance testing procedures for SIP in Q.3946.x) * NcSIP (SIP Between G-MSCs?) http://www.3gpp.org/DynaReport/29802.htm http://www.3gpp.org/DynaReport/WiCr--320018.htm http://www.3gpp.org/DynaReport/WiCr--360025.htm On Sat, Feb 27, 2016 at 10:21:56AM +0100, Harald Welte wrote: > A high-level description seems to be offered in TS 23.284 > (http://www.etsi.org/deliver/etsi_ts/123200_123299/123284/13.00.00_60/ts_123284v130000p.pdf) > > http://www.3gpp.org/DynaReport/WiCr--430001.htm contains a list of > changes made to other 3GPP specs for LCLS support. There's also a follow-up to that in http://www.3gpp.org/DynaReport/WiCr--440021.htm -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From hwelte at sysmocom.de Sat Feb 27 11:58:33 2016 From: hwelte at sysmocom.de (Harald Welte) Date: Sat, 27 Feb 2016 12:58:33 +0100 Subject: Interesting 3GPP specs / work areas to look at Message-ID: <20160227115833.GS23371@nataraja> Dear all, I've gone through the high-level list of change areas / projects from Rel-4 through Rel-14 and collected a list of those parts that seemed like they could be interesting from an Osmocom point of view. In case you're curious and enjoy reading 3GPP docs as much as I do, feel free to check out http://projects.osmocom.org/projects/cellular-infrastructure/wiki/Interesting3GPPSpecsForDevelopers Some parts were just recently mentioned, like Extended Uplink TBF, Network Assisted Cell Change, MNCC-SIP interface, Local Call Local Switch. We also already knew about the "Real" A-over-IP specification (different from the SCCPlite A interface that OsmoBSC implements), and A5/4. There's quite some other interesting bits and pieces, such as for example the feasibility study on GSM/EDGE BTS power saving, where they propose (it's not accepted yet) to reduce the transmit power on the BCCH-carrying TRX at certain points in the time multiplex. Enjoy, Harald -- - Harald Welte http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte From laforge at gnumonks.org Sun Feb 28 09:59:40 2016 From: laforge at gnumonks.org (Harald Welte) Date: Sun, 28 Feb 2016 10:59:40 +0100 Subject: OsmoDevCon 2016 planning / wiki page In-Reply-To: <20160205235433.GP10932@nataraja> References: <20160112151200.GP1762@nataraja> <20160113133526.GO9964@nataraja> <20160205235433.GP10932@nataraja> Message-ID: <20160228095940.GC23371@nataraja> Dear all, On Sat, Feb 06, 2016 at 12:54:33AM +0100, Harald Welte wrote: > I've just created the template wiki page for OsmoDevCon2016 at > > http://openbsc.osmocom.org/trac/wiki/OsmoDevCon2016 > > please add your name to the list if you're interested to attend (and > qualify as somebody who contributed to Osmocom projects). We have meanwhile migrated this to the new redmine installation at http://projects.osmocom.org/projects/openbsc/wiki/OsmoDevCon2016 As today is February 28 (indicated as the last day for registration), please let me know if you still have not added your name but are an existing Osmocom developer/contributor and would like to attend. Please also feel free to suggest further talks / discusison topics, either about which you would like to talk, or about which you would like to hear others talk. Also, the current list of topics is merely a suggestion. Please share openly if you think you don't want to hear about one of the topics :) Regards, Harald -- - Harald Welte http://laforge.gnumonks.org/ ============================================================================ "Privacy in residential applications is a desirable marketing option." (ETSI EN 300 175-7 Ch. A6) From holger at freyther.de Sun Feb 28 11:34:11 2016 From: holger at freyther.de (Holger Freyther) Date: Sun, 28 Feb 2016 12:34:11 +0100 Subject: RFC MNCC to SIP bridge In-Reply-To: <20160227112915.GO23371@nataraja> References: <8B330E0B-85A9-4ED1-9A49-5E210AE6742B@freyther.de> <20160226184504.GM23371@nataraja> <4538D1DD-C949-4A1A-B896-D8FC8B69F9DE@freyther.de> <20160227092156.GN23371@nataraja> <20160227112915.GO23371@nataraja> Message-ID: <4592849A-B74D-4437-93FF-19DB81C26EE0@freyther.de> > On 27 Feb 2016, at 12:29, Harald Welte wrote: > > Hi Holger, Dear Harald, > I'm sorry for again making this more complex than neccessary. It's up > to you whether you would like to go down that route, of course :) thank you for the pointers. I will have a look and probably still concentrate on the first items that is delaying the point where the audio codec will be picked and to have nice sofia-sip event loop integration without resorting to polling every n-seconds. kind regards holger From nhofmeyr at sysmocom.de Mon Feb 29 00:08:11 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 29 Feb 2016 01:08:11 +0100 Subject: gsm 7bit decode: *8/7 Message-ID: <20160229000810.GA28083@dub6> Hi list, I just thought I had fixed gsm_7bit_decode_n(), since its API doc says * \param length The length of the input sequence (in octets). int gsm_7bit_decode_n([...], uint8_t length); but the implementation is int gsm_7bit_decode_n([...], uint8_t septet_l) and indeed the length parameter is handled as septet length. So, logically, I came up with this patch: diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index e8e452f..a9afc1a 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -184,8 +184,9 @@ return text - text_buf_begin; } -int gsm_7bit_decode_n(char *text, size_t n, const uint8_t *user_data, uint8_t septet_l) +int gsm_7bit_decode_n(char *text, size_t n, const uint8_t *user_data, uint8_t octet_l) { + uint8_t septet_l = ((uint16_t)octet_l * 8) / 7; return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0); } (the cast to uint16_t makes 100% sure the calculation isn't truncated to uint8_t after the *8 multiplication -- I picked this up while hacking on 8bit microcontrollers. That truncation doesn't really happen on our 32bit/64bit machines, but if it did, the length would effectively be limited to 255/8 == 31 characters.) Then I noticed that callers actually do *8/7 before calling the function: parse_process_uss_req(): num_chars = (uss_req_data[6] * 8) / 7; /* Prevent a mobile-originated buffer-overrun! */ if (num_chars > MAX_LEN_USSD_STRING) num_chars = MAX_LEN_USSD_STRING; gsm_7bit_decode_n_ussd((char *)req->ussd_text, sizeof(req->ussd_text), &(uss_req_data[7]), num_chars); (This is gsm_7bit_decode_n_ussd(), its API doc says "see gsm_7bit_decode_n()") So we have the API talking about length "in octets" while the implementation clearly employs septet length. Fixing the implementation to match the API doc would break binary compatibility. I should probably fix the API doc to match that weird implementation, but it nags and hurts a little. Any opinions? ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From axilirator at gmail.com Mon Feb 29 04:17:43 2016 From: axilirator at gmail.com (=?UTF-8?B?0JLQsNC00LjQvCDQr9C90LjRhtC60LjQuQ==?=) Date: Mon, 29 Feb 2016 10:17:43 +0600 Subject: Redmine theme Message-ID: Dear all, I suggest to change a stock Redmine theme to something more beautiful, for example gitmike: https://github.com/makotokw/redmine-theme-gitmike which used by srlabs.de and looks like pretty. Furthermore, the Osmocom logo will look better on light background. Opinions? ? ?????????? ???????????, ??????? ?????. -------------- next part -------------- An HTML attachment was scrubbed... URL: From holger at freyther.de Mon Feb 29 08:24:57 2016 From: holger at freyther.de (Holger Freyther) Date: Mon, 29 Feb 2016 09:24:57 +0100 Subject: gsm 7bit decode: *8/7 In-Reply-To: <20160229000810.GA28083@dub6> References: <20160229000810.GA28083@dub6> Message-ID: <47CED3E9-753C-4382-8E56-F1816B462D29@freyther.de> > On 29 Feb 2016, at 01:08, Neels Hofmeyr wrote: > > > > So we have the API talking about length "in octets" while the implementation > clearly employs septet length. > > Fixing the implementation to match the API doc would break binary > compatibility. I should probably fix the API doc to match that weird > implementation, but it nags and hurts a little. > > Any opinions? please fix the API comment. IIRC there are several fields in encoded messages where the length is passed as septets. E.g. for SMS the last 7 bits of an octet might not belong to the text anymore. Passing the number of septets avoids this issue. holger From nhofmeyr at sysmocom.de Mon Feb 29 09:21:13 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 29 Feb 2016 10:21:13 +0100 Subject: Redmine theme In-Reply-To: References: Message-ID: <20160229092113.GA2199@dub6> On Mon, Feb 29, 2016 at 10:17:43AM +0600, ????? ??????? wrote: > I suggest to change a stock Redmine theme to something more beautiful, > for example gitmike: https://github.com/makotokw/redmine-theme-gitmike +0.5 for using a different theme. gitmike does look slick but IMHO tends to have not enough contrast. And whether we want to look like github of all things is a bikeshed, too ;) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Feb 29 11:53:37 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 29 Feb 2016 12:53:37 +0100 Subject: milestone: 3G CS Location Update Accept Message-ID: <20160229115337.GB1913@dub6> Hi list, I've just seen my first Location Update Accept from our UMTS UE+femtoCell using osmo-cscn as IuCS network core :D The Identity Request (IMSI) that the UE used to not answer is now being answered, and I am getting a successful Location Update Accept from osmo-cscn after that. The reason why it didn't work last time isn't entirely clear. All I changed since is the *test* program that simulates the UE+hNodeB, and I merely verified that osmo-cscn works (as far as LU is concerned). A hint is, Daniel told me that the IuPS setup had one day stopped to reply with a message that used to work before, and has since again started working. So it might've been a timing issue in the reply towards UE. Next steps: Next I will briefly try to run Daniel's 3G SGSN together with CSCN to see whether the premature Iu Release (?) he sees still happens when CS is connected successfully. There is also still a segfault in osmo-hnbgw, triggered by reconnecting a second time with our hnb-test that simulates an hNodeB. That's next on the hacking todo list. According to the specs, proper Authentication is mandatory for UMTS, which osmo-cscn should initiate. That's not happening yet. It seems our testing UE is fine with that, so I'll see when I'll get to that. ~Neels -- - Neels Hofmeyr http://www.sysmocom.de/ ======================================================================= * sysmocom - systems for mobile communications GmbH * Alt-Moabit 93 * 10559 Berlin, Germany * Sitz / Registered office: Berlin, HRB 134158 B * Gesch?ftsf?hrer / Managing Directors: Holger Freyther, Harald Welte -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From nhofmeyr at sysmocom.de Mon Feb 29 17:23:07 2016 From: nhofmeyr at sysmocom.de (Neels Hofmeyr) Date: Mon, 29 Feb 2016 18:23:07 +0100 Subject: milestone: 3G CS Location Update Accept In-Reply-To: <20160229115337.GB1913@dub6> References: <20160229115337.GB1913@dub6> Message-ID: <20160229172307.GC1913@dub6> It's not really like we properly reached the LU milestone yet. I observe two MM failure modes, one fails after the first reply the MSC sends to the UE, the other fails one or two messages after that (depending on how I count them). Let's call them MM.1 and MM.2 When I power cycle the hNodeB, I randomly get one of these two failures. I tend to have to power cycle it, because it seems that SCTP stops working (see below). MM.1) UE hNodeB osmo-hnbgw osmo-cscn | | | --- LU REQ ---------------> | | <--------- ID REQ (IMSI) -- | | [seconds pass] | | <------- LU REJ (timeout)-- | missing/expecting: | --- ID RESP --------------> | This what I called "probably a timing issue of the reply towards the UE". MM.2) UE hNodeB osmo-hnbgw osmo-cscn | | | --- LU REQ ---------------> | | <--------- ID REQ (IMSI) -- | | --- ID RESP --------------> | | <------------- LU ACCEPT -- | | <--------------- MM INFO -- | | [seconds pass] | | <------- LU REJ (timeout)-- | missing/expecting: | --- TMSI REALLOC COMPL----> | SCTP) When one of above failures has occured, I no longer get the HEARTBEAT/HEARTBEAT_ACK messages that go through SCTP roughly every 6 seconds. Instead, wireshark shows a bunch of errors and retransmissions "Destination unreachable (Protocol unreachable)" or even "ABORT [Malformed package]" or "ABORT" / "Protocol violation" with Cause Intormation "Association exceeded its max retans count" [sic: "retans"] It seems SCTP itself has stopped working in that case. GW-sctp_recvmsg) In addition to that, I get an omso-hnbgw failure mode if after testing the above cases (doesn't matter which one) I let a few minutes pass. After a little while, I get <0000> hnbgw.c:171 Error during sctp_recvmsg() (-1 returned by sctp_recvmsg() impossible to further qualify short of heading into kernel debugging) During local testing of the same situation with hnb-test via loopback (127.0.0.1 as well as the same machine's "public" IP), this SCTP error doesn't occur, and consequently osmo-hnbgw doesn't segfault. When I run hnb-test from a different box and connect it to the osmo-hnbgw running on my machine, it also works without problems. Only when the hNodeB does the same, the sctp_recvmsg() error occurs. GW.segf) Shortly after the SCTP error, osmo-hnbgw segfaults. This is probably due to wrong/missing osmo-fd/timer cleanup after the sctp_recvmsg() error code. MSC) And I also get crashes of the MSC in form of the CSCN in conjunction with a LU reject due to timeout and invalidation of a subscriber conn. One time I got a cpu eater where two rb tree nodes pointed at each other via rb_left, and rb_erase kept looping through those two. Mostly I get a plain segfault. This is not as reproducable as the others though. Solutions? - connect the hNodeB with a proper timing source? So far no GPS is connected. - SCTP debugging? - Rather concentrate on further development using hNodeB mocking test programs? (Obviously catch the segfaults in the osmo code, but they are not the real problem. Once they are solved, the basic messaging problems will still exist.) ~Neels -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: From holger at freyther.de Mon Feb 29 17:44:43 2016 From: holger at freyther.de (Holger Freyther) Date: Mon, 29 Feb 2016 18:44:43 +0100 Subject: Fwd: New Defects reported by Coverity Scan for Osmocom References: <56d4763a256cf_179cabd330944cb@ss1435.mail> Message-ID: Hi guys, FYI after adding the do{} while and the log_check_level call coverity has found some dead code. The found_partial is a funny case of dead code. :) holger > Begin forwarded message: > > From: scan-admin at coverity.com > Subject: New Defects reported by Coverity Scan for Osmocom > Date: 29 February 2016 at 17:47:54 GMT+1 > To: holger at freyther.de > > > Hi, > > Please find the latest report on new defect(s) introduced to Osmocom found with Coverity Scan. > > 3 new defect(s) introduced to Osmocom found with Coverity Scan. > 1 defect(s), reported by Coverity Scan earlier, were marked fixed in the recent build analyzed by Coverity Scan. > > New defect(s) Reported-by: Coverity Scan > Showing 3 of 3 defect(s) > > > ** CID 70677: Control flow issues (DEADCODE) > /source-iuh/osmo-pcu/src/gprs_rlcmac_ts_alloc.cpp: 907 in alloc_algorithm_b() > > > ________________________________________________________________________________________________________ > *** CID 70677: Control flow issues (DEADCODE) > /source-iuh/osmo-pcu/src/gprs_rlcmac_ts_alloc.cpp: 907 in alloc_algorithm_b() > 901 dl_slots, 'D'), > 902 single ? ", single" : ""); > 903 > 904 /* assign downlink */ > 905 if (dl_slots == 0) { > 906 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots " >>>> CID 70677: Control flow issues (DEADCODE) >>>> Execution cannot reach this statement "do { > if (log_check_level...". > 907 "available\n"); > 908 return -EINVAL; > 909 } > 910 slotcount = pcu_bitcount(dl_slots); > 911 first_ts = ffs(dl_slots) - 1; > 912 avail_count = pcu_bitcount(reserved_dl_slots); > > ** CID 70676: Control flow issues (DEADCODE) > /source-iuh/libosmo-netif/src/rtp.c: 124 in osmo_rtp_get_payload() > > > ________________________________________________________________________________________________________ > *** CID 70676: Control flow issues (DEADCODE) > /source-iuh/libosmo-netif/src/rtp.c: 124 in osmo_rtp_get_payload() > 118 return NULL; > 119 } > 120 } > 121 if (rtph->padding) { > 122 if (payload_len < 0) { > 123 DEBUGPC(DLMUX, "received RTP frame too short for " >>>> CID 70676: Control flow issues (DEADCODE) >>>> Execution cannot reach this statement "do { > if (log_check_level...". > 124 "padding length\n"); > 125 return NULL; > 126 } > 127 payload_len -= payload[payload_len - 1]; > 128 if (payload_len < 0) { > 129 DEBUGPC(DLMUX, "received RTP frame with padding " > > ** CID 70675: Control flow issues (DEADCODE) > /source-iuh/libosmo-netif/src/channel.c: 57 in osmo_chan_create() > > > ________________________________________________________________________________________________________ > *** CID 70675: Control flow issues (DEADCODE) > /source-iuh/libosmo-netif/src/channel.c: 57 in osmo_chan_create() > 51 LOGP(DLINP, LOGL_ERROR, "unsupported channel type `%s'\n", > 52 cur->name); > 53 return NULL; > 54 } > 55 if (found_partial) { > 56 LOGP(DLINP, LOGL_ERROR, "Sorry, channel type `%s' does not " >>>> CID 70675: Control flow issues (DEADCODE) >>>> Execution cannot reach this statement "do { > if (log_check_level...". > 57 "support subtype `%u'\n", cur->name, subtype_id); > 58 return NULL; > 59 } > 60 > 61 c = talloc_zero_size(osmo_chan_ctx, > 62 sizeof(struct osmo_chan) + cur->datasiz); > > > ________________________________________________________________________________________________________ > To view the defects in Coverity Scan visit, https://scan.coverity.com/projects/osmocom?tab=overview > > To manage Coverity Scan email notifications for "holger at freyther.de", click https://scan.coverity.com/subscriptions/edit?email=holger%40freyther.de&token=90b620c1f1eaf964c8f6d3882b84a613 > From robert.steve07 at gmail.com Mon Feb 29 14:26:22 2016 From: robert.steve07 at gmail.com (robert) Date: Mon, 29 Feb 2016 16:26:22 +0200 Subject: command for location update Message-ID: <6FEFE9A1-D0AE-4866-9960-1313954849A0@gmail.com> Hi, Is it possible to have the virtual BTS start a location update at a specific time. In other words, can I add a command that asks all phones to request a location update at any desired time ? Best regards, Robert,