aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debian/copyright81
-rw-r--r--debian/patches/01_location_of_gsm_data_shared.patch18
-rw-r--r--debian/patches/series2
-rw-r--r--debian/source/format2
-rw-r--r--include/osmo-bts/control_if.h3
-rw-r--r--include/osmo-bts/dtx_dl_amr_fsm.h2
-rw-r--r--include/osmo-bts/msg_utils.h1
-rw-r--r--include/osmo-bts/oml.h6
-rw-r--r--include/osmo-bts/scheduler.h4
-rw-r--r--src/common/bts.c11
-rw-r--r--src/common/bts_ctrl_lookup.c6
-rw-r--r--src/common/dtx_dl_amr_fsm.c55
-rw-r--r--src/common/l1sap.c80
-rw-r--r--src/common/main.c18
-rw-r--r--src/common/measurement.c2
-rw-r--r--src/common/msg_utils.c97
-rw-r--r--src/common/oml.c223
-rw-r--r--src/common/pcu_sock.c4
-rw-r--r--src/common/rsl.c41
-rw-r--r--src/common/scheduler.c53
-rw-r--r--src/osmo-bts-litecell15/l1_if.c7
-rw-r--r--src/osmo-bts-litecell15/tch.c3
-rw-r--r--src/osmo-bts-sysmo/l1_if.c7
-rw-r--r--src/osmo-bts-sysmo/tch.c3
24 files changed, 514 insertions, 215 deletions
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..302d1d9
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,81 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: osmo-bts
+Source: http://cgit.osmocom.org/osmo-bts/
+
+Files: *
+Copyright: 2008-2014 Harald Welte <laforge@gnumonks.org>
+ 2009,2011,2013 Andreas Eversberg <jolly@eversberg.eu>
+ 2010,2011 On-Waves
+ 2012-2015 Holger Hans Peter Freyther
+ 2014 sysmocom s.f.m.c. Gmbh
+ 2015 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
+License: AGPL-3+
+
+Files: src/osmo-bts-sysmo/eeprom.c
+ src/osmo-bts-sysmo/eeprom.h
+Copyright: 2012 Nutaq
+License: MIT
+Comment: Yves Godin is the author
+
+Files: src/common/pcu_sock.c
+Copyright: 2008-2010 Harald Welte <laforge@gnumonks.org>
+ 2009-2012 Andreas Eversberg <jolly@eversberg.eu>
+ 2012 Holger Hans Peter Freyther
+License: GPL-2+
+
+Files: debian/*
+Copyright: 2015-2016 Ruben Undheim <ruben.undheim@gmail.com>
+License: AGPL-3+
+
+
+License: AGPL-3+
+ 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 <http://www.gnu.org/licenses/>.
+
+
+License: GPL-2+
+ This package 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, see <http://www.gnu.org/licenses/>.
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
+
+
+License: MIT
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
diff --git a/debian/patches/01_location_of_gsm_data_shared.patch b/debian/patches/01_location_of_gsm_data_shared.patch
new file mode 100644
index 0000000..b0a1499
--- /dev/null
+++ b/debian/patches/01_location_of_gsm_data_shared.patch
@@ -0,0 +1,18 @@
+From: Ruben Undheim <ruben.undheim@gmail.com>
+Date: Sat, 28 May 2016 09:38:56 +0200
+Subject: In order to build osmo-bts,
+ some files shared with openbsc needs to be available. This replaces
+ the search path for these files so that they are picked from the openbsc-dev
+ package.
+
+---
+ src/common/gsm_data_shared.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/common/gsm_data_shared.c b/src/common/gsm_data_shared.c
+index 706892d..932d71f 100644
+--- a/src/common/gsm_data_shared.c
++++ b/src/common/gsm_data_shared.c
+@@ -1 +1 @@
+-#include "../../../openbsc/openbsc/src/libcommon/gsm_data_shared.c"
++#include "/usr/src/osmocom/openbsc/libcommon/gsm_data_shared.c"
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..e753172
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+01_location_of_gsm_data_shared.patch
+
diff --git a/debian/source/format b/debian/source/format
index 89ae9db..163aaf8 100644
--- a/debian/source/format
+++ b/debian/source/format
@@ -1 +1 @@
-3.0 (native)
+3.0 (quilt)
diff --git a/include/osmo-bts/control_if.h b/include/osmo-bts/control_if.h
index 750f6bd..490c87a 100644
--- a/include/osmo-bts/control_if.h
+++ b/include/osmo-bts/control_if.h
@@ -1,4 +1,5 @@
#pragma once
int bts_ctrl_cmds_install(struct gsm_bts *bts);
-struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts);
+struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
+ const char *bind_addr, uint16_t port);
diff --git a/include/osmo-bts/dtx_dl_amr_fsm.h b/include/osmo-bts/dtx_dl_amr_fsm.h
index 4fb2f25..f747f9f 100644
--- a/include/osmo-bts/dtx_dl_amr_fsm.h
+++ b/include/osmo-bts/dtx_dl_amr_fsm.h
@@ -14,6 +14,7 @@ enum dtx_dl_amr_fsm_states {
ST_SID_F2,
ST_F1_INH,
ST_U_INH,
+ ST_U_NOINH,
ST_F1_INH_REC,
ST_U_INH_REC,
ST_SID_U,
@@ -29,6 +30,7 @@ enum dtx_dl_amr_fsm_events {
E_ONSET,
E_FACCH,
E_COMPL,
+ E_FIRST,
E_INHIB,
E_SID_F,
E_SID_U,
diff --git a/include/osmo-bts/msg_utils.h b/include/osmo-bts/msg_utils.h
index 55e8475..7ddbe88 100644
--- a/include/osmo-bts/msg_utils.h
+++ b/include/osmo-bts/msg_utils.h
@@ -37,6 +37,7 @@ bool dtx_dl_amr_enabled(const struct gsm_lchan *lchan);
void dtx_dispatch(struct gsm_lchan *lchan, enum dtx_dl_amr_fsm_events e);
bool dtx_recursion(const struct gsm_lchan *lchan);
void dtx_int_signal(struct gsm_lchan *lchan);
+bool dtx_is_first_p1(const struct gsm_lchan *lchan);
void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload,
size_t length, uint32_t fn, int update);
int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h
index 9f49444..217ec64 100644
--- a/include/osmo-bts/oml.h
+++ b/include/osmo-bts/oml.h
@@ -1,6 +1,8 @@
#ifndef _OML_H
#define _OML_H
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
struct gsm_bts;
struct gsm_abis_mo;
struct msgb;
@@ -42,4 +44,8 @@ int oml_mo_fom_ack_nack(struct gsm_abis_mo *mo, uint8_t orig_msg_type,
int oml_set_lchan_t200(struct gsm_lchan *lchan);
extern const unsigned int oml_default_t200_ms[7];
+/* Transmit failure event report */
+int oml_tx_failure_event_rep(struct gsm_abis_mo *mo, uint16_t cause_value,
+ const char *fmt, ...);
+
#endif // _OML_H */
diff --git a/include/osmo-bts/scheduler.h b/include/osmo-bts/scheduler.h
index b0387db..33a99bb 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 <osmocom/core/utils.h>
+
#include <osmo-bts/gsm_data.h>
/* These types define the different channels on a multiframe.
@@ -48,6 +50,8 @@ enum trx_chan_type {
_TRX_CHAN_MAX
};
+extern const struct value_string trx_chan_type_names[];
+
#define GSM_BURST_LEN 148
#define GPRS_BURST_LEN GSM_BURST_LEN
#define EGPRS_BURST_LEN 444
diff --git a/src/common/bts.c b/src/common/bts.c
index 9c2f0e0..efefb86 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -45,6 +45,7 @@
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
#include <osmo-bts/signal.h>
+#include <osmo-bts/dtx_dl_amr_fsm.h>
#define MIN_QUAL_RACH 5.0f /* at least 5 dB C/I */
#define MIN_QUAL_NORM -0.5f /* at least -1 dB C/I */
@@ -255,6 +256,7 @@ int trx_link_estab(struct gsm_bts_trx *trx)
{
struct e1inp_sign_link *link = trx->rsl_link;
uint8_t radio_state = link ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
+ int rc;
LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n",
trx->nr, link ? "up" : "down");
@@ -262,10 +264,13 @@ int trx_link_estab(struct gsm_bts_trx *trx)
oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK);
if (link)
- rsl_tx_rf_res(trx);
+ rc = rsl_tx_rf_res(trx);
else
- bts_model_trx_deact_rf(trx);
-
+ rc = bts_model_trx_deact_rf(trx);
+ if (rc < 0)
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_RSL_FAIL, link ?
+ "Failed to establish RSL link (%d)\n" :
+ "Failed to deactivate RF (%d)\n", rc);
return 0;
}
diff --git a/src/common/bts_ctrl_lookup.c b/src/common/bts_ctrl_lookup.c
index 3ee9b4a..f0157e9 100644
--- a/src/common/bts_ctrl_lookup.c
+++ b/src/common/bts_ctrl_lookup.c
@@ -87,12 +87,14 @@ err_index:
return -ERANGE;
}
-struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts)
+struct ctrl_handle *bts_controlif_setup(struct gsm_bts *bts,
+ const char *bind_addr, uint16_t port)
{
struct ctrl_handle *hdl;
int rc = 0;
- hdl = ctrl_interface_setup(bts, OSMO_CTRL_PORT_BTS, bts_ctrl_node_lookup);
+ hdl = ctrl_interface_setup_dynip(bts, bind_addr, port,
+ bts_ctrl_node_lookup);
if (!hdl)
return NULL;
diff --git a/src/common/dtx_dl_amr_fsm.c b/src/common/dtx_dl_amr_fsm.c
index d903b0c..832e8b4 100644
--- a/src/common/dtx_dl_amr_fsm.c
+++ b/src/common/dtx_dl_amr_fsm.c
@@ -47,7 +47,7 @@ void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Was observed during testing, let's just ignore it for now */
break;
case E_SID_U:
- osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0);
+ osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
break;
case E_VOICE:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
@@ -55,7 +55,7 @@ void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_FACCH:
osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
break;
- case E_COMPL:
+ case E_FIRST:
osmo_fsm_inst_state_chg(fi, ST_SID_F2, 0, 0);
break;
case E_INHIB:
@@ -74,7 +74,7 @@ void dtx_fsm_sid_f1(struct osmo_fsm_inst *fi, uint32_t event, void *data)
void dtx_fsm_sid_f2(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
- case E_SID_U:
+ case E_COMPL:
osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0);
break;
case E_VOICE:
@@ -145,7 +145,7 @@ void dtx_fsm_u_inh_rec(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
-void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+void dtx_fsm_u_noinh(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
case E_FACCH:
@@ -154,8 +154,8 @@ void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
case E_VOICE:
osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
break;
- case E_INHIB:
- osmo_fsm_inst_state_chg(fi, ST_U_INH, 0, 0);
+ case E_COMPL:
+ osmo_fsm_inst_state_chg(fi, ST_SID_U, 0, 0);
break;
case E_SID_U:
case E_SID_F:
@@ -172,6 +172,29 @@ void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
}
}
+void dtx_fsm_sid_upd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ switch (event) {
+ case E_FACCH:
+ osmo_fsm_inst_state_chg(fi, ST_ONSET_F, 0, 0);
+ break;
+ case E_VOICE:
+ osmo_fsm_inst_state_chg(fi, ST_VOICE, 0, 0);
+ break;
+ case E_INHIB:
+ osmo_fsm_inst_state_chg(fi, ST_U_INH, 0, 0);
+ break;
+ case E_SID_U:
+ case E_SID_F:
+ osmo_fsm_inst_state_chg(fi, ST_U_NOINH, 0, 0);
+ break;
+ default:
+ LOGP(DL1P, LOGL_ERROR, "Unexpected event %d\n", event);
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
void dtx_fsm_onset_v(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
@@ -255,15 +278,15 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
/* SID-FIRST or SID-FIRST-P1 in case of AMR HR:
start of silence period (might be interrupted in case of AMR HR) */
[ST_SID_F1]= {
- .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_COMPL) | X(E_INHIB) | X(E_ONSET),
- .out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V),
+ .in_event_mask = X(E_SID_F) | X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_FIRST) | X(E_INHIB) | X(E_ONSET),
+ .out_state_mask = X(ST_U_NOINH) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_SID_F2) | X(ST_F1_INH) | X(ST_ONSET_V),
.name = "SID-FIRST (P1)",
.action = dtx_fsm_sid_f1,
},
/* SID-FIRST P2 (only for AMR HR):
actual start of silence period in case of AMR HR */
[ST_SID_F2]= {
- .in_event_mask = X(E_SID_U) | X(E_VOICE) | X(E_FACCH) | X(E_ONSET),
+ .in_event_mask = X(E_COMPL) | X(E_VOICE) | X(E_FACCH) | X(E_ONSET),
.out_state_mask = X(ST_SID_U) | X(ST_VOICE) | X(ST_ONSET_F) | X(ST_ONSET_V),
.name = "SID-FIRST (P2)",
.action = dtx_fsm_sid_f2,
@@ -282,6 +305,13 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
.name = "SID-UPDATE (Inh)",
.action = dtx_fsm_u_inh,
},
+ /* SID-UPDATE: Inhibited not allowed (only for AMR HR) */
+ [ST_U_NOINH]= {
+ .in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_COMPL) | X(E_SID_U) | X(E_SID_F) | X(E_ONSET),
+ .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_SID_U) | X(ST_ONSET_V),
+ .name = "SID-UPDATE (NoInh)",
+ .action = dtx_fsm_u_noinh,
+ },
/* SID-FIRST Inhibition recursion in progress:
Inhibit itself was already sent, now have to send the voice that caused it */
[ST_F1_INH_REC]= {
@@ -300,9 +330,9 @@ static struct osmo_fsm_state dtx_dl_amr_fsm_states[] = {
},
/* Silence period with periodic comfort noise data updates */
[ST_SID_U]= {
- .in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F) | X(E_ONSET),
- .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH) | X(ST_SID_U) | X(ST_ONSET_V),
- .name = "SID-UPDATE",
+ .in_event_mask = X(E_FACCH) | X(E_VOICE) | X(E_INHIB) | X(E_SID_U) | X(E_SID_F),
+ .out_state_mask = X(ST_ONSET_F) | X(ST_VOICE) | X(ST_U_INH) | X(ST_U_NOINH),
+ .name = "SID-UPDATE (AMR/HR)",
.action = dtx_fsm_sid_upd,
},
/* ONSET - end of silent period due to incoming SPEECH frame */
@@ -350,6 +380,7 @@ const struct value_string dtx_dl_amr_fsm_event_names[] = {
{ E_ONSET, "ONSET" },
{ E_FACCH, "FACCH" },
{ E_COMPL, "Complete" },
+ { E_FIRST, "FIRST P1->P2" },
{ E_INHIB, "Inhibit" },
{ E_SID_F, "SID-FIRST" },
{ E_SID_U, "SID-UPDATE" },
diff --git a/src/common/l1sap.c b/src/common/l1sap.c
index e9c94f0..9116e23 100644
--- a/src/common/l1sap.c
+++ b/src/common/l1sap.c
@@ -44,6 +44,7 @@
#include <osmo-bts/measurement.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
+#include <osmo-bts/oml.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/handover.h>
#include <osmo-bts/power_control.h>
@@ -351,18 +352,67 @@ static int to_gsmtap(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
return 0;
}
+/* Calculate the number of RACH slots that expire in a certain GSM frame
+ * See also 3GPP TS 05.02 Clause 7 Table 5 of 9 */
+static unsigned int calc_exprd_rach_frames(struct gsm_bts *bts, uint32_t fn)
+{
+ int rach_frames_expired = 0;
+ uint8_t ccch_conf;
+ struct gsm48_system_information_type_3 *si3;
+ unsigned int blockno;
+
+ si3 = GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+ ccch_conf = si3->control_channel_desc.ccch_conf;
+
+ if (ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
+ /* It is possible to combine a CCCH with an SDCCH4, in this
+ * case the CCCH will have to share the available frames with
+ * the other channel, this results in a limited number of
+ * available rach slots */
+ blockno = fn % 51;
+ if (blockno == 4 || blockno == 5
+ || (blockno >= 15 && blockno <= 36) || blockno == 45
+ || blockno == 46)
+ rach_frames_expired = 1;
+ } else {
+ /* It is possible to have multiple CCCH channels on
+ * different physical channels (large cells), this
+ * also multiplies the available/expired RACH channels.
+ * See also TS 04.08, Chapter 10.5.2.11, table 10.29 */
+ if (ccch_conf == RSL_BCCH_CCCH_CONF_2_NC)
+ rach_frames_expired = 2;
+ else if (ccch_conf == RSL_BCCH_CCCH_CONF_3_NC)
+ rach_frames_expired = 3;
+ else if (ccch_conf == RSL_BCCH_CCCH_CONF_4_NC)
+ rach_frames_expired = 4;
+ else
+ rach_frames_expired = 1;
+ }
+
+ /* Each Frame has room for 4 RACH slots, since RACH
+ * slots are short enough to fit into a single radio
+ * burst, so we need to multiply the final result by 4 */
+ return rach_frames_expired * 4;
+}
+
/* time information received from bts model */
static int l1sap_info_time_ind(struct gsm_bts *bts,
- struct osmo_phsap_prim *l1sap,
- struct info_time_ind_param *info_time_ind)
+ struct osmo_phsap_prim *l1sap,
+ struct info_time_ind_param *info_time_ind)
{
struct gsm_bts_trx *trx;
struct gsm_bts_role_bts *btsb = bts->role;
-
- int frames_expired = info_time_ind->fn - btsb->gsm_time.fn;
+ int frames_expired;
DEBUGP(DL1P, "MPH_INFO time ind %u\n", info_time_ind->fn);
+ /* Calculate and check frame difference */
+ frames_expired = info_time_ind->fn - btsb->gsm_time.fn;
+ if (frames_expired > 1) {
+ LOGP(DL1P, LOGL_ERROR,
+ "Invalid condition detected: Frame difference is > 1!\n");
+ }
+
/* Update our data structures with the current GSM time */
gsm_fn2gsmtime(&btsb->gsm_time, info_time_ind->fn);
@@ -372,24 +422,15 @@ static int l1sap_info_time_ind(struct gsm_bts *bts,
/* check if the measurement period of some lchan has ended
* and pre-compute the respective measurement */
llist_for_each_entry(trx, &bts->trx_list, list)
- trx_meas_check_compute(trx, info_time_ind->fn - 1);
+ trx_meas_check_compute(trx, info_time_ind->fn - 1);
/* increment number of RACH slots that have passed by since the
* last time indication */
- if (trx == bts->c0) {
- unsigned int num_rach_per_frame;
- /* 27 / 51 taken from TS 05.01 Figure 3 */
- if (bts->c0->ts[0].pchan == GSM_PCHAN_CCCH_SDCCH4)
- num_rach_per_frame = 27;
- else
- num_rach_per_frame = 51;
-
- btsb->load.rach.total += frames_expired * num_rach_per_frame;
- }
+ btsb->load.rach.total +=
+ calc_exprd_rach_frames(bts, info_time_ind->fn) * frames_expired;
return 0;
}
-
/* measurement information received from bts model */
static int l1sap_info_meas_ind(struct gsm_bts_trx *trx,
struct osmo_phsap_prim *l1sap,
@@ -1024,6 +1065,10 @@ int l1sap_up(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap)
default:
LOGP(DL1P, LOGL_NOTICE, "unknown prim %d op %d\n",
l1sap->oph.primitive, l1sap->oph.operation);
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_UKWN_MSG,
+ "unknown prim %d op %d\n",
+ l1sap->oph.primitive,
+ l1sap->oph.operation);
break;
}
@@ -1161,8 +1206,7 @@ int l1sap_chan_act(struct gsm_bts_trx *trx, uint8_t chan_nr, struct tlv_parsed *
return -RSL_ERR_EQUIPMENT_FAIL;
/* Init DTX DL FSM if necessary */
- //FIXME: only do it for AMR TCH/*
- if (trx->bts->dtxd)
+ if (trx->bts->dtxd && lchan->type != GSM_LCHAN_SDCCH)
lchan->tch.dtx.dl_amr_fsm = osmo_fsm_inst_alloc(&dtx_dl_amr_fsm,
tall_bts_ctx,
lchan,
diff --git a/src/common/main.c b/src/common/main.c
index 1b2549e..00c8b23 100644
--- a/src/common/main.c
+++ b/src/common/main.c
@@ -50,6 +50,11 @@
#include <osmo-bts/bts_model.h>
#include <osmo-bts/pcu_if.h>
#include <osmo-bts/control_if.h>
+#include <osmocom/ctrl/control_if.h>
+#include <osmocom/ctrl/ports.h>
+#include <osmocom/ctrl/control_vty.h>
+#include <openbsc/ctrl.h>
+#include <osmo-bts/oml.h>
int quit = 0;
static const char *config_file = "osmo-bts.cfg";
@@ -181,13 +186,21 @@ static void signal_handler(int signal)
switch (signal) {
case SIGINT:
//osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
- if (!quit)
+ if (!quit) {
+ oml_tx_failure_event_rep(&bts->mo,
+ OSMO_EVT_CRIT_PROC_STOP,
+ "BTS: SIGINT received -> "
+ "shutdown\n");
bts_shutdown(bts, "SIGINT");
+ }
quit++;
break;
case SIGABRT:
case SIGUSR1:
case SIGUSR2:
+ oml_tx_failure_event_rep(&bts->mo, OSMO_EVT_CRIT_PROC_STOP,
+ "BTS: signal %s received\n",
+ strsignal(signal));
talloc_report_full(tall_bts_ctx, stderr);
break;
default:
@@ -228,6 +241,7 @@ int bts_main(int argc, char **argv)
bts_log_init(NULL);
vty_init(&bts_vty_info);
+ ctrl_vty_init(tall_bts_ctx);
handle_options(argc, argv);
@@ -299,7 +313,7 @@ int bts_main(int argc, char **argv)
write_pid_file("osmo-bts");
- bts_controlif_setup(bts);
+ bts_controlif_setup(bts, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_BTS);
rc = telnet_init_dynif(tall_bts_ctx, NULL, vty_get_bind_addr(),
g_vty_port_num);
diff --git a/src/common/measurement.c b/src/common/measurement.c
index be1d4f6..6a11888 100644
--- a/src/common/measurement.c
+++ b/src/common/measurement.c
@@ -144,7 +144,7 @@ static int lchan_meas_check_compute(struct gsm_lchan *lchan, uint32_t fn)
int i;
/* if measurement period is not complete, abort */
- if (!is_meas_complete(lchan->ts->pchan, lchan->ts->nr,
+ if (!is_meas_complete(ts_pchan(lchan->ts), lchan->ts->nr,
lchan->nr, fn))
return 0;
diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c
index 9de9b6d..062f5e3 100644
--- a/src/common/msg_utils.c
+++ b/src/common/msg_utils.c
@@ -93,6 +93,28 @@ static int check_manuf(struct msgb *msg, struct abis_om_hdr *omh, size_t msg_siz
return type;
}
+/* check that DTX is in the middle of silence */
+static inline bool dtx_is_update(const struct gsm_lchan *lchan)
+{
+ if (!dtx_dl_amr_enabled(lchan))
+ return false;
+ if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_NOINH)
+ return true;
+ return false;
+}
+
+/* check that DTX is in the beginning of silence for AMR HR */
+bool dtx_is_first_p1(const struct gsm_lchan *lchan)
+{
+ if (!dtx_dl_amr_enabled(lchan))
+ return false;
+ if ((lchan->type == GSM_LCHAN_TCH_H &&
+ lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1))
+ return true;
+ return false;
+}
+
/* update lchan SID status */
void lchan_set_marker(bool t, struct gsm_lchan *lchan)
{
@@ -123,9 +145,7 @@ void dtx_cache_payload(struct gsm_lchan *lchan, const uint8_t *l1_payload,
if (update == 0) {
lchan->tch.dtx.is_update = false; /* Mark SID FIRST explicitly */
/* for non-AMR case - always update FN for incoming SID FIRST */
- if (!amr ||
- (dtx_dl_amr_enabled(lchan) &&
- lchan->tch.dtx.dl_amr_fsm->state != ST_SID_U))
+ if (!amr || !dtx_is_update(lchan))
lchan->tch.dtx.fn = fn;
/* for AMR case - do not update FN if SID FIRST arrives in a
middle of silence: this should not be happening according to
@@ -157,12 +177,24 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
int rc;
if (dtx_dl_amr_enabled(lchan)) {
- if (lchan->type == GSM_LCHAN_TCH_H &&
- lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 && !rtp_pl) {
- *len = 3; /* SID-FIRST P1 -> P2 completion */
- memcpy(l1_payload, lchan->tch.dtx.cache, 2);
- dtx_dispatch(lchan, E_SID_U);
- return 0;
+ if (lchan->type == GSM_LCHAN_TCH_H && !rtp_pl) {
+ /* we're called by gen_empty_tch_msg() to handle states
+ specific to AMR HR DTX */
+ switch (lchan->tch.dtx.dl_amr_fsm->state) {
+ case ST_SID_F2:
+ *len = 3; /* SID-FIRST P1 -> P2 completion */
+ memcpy(l1_payload, lchan->tch.dtx.cache, 2);
+ rc = 0;
+ dtx_dispatch(lchan, E_COMPL);
+ break;
+ case ST_SID_U:
+ rc = -EBADMSG;
+ dtx_dispatch(lchan, E_SID_U);
+ break;
+ default:
+ rc = -EBADMSG;
+ }
+ return rc;
}
}
@@ -171,8 +203,8 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
rc = osmo_amr_rtp_dec(rtp_pl, rtp_pl_len, &cmr, &cmi, &ft, &bfi, &sti);
if (rc < 0) {
- LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu)\n",
- rtp_pl_len);
+ LOGP(DRTP, LOGL_ERROR, "failed to decode AMR RTP (length %zu, "
+ "%p)\n", rtp_pl_len, rtp_pl);
return rc;
}
@@ -197,19 +229,29 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
return 0;
if (osmo_amr_is_speech(ft)) {
- /* AMR HR - Inhibition */
- if (lchan->type == GSM_LCHAN_TCH_H && marker &&
- lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1)
+ /* AMR HR - SID-FIRST_P1 Inhibition */
+ if (marker && dtx_is_first_p1(lchan))
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
E_INHIB, (void *)lchan);
+
+ /* AMR HR - SID-UPDATE Inhibition */
+ if (marker && lchan->type == GSM_LCHAN_TCH_H &&
+ lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U)
+ return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
+ E_INHIB, (void *)lchan);
+
/* AMR FR & HR - generic */
if (marker && (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1 ||
lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2 ||
- lchan->tch.dtx.dl_amr_fsm->state == ST_SID_U ))
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_NOINH))
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
E_ONSET, (void *)lchan);
- return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm, E_VOICE,
- (void *)lchan);
+
+ if (lchan->tch.dtx.dl_amr_fsm->state != ST_VOICE)
+ return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
+ E_VOICE, (void *)lchan);
+
+ return 0;
}
if (ft == AMR_SID) {
@@ -220,8 +262,11 @@ int dtx_dl_amr_fsm_step(struct gsm_lchan *lchan, const uint8_t *rtp_pl,
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, false);
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
E_SID_F, (void *)lchan);
- } else
+ } else if (lchan->tch.dtx.dl_amr_fsm->state != ST_FACCH)
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, sti);
+ if (lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F2)
+ return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
+ E_COMPL, (void *)lchan);
return osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
sti ? E_SID_U : E_SID_F,
(void *)lchan);
@@ -357,6 +402,7 @@ bool dtx_recursion(const struct gsm_lchan *lchan)
return false;
if (lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH ||
+ lchan->tch.dtx.dl_amr_fsm->state == ST_U_INH_REC ||
lchan->tch.dtx.dl_amr_fsm->state == ST_F1_INH ||
lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_F ||
lchan->tch.dtx.dl_amr_fsm->state == ST_ONSET_V ||
@@ -389,9 +435,7 @@ void dtx_int_signal(struct gsm_lchan *lchan)
if (!dtx_dl_amr_enabled(lchan))
return;
- if ((lchan->type == GSM_LCHAN_TCH_H &&
- lchan->tch.dtx.dl_amr_fsm->state == ST_SID_F1) ||
- dtx_recursion(lchan))
+ if (dtx_is_first_p1(lchan) || dtx_recursion(lchan))
dtx_dispatch(lchan, E_COMPL);
}
@@ -425,12 +469,17 @@ uint8_t repeat_last_sid(struct gsm_lchan *lchan, uint8_t *dst, uint32_t fn)
osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
E_SID_U, (void *)lchan);
dtx_sti_unset(lchan);
- } else if (lchan->tch.dtx.dl_amr_fsm->state ==
- ST_SID_U) {
+ } else if (dtx_is_update(lchan)) {
/* enforce SID UPDATE for next repetition: it
might have been altered by FACCH handling */
dtx_sti_set(lchan);
- lchan->tch.dtx.is_update = true;
+ if (lchan->type == GSM_LCHAN_TCH_H &&
+ lchan->tch.dtx.dl_amr_fsm->state ==
+ ST_U_NOINH)
+ osmo_fsm_inst_dispatch(lchan->tch.dtx.dl_amr_fsm,
+ E_COMPL,
+ (void *)lchan);
+ lchan->tch.dtx.is_update = true;
}
}
memcpy(dst, lchan->tch.dtx.cache, lchan->tch.dtx.len);
diff --git a/src/common/oml.c b/src/common/oml.c
index c4f3d7e..1482410 100644
--- a/src/common/oml.c
+++ b/src/common/oml.c
@@ -42,111 +42,12 @@
#include <osmo-bts/bts.h>
#include <osmo-bts/signal.h>
-/* FIXME: move this to libosmocore */
-static struct tlv_definition abis_nm_att_tlvdef_ipa = {
- .def = {
- /* ip.access specifics */
- [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
- [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
- [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
- [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
- [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
- [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
- [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
- },
-};
-
static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg);
/*
* support
*/
-struct tlv_parsed *tlvp_copy(const struct tlv_parsed *tp_orig, void *ctx)
-{
- struct tlv_parsed *tp_out;
- unsigned int i;
-
- tp_out = talloc_zero(ctx, struct tlv_parsed);
- if (!tp_out)
- return NULL;
-
- /* if the original is NULL, return empty tlvp */
- if (!tp_orig)
- return tp_out;
-
- for (i = 0; i < ARRAY_SIZE(tp_orig->lv); i++) {
- unsigned int len = tp_orig->lv[i].len;
- tp_out->lv[i].len = len;
- if (len && tp_out->lv[i].val) {
- tp_out->lv[i].val = talloc_zero_size(tp_out, len);
- if (!tp_out->lv[i].val) {
- talloc_free(tp_out);
- return NULL;
- }
- memcpy((uint8_t *)tp_out->lv[i].val, tp_orig->lv[i].val, len);
- }
- }
-
- return tp_out;
-}
-
-/* merge all attributes of 'new' into 'out' */
-int tlvp_merge(struct tlv_parsed *out, const struct tlv_parsed *new)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(out->lv); i++) {
- unsigned int len = new->lv[i].len;
- if (len == 0 || new->lv[i].val == NULL)
- continue;
- if (out->lv[i].val) {
- talloc_free((uint8_t *) out->lv[i].val);
- out->lv[i].len = 0;
- }
- out->lv[i].val = talloc_zero_size(out, len);
- if (!out->lv[i].val)
- return -ENOMEM;
- memcpy((uint8_t *) out->lv[i].val, new->lv[i].val, len);
- }
- return 0;
-}
-
static int oml_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len)
{
return tlv_parse(tp, &abis_nm_att_tlvdef_ipa, buf, len, 0, 0);
@@ -369,28 +270,6 @@ int oml_mo_tx_sw_act_rep(struct gsm_abis_mo *mo)
return oml_mo_send_msg(mo, nmsg, NM_MT_SW_ACTIVATED_REP);
}
-/* TS 12.21 9.4.53 */
-enum abis_nm_t200_idx {
- T200_SDCCH = 0,
- T200_FACCH_F = 1,
- T200_FACCH_H = 2,
- T200_SACCH_TCH_SAPI0 = 3,
- T200_SACCH_SDCCH = 4,
- T200_SDCCH_SAPI3 = 5,
- T200_SACCH_TCH_SAPI3 = 6
-};
-
-/* TS 12.21 9.4.53 */
-static const uint8_t abis_nm_t200_mult[] = {
- [T200_SDCCH] = 5,
- [T200_FACCH_F] = 5,
- [T200_FACCH_H] = 5,
- [T200_SACCH_TCH_SAPI0] = 10,
- [T200_SACCH_SDCCH] = 10,
- [T200_SDCCH_SAPI3] = 5,
- [T200_SACCH_TCH_SAPI3] = 10
-};
-
/* the below defaults correpsond to the libocmocore default of 1s for
* DCCH and 2s for ACCH. The BSC should overried this via OML anyway. */
const unsigned int oml_default_t200_ms[7] = {
@@ -466,25 +345,34 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
DEBUGPC(DOML, "Rx SET BTS ATTR\n");
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
- if (rc < 0)
+ if (rc < 0) {
+ oml_tx_failure_event_rep(&bts->mo, OSMO_EVT_MAJ_UNSUP_ATTR,
+ "New value for Attribute not supported\n");
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+ }
/* Test for globally unsupported stuff here */
if (TLVP_PRESENT(&tp, NM_ATT_BCCH_ARFCN)) {
uint16_t arfcn = ntohs(tlvp_val16_unal(&tp, NM_ATT_BCCH_ARFCN));
if (arfcn > 1024) {
+ oml_tx_failure_event_rep(&bts->mo, OSMO_EVT_WARN_SW_WARN,
+ "Given ARFCN %d is not supported.\n",
+ arfcn);
LOGP(DOML, LOGL_NOTICE, "Given ARFCN %d is not supported.\n", arfcn);
return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL);
}
}
/* 9.4.52 Starting Time */
if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) {
+ oml_tx_failure_event_rep(&bts->mo, OSMO_EVT_MAJ_UNSUP_ATTR,
+ "NM_ATT_START_TIME Attribute not "
+ "supported\n");
return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
}
/* merge existing BTS attributes with new attributes */
- tp_merged = tlvp_copy(bts->mo.nm_attr, bts);
- tlvp_merge(tp_merged, &tp);
+ tp_merged = osmo_tlvp_copy(bts->mo.nm_attr, bts);
+ osmo_tlvp_merge(tp_merged, &tp);
/* Ask BTS driver to validate new merged attributes */
rc = bts_model_check_oml(bts, foh->msg_type, bts->mo.nm_attr, tp_merged, bts);
@@ -531,7 +419,7 @@ static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
if (TLVP_PRESENT(&tp, NM_ATT_T200)) {
payload = TLVP_VAL(&tp, NM_ATT_T200);
for (i = 0; i < ARRAY_SIZE(btsb->t200_ms); i++) {
- uint32_t t200_ms = payload[i] * abis_nm_t200_mult[i];
+ uint32_t t200_ms = payload[i] * abis_nm_t200_ms[i];
#if 0
btsb->t200_ms[i] = t200_ms;
DEBUGP(DOML, "T200[%u]: OML=%u, mult=%u => %u ms\n",
@@ -615,12 +503,16 @@ static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
DEBUGPC(DOML, "Rx SET RADIO CARRIER ATTR\n");
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
- if (rc < 0)
+ if (rc < 0) {
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_UNSUP_ATTR,
+ "New value for Set Radio Attribute not"
+ " supported\n");
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+ }
/* merge existing BTS attributes with new attributes */
- tp_merged = tlvp_copy(trx->mo.nm_attr, trx->bts);
- tlvp_merge(tp_merged, &tp);
+ tp_merged = osmo_tlvp_copy(trx->mo.nm_attr, trx->bts);
+ osmo_tlvp_merge(tp_merged, &tp);
/* Ask BTS driver to validate new merged attributes */
rc = bts_model_check_oml(trx->bts, foh->msg_type, trx->mo.nm_attr, tp_merged, trx);
@@ -777,8 +669,12 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
DEBUGPC(DOML, "Rx SET CHAN ATTR\n");
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
- if (rc < 0)
+ if (rc < 0) {
+ oml_tx_failure_event_rep(&ts->mo, OSMO_EVT_MAJ_UNSUP_ATTR,
+ "New value for Set Channel Attribute "
+ "not supported\n");
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+ }
/* 9.4.21 HSN... */
/* 9.4.27 MAIO */
@@ -794,8 +690,8 @@ static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
}
/* merge existing BTS attributes with new attributes */
- tp_merged = tlvp_copy(ts->mo.nm_attr, bts);
- tlvp_merge(tp_merged, &tp);
+ tp_merged = osmo_tlvp_copy(ts->mo.nm_attr, bts);
+ osmo_tlvp_merge(tp_merged, &tp);
/* Call into BTS driver to check attribute values */
rc = bts_model_check_oml(bts, foh->msg_type, ts->mo.nm_attr, tp_merged, ts);
@@ -912,11 +808,29 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg)
if (msgb_l2len(msg) < sizeof(*foh)) {
LOGP(DOML, LOGL_NOTICE, "Formatted O&M message too short\n");
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (trx) {
+ trx->mo.obj_inst.bts_nr = 0;
+ trx->mo.obj_inst.trx_nr = foh->obj_inst.trx_nr;
+ trx->mo.obj_inst.ts_nr = 0xff;
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_UKWN_MSG,
+ "Formatted O&M message too short\n");
+ }
return -EIO;
}
if (foh->obj_inst.bts_nr != 0 && foh->obj_inst.bts_nr != 0xff) {
LOGP(DOML, LOGL_INFO, "Formatted O&M with BTS %d out of range.\n", foh->obj_inst.bts_nr);
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (trx) {
+ trx->mo.obj_inst.bts_nr = 0;
+ trx->mo.obj_inst.trx_nr = foh->obj_inst.trx_nr;
+ trx->mo.obj_inst.ts_nr = 0xff;
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_UKWN_MSG,
+ "Formatted O&M with BTS %d out"
+ " of range (0:0xFF).\n",
+ foh->obj_inst.bts_nr);
+ }
return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN);
}
@@ -950,6 +864,20 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg)
default:
LOGP(DOML, LOGL_INFO, "unknown Formatted O&M msg_type 0x%02x\n",
foh->msg_type);
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (trx) {
+ trx->mo.obj_inst.bts_nr = 0;
+ trx->mo.obj_inst.trx_nr = foh->obj_inst.trx_nr;
+ trx->mo.obj_inst.ts_nr = 0xff;
+ oml_tx_failure_event_rep(&trx->mo, OSMO_EVT_MAJ_UKWN_MSG,
+ "unknown Formatted O&M "
+ "msg_type 0x%02x\n",
+ foh->msg_type);
+ } else
+ oml_tx_failure_event_rep(&bts->mo, OSMO_EVT_MAJ_UKWN_MSG,
+ "unknown Formatted O&M "
+ "msg_type 0x%02x\n",
+ foh->msg_type);
ret = oml_fom_ack_nack(msg, NM_NACK_MSGTYPE_INVAL);
}
@@ -960,11 +888,6 @@ static int down_fom(struct gsm_bts *bts, struct msgb *msg)
* manufacturer related messages
*/
-#ifndef TLVP_PRES_LEN /* old libosmocore */
-#define TLVP_PRES_LEN(tp, tag, min_len) \
- (TLVP_PRESENT(tp, tag) && TLVP_LEN(tp, tag) >= min_len)
-#endif
-
static int oml_ipa_mo_set_attr_nse(void *obj, struct tlv_parsed *tp)
{
struct gsm_bts *bts = container_of(obj, struct gsm_bts, gprs.nse);
@@ -1118,8 +1041,15 @@ static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg)
DEBUGPC(DOML, "Rx IPA SET ATTR\n");
rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
- if (rc < 0)
+ if (rc < 0) {
+ mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
+ if (!mo)
+ return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ oml_tx_failure_event_rep(mo, OSMO_EVT_MAJ_UNSUP_ATTR,
+ "New value for IPAC Set Attribute not "
+ "supported\n");
return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+ }
/* Resolve MO by obj_class/obj_inst */
mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
@@ -1261,6 +1191,25 @@ int down_oml(struct gsm_bts *bts, struct msgb *msg)
return ret;
}
+/* 3GPP TS 12.21 ยง 8.8.2 */
+int oml_tx_failure_event_rep(struct gsm_abis_mo *mo, uint16_t cause_value,
+ const char *fmt, ...)
+{
+ struct msgb *nmsg;
+ va_list ap;
+
+ va_start(ap, fmt);
+ nmsg = abis_nm_fail_evt_rep(NM_EVT_PROC_FAIL, NM_SEVER_CRITICAL,
+ NM_PCAUSE_T_MANUF, cause_value, fmt, ap);
+ LOGP(DOML, LOGL_INFO, fmt, ap);
+ va_end(ap);
+
+ if (!nmsg)
+ return -ENOMEM;
+
+ return oml_mo_send_msg(mo, nmsg, NM_MT_FAILURE_EVENT_REP);
+}
+
int oml_init(void)
{
DEBUGP(DOML, "Initializing OML attribute definitions\n");
diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c
index 62f18a7..afd880f 100644
--- a/src/common/pcu_sock.c
+++ b/src/common/pcu_sock.c
@@ -861,8 +861,8 @@ int pcu_sock_init(const char *path)
bfd->fd = osmo_sock_unix_init(SOCK_SEQPACKET, 0, path,
OSMO_SOCK_F_BIND);
if (bfd->fd < 0) {
- LOGP(DPCU, LOGL_ERROR, "Could not create unix socket: %s\n",
- strerror(errno));
+ LOGP(DPCU, LOGL_ERROR, "Could not create %s unix socket: %s\n",
+ path, strerror(errno));
talloc_free(state);
return -1;
}
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 9e9cbb6..a34c455 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -401,7 +401,11 @@ static int rsl_rx_paging_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
rc = paging_add_identity(btsb->paging_state, paging_group,
identity_lv, chan_needed);
if (rc < 0) {
- /* FIXME: notfiy the BSC somehow ?*/
+ /* FIXME: notfiy the BSC on other errors? */
+ if (rc == -ENOSPC)
+ oml_tx_failure_event_rep(&trx->mo,
+ OSMO_EVT_MIN_PAG_TAB_FULL,
+ "BTS paging table is full\n");
}
pcu_tx_pag_req(identity_lv, chan_needed);
@@ -1649,6 +1653,11 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
LOGP(DRSL, LOGL_ERROR,
"%s IPAC Failed to create RTP/RTCP sockets\n",
gsm_lchan_name(lchan));
+ oml_tx_failure_event_rep(&lchan->ts->trx->mo,
+ OSMO_EVT_CRIT_RTP_TOUT,
+ "%s IPAC Failed to create "
+ "RTP/RTCP sockets\n",
+ gsm_lchan_name(lchan));
return tx_ipac_XXcx_nack(lchan, RSL_ERR_RES_UNAVAIL,
inc_ip_port, dch->c.msg_type);
}
@@ -1688,6 +1697,11 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
LOGP(DRSL, LOGL_ERROR,
"%s IPAC Failed to bind RTP/RTCP sockets\n",
gsm_lchan_name(lchan));
+ oml_tx_failure_event_rep(&lchan->ts->trx->mo,
+ OSMO_EVT_CRIT_RTP_TOUT,
+ "%s IPAC Failed to bind "
+ "RTP/RTCP sockets\n",
+ gsm_lchan_name(lchan));
osmo_rtp_socket_free(lchan->abis_ip.rtp_socket);
lchan->abis_ip.rtp_socket = NULL;
msgb_queue_flush(&lchan->dl_tch_queue);
@@ -1994,6 +2008,8 @@ static void osmo_dyn_ts_disconnected(struct gsm_bts_trx_ts *ts)
void cb_ts_disconnected(struct gsm_bts_trx_ts *ts)
{
+ OSMO_ASSERT(ts);
+
switch (ts->pchan) {
case GSM_PCHAN_TCH_F_PDCH:
return ipacc_dyn_pdch_ts_disconnected(ts);
@@ -2079,6 +2095,8 @@ static void osmo_dyn_ts_connected(struct gsm_bts_trx_ts *ts)
void cb_ts_connected(struct gsm_bts_trx_ts *ts)
{
+ OSMO_ASSERT(ts);
+
switch (ts->pchan) {
case GSM_PCHAN_TCH_F_PDCH:
return ipacc_dyn_pdch_ts_connected(ts);
@@ -2091,7 +2109,10 @@ void cb_ts_connected(struct gsm_bts_trx_ts *ts)
void ipacc_dyn_pdch_complete(struct gsm_bts_trx_ts *ts, int rc)
{
- bool pdch_act = ts->flags & TS_F_PDCH_ACT_PENDING;
+ bool pdch_act;
+ OSMO_ASSERT(ts);
+
+ pdch_act = ts->flags & TS_F_PDCH_ACT_PENDING;
if ((ts->flags & TS_F_PDCH_PENDING_MASK) == TS_F_PDCH_PENDING_MASK)
LOGP(DRSL, LOGL_ERROR,
@@ -2242,7 +2263,12 @@ static int rsl_tx_meas_res(struct gsm_lchan *lchan, uint8_t *l3, int l3_len)
int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
{
struct gsm_lchan *lchan = ctx;
- struct abis_rsl_common_hdr *rh = msgb_l2(msg);
+ struct abis_rsl_common_hdr *rh;
+
+ /* NOTE: Parameter lapdm_entity *le is ignored */
+
+ OSMO_ASSERT(msg);
+ rh = msgb_l2(msg);
if (lchan->state != LCHAN_S_ACTIVE) {
LOGP(DRSL, LOGL_INFO, "%s(%s) is not active . Dropping message.\n",
@@ -2468,15 +2494,22 @@ static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg)
int lchan_deactivate(struct gsm_lchan *lchan)
{
+ OSMO_ASSERT(lchan);
+
lchan->ciph_state = 0;
return bts_model_lchan_deactivate(lchan);
}
int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg)
{
- struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
+ struct abis_rsl_common_hdr *rslh;
int ret = 0;
+ OSMO_ASSERT(trx);
+ OSMO_ASSERT(msg);
+
+ rslh = msgb_l2(msg);
+
if (msgb_l2len(msg) < sizeof(*rslh)) {
LOGP(DRSL, LOGL_NOTICE, "RSL message too short\n");
msgb_free(msg);
diff --git a/src/common/scheduler.c b/src/common/scheduler.c
index fd5c584..724fb5a 100644
--- a/src/common/scheduler.c
+++ b/src/common/scheduler.c
@@ -156,6 +156,48 @@ const struct trx_chan_desc trx_chan_desc[_TRX_CHAN_MAX] = {
{ 1, TRXC_PTCCH, 0x08, LID_DEDIC, "PTCCH", rts_data_fn, tx_data_fn, rx_data_fn, 0 },
};
+const struct value_string trx_chan_type_names[] = {
+ OSMO_VALUE_STRING(TRXC_IDLE),
+ OSMO_VALUE_STRING(TRXC_FCCH),
+ OSMO_VALUE_STRING(TRXC_SCH),
+ OSMO_VALUE_STRING(TRXC_BCCH),
+ OSMO_VALUE_STRING(TRXC_RACH),
+ OSMO_VALUE_STRING(TRXC_CCCH),
+ OSMO_VALUE_STRING(TRXC_TCHF),
+ OSMO_VALUE_STRING(TRXC_TCHH_0),
+ OSMO_VALUE_STRING(TRXC_TCHH_1),
+ OSMO_VALUE_STRING(TRXC_SDCCH4_0),
+ OSMO_VALUE_STRING(TRXC_SDCCH4_1),
+ OSMO_VALUE_STRING(TRXC_SDCCH4_2),
+ OSMO_VALUE_STRING(TRXC_SDCCH4_3),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_0),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_1),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_2),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_3),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_4),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_5),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_6),
+ OSMO_VALUE_STRING(TRXC_SDCCH8_7),
+ OSMO_VALUE_STRING(TRXC_SACCHTF),
+ OSMO_VALUE_STRING(TRXC_SACCHTH_0),
+ OSMO_VALUE_STRING(TRXC_SACCHTH_1),
+ OSMO_VALUE_STRING(TRXC_SACCH4_0),
+ OSMO_VALUE_STRING(TRXC_SACCH4_1),
+ OSMO_VALUE_STRING(TRXC_SACCH4_2),
+ OSMO_VALUE_STRING(TRXC_SACCH4_3),
+ OSMO_VALUE_STRING(TRXC_SACCH8_0),
+ OSMO_VALUE_STRING(TRXC_SACCH8_1),
+ OSMO_VALUE_STRING(TRXC_SACCH8_2),
+ OSMO_VALUE_STRING(TRXC_SACCH8_3),
+ OSMO_VALUE_STRING(TRXC_SACCH8_4),
+ OSMO_VALUE_STRING(TRXC_SACCH8_5),
+ OSMO_VALUE_STRING(TRXC_SACCH8_6),
+ OSMO_VALUE_STRING(TRXC_SACCH8_7),
+ OSMO_VALUE_STRING(TRXC_PDTCH),
+ OSMO_VALUE_STRING(TRXC_PTCCH),
+ OSMO_VALUE_STRING(_TRX_CHAN_MAX),
+ { 0, NULL }
+};
/*
* init / exit
@@ -264,10 +306,13 @@ free_msg:
}
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);
+ "is out of range, or channel %s with type %s is "
+ "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,
+ get_lchan_by_chan_nr(l1t->trx, chan_nr)->name,
+ get_value_string(trx_chan_type_names, chan), fn);
/* unlink and free message */
llist_del(&msg->list);
msgb_free(msg);
diff --git a/src/osmo-bts-litecell15/l1_if.c b/src/osmo-bts-litecell15/l1_if.c
index d959338..c70bd9e 100644
--- a/src/osmo-bts-litecell15/l1_if.c
+++ b/src/osmo-bts-litecell15/l1_if.c
@@ -416,6 +416,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
if (sapi == GsmL1_Sapi_FacchH) {
sapi = GsmL1_Sapi_TchH;
+ subCh = L1SAP_CHAN2SS_TCHH(chan_nr);
}
if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) {
/* FACCH interruption of DTX silence */
@@ -542,7 +543,10 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
/* send message to DSP's queue */
osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg);
- dtx_int_signal(lchan);
+ if (dtx_is_first_p1(lchan))
+ dtx_dispatch(lchan, E_FIRST);
+ else
+ dtx_int_signal(lchan);
if (dtx_recursion(lchan)) /* DTX: send voice after ONSET was sent */
return ph_tch_req(trx, l1sap->oph.msg, l1sap, true, false);
@@ -643,6 +647,7 @@ static int handle_mph_time_ind(struct lc15l1_hdl *fl1,
/* ignore every time indication, except for c0 */
if (trx != bts->c0) {
+ msgb_free(msg);
return 0;
}
diff --git a/src/osmo-bts-litecell15/tch.c b/src/osmo-bts-litecell15/tch.c
index de3c7e3..4b22b64 100644
--- a/src/osmo-bts-litecell15/tch.c
+++ b/src/osmo-bts-litecell15/tch.c
@@ -322,6 +322,7 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
return 1;
case ST_SID_U:
+ case ST_U_NOINH:
return -EAGAIN;
case ST_FACCH:
return -EBADMSG;
@@ -362,7 +363,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
uint8_t payload_type = data_ind->msgUnitParam.u8Buffer[0];
uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1;
- uint8_t payload_len, sid_first[7] = {0};
+ uint8_t payload_len, sid_first[9] = { 0 };
struct msgb *rmsg = NULL;
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];
diff --git a/src/osmo-bts-sysmo/l1_if.c b/src/osmo-bts-sysmo/l1_if.c
index 2a3caf9..82db8d7 100644
--- a/src/osmo-bts-sysmo/l1_if.c
+++ b/src/osmo-bts-sysmo/l1_if.c
@@ -411,6 +411,7 @@ static int ph_data_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
if (sapi == GsmL1_Sapi_FacchH) {
sapi = GsmL1_Sapi_TchH;
+ subCh = L1SAP_CHAN2SS_TCHH(chan_nr);
}
if (sapi == GsmL1_Sapi_TchH || sapi == GsmL1_Sapi_TchF) {
/* FACCH interruption of DTX silence */
@@ -537,7 +538,10 @@ static int ph_tch_req(struct gsm_bts_trx *trx, struct msgb *msg,
}
/* send message to DSP's queue */
osmo_wqueue_enqueue(&fl1->write_q[MQ_L1_WRITE], nmsg);
- dtx_int_signal(lchan);
+ if (dtx_is_first_p1(lchan))
+ dtx_dispatch(lchan, E_FIRST);
+ else
+ dtx_int_signal(lchan);
if (dtx_recursion(lchan)) /* DTX: send voice after ONSET was sent */
return ph_tch_req(trx, l1sap->oph.msg, l1sap, true, false);
@@ -638,6 +642,7 @@ static int handle_mph_time_ind(struct femtol1_hdl *fl1,
/* ignore every time indication, except for c0 */
if (trx != bts->c0) {
+ msgb_free(msg);
return 0;
}
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c
index 16c2cf3..8eb419b 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -420,6 +420,7 @@ int l1if_tch_encode(struct gsm_lchan *lchan, uint8_t *data, uint8_t *len,
dtx_cache_payload(lchan, rtp_pl, rtp_pl_len, fn, 0);
return 1;
case ST_SID_U:
+ case ST_U_NOINH:
return -EAGAIN;
case ST_FACCH:
return -EBADMSG;
@@ -460,7 +461,7 @@ int l1if_tch_rx(struct gsm_bts_trx *trx, uint8_t chan_nr, struct msgb *l1p_msg)
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
uint8_t payload_type = data_ind->msgUnitParam.u8Buffer[0];
uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1;
- uint8_t payload_len, sid_first[7] = {0};
+ uint8_t payload_len, sid_first[9] = { 0 };
struct msgb *rmsg = NULL;
struct gsm_lchan *lchan = &trx->ts[L1SAP_CHAN2TS(chan_nr)].lchan[l1sap_chan2ss(chan_nr)];