Speech codings which are not supported by BTS will be removed from the bearer capability information element after parsing. This way it is not required for the MNCC application to consider support of each BTS.
Only GSM full rate is supported by default. --- openbsc/include/openbsc/gsm_data_shared.h | 10 ++ openbsc/src/libbsc/bsc_vty.c | 179 +++++++++++++++++++++++++++++ openbsc/src/libmsc/gsm_04_08.c | 28 +++++ 3 files changed, 217 insertions(+), 0 deletions(-)
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 84d15ef..dd20b2f 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -143,6 +143,13 @@ struct bts_ul_meas { uint8_t inv_rssi; };
+struct bts_codec_conf { + uint8_t hr; + uint8_t efr; + uint8_t afs; + uint8_t ahs; +}; + struct amr_mode { uint8_t mode; uint8_t threshold; @@ -704,6 +711,9 @@ struct gsm_bts {
/* exclude the BTS from the global RF Lock handling */ int excl_from_rf_lock; + + /* supported codecs beside FR */ + struct bts_codec_conf codec; #endif /* ROLE_BSC */ void *role; }; diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index b034981..d03cafc 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -629,6 +629,17 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) } }
+ vty_out(vty, " codec-support fr"); + if (bts->codec.hr) + vty_out(vty, " hr"); + if (bts->codec.efr) + vty_out(vty, " efr"); + if (bts->codec.afs) + vty_out(vty, " afs"); + if (bts->codec.ahs) + vty_out(vty, " ahs"); + vty_out(vty, "%s", VTY_NEWLINE); + config_write_bts_gprs(vty, bts);
if (bts->excl_from_rf_lock) @@ -2635,6 +2646,169 @@ DEFUN(cfg_bts_no_excl_rf_lock, return CMD_SUCCESS; }
+DEFUN(cfg_bts_codec1, cfg_bts_codec1_cmd, + "codec-support (fr|hr|efr|afs|ahs)", + "Codec Support settings\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n") +{ + struct gsm_bts *bts = vty->index; + struct bts_codec_conf *codec = &bts->codec; + int i; + + codec->hr = 0; + codec->efr = 0; + codec->afs = 0; + codec->ahs = 0; + for (i = 0; i < 1; i++) { + if (!strcmp(argv[i], "hr")) + codec->hr = 1; + if (!strcmp(argv[i], "efr")) + codec->efr = 1; + if (!strcmp(argv[i], "afs")) + codec->afs = 1; + if (!strcmp(argv[i], "ahs")) + codec->ahs = 1; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_codec2, cfg_bts_codec2_cmd, + "codec-support (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)", + "Codec Support settings\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n") +{ + struct gsm_bts *bts = vty->index; + struct bts_codec_conf *codec = &bts->codec; + int i; + + codec->hr = 0; + codec->efr = 0; + codec->afs = 0; + codec->ahs = 0; + for (i = 0; i < 2; i++) { + if (!strcmp(argv[i], "hr")) + codec->hr = 1; + if (!strcmp(argv[i], "efr")) + codec->efr = 1; + if (!strcmp(argv[i], "afs")) + codec->afs = 1; + if (!strcmp(argv[i], "ahs")) + codec->ahs = 1; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_codec3, cfg_bts_codec3_cmd, + "codec-support (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)" + " (fr|hr|efr|afs|ahs)", + "Codec Support settings\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n") +{ + struct gsm_bts *bts = vty->index; + struct bts_codec_conf *codec = &bts->codec; + int i; + + codec->hr = 0; + codec->efr = 0; + codec->afs = 0; + codec->ahs = 0; + for (i = 0; i < 3; i++) { + if (!strcmp(argv[i], "hr")) + codec->hr = 1; + if (!strcmp(argv[i], "efr")) + codec->efr = 1; + if (!strcmp(argv[i], "afs")) + codec->afs = 1; + if (!strcmp(argv[i], "ahs")) + codec->ahs = 1; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_codec4, cfg_bts_codec4_cmd, + "codec-support (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)" + " (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)", + "Codec Support settings\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n") +{ + struct gsm_bts *bts = vty->index; + struct bts_codec_conf *codec = &bts->codec; + int i; + + codec->hr = 0; + codec->efr = 0; + codec->afs = 0; + codec->ahs = 0; + for (i = 0; i < 4; i++) { + if (!strcmp(argv[i], "hr")) + codec->hr = 1; + if (!strcmp(argv[i], "efr")) + codec->efr = 1; + if (!strcmp(argv[i], "afs")) + codec->afs = 1; + if (!strcmp(argv[i], "ahs")) + codec->ahs = 1; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_codec5, cfg_bts_codec5_cmd, + "codec-support (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)" + " (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs) (fr|hr|efr|afs|ahs)", + "Codec Support settings\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n" + "Full Rate (mandatory)\nHalf Rate\nEnhanced Full Rate\n" + "Adaptive Multirate on TCH/F\nAdaptive Multirate on TCH/H\n") +{ + struct gsm_bts *bts = vty->index; + struct bts_codec_conf *codec = &bts->codec; + int i; + + codec->hr = 0; + codec->efr = 0; + codec->afs = 0; + codec->ahs = 0; + for (i = 0; i < 5; i++) { + if (!strcmp(argv[i], "hr")) + codec->hr = 1; + if (!strcmp(argv[i], "efr")) + codec->efr = 1; + if (!strcmp(argv[i], "afs")) + codec->afs = 1; + if (!strcmp(argv[i], "ahs")) + codec->ahs = 1; + } + + return CMD_SUCCESS; +} + #define TRX_TEXT "Radio Transceiver\n"
/* per TRX configuration */ @@ -3231,6 +3405,11 @@ int bsc_vty_init(const struct log_info *cat) install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd); install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd); install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd); + install_element(BTS_NODE, &cfg_bts_codec1_cmd); + install_element(BTS_NODE, &cfg_bts_codec2_cmd); + install_element(BTS_NODE, &cfg_bts_codec3_cmd); + install_element(BTS_NODE, &cfg_bts_codec4_cmd); + install_element(BTS_NODE, &cfg_bts_codec5_cmd);
install_element(BTS_NODE, &cfg_trx_cmd); install_node(&trx_node, dummy_config_write); diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 3cfc455..775fe66 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -79,6 +79,29 @@ struct gsm_lai { uint16_t lac; };
+static int apply_codec_restrictions(struct gsm_bts *bts, + struct gsm_mncc_bearer_cap *bcap) +{ + int i, j; + + /* remove unsupported speech versions from list */ + for (i = 0, j = 0; bcap->speech_ver[i] >= 0; i++) { + if (bcap->speech_ver[i] == 0) + bcap->speech_ver[j++] = 0; + if (bcap->speech_ver[i] == 2 && bts->codec.efr) + bcap->speech_ver[j++] = 2; + if (bcap->speech_ver[i] == 4 && bts->codec.afs) + bcap->speech_ver[j++] = 4; + if (bcap->speech_ver[i] == 1 && bts->codec.hr) + bcap->speech_ver[j++] = 1; + if (bcap->speech_ver[i] == 5 && bts->codec.ahs) + bcap->speech_ver[j++] = 5; + } + bcap->speech_ver[j] = -1; + + return 0; +} + static uint32_t new_callref = 0x80000001;
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg) @@ -1763,6 +1786,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) setup.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&setup.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); + apply_codec_restrictions(trans->conn->bts, &setup.bearer_cap); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { @@ -1916,6 +1940,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) call_conf.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&call_conf.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); + apply_codec_restrictions(trans->conn->bts, &call_conf.bearer_cap); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { @@ -2604,6 +2629,7 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg) modify.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); + apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); }
new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY); @@ -2646,6 +2672,7 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg modify.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); + apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); }
new_cc_state(trans, GSM_CSTATE_ACTIVE); @@ -2686,6 +2713,7 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg) modify.fields |= GSM48_IE_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); + apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
From: Andreas Eversberg andreas@eversberg.eu
When writing config file, OML configuration must be written for all E1 based BTS, which includes Nokia *Site BTS. --- openbsc/src/libbsc/bsc_vty.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index d03cafc..af0ecf9 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -601,7 +601,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) break; case GSM_BTS_TYPE_NOKIA_SITE: vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE); - break; + /* fall through: Nokia requires "oml e1" parameters also */ default: config_write_e1_link(vty, &bts->oml_e1_link, " oml "); vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
On Thu, Dec 05, 2013 at 04:02:37PM +0100, Andreas Eversberg wrote:
case GSM_BTS_TYPE_NOKIA_SITE: vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE);
break;
/* fall through: Nokia requires "oml e1" parameters also */
do you or any other Nokia BTS owner care enough to make a VTY regression test for this issue?
From: Andreas Eversberg andreas@eversberg.eu
TS 04.06 Chapter 5.4.4.4 "Local end release procedure" states that a confirm must be sent by layer 2 when receiving a local end release request. Nokia BTS might not send it, so this patch assumes that it has been received already.
In order to correctly switch a channel (handover or assignment), local end release is required. --- openbsc/include/openbsc/gsm_data.h | 12 ++++++++++++ openbsc/src/libbsc/abis_rsl.c | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletions(-)
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 8741505..7c3ca84 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -370,6 +370,18 @@ static inline int is_siemens_bts(struct gsm_bts *bts) return 0; }
+static inline int is_nokia_bts(struct gsm_bts *bts) +{ + switch (bts->type) { + case GSM_BTS_TYPE_NOKIA_SITE: + return 1; + default: + break; + } + + return 0; +} + enum gsm_auth_policy gsm_auth_policy_parse(const char *arg); const char *gsm_auth_policy_name(enum gsm_auth_policy policy);
diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 41bfcdc..b107854 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -867,6 +867,8 @@ int rsl_establish_request(struct gsm_lchan *lchan, uint8_t link_id) return abis_rsl_sendmsg(msg); }
+static void rsl_handle_release(struct gsm_lchan *lchan); + /* Chapter 8.3.7 Request the release of multiframe mode of RLL connection. This is what higher layers should call. The BTS then responds with RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE, @@ -890,7 +892,18 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, DEBUGP(DRLL, "%s RSL RLL RELEASE REQ (link_id=0x%02x, reason=%u)\n", gsm_lchan_name(lchan), link_id, release_mode);
- return abis_rsl_sendmsg(msg); + abis_rsl_sendmsg(msg); + + /* Do not wait for Nokia BTS to send the confirm. */ + if (is_nokia_bts(lchan->ts->trx->bts) + && release_mode == RSL_REL_LOCAL_END) { + DEBUGP(DRLL, "Do not wait for RELease CONFirm, because Nokia" + " BTS does not send it.\n"); + lchan->sapis[link_id & 0x7] = LCHAN_SAPI_UNUSED; + rsl_handle_release(lchan); + } + + return 0; }
int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
On Thu, Dec 05, 2013 at 04:02:38PM +0100, Andreas Eversberg wrote:
TS 04.06 Chapter 5.4.4.4 "Local end release procedure" states that a confirm must be sent by layer 2 when receiving a local end release request. Nokia BTS might not send it, so this patch assumes that it has been received already.
"migh". Did you or any other owner of Nokia equipment check if a local end release was sent? Please document the product and firmware version you were using (just in case newer equipment will behave differently and we need to change the patch to be more selective)
On Thu, Dec 05, 2013 at 04:02:38PM +0100, Andreas Eversberg wrote:
@@ -890,7 +892,18 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id, DEBUGP(DRLL, "%s RSL RLL RELEASE REQ (link_id=0x%02x, reason=%u)\n", gsm_lchan_name(lchan), link_id, release_mode);
- return abis_rsl_sendmsg(msg);
- abis_rsl_sendmsg(msg);
- /* Do not wait for Nokia BTS to send the confirm. */
- if (is_nokia_bts(lchan->ts->trx->bts)
&& release_mode == RSL_REL_LOCAL_END) {DEBUGP(DRLL, "Do not wait for RELease CONFirm, because Nokia"" BTS does not send it.\n");lchan->sapis[link_id & 0x7] = LCHAN_SAPI_UNUSED;rsl_handle_release(lchan);
In addition to what I wrote yesterday. This is also violating the principle of the least surprise and in fact breaks the error handling release.
Before: The "effect" rsl_release_request could be observed after the event loop has been reached (only then we will parse the result from the BTS).
Your patch: * RLL indication for the release is missing for the NokiaBTS (that is an issue and should be resolved by moving the sapi handling code out of the RSL_MT_REL_IND case into a method) * You directly call rsl_handle_release and can get ahead of itself. This is a problem for:
if (deact_sacch == SACCH_DEACTIVATE) rsl_deact_sacch(lchan); rsl_release_sapis_from(lchan, 0, RSL_REL_LOCAL_END);
/* TODO: start T3109 now. */ rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
So with your change rsl_handle_release will be called when lchan->state is not set to LCHAN_S_REL_ERR yet.
holger
You directly call rsl_handle_release and can get ahead of itself. This is a problem for:
if (deact_sacch == SACCH_DEACTIVATE) rsl_deact_sacch(lchan); rsl_release_sapis_from(lchan, 0, RSL_REL_LOCAL_END);
/* TODO: start T3109 now. */ rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);So with your change rsl_handle_release will be called when lchan->state is not set to LCHAN_S_REL_ERR yet.
you are right. i have no solution for this problem yet. at osmocombb/mobile i use queues to solve these kind of problems. whenever i want to handle something after osmo_select_main() was processed, i write into a specific queue. the main loop will call all dequeue functions in a loop, until all queues are empty and then continue with next osmo_select_main() call. one solution for handling the missing RELease CONFirm from BTS could be a timer with 0 duration. the timer will be handled right after the process you showed above is done. this timer could also have a duration of 1 second. if the BTS acutally sends a confirm, the timer could be stopped. this way it would also work with BTS firmwares that actually send a confirm.
On Fri, Dec 06, 2013 at 11:04:49AM +0100, Andreas Eversberg wrote:
you are right. i have no solution for this problem yet. at osmocombb/mobile i use queues to solve these kind of problems. whenever i want to handle something after osmo_select_main() was processed, i write into a specific queue. the main loop will call all dequeue functions in a loop, until all queues are empty and then continue with next osmo_select_main() call. one solution for handling the missing RELease CONFirm from BTS could be a timer with 0 duration. the timer will be handled right after the process you showed above is done. this timer could also have a duration of 1 second. if the BTS acutally sends a confirm, the timer could be stopped. this way it would also work with BTS firmwares that actually send a confirm.
Your last proposal is asking for introducing a race condition. This is a very bad idea. You have two options. You can use multiple 0 duration timers and fake the release confirm. The other option is to make the callers aware of missing release confirms.
On Fri, Dec 06, 2013 at 02:15:59PM +0100, Holger Hans Peter Freyther wrote:
Dear Andreas,
Your last proposal is asking for introducing a race condition. This is a very bad idea. You have two options. You can use multiple 0 duration timers and fake the release confirm. The other option is to make the callers aware of missing release confirms.
do you have an updated patch for that? The easiest would be to have a single timer per lchan and in rsl_release_sapis_from start a timer and in lchan->sapis[sapi] store a new enum value of something like LCHAN_SAPI_REL_REQUESTED?
holger
Holger Hans Peter Freyther wrote:
Your last proposal is asking for introducing a race condition. This
is a very bad idea. You have two options. You can use multiple 0 duration timers and fake the release confirm. The other option is to make the callers aware of missing release confirms.
do you have an updated patch for that? The easiest would be to have a single timer per lchan and in rsl_release_sapis_from start a timer and in lchan->sapis[sapi] store a new enum value of something like LCHAN_SAPI_REL_REQUESTED?
hi holger,
i have no update yet, but i will implement your suggestion.
best regards,
andreas
Holger Hans Peter Freyther wrote:
do you have an updated patch for that? The easiest would be to have a single timer per lchan and in rsl_release_sapis_from start a timer and in lchan->sapis[sapi] store a new enum value of something like LCHAN_SAPI_REL_REQUESTED?
i started timer in rsl_release_request, because there may be other users that call it with local end release.
since we don't know what other BTS firmware have this release bug, i added this workaround as an option to the VTY, which is disabled by default.
note that this patch is just a preview. it works but has only been tested briefly.
On Thu, Dec 19, 2013 at 01:40:40PM +0100, Andreas Eversberg wrote:
note that this patch is just a preview. it works but has only been tested briefly.
Shall we apply this patch?
Holger Hans Peter Freyther wrote:
On Thu, Dec 19, 2013 at 01:40:40PM +0100, Andreas Eversberg wrote:
note that this patch is just a preview. it works but has only been tested briefly.
Shall we apply this patch?
dear holger,
after several handover tests, i can confirm that this patch works. please use the recently rebased and distchecked version: a83f36b24d3a6bcec3cd70b3cb70a21e7fc8571a
regards,
andreas
On Wed, Jan 08, 2014 at 12:47:12PM +0100, Andreas Eversberg wrote:
Good Morning,
after several handover tests, i can confirm that this patch works. please use the recently rebased and distchecked version: a83f36b24d3a6bcec3cd70b3cb70a21e7fc8571a
I have pushed this change. IIRC the local release also applies to SAPI==3 as well. So the workaround should already trigger when SMS is being sent.
holger
From: Andreas Eversberg andreas@eversberg.eu
E1 based BTS use TRAU muxer to decode TRAU frames. After changing channel from one timeslot to another (due to handover or assignment), the TRAU muxer must be updated. The call reference of the call is disconnected from the old channel and connected to the new channel. --- openbsc/include/openbsc/gsm_data.h | 14 ++++++++++++++ openbsc/include/openbsc/trau_mux.h | 3 +++ openbsc/src/libbsc/bsc_api.c | 5 +++++ openbsc/src/libbsc/handover_logic.c | 7 +++++-- openbsc/src/libmsc/gsm_04_08.c | 12 +++++++++--- openbsc/src/libtrau/trau_mux.c | 18 ++++++++++++++++++ 6 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 7c3ca84..41fe328 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -382,6 +382,20 @@ static inline int is_nokia_bts(struct gsm_bts *bts) return 0; }
+static inline int is_e1_bts(struct gsm_bts *bts) +{ + switch (bts->type) { + case GSM_BTS_TYPE_BS11: + case GSM_BTS_TYPE_RBS2000: + case GSM_BTS_TYPE_NOKIA_SITE: + return 1; + default: + break; + } + + return 0; +} + enum gsm_auth_policy gsm_auth_policy_parse(const char *arg); const char *gsm_auth_policy_name(enum gsm_auth_policy policy);
diff --git a/openbsc/include/openbsc/trau_mux.h b/openbsc/include/openbsc/trau_mux.h index 2c01b06..667f623 100644 --- a/openbsc/include/openbsc/trau_mux.h +++ b/openbsc/include/openbsc/trau_mux.h @@ -51,5 +51,8 @@ int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref); /* send trau from application */ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame);
+/* switch trau muxer to new lchan */ +int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan); + /* callback invoked if we receive TRAU frames */ int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len, void *_priv); diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index 86d2493..e567038 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -31,6 +31,7 @@ #include <openbsc/handover.h> #include <openbsc/debug.h> #include <openbsc/gsm_04_08.h> +#include <openbsc/trau_mux.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
@@ -419,6 +420,10 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn, return; }
+ /* switch TRAU muxer for E1 based BTS from one channel to another */ + if (is_e1_bts(conn->bts)) + switch_trau_mux(conn->lchan, conn->secondary_lchan); + /* swap channels */ osmo_timer_del(&conn->T10);
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 9cf26af..36a758b 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -39,6 +39,7 @@ #include <openbsc/signal.h> #include <osmocom/core/talloc.h> #include <openbsc/transaction.h> +#include <openbsc/trau_mux.h>
struct bsc_handover { struct llist_head list; @@ -264,6 +265,10 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
osmo_timer_del(&ho->T3103);
+ /* switch TRAU muxer for E1 based BTS from one channel to another */ + if (is_e1_bts(new_lchan->conn->bts)) + switch_trau_mux(ho->old_lchan, new_lchan); + /* Replace the ho lchan with the primary one */ if (ho->old_lchan != new_lchan->conn->lchan) LOGP(DHO, LOGL_ERROR, "Primary lchan changed during handover.\n"); @@ -278,8 +283,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE); lchan_release(ho->old_lchan, 0, RSL_REL_LOCAL_END);
- /* do something to re-route the actual speech frames ! */ - llist_del(&ho->list); talloc_free(ho);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 775fe66..4dedd67 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1612,6 +1612,9 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) lchan = trans->conn->lchan; bts = lchan->ts->trx->bts;
+ /* store receive state */ + trans->tch_recv = enable; + switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: case GSM_BTS_TYPE_OSMO_SYSMO: @@ -1619,10 +1622,8 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) LOGP(DCC, LOGL_ERROR, "Error: RTP proxy is disabled\n"); return -EINVAL; } - /* in case, we don't have a RTP socket yet, we note this - * in the transaction and try later */ + /* in case, we don't have a RTP socket yet, we try later */ if (!lchan->abis_ip.rtp_socket) { - trans->tch_recv = enable; DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable); return 0; } @@ -1641,6 +1642,11 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) case GSM_BTS_TYPE_BS11: case GSM_BTS_TYPE_RBS2000: case GSM_BTS_TYPE_NOKIA_SITE: + /* in case we don't have a TCH with correct mode, we try later */ + if (lchan->tch_mode == GSM48_CMODE_SIGN) { + DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable); + return 0; + } if (enable) return trau_recv_lchan(lchan, callref); return trau_mux_unmap(NULL, callref); diff --git a/openbsc/src/libtrau/trau_mux.c b/openbsc/src/libtrau/trau_mux.c index 9272ac0..d25e78f 100644 --- a/openbsc/src/libtrau/trau_mux.c +++ b/openbsc/src/libtrau/trau_mux.c @@ -30,6 +30,7 @@ #include <openbsc/debug.h> #include <osmocom/core/talloc.h> #include <openbsc/trau_upqueue.h> +#include <openbsc/transaction.h>
/* this corresponds to the bit-lengths of the individual codec * parameters as indicated in Table 1.1 of TS 06.10 */ @@ -327,3 +328,20 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame) return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, TRAU_FRAME_BITS); } + +/* switch trau muxer to new lchan */ +int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan) +{ + struct gsm_network *net = old_lchan->ts->trx->bts->network; + struct gsm_trans *trans; + + /* look up transaction with TCH frame receive enabled */ + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->conn && trans->conn->lchan == old_lchan && trans->tch_recv) { + /* switch */ + trau_recv_lchan(new_lchan, trans->callref); + } + } + + return 0; +}
On Thu, Dec 05, 2013 at 04:02:39PM +0100, Andreas Eversberg wrote:
/* in case we don't have a TCH with correct mode, we try later */if (lchan->tch_mode == GSM48_CMODE_SIGN) {
When exactly is later and how will it be retried?
holger
On Thu, Dec 05, 2013 at 06:57:26PM +0100, Holger Hans Peter Freyther wrote:
When exactly is later and how will it be retried?
It appears to be sufficiently clear to me: When: Whenever the next frame from MNCC arrives. How: because MNCC is heanding in a stream of voice frames. Why different: Because at some point I hope that the channel mode is switched from SIGNALLING to VOICE.
Regards,
On Thu, Dec 05, 2013 at 04:02:36PM +0100, Andreas Eversberg wrote:
+struct bts_codec_conf {
- uint8_t hr;
- uint8_t efr;
- uint8_t afs;
- uint8_t ahs;
this naming appears odd. Where is it coming from? Do you know of a BTS that supports AMR on TCH/F but not on TCH/H?
+DEFUN(cfg_bts_codec1, cfg_bts_codec1_cmd, +DEFUN(cfg_bts_codec2, cfg_bts_codec2_cmd, +DEFUN(cfg_bts_codec3, cfg_bts_codec3_cmd, +DEFUN(cfg_bts_codec4, cfg_bts_codec4_cmd, +DEFUN(cfg_bts_codec5, cfg_bts_codec5_cmd,
please remove the code duplication and add a VTY testcase for setting and reading this value.
+static int apply_codec_restrictions(struct gsm_bts *bts,
- struct gsm_mncc_bearer_cap *bcap)
+{
- int i, j;
- /* remove unsupported speech versions from list */
- for (i = 0, j = 0; bcap->speech_ver[i] >= 0; i++) {
if (bcap->speech_ver[i] == 0)bcap->speech_ver[j++] = 0;if (bcap->speech_ver[i] == 2 && bts->codec.efr)bcap->speech_ver[j++] = 2;if (bcap->speech_ver[i] == 4 && bts->codec.afs)bcap->speech_ver[j++] = 4;if (bcap->speech_ver[i] == 1 && bts->codec.hr)bcap->speech_ver[j++] = 1;if (bcap->speech_ver[i] == 5 && bts->codec.ahs)bcap->speech_ver[j++] = 5;- }
please use the values of the gsm48_bcap_speech_ver enum instead of the magic numbers.
Holger Hans Peter Freyther wrote:
please remove the code duplication and add a VTY testcase for setting and reading this value.
dear holger,
i tried to run the vty test with "make check" (without anything added by me):
... /usr/bin/python ./vty_test_runner.py -w /usr/src/openbsc/openbsc -v confpath ., workdir /usr/src/openbsc/openbsc Running tests for specific VTY commands Skipping the BSC test Skipping the NAT test testConfigNetworkTree (__main__.TestVTYNITB) ... Launch: ./src/osmo-nitb/osmo-nitb -c ./doc/examples/osmo-nitb/nanobts/openbsc.cfg from /usr/src/openbsc/openbsc
the test gets stuck here. it tried "https://github.com/janfizza/osmocom-python.git" and "https://github.com/janfizza/osmocom-python.git". any hint?
best regards,
andreas
On Thu, Dec 05, 2013 at 06:53:48PM +0100, Holger Hans Peter Freyther wrote:
+struct bts_codec_conf {
- uint8_t hr;
- uint8_t efr;
- uint8_t afs;
- uint8_t ahs;
this naming appears odd. Where is it coming from?
this is regular layer1 naming :) TCH/AFS, TCH/AHS is used in various parts of the spec (05.x series mainly, I would say).
Hi Andreas,
I think there is a lot of code duplication that should be fixed, like, what I'm quiting below.
There are also the repeated blocks of "codec->* = 0" that should be moved into a function. Please try to avoid copy+paste style code.
Regards, Harald
On Thu, Dec 05, 2013 at 04:02:36PM +0100, Andreas Eversberg wrote:
@@ -629,6 +629,17 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) } }
- vty_out(vty, " codec-support fr");
- if (bts->codec.hr)
vty_out(vty, " hr");- if (bts->codec.efr)
vty_out(vty, " efr");- if (bts->codec.afs)
vty_out(vty, " afs");- if (bts->codec.ahs)
vty_out(vty, " ahs");- vty_out(vty, "%s", VTY_NEWLINE);
- for (i = 0; i < 1; i++) {
if (!strcmp(argv[i], "hr"))codec->hr = 1;if (!strcmp(argv[i], "efr"))codec->efr = 1;if (!strcmp(argv[i], "afs"))codec->afs = 1;if (!strcmp(argv[i], "ahs"))codec->ahs = 1;- }
- for (i = 0; i < 2; i++) {
if (!strcmp(argv[i], "hr"))codec->hr = 1;if (!strcmp(argv[i], "efr"))codec->efr = 1;if (!strcmp(argv[i], "afs"))codec->afs = 1;if (!strcmp(argv[i], "ahs"))codec->ahs = 1;- }
- for (i = 0; i < 3; i++) {
if (!strcmp(argv[i], "hr"))codec->hr = 1;if (!strcmp(argv[i], "efr"))codec->efr = 1;if (!strcmp(argv[i], "afs"))codec->afs = 1;if (!strcmp(argv[i], "ahs"))codec->ahs = 1;- }
- for (i = 0; i < 4; i++) {
if (!strcmp(argv[i], "hr"))codec->hr = 1;if (!strcmp(argv[i], "efr"))codec->efr = 1;if (!strcmp(argv[i], "afs"))codec->afs = 1;if (!strcmp(argv[i], "ahs"))codec->ahs = 1;- }
- for (i = 0; i < 5; i++) {
if (!strcmp(argv[i], "hr"))codec->hr = 1;if (!strcmp(argv[i], "efr"))codec->efr = 1;if (!strcmp(argv[i], "afs"))codec->afs = 1;if (!strcmp(argv[i], "ahs"))codec->ahs = 1;