lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
gerrit-log@lists.osmocom.org

January 2024

  • 1 participants
  • 1559 discussions
[S] Change in osmocom-bb[master]: doc/examples/mobile: add tch-{data,voice} sections
by fixeria 22 Jan '24

22 Jan '24
Attention is currently required from: fixeria. Hello Jenkins Builder, laforge, pespin, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/c/osmocom-bb/+/35636?usp=email to look at the new patch set (#5). The following approvals got outdated and were removed: Verified+1 by Jenkins Builder The change is no longer submittable: Verified is unsatisfied now. Change subject: doc/examples/mobile: add tch-{data,voice} sections ...................................................................... doc/examples/mobile: add tch-{data,voice} sections Change-Id: I9e53d4c429445ded07d77b27b6a31aa404b00e27 Related: OS#4396 --- M doc/examples/mobile/default.cfg M doc/examples/mobile/multi_ms.cfg 2 files changed, 31 insertions(+), 6 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/36/35636/5 -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35636?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I9e53d4c429445ded07d77b27b6a31aa404b00e27 Gerrit-Change-Number: 35636 Gerrit-PatchSet: 5 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-MessageType: newpatchset
1 0
0 0
[S] Change in osmocom-bb[master]: firmware (libosmocore): fix gsm48_chan_mode for TCH/[FH]2.4
by fixeria 22 Jan '24

22 Jan '24
Attention is currently required from: fixeria. Hello Jenkins Builder, laforge, I'd like you to reexamine a change. Please visit https://gerrit.osmocom.org/c/osmocom-bb/+/35637?usp=email to look at the new patch set (#5). The following approvals got outdated and were removed: Verified+1 by Jenkins Builder The change is no longer submittable: Verified is unsatisfied now. Change subject: firmware (libosmocore): fix gsm48_chan_mode for TCH/[FH]2.4 ...................................................................... firmware (libosmocore): fix gsm48_chan_mode for TCH/[FH]2.4 This is basically a back-port of the fix that was merged to libosmocore.git back in 2013. Our ancient copy of libosmocore, which is used for building the firmware, predates this commit. Ideally, we should rip off this ancient copy and build the firmware against recent master (see OS#2378). But for now, let's just fix our local copy. Otherwise TCH/[FH]2.4 support is broken. Change-Id: I99f528f3e1cd4c04ebb9d8becf1572688dd531ae Related: libosmocore.git 31e844bfe2756e36dd50f8bed9fa8b087ee6a1d9 Related: OS#4396 --- M src/shared/libosmocore/include/osmocom/gsm/protocol/gsm_04_08.h 1 file changed, 20 insertions(+), 1 deletion(-) git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/37/35637/5 -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35637?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I99f528f3e1cd4c04ebb9d8becf1572688dd531ae Gerrit-Change-Number: 35637 Gerrit-PatchSet: 5 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-CC: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-MessageType: newpatchset
1 0
0 0
[S] Change in osmo-trx[master]: Transceiver::ctrl_sock_handle_rx(): fix copy-pasted comments
by fixeria 22 Jan '24

22 Jan '24
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-trx/+/35655?usp=email ) Change subject: Transceiver::ctrl_sock_handle_rx(): fix copy-pasted comments ...................................................................... Transceiver::ctrl_sock_handle_rx(): fix copy-pasted comments Change-Id: If31c0de0b3562c06220dcb9ad6f0c13d8621f6e3 --- M Transceiver52M/Transceiver.cpp 1 file changed, 11 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/55/35655/1 diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index fed4289..f5ddd9b 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -959,19 +959,18 @@ sprintf(response, "RSP NOHANDOVER 0 %u %u", ts, ss); } } else if (match_cmd(command, "SETMAXDLY", &params)) { - //set expected maximum time-of-arrival + //set expected maximum time-of-arrival for Access Bursts int maxDelay; sscanf(params, "%d", &maxDelay); mMaxExpectedDelayAB = maxDelay; // 1 GSM symbol is approx. 1 km sprintf(response,"RSP SETMAXDLY 0 %d",maxDelay); } else if (match_cmd(command, "SETMAXDLYNB", &params)) { - //set expected maximum time-of-arrival + //set expected maximum time-of-arrival for Normal Bursts int maxDelay; sscanf(params, "%d", &maxDelay); mMaxExpectedDelayNB = maxDelay; // 1 GSM symbol is approx. 1 km sprintf(response,"RSP SETMAXDLYNB 0 %d",maxDelay); } else if (match_cmd(command, "SETRXGAIN", &params)) { - //set expected maximum time-of-arrival int newGain; sscanf(params, "%d", &newGain); newGain = mRadioInterface->setRxGain(newGain, chan); -- To view, visit https://gerrit.osmocom.org/c/osmo-trx/+/35655?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-trx Gerrit-Branch: master Gerrit-Change-Id: If31c0de0b3562c06220dcb9ad6f0c13d8621f6e3 Gerrit-Change-Number: 35655 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-MessageType: newchange
1 0
0 0
[M] Change in osmo-bts[master]: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages
by fixeria 22 Jan '24

22 Jan '24
fixeria has uploaded a new patch set (#2). ( https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email ) Change subject: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages ...................................................................... osmo-bts-trx: add test VTY command to send arbitrary TRXC messages Change-Id: Iabc9b702e5f1513187e24f45d9ffe06ea940c3ec --- M src/osmo-bts-trx/trx_if.c M src/osmo-bts-trx/trx_if.h M src/osmo-bts-trx/trx_vty.c 3 files changed, 50 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/54/35654/2 -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Iabc9b702e5f1513187e24f45d9ffe06ea940c3ec Gerrit-Change-Number: 35654 Gerrit-PatchSet: 2 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-CC: Jenkins Builder Gerrit-MessageType: newpatchset
1 0
0 0
[M] Change in osmo-bts[master]: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages
by Jenkins Builder 22 Jan '24

22 Jan '24
Jenkins Builder has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email ) Change subject: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages ...................................................................... Patch Set 1: (1 comment) File src/osmo-bts-trx/trx_vty.c: Robot Comment from checkpatch (run ID jenkins-gerrit-lint-13787): https://gerrit.osmocom.org/c/osmo-bts/+/35654/comment/54cc0aaa_0671ae4d PS1, Line 212: vty_out(vty, "%% Cound not find TRX%s", VTY_NEWLINE); 'Cound' may be misspelled - perhaps 'Could'? -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Iabc9b702e5f1513187e24f45d9ffe06ea940c3ec Gerrit-Change-Number: 35654 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-CC: Jenkins Builder Gerrit-Comment-Date: Mon, 22 Jan 2024 20:54:36 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: No Gerrit-MessageType: comment
1 0
0 0
[M] Change in osmo-bts[master]: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages
by fixeria 22 Jan '24

22 Jan '24
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email ) Change subject: osmo-bts-trx: add test VTY command to send arbitrary TRXC messages ...................................................................... osmo-bts-trx: add test VTY command to send arbitrary TRXC messages Change-Id: Iabc9b702e5f1513187e24f45d9ffe06ea940c3ec --- M src/osmo-bts-trx/trx_if.c M src/osmo-bts-trx/trx_if.h M src/osmo-bts-trx/trx_vty.c 3 files changed, 50 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/54/35654/1 diff --git a/src/osmo-bts-trx/trx_if.c b/src/osmo-bts-trx/trx_if.c index 89078a3..b6b20e9 100644 --- a/src/osmo-bts-trx/trx_if.c +++ b/src/osmo-bts-trx/trx_if.c @@ -227,8 +227,8 @@ * The new command will be added to the end of the control command * queue. */ -static int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, const char *cmd, - const char *fmt, ...) +int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, + const char *cmd, const char *fmt, ...) { struct trx_ctrl_msg *tcm; struct trx_ctrl_msg *prev = NULL; @@ -277,7 +277,6 @@ return 0; } -#define trx_ctrl_cmd(l1h, critical, cmd, fmt, ...) trx_ctrl_cmd_cb(l1h, critical, NULL, cmd, fmt, ##__VA_ARGS__) /*! Send "POWEROFF" command to TRX */ int trx_if_cmd_poweroff(struct trx_l1h *l1h, trx_if_cmd_poweronoff_cb *cb) diff --git a/src/osmo-bts-trx/trx_if.h b/src/osmo-bts-trx/trx_if.h index b838b76..3a22a1b 100644 --- a/src/osmo-bts-trx/trx_if.h +++ b/src/osmo-bts-trx/trx_if.h @@ -48,3 +48,7 @@ /* Format negotiation command */ int trx_if_cmd_setformat(struct trx_l1h *l1h, uint8_t ver, trx_if_cmd_generic_cb *cb); + +int trx_ctrl_cmd_cb(struct trx_l1h *l1h, int critical, void *cb, + const char *cmd, const char *fmt, ...); +#define trx_ctrl_cmd(l1h, critical, cmd, fmt, ...) trx_ctrl_cmd_cb(l1h, critical, NULL, cmd, fmt, ##__VA_ARGS__) diff --git a/src/osmo-bts-trx/trx_vty.c b/src/osmo-bts-trx/trx_vty.c index 998e9cb..f132937 100644 --- a/src/osmo-bts-trx/trx_vty.c +++ b/src/osmo-bts-trx/trx_vty.c @@ -194,6 +194,39 @@ return CMD_SUCCESS; } +DEFUN_HIDDEN(test_send_trxc, + test_send_trxc_cmd, + "test send-trxc-cmd <0-255> CMD [.ARGS]", + "Various testing commands\n" + "Send an arbitrary TRX command\n" + "Transceiver number\n" + "TRXC command\n" "TRXC command arguments\n") +{ + const struct gsm_bts_trx *trx; + const struct phy_instance *pinst; + struct trx_l1h *l1h; + int rc; + + trx = gsm_bts_trx_num(g_bts, atoi(argv[0])); + if (trx == NULL) { + vty_out(vty, "%% Cound not find TRX%s", VTY_NEWLINE); + return CMD_WARNING; + } + + pinst = trx_phy_instance(trx); + l1h = pinst->u.osmotrx.hdl; + + if (argc > 2) { + char *cmd_args = argv_concat(argv, argc, 2); + rc = trx_ctrl_cmd(l1h, 0, argv[1], "%s", cmd_args); + talloc_free(cmd_args); + } else { + rc = trx_ctrl_cmd(l1h, 0, argv[1], ""); + } + + return (rc == 0) ? CMD_SUCCESS : CMD_WARNING; +} + DEFUN_USRATTR(cfg_trx_nominal_power, cfg_trx_nominal_power_cmd, X(BTS_VTY_TRX_POWERCYCLE), "nominal-tx-power <-10-100>", @@ -630,6 +663,8 @@ install_element_ve(&show_transceiver_cmd); install_element_ve(&show_phy_cmd); + install_element(ENABLE_NODE, &test_send_trxc_cmd); + install_element(TRX_NODE, &cfg_trx_nominal_power_cmd); install_element(TRX_NODE, &cfg_trx_no_nominal_power_cmd); -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/35654?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Iabc9b702e5f1513187e24f45d9ffe06ea940c3ec Gerrit-Change-Number: 35654 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-MessageType: newchange
1 0
0 0
[L] Change in osmocom-bb[master]: mobile: split voice specific TCH handling into its own file
by fixeria 22 Jan '24

22 Jan '24
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/35581?usp=email ) Change subject: mobile: split voice specific TCH handling into its own file ...................................................................... mobile: split voice specific TCH handling into its own file Change-Id: Ib917d95fe77da3e60bc932cce56714d81095c7d4 Related: OS#4396 --- M src/host/layer23/src/mobile/Makefile.am M src/host/layer23/src/mobile/tch.c A src/host/layer23/src/mobile/tch_voice.c 3 files changed, 180 insertions(+), 118 deletions(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am index ed2146f..0639916 100644 --- a/src/host/layer23/src/mobile/Makefile.am +++ b/src/host/layer23/src/mobile/Makefile.am @@ -31,6 +31,7 @@ mncc_sock.c \ primitives.c \ tch.c \ + tch_voice.c \ transaction.c \ vty_interface.c \ $(NULL) diff --git a/src/host/layer23/src/mobile/tch.c b/src/host/layer23/src/mobile/tch.c index adeaad5..ad5a724 100644 --- a/src/host/layer23/src/mobile/tch.c +++ b/src/host/layer23/src/mobile/tch.c @@ -30,82 +30,17 @@ #include <osmocom/bb/common/logging.h> #include <osmocom/bb/common/osmocom_data.h> #include <osmocom/bb/common/ms.h> -#include <osmocom/bb/mobile/gapk_io.h> #include <osmocom/bb/mobile/mncc.h> #include <osmocom/bb/mobile/mncc_sock.h> #include <osmocom/bb/mobile/transaction.h> #include <osmocom/bb/mobile/tch.h> -/* Forward a Downlink voice frame to the external MNCC handler */ -static int tch_forward_mncc(struct osmocom_ms *ms, struct msgb *msg) -{ - struct gsm_data_frame *mncc; +int tch_voice_state_init(struct gsm_trans *trans, + struct tch_voice_state *state); +void tch_voice_state_free(struct tch_voice_state *state); - /* Drop the l1ctl_info_dl header */ - msgb_pull_to_l2(msg); - /* push mncc header in front of data */ - mncc = (struct gsm_data_frame *) - msgb_push(msg, sizeof(struct gsm_data_frame)); - mncc->callref = ms->mncc_entity.ref; - - switch (ms->rrlayer.cd_now.mode) { - case GSM48_CMODE_SPEECH_V1: - { - const uint8_t cbits = ms->rrlayer.cd_now.chan_nr >> 3; - if (cbits == ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs) - mncc->msg_type = GSM_TCHF_FRAME; - else - mncc->msg_type = GSM_TCHH_FRAME; - break; - } - case GSM48_CMODE_SPEECH_EFR: - mncc->msg_type = GSM_TCHF_FRAME_EFR; - break; - case GSM48_CMODE_SPEECH_AMR: /* TODO: no AMR support yet */ - default: - /* TODO: print error message here */ - goto exit_free; - } - - /* distribute and then free */ - if (ms->mncc_entity.sock_state && ms->mncc_entity.ref) - return mncc_sock_from_cc(ms->mncc_entity.sock_state, msg); - -exit_free: - msgb_free(msg); - return 0; -} - -/* Receive a Downlink voice frame from the lower layers */ -static int tch_recv_voice(struct osmocom_ms *ms, struct msgb *msg) -{ - struct tch_state *state = ms->tch_state; - - switch (state->voice.handler) { - case TCH_VOICE_IOH_LOOPBACK: - /* Remove the DL info header */ - msgb_pull_to_l2(msg); - /* Send voice frame back */ - return tch_send_msg(ms, msg); - case TCH_VOICE_IOH_MNCC_SOCK: - return tch_forward_mncc(ms, msg); - case TCH_VOICE_IOH_GAPK: -#ifdef WITH_GAPK_IO - /* Enqueue a frame to the DL TCH buffer */ - if (state->voice.gapk_io != NULL) - gapk_io_enqueue_dl(state->voice.gapk_io, msg); - else - msgb_free(msg); - break; -#endif - case TCH_VOICE_IOH_L1PHY: - case TCH_VOICE_IOH_NONE: - /* Drop voice frame */ - msgb_free(msg); - } - - return 0; -} +int tch_voice_recv(struct osmocom_ms *ms, struct msgb *msg); +int tch_voice_serve_ms(struct osmocom_ms *ms); /* Receive a Downlink traffic (voice/data) frame from the lower layers */ static int tch_recv_cb(struct osmocom_ms *ms, struct msgb *msg) @@ -119,7 +54,7 @@ } if (state->is_voice) - rc = tch_recv_voice(ms, msg); + rc = tch_voice_recv(ms, msg); else /* TODO: tch_recv_data() */ msgb_free(msg); @@ -169,53 +104,15 @@ int tch_serve_ms(struct osmocom_ms *ms) { struct tch_state *state = ms->tch_state; + int rc = 0; if (state == NULL) return 0; - if (state->is_voice) { -#ifdef WITH_GAPK_IO - if (state->voice.handler == TCH_VOICE_IOH_GAPK) - return gapk_io_serve_ms(ms, state->voice.gapk_io); -#endif - } + if (state->is_voice) + rc = tch_voice_serve_ms(ms); + /* TODO: else tch_data_serve_ms() */ - return 0; -} - -static int tch_state_init_voice(struct osmocom_ms *ms, - struct tch_voice_state *state) -{ - const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now; - - switch (state->handler) { -#ifdef WITH_GAPK_IO - case TCH_VOICE_IOH_GAPK: - if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs) - state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, true); - else /* RSL_CHAN_Lm_ACCHs */ - state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, false); - if (state->gapk_io == NULL) - return -1; - break; -#endif - default: - break; - } - - return 0; -} - -static void tch_state_free_voice(struct tch_voice_state *state) -{ - switch (state->handler) { -#ifdef WITH_GAPK_IO - case TCH_VOICE_IOH_GAPK: - gapk_io_state_free(state->gapk_io); - break; -#endif - default: - break; - } + return rc; } static void tch_trans_cstate_active_cb(struct gsm_trans *trans) @@ -237,7 +134,7 @@ case GSM48_CMODE_SPEECH_AMR: state->is_voice = true; state->voice.handler = ms->settings.tch_voice.io_handler; - if (tch_state_init_voice(ms, &state->voice) != 0) + if (tch_voice_state_init(trans, &state->voice) != 0) goto exit_free; break; case GSM48_CMODE_DATA_14k5: @@ -247,8 +144,8 @@ #if 0 state->is_voice = false; state->data.handler = ms->settings.tch_data.io_handler; - /* TODO: tch_state_init_data() */ - if (tch_state_init_data(ms, &state->data) != 0) + /* TODO: tch_data_state_init() */ + if (tch_data_state_init(trans, &state->data) != 0) goto exit_free; break; #endif @@ -272,7 +169,7 @@ if (state == NULL) return; if (state->is_voice) - tch_state_free_voice(&state->voice); + tch_voice_state_free(&state->voice); #if 0 else /* TODO: tch_state_free_data() */ tch_state_free_data(&state->data); diff --git a/src/host/layer23/src/mobile/tch_voice.c b/src/host/layer23/src/mobile/tch_voice.c new file mode 100644 index 0000000..f4bbcfa --- /dev/null +++ b/src/host/layer23/src/mobile/tch_voice.c @@ -0,0 +1,154 @@ +/* + * (C) 2017-2018 by Vadim Yanitskiy <axilirator(a)gmail.com> + * (C) 2022-2024 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de> + * + * 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. + * + */ + +#include <stdint.h> +#include <errno.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/msgb.h> + +#include <osmocom/gsm/protocol/gsm_04_08.h> +#include <osmocom/gsm/protocol/gsm_08_58.h> + +#include <osmocom/bb/common/logging.h> +#include <osmocom/bb/common/osmocom_data.h> +#include <osmocom/bb/common/ms.h> +#include <osmocom/bb/mobile/gapk_io.h> +#include <osmocom/bb/mobile/mncc.h> +#include <osmocom/bb/mobile/mncc_sock.h> +#include <osmocom/bb/mobile/transaction.h> +#include <osmocom/bb/mobile/tch.h> + +/* Forward a Downlink voice frame to the external MNCC handler */ +static int tch_forward_mncc(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm_data_frame *mncc; + + /* Drop the l1ctl_info_dl header */ + msgb_pull_to_l2(msg); + /* push mncc header in front of data */ + mncc = (struct gsm_data_frame *) + msgb_push(msg, sizeof(struct gsm_data_frame)); + mncc->callref = ms->mncc_entity.ref; + + switch (ms->rrlayer.cd_now.mode) { + case GSM48_CMODE_SPEECH_V1: + { + const uint8_t cbits = ms->rrlayer.cd_now.chan_nr >> 3; + if (cbits == ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs) + mncc->msg_type = GSM_TCHF_FRAME; + else + mncc->msg_type = GSM_TCHH_FRAME; + break; + } + case GSM48_CMODE_SPEECH_EFR: + mncc->msg_type = GSM_TCHF_FRAME_EFR; + break; + case GSM48_CMODE_SPEECH_AMR: /* TODO: no AMR support yet */ + default: + /* TODO: print error message here */ + goto exit_free; + } + + /* distribute and then free */ + if (ms->mncc_entity.sock_state && ms->mncc_entity.ref) + return mncc_sock_from_cc(ms->mncc_entity.sock_state, msg); + +exit_free: + msgb_free(msg); + return 0; +} + +int tch_voice_recv(struct osmocom_ms *ms, struct msgb *msg) +{ + struct tch_voice_state *state = &ms->tch_state->voice; + + switch (state->handler) { + case TCH_VOICE_IOH_LOOPBACK: + /* Remove the DL info header */ + msgb_pull_to_l2(msg); + /* Send voice frame back */ + return tch_send_msg(ms, msg); + case TCH_VOICE_IOH_MNCC_SOCK: + return tch_forward_mncc(ms, msg); + case TCH_VOICE_IOH_GAPK: +#ifdef WITH_GAPK_IO + /* Enqueue a frame to the DL TCH buffer */ + if (state->gapk_io != NULL) + gapk_io_enqueue_dl(state->gapk_io, msg); + else + msgb_free(msg); + break; +#endif + case TCH_VOICE_IOH_L1PHY: + case TCH_VOICE_IOH_NONE: + /* Drop voice frame */ + msgb_free(msg); + break; + } + + return 0; +} + +int tch_voice_serve_ms(struct osmocom_ms *ms) +{ +#ifdef WITH_GAPK_IO + struct tch_voice_state *state = &ms->tch_state->voice; + + if (state->handler == TCH_VOICE_IOH_GAPK) + return gapk_io_serve_ms(ms, state->gapk_io); +#endif + + return 0; +} + +int tch_voice_state_init(struct gsm_trans *trans, struct tch_voice_state *state) +{ +#ifdef WITH_GAPK_IO + struct osmocom_ms *ms = trans->ms; + const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now; + + switch (state->handler) { + case TCH_VOICE_IOH_GAPK: + if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs) + state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, true); + else /* RSL_CHAN_Lm_ACCHs */ + state->gapk_io = gapk_io_state_alloc_mode_rate(ms, cd->mode, false); + if (state->gapk_io == NULL) + return -1; + break; + default: + break; + } +#endif + + return 0; +} + +void tch_voice_state_free(struct tch_voice_state *state) +{ + switch (state->handler) { +#ifdef WITH_GAPK_IO + case TCH_VOICE_IOH_GAPK: + gapk_io_state_free(state->gapk_io); + break; +#endif + default: + break; + } +} -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35581?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: Ib917d95fe77da3e60bc932cce56714d81095c7d4 Gerrit-Change-Number: 35581 Gerrit-PatchSet: 5 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-CC: jolly <andreas(a)eversberg.eu> Gerrit-MessageType: merged
1 0
0 0
[L] Change in osmocom-bb[master]: mobile: integrate V.110 TA & soft-UART from libosmocore
by fixeria 22 Jan '24

22 Jan '24
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email ) Change subject: mobile: integrate V.110 TA & soft-UART from libosmocore ...................................................................... mobile: integrate V.110 TA & soft-UART from libosmocore Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0 Depends: libosmocore.git I6d2f8e250df31c233a2741163113dc07515409ae Depends: libosmocore.git I5716bd6fd0201ee7a7a29e72f775972cd374082f Depends: libosmocore.git I2ca95963fd5852ddb89bdd35b86b31489127fe84 Related: OS#4396 --- M src/host/layer23/configure.ac M src/host/layer23/include/osmocom/bb/mobile/tch.h M src/host/layer23/src/mobile/Makefile.am M src/host/layer23/src/mobile/tch.c A src/host/layer23/src/mobile/tch_data.c 5 files changed, 511 insertions(+), 13 deletions(-) Approvals: Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve fixeria: Looks good to me, approved diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac index b4eb860..7fb8bf1 100644 --- a/src/host/layer23/configure.ac +++ b/src/host/layer23/configure.ac @@ -45,6 +45,7 @@ PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm) +PKG_CHECK_MODULES(LIBOSMOISDN, libosmoisdn) PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec) PKG_CHECK_MODULES(LIBOSMOGPRSRLCMAC, libosmo-gprs-rlcmac) PKG_CHECK_MODULES(LIBOSMOGPRSLLC, libosmo-gprs-llc) diff --git a/src/host/layer23/include/osmocom/bb/mobile/tch.h b/src/host/layer23/include/osmocom/bb/mobile/tch.h index b99b834..8672860 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/tch.h +++ b/src/host/layer23/include/osmocom/bb/mobile/tch.h @@ -13,6 +13,10 @@ } voice; struct tch_data_state { enum tch_data_io_handler handler; + struct osmo_v110_ta *v110_ta; + struct osmo_soft_uart *suart; + unsigned int num_tx; + uint8_t e1e2e3[3]; } data; }; }; diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am index 0639916..b4e45e2 100644 --- a/src/host/layer23/src/mobile/Makefile.am +++ b/src/host/layer23/src/mobile/Makefile.am @@ -8,6 +8,7 @@ $(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOVTY_CFLAGS) \ $(LIBOSMOGSM_CFLAGS) \ + $(LIBOSMOISDN_CFLAGS) \ $(LIBOSMOGPRSRLCMAC_CFLAGS) \ $(LIBOSMOGPRSLLC_CFLAGS) \ $(LIBOSMOGPRSSNDCP_CFLAGS) \ @@ -31,6 +32,7 @@ mncc_sock.c \ primitives.c \ tch.c \ + tch_data.c \ tch_voice.c \ transaction.c \ vty_interface.c \ @@ -45,6 +47,7 @@ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOVTY_LIBS) \ $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOISDN_LIBS) \ $(LIBOSMOGPRSRLCMAC_LIBS) \ $(LIBOSMOGPRSLLC_LIBS) \ $(LIBOSMOGPRSSNDCP_LIBS) \ diff --git a/src/host/layer23/src/mobile/tch.c b/src/host/layer23/src/mobile/tch.c index ad5a724..70c9163 100644 --- a/src/host/layer23/src/mobile/tch.c +++ b/src/host/layer23/src/mobile/tch.c @@ -37,16 +37,21 @@ int tch_voice_state_init(struct gsm_trans *trans, struct tch_voice_state *state); +int tch_data_state_init(struct gsm_trans *trans, + struct tch_data_state *state); + void tch_voice_state_free(struct tch_voice_state *state); +void tch_data_state_free(struct tch_data_state *state); int tch_voice_recv(struct osmocom_ms *ms, struct msgb *msg); +int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg); int tch_voice_serve_ms(struct osmocom_ms *ms); /* Receive a Downlink traffic (voice/data) frame from the lower layers */ static int tch_recv_cb(struct osmocom_ms *ms, struct msgb *msg) { struct tch_state *state = ms->tch_state; - int rc = 0; + int rc; if (state == NULL) { msgb_free(msg); @@ -55,9 +60,8 @@ if (state->is_voice) rc = tch_voice_recv(ms, msg); - else /* TODO: tch_recv_data() */ - msgb_free(msg); - + else + rc = tch_data_recv(ms, msg); return rc; } @@ -126,6 +130,7 @@ state = talloc_zero(ms, struct tch_state); OSMO_ASSERT(state != NULL); + ms->tch_state = state; ch_mode = ms->rrlayer.cd_now.mode; switch (ch_mode) { @@ -141,24 +146,20 @@ case GSM48_CMODE_DATA_12k0: case GSM48_CMODE_DATA_6k0: case GSM48_CMODE_DATA_3k6: -#if 0 state->is_voice = false; state->data.handler = ms->settings.tch_data.io_handler; - /* TODO: tch_data_state_init() */ if (tch_data_state_init(trans, &state->data) != 0) goto exit_free; break; -#endif case GSM48_CMODE_SIGN: default: LOGP(DL1C, LOGL_ERROR, "Unhandled channel mode %s\n", get_value_string(gsm48_chan_mode_names, ch_mode)); exit_free: talloc_free(state); + ms->tch_state = NULL; return; } - - ms->tch_state = state; } static void tch_trans_free_cb(struct gsm_trans *trans) @@ -170,10 +171,8 @@ return; if (state->is_voice) tch_voice_state_free(&state->voice); -#if 0 - else /* TODO: tch_state_free_data() */ - tch_state_free_data(&state->data); -#endif + else + tch_data_state_free(&state->data); talloc_free(state); ms->tch_state = NULL; diff --git a/src/host/layer23/src/mobile/tch_data.c b/src/host/layer23/src/mobile/tch_data.c new file mode 100644 index 0000000..9f46641 --- /dev/null +++ b/src/host/layer23/src/mobile/tch_data.c @@ -0,0 +1,478 @@ +/* + * (C) 2023-2024 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de> + * Author: Vadim Yanitskiy <vyanitskiy(a)sysmocom.de> + * + * 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. + * + */ + +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/soft_uart.h> + +#include <osmocom/gsm/protocol/gsm_08_58.h> +#include <osmocom/gsm/gsm44021.h> + +#include <osmocom/isdn/v110.h> +#include <osmocom/isdn/v110_ta.h> + +#include <osmocom/bb/common/logging.h> +#include <osmocom/bb/common/osmocom_data.h> +#include <osmocom/bb/common/ms.h> +#include <osmocom/bb/mobile/mncc.h> +#include <osmocom/bb/mobile/transaction.h> +#include <osmocom/bb/mobile/tch.h> + +struct csd_v110_frame_desc { + uint16_t num_blocks; + uint16_t num_bits; +}; + +struct csd_v110_lchan_desc { + struct csd_v110_frame_desc fr; + struct csd_v110_frame_desc hr; +}; + +/* key is enum gsm48_chan_mode, so assuming a value in range 0..255 */ +const struct csd_v110_lchan_desc csd_v110_lchan_desc[256] = { +#if 0 + [GSM48_CMODE_DATA_14k5] = { + /* TCH/F14.4: 290 bits every 20 ms (14.5 kbit/s) */ + .fr = { .num_blocks = 1, .num_bits = 290 }, + }, +#endif + [GSM48_CMODE_DATA_12k0] = { + /* TCH/F9.6: 4 * 60 bits every 20 ms (12.0 kbit/s) */ + .fr = { .num_blocks = 4, .num_bits = 60 }, + }, + [GSM48_CMODE_DATA_6k0] = { + /* TCH/F4.8: 2 * 60 bits every 20 ms (6.0 kbit/s) */ + .fr = { .num_blocks = 2, .num_bits = 60 }, + /* TCH/H4.8: 4 * 60 bits every 40 ms (6.0 kbit/s) */ + .hr = { .num_blocks = 4, .num_bits = 60 }, + }, + [GSM48_CMODE_DATA_3k6] = { + /* TCH/F2.4: 2 * 36 bits every 20 ms (3.6 kbit/s) */ + .fr = { .num_blocks = 2, .num_bits = 36 }, + /* TCH/H2.4: 4 * 36 bits every 40 ms (3.6 kbit/s) */ + .hr = { .num_blocks = 4, .num_bits = 36 }, + }, +}; + +static void tch_soft_uart_rx_cb(void *priv, struct msgb *msg, unsigned int flags) +{ + LOGP(DL1C, LOGL_FATAL, "%s(): [flags=0x%08x] %s\n", + __func__, flags, msgb_hexdump(msg)); + msgb_free(msg); +} + +static void tch_soft_uart_tx_cb(void *priv, struct msgb *msg) +{ + const char *data = "TEST\r\n"; + size_t n_bytes; + + n_bytes = OSMO_MIN(msg->data_len, strlen(data)); + if (n_bytes > 0) + memcpy(msgb_put(msg, n_bytes), (void *)data, n_bytes); +} + +struct osmo_soft_uart *tch_soft_uart_alloc(struct osmocom_ms *ms, + const struct gsm_mncc_bearer_cap *bcap) +{ + struct osmo_soft_uart *suart; + + struct osmo_soft_uart_cfg cfg = { + .num_data_bits = bcap->data.nr_data_bits, + .num_stop_bits = bcap->data.nr_stop_bits, + /* .parity_mode is set below */ + .rx_buf_size = 1024, /* TODO: align with the current TCH mode */ + .rx_timeout_ms = 100, /* TODO: align with TCH framing interval */ + .priv = (void *)&ms->tch_state->data, + .rx_cb = &tch_soft_uart_rx_cb, + .tx_cb = &tch_soft_uart_tx_cb, + }; + + switch (bcap->data.parity) { + case GSM48_BCAP_PAR_ODD: + cfg.parity_mode = OSMO_SUART_PARITY_ODD; + break; + case GSM48_BCAP_PAR_EVEN: + cfg.parity_mode = OSMO_SUART_PARITY_EVEN; + break; + case GSM48_BCAP_PAR_ZERO: + cfg.parity_mode = OSMO_SUART_PARITY_SPACE; + break; + case GSM48_BCAP_PAR_ONE: + cfg.parity_mode = OSMO_SUART_PARITY_MARK; + break; + case GSM48_BCAP_PAR_NONE: + default: + cfg.parity_mode = OSMO_SUART_PARITY_NONE; + break; + } + + suart = osmo_soft_uart_alloc(ms, "csd_soft_uart", &cfg); + if (suart == NULL) + return NULL; + + osmo_soft_uart_set_rx(suart, true); + osmo_soft_uart_set_tx(suart, true); + + return suart; +} + +/*************************************************************************************/ + +static void tch_v110_ta_rx_cb(void *priv, const ubit_t *buf, size_t buf_size) +{ + /* TODO: send to the configured I/O handler */ +} + +static void tch_v110_ta_tx_cb(void *priv, ubit_t *buf, size_t buf_size) +{ + /* TODO: send to the configured I/O handler */ +} + +static void tch_v110_ta_async_rx_cb(void *priv, const ubit_t *buf, size_t buf_size) +{ + const struct tch_data_state *state = (struct tch_data_state *)priv; + + osmo_soft_uart_rx_ubits(state->suart, buf, buf_size); +} + +static void tch_v110_ta_async_tx_cb(void *priv, ubit_t *buf, size_t buf_size) +{ + const struct tch_data_state *state = (struct tch_data_state *)priv; + + osmo_soft_uart_tx_ubits(state->suart, buf, buf_size); +} + +static void tch_v110_ta_status_update_cb(void *priv, unsigned int status) +{ + LOGP(DL1C, LOGL_DEBUG, "%s(): [status=0x%08x]\n", __func__, status); + + /* TODO: update status lines of the soft-UART (if state.suart != NULL) */ +} + +struct osmo_v110_ta *tch_v110_ta_alloc(struct osmocom_ms *ms, + const struct gsm_mncc_bearer_cap *bcap) +{ + struct tch_data_state *state = &ms->tch_state->data; + + struct osmo_v110_ta_cfg cfg = { + /* .rate is set below */ + .priv = (void *)state, + .rx_cb = &tch_v110_ta_rx_cb, + .tx_cb = &tch_v110_ta_tx_cb, + .status_update_cb = &tch_v110_ta_status_update_cb, + }; + + if (bcap->data.async) { + OSMO_ASSERT(state->suart != NULL); + cfg.rx_cb = &tch_v110_ta_async_rx_cb; + cfg.tx_cb = &tch_v110_ta_async_tx_cb; + } + +#define BCAP_RATE(interm_rate, user_rate) \ + ((interm_rate << 8) | (user_rate << 0)) + + switch (BCAP_RATE(bcap->data.interm_rate, bcap->data.user_rate)) { + case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_1200): + cfg.rate = OSMO_V110_SYNC_RA1_1200; + break; + case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_2400): + cfg.rate = OSMO_V110_SYNC_RA1_2400; + break; + case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_4800): + cfg.rate = OSMO_V110_SYNC_RA1_4800; + break; + case BCAP_RATE(GSM48_BCAP_IR_16k, GSM48_BCAP_UR_9600): + cfg.rate = OSMO_V110_SYNC_RA1_9600; + break; + /* TODO: according to 3GPP TS 44.021, section 4.1, the 300 bit/s user data + * signalling rate shall be adapted to a synchronous 600 bit/s stream. */ + case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_300): + default: + LOGP(DCC, LOGL_ERROR, + "%s(): User rate 0x%02x (octets 6a) is not supported (IR=0x%02x)\n", + __func__, bcap->data.user_rate, bcap->data.interm_rate); + return NULL; + } + +#undef BCAP_RATE + + osmo_v110_e1e2e3_set(state->e1e2e3, cfg.rate); + + return osmo_v110_ta_alloc(ms, "csd_v110_ta", &cfg); +} + +/*************************************************************************************/ + +static void swap_words(uint8_t *data, size_t data_len) +{ + /* swap bytes in words */ + while (data_len >= 2) { + uint8_t tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; + data_len -= 2; + data += 2; + } +} + +static int tch_csd_rx_from_l1(struct osmocom_ms *ms, struct msgb *msg) +{ + const struct tch_data_state *state = &ms->tch_state->data; + const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now; + const struct csd_v110_frame_desc *desc; + ubit_t data[4 * 60]; + + if (msgb_l3len(msg) < 30) + return -EINVAL; + + if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs) + desc = &csd_v110_lchan_desc[cd->mode].fr; + else /* RSL_CHAN_Lm_ACCHs */ + desc = &csd_v110_lchan_desc[cd->mode].hr; + if (OSMO_UNLIKELY(desc->num_blocks == 0)) + return -ENOTSUP; + + switch (ms->settings.tch_data.io_format) { + case TCH_DATA_IOF_OSMO: + break; + case TCH_DATA_IOF_TI: + /* the layer1 firmware emits frames with swapped words (LE ordering) */ + swap_words(msgb_l3(msg), msgb_l3len(msg)); + break; + } + + /* unpack packed bits (MSB goes first) */ + osmo_pbit2ubit_ext(data, 0, msgb_l3(msg), 0, sizeof(data), 1); + + for (unsigned int i = 0; i < desc->num_blocks; i++) { + struct osmo_v110_decoded_frame df; + + if (desc->num_bits == 60) + osmo_csd_12k_6k_decode_frame(&df, &data[i * 60], 60); + else /* desc->num_bits == 36 */ + osmo_csd_3k6_decode_frame(&df, &data[i * 36], 36); + + /* E1/E2/E3 is out-of-band knowledge in GSM/CSD */ + memcpy(df.e_bits, state->e1e2e3, sizeof(state->e1e2e3)); + + osmo_v110_ta_frame_in(state->v110_ta, &df); + } + + if (state->suart != NULL) + osmo_soft_uart_flush_rx(state->suart); + + return 0; +} + +static int tch_csd_tx_to_l1(struct osmocom_ms *ms) +{ + struct tch_data_state *state = &ms->tch_state->data; + const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now; + const struct csd_v110_frame_desc *desc; + ubit_t data[60 * 4]; + struct msgb *nmsg; + + if ((cd->chan_nr & RSL_CHAN_NR_MASK) == RSL_CHAN_Bm_ACCHs) + desc = &csd_v110_lchan_desc[cd->mode].fr; + else /* RSL_CHAN_Lm_ACCHs */ + desc = &csd_v110_lchan_desc[cd->mode].hr; + if (OSMO_UNLIKELY(desc->num_blocks == 0)) + return -ENOTSUP; + + for (unsigned int i = 0; i < desc->num_blocks; i++) { + struct osmo_v110_decoded_frame df; + + if (osmo_v110_ta_frame_out(state->v110_ta, &df) != 0) + memset(&df, 0x01, sizeof(df)); + + /* If E1/E2/E3 bits indicate a meaningful user data rate (see Table 5/V.110), + * set E7 to binary 0 in every 4-th frame (as per 3GPP TS 44.021, subclause 10.2.1). + * ITU-T V.110 requires this only for 600 bps, but 3GPP TS 44.021 clearly states + * that "such a multiframe structure exists for all user data rates". */ + if ((df.e_bits[0] + df.e_bits[1] + df.e_bits[2]) == 2) + df.e_bits[6] = (state->num_tx != 0); + state->num_tx = (state->num_tx + 1) & 0x03; + + if (desc->num_bits == 60) + osmo_csd_12k_6k_encode_frame(&data[i * 60], 60, &df); + else /* desc->num_bits == 36 */ + osmo_csd_3k6_encode_frame(&data[i * 36], 36, &df); + } + + nmsg = msgb_alloc_headroom(33 + 64, 64, __func__); + OSMO_ASSERT(nmsg != NULL); + + nmsg->l2h = msgb_put(nmsg, 33); /* XXX: proper size */ + + /* pack unpacked bits (MSB goes first) */ + osmo_ubit2pbit_ext(msgb_l2(nmsg), 0, &data[0], 0, sizeof(data), 1); + + switch (ms->settings.tch_data.io_format) { + case TCH_DATA_IOF_OSMO: + break; + case TCH_DATA_IOF_TI: + /* the layer1 firmware expects frames with swapped words (LE ordering) */ + swap_words(msgb_l2(nmsg), msgb_l2len(nmsg)); + break; + } + + return gsm48_rr_tx_traffic(ms, nmsg); +} + +static int tch_data_check_bcap(const struct gsm_mncc_bearer_cap *bcap) +{ + if (bcap == NULL) { + LOGP(DL1C, LOGL_ERROR, + "%s(): CC transaction without BCap\n", + __func__); + return -ENODEV; + } + + if (bcap->mode != GSM48_BCAP_TMOD_CIRCUIT) { + LOGP(DCC, LOGL_ERROR, + "%s(): Transfer mode 0x%02x is not supported\n", + __func__, bcap->mode); + return -ENOTSUP; + } + if (bcap->coding != GSM48_BCAP_CODING_GSM_STD) { + LOGP(DCC, LOGL_ERROR, + "%s(): Coding standard 0x%02x is not supported\n", + __func__, bcap->coding); + return -ENOTSUP; + } + + switch (bcap->transfer) { + case GSM48_BCAP_ITCAP_UNR_DIG_INF: + case GSM48_BCAP_ITCAP_3k1_AUDIO: + case GSM48_BCAP_ITCAP_FAX_G3: + break; + default: + LOGP(DCC, LOGL_ERROR, + "%s(): Information transfer capability 0x%02x is not supported\n", + __func__, bcap->transfer); + return -ENOTSUP; + } + + if (bcap->data.rate_adaption != GSM48_BCAP_RA_V110_X30) { + LOGP(DCC, LOGL_ERROR, + "%s(): Rate adaption (octet 5) 0x%02x is not supported\n", + __func__, bcap->data.rate_adaption); + return -ENOTSUP; + } + if (bcap->data.sig_access != GSM48_BCAP_SA_I440_I450) { + LOGP(DCC, LOGL_ERROR, + "%s(): Signalling access protocol (octet 5) 0x%02x is not supported\n", + __func__, bcap->data.sig_access); + return -ENOTSUP; + } + if (bcap->data.transp != GSM48_BCAP_TR_TRANSP) { + LOGP(DCC, LOGL_ERROR, + "%s(): only transparent calls are supported so far\n", + __func__); + return -ENOTSUP; + } + + return 0; +} + +/*************************************************************************************/ + +int tch_data_recv(struct osmocom_ms *ms, struct msgb *msg) +{ + struct tch_data_state *state = &ms->tch_state->data; + + switch (state->handler) { + case TCH_DATA_IOH_LOOPBACK: + /* Remove the DL info header */ + msgb_pull_to_l2(msg); + /* Send data frame back */ + return tch_send_msg(ms, msg); + case TCH_DATA_IOH_UNIX_SOCK: + tch_csd_rx_from_l1(ms, msg); + tch_csd_tx_to_l1(ms); + msgb_free(msg); + break; + case TCH_DATA_IOH_NONE: + /* Drop voice frame */ + msgb_free(msg); + break; + } + + return 0; +} + +int tch_data_state_init(struct gsm_trans *trans, + struct tch_data_state *state) +{ + struct osmocom_ms *ms = trans->ms; + const struct gsm_mncc_bearer_cap *bcap = trans->cc.bcap; + int rc; + + if ((rc = tch_data_check_bcap(bcap)) != 0) + return rc; + + switch (state->handler) { + case TCH_DATA_IOH_UNIX_SOCK: + /* TODO: open listening socket */ + break; + case TCH_DATA_IOH_LOOPBACK: + case TCH_DATA_IOH_NONE: + /* we don't need V.110 TA / soft-UART */ + return 0; + default: + break; + } + + if (bcap->data.async) { + state->suart = tch_soft_uart_alloc(ms, bcap); + if (state->suart == NULL) + goto exit_free; + } + + state->v110_ta = tch_v110_ta_alloc(ms, bcap); + if (state->v110_ta == NULL) + goto exit_free; + + return 0; + +exit_free: + if (state->suart != NULL) + osmo_soft_uart_free(state->suart); + if (state->v110_ta != NULL) + osmo_v110_ta_free(state->v110_ta); + return -1; +} + +void tch_data_state_free(struct tch_data_state *state) +{ + switch (state->handler) { + case TCH_DATA_IOH_UNIX_SOCK: + /* TODO: close listening socket */ + break; + default: + break; + } + + if (state->suart != NULL) + osmo_soft_uart_free(state->suart); + if (state->v110_ta != NULL) + osmo_v110_ta_free(state->v110_ta); +} -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35582?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I7ac9c0e5010730fa4d8bc7a7a3c7ff85e11731c0 Gerrit-Change-Number: 35582 Gerrit-PatchSet: 6 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 0
0 0
[L] Change in osmocom-bb[master]: mobile: implement sending CSD data over UNIX socket
by fixeria 22 Jan '24

22 Jan '24
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/35583?usp=email ) Change subject: mobile: implement sending CSD data over UNIX socket ...................................................................... mobile: implement sending CSD data over UNIX socket Change-Id: Id054af7b3d9d0a41715f7981deb420f6e09bf30c Related: OS#4396 --- M src/host/layer23/include/osmocom/bb/mobile/tch.h M src/host/layer23/src/mobile/Makefile.am M src/host/layer23/src/mobile/tch_data.c A src/host/layer23/src/mobile/tch_data_sock.c 4 files changed, 319 insertions(+), 11 deletions(-) Approvals: laforge: Looks good to me, but someone else must approve Jenkins Builder: Verified fixeria: Looks good to me, approved pespin: Looks good to me, but someone else must approve diff --git a/src/host/layer23/include/osmocom/bb/mobile/tch.h b/src/host/layer23/include/osmocom/bb/mobile/tch.h index 8672860..92bc722 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/tch.h +++ b/src/host/layer23/include/osmocom/bb/mobile/tch.h @@ -13,6 +13,7 @@ } voice; struct tch_data_state { enum tch_data_io_handler handler; + struct tch_csd_sock_state *sock; struct osmo_v110_ta *v110_ta; struct osmo_soft_uart *suart; unsigned int num_tx; diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am index b4e45e2..d00e45e 100644 --- a/src/host/layer23/src/mobile/Makefile.am +++ b/src/host/layer23/src/mobile/Makefile.am @@ -33,6 +33,7 @@ primitives.c \ tch.c \ tch_data.c \ + tch_data_sock.c \ tch_voice.c \ transaction.c \ vty_interface.c \ diff --git a/src/host/layer23/src/mobile/tch_data.c b/src/host/layer23/src/mobile/tch_data.c index 9f46641..c58f485 100644 --- a/src/host/layer23/src/mobile/tch_data.c +++ b/src/host/layer23/src/mobile/tch_data.c @@ -72,21 +72,32 @@ }, }; +struct tch_csd_sock_state *tch_csd_sock_init(struct osmocom_ms *ms); +void tch_csd_sock_recv(struct tch_csd_sock_state *state, struct msgb *msg); +void tch_csd_sock_send(struct tch_csd_sock_state *state, struct msgb *msg); +void tch_csd_sock_exit(struct tch_csd_sock_state *state); + static void tch_soft_uart_rx_cb(void *priv, struct msgb *msg, unsigned int flags) { - LOGP(DL1C, LOGL_FATAL, "%s(): [flags=0x%08x] %s\n", + struct tch_data_state *state = (struct tch_data_state *)priv; + + LOGP(DL1C, LOGL_DEBUG, "%s(): [flags=0x%08x] %s\n", __func__, flags, msgb_hexdump(msg)); - msgb_free(msg); + + if (state->sock != NULL && msgb_length(msg) > 0) + tch_csd_sock_send(state->sock, msg); + else + msgb_free(msg); } static void tch_soft_uart_tx_cb(void *priv, struct msgb *msg) { - const char *data = "TEST\r\n"; - size_t n_bytes; + struct tch_data_state *state = (struct tch_data_state *)priv; - n_bytes = OSMO_MIN(msg->data_len, strlen(data)); - if (n_bytes > 0) - memcpy(msgb_put(msg, n_bytes), (void *)data, n_bytes); + tch_csd_sock_recv(state->sock, msg); + + LOGP(DL1C, LOGL_DEBUG, "%s(): [n_bytes=%u/%u] %s\n", + __func__, msg->len, msg->data_len, msgb_hexdump(msg)); } struct osmo_soft_uart *tch_soft_uart_alloc(struct osmocom_ms *ms, @@ -138,12 +149,28 @@ static void tch_v110_ta_rx_cb(void *priv, const ubit_t *buf, size_t buf_size) { - /* TODO: send to the configured I/O handler */ + const struct tch_data_state *state = (struct tch_data_state *)priv; + + if (state->sock != NULL && buf_size > 0) { + struct msgb *msg = msgb_alloc(buf_size, __func__); + tch_csd_sock_send(state->sock, msg); + } } static void tch_v110_ta_tx_cb(void *priv, ubit_t *buf, size_t buf_size) { - /* TODO: send to the configured I/O handler */ + const struct tch_data_state *state = (struct tch_data_state *)priv; + + if (state->sock != NULL && buf_size > 0) { + struct msgb *msg = msgb_alloc(buf_size, __func__); + + tch_csd_sock_recv(state->sock, msg); + if (msgb_length(msg) < buf_size) { + LOGP(DL1C, LOGL_NOTICE, + "%s(): not enough bytes for sync Tx (%u < %zu)\n", + __func__, msgb_length(msg), buf_size); + } + } } static void tch_v110_ta_async_rx_cb(void *priv, const ubit_t *buf, size_t buf_size) @@ -431,7 +458,9 @@ switch (state->handler) { case TCH_DATA_IOH_UNIX_SOCK: - /* TODO: open listening socket */ + state->sock = tch_csd_sock_init(ms); + if (state->sock == NULL) + return -ENOMEM; break; case TCH_DATA_IOH_LOOPBACK: case TCH_DATA_IOH_NONE: @@ -454,6 +483,8 @@ return 0; exit_free: + if (state->sock != NULL) + tch_csd_sock_exit(state->sock); if (state->suart != NULL) osmo_soft_uart_free(state->suart); if (state->v110_ta != NULL) @@ -465,7 +496,8 @@ { switch (state->handler) { case TCH_DATA_IOH_UNIX_SOCK: - /* TODO: close listening socket */ + if (state->sock != NULL) + tch_csd_sock_exit(state->sock); break; default: break; @@ -476,3 +508,24 @@ if (state->v110_ta != NULL) osmo_v110_ta_free(state->v110_ta); } + +void tch_csd_sock_state_cb(struct osmocom_ms *ms, bool connected) +{ + struct tch_data_state *state = NULL; + + if (ms->tch_state == NULL || ms->tch_state->is_voice) { + LOGP(DCC, LOGL_INFO, "No data call is ongoing, " + "ignoring [dis]connection event for CSD socket\n"); + return; + } + + state = &ms->tch_state->data; + osmo_v110_ta_set_circuit(state->v110_ta, OSMO_V110_TA_C_108, connected); + + /* GSM/CSD employs the modified 60-bit V.110 frame format, which is basically + * a stripped down version of the nurmal 80-bit V.110 frame without E1/E2/E3 + * bits and without the sync pattern. These 60-bit V.110 frames are perfectly + * aligned with the radio interface block boundaries, so we're always in sync. */ + if (connected) + osmo_v110_ta_sync_ind(state->v110_ta); +} diff --git a/src/host/layer23/src/mobile/tch_data_sock.c b/src/host/layer23/src/mobile/tch_data_sock.c new file mode 100644 index 0000000..7bfebf3 --- /dev/null +++ b/src/host/layer23/src/mobile/tch_data_sock.c @@ -0,0 +1,243 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de> + * Author: Vadim Yanitskiy <vyanitskiy(a)sysmocom.de> + * + * 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. + * + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <stdint.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/core/select.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> + +#include <osmocom/bb/common/logging.h> +#include <osmocom/bb/common/osmocom_data.h> +#include <osmocom/bb/common/ms.h> +#include <osmocom/bb/mobile/tch.h> + +struct tch_csd_sock_state { + struct osmocom_ms *ms; /* the MS instance we belong to */ + struct osmo_fd listen_bfd; /* fd for listen socket */ + struct osmo_fd conn_bfd; /* fd for a client connection */ + struct llist_head rxqueue; + struct llist_head txqueue; +}; + +void tch_csd_sock_state_cb(struct osmocom_ms *ms, bool connected); + +static void tch_csd_sock_close(struct tch_csd_sock_state *state) +{ + struct osmo_fd *bfd = &state->conn_bfd; + + LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock has closed connection\n"); + + tch_csd_sock_state_cb(state->ms, false); + + osmo_fd_unregister(bfd); + close(bfd->fd); + bfd->fd = -1; + + /* re-enable the generation of ACCEPT for new connections */ + osmo_fd_read_enable(&state->listen_bfd); + + /* flush the queues */ + while (!llist_empty(&state->rxqueue)) + msgb_free(msgb_dequeue(&state->rxqueue)); + while (!llist_empty(&state->txqueue)) + msgb_free(msgb_dequeue(&state->txqueue)); +} + +static int tch_csd_sock_read(struct osmo_fd *bfd) +{ + struct tch_csd_sock_state *state = (struct tch_csd_sock_state *)bfd->data; + struct msgb *msg; + int rc; + + msg = msgb_alloc(256, "tch_csd_sock_rx"); + if (!msg) + return -ENOMEM; + + rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0); + if (rc == 0) + goto close; + if (rc < 0) { + if (errno == EAGAIN) + return 0; + goto close; + } + + msgb_put(msg, rc); + msgb_enqueue(&state->rxqueue, msg); + return rc; + +close: + msgb_free(msg); + tch_csd_sock_close(state); + return -1; +} + +static int tch_csd_sock_write(struct osmo_fd *bfd) +{ + struct tch_csd_sock_state *state = bfd->data; + + while (!llist_empty(&state->txqueue)) { + struct msgb *msg; + int rc; + + /* dequeue a msgb */ + msg = msgb_dequeue(&state->txqueue); + + /* try to send it over the socket */ + rc = write(bfd->fd, msgb_data(msg), msgb_length(msg)); + if (rc < 0 && errno == EAGAIN) { + llist_add(&msg->list, &state->txqueue); + return 0; + } + msgb_free(msg); + if (rc <= 0) + goto close; + } + + osmo_fd_write_disable(bfd); + return 0; + +close: + tch_csd_sock_close(state); + return -1; +} + +static int tch_csd_sock_cb(struct osmo_fd *bfd, unsigned int flags) +{ + int rc = 0; + + if (flags & OSMO_FD_READ) { + rc = tch_csd_sock_read(bfd); + if (rc < 0) + return rc; + } + + if (flags & OSMO_FD_WRITE) + rc = tch_csd_sock_write(bfd); + + return rc; +} + +static int tch_csd_sock_accept(struct osmo_fd *bfd, unsigned int flags) +{ + struct tch_csd_sock_state *state = (struct tch_csd_sock_state *)bfd->data; + struct osmo_fd *conn_bfd = &state->conn_bfd; + struct sockaddr_un un_addr; + socklen_t len; + int rc; + + len = sizeof(un_addr); + rc = accept(bfd->fd, (struct sockaddr *)&un_addr, &len); + if (rc < 0) { + LOGP(DMOB, LOGL_ERROR, "Failed to accept() a new connection\n"); + return -1; + } + + if (conn_bfd->fd >= 0) { + LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock already has an active connection\n"); + close(rc); /* reject this connection request */ + return 0; + } + + osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, &tch_csd_sock_cb, state, 0); + if (osmo_fd_register(conn_bfd) != 0) { + LOGP(DMOB, LOGL_ERROR, "osmo_fd_register() failed\n"); + close(conn_bfd->fd); + conn_bfd->fd = -1; + return -1; + } + + LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock got a connection\n"); + + tch_csd_sock_state_cb(state->ms, true); + + return 0; +} + +struct tch_csd_sock_state *tch_csd_sock_init(struct osmocom_ms *ms) +{ + const char *sock_path = ms->settings.tch_data.unix_socket_path; + struct tch_csd_sock_state *state; + struct osmo_fd *bfd; + int rc; + + state = talloc_zero(ms, struct tch_csd_sock_state); + if (state == NULL) + return NULL; + + INIT_LLIST_HEAD(&state->rxqueue); + INIT_LLIST_HEAD(&state->txqueue); + state->conn_bfd.fd = -1; + state->ms = ms; + + bfd = &state->listen_bfd; + + rc = osmo_sock_unix_init_ofd(bfd, SOCK_STREAM, 0, sock_path, OSMO_SOCK_F_BIND); + if (rc < 0) { + LOGP(DMOB, LOGL_ERROR, "Could not create unix socket: %s\n", strerror(errno)); + talloc_free(state); + return NULL; + } + + bfd->cb = &tch_csd_sock_accept; + bfd->data = state; + + return state; +} + +void tch_csd_sock_exit(struct tch_csd_sock_state *state) +{ + if (state->conn_bfd.fd > -1) + tch_csd_sock_close(state); + osmo_fd_unregister(&state->listen_bfd); + close(state->listen_bfd.fd); + talloc_free(state); +} + +void tch_csd_sock_recv(struct tch_csd_sock_state *state, struct msgb *msg) +{ + while (msgb_tailroom(msg) > 0) { + struct msgb *rmsg = msgb_dequeue(&state->rxqueue); + if (rmsg == NULL) + break; + size_t len = OSMO_MIN(msgb_tailroom(msg), msgb_length(rmsg)); + memcpy(msgb_put(msg, len), msgb_data(rmsg), len); + msgb_pull(rmsg, len); + if (msgb_length(rmsg) > 0) + llist_add(&rmsg->list, &state->rxqueue); + else + msgb_free(rmsg); + } +} + +void tch_csd_sock_send(struct tch_csd_sock_state *state, struct msgb *msg) +{ + msgb_enqueue(&state->txqueue, msg); + osmo_fd_write_enable(&state->conn_bfd); +} -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35583?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: Id054af7b3d9d0a41715f7981deb420f6e09bf30c Gerrit-Change-Number: 35583 Gerrit-PatchSet: 7 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-CC: jolly <andreas(a)eversberg.eu> Gerrit-MessageType: merged
1 0
0 0
[S] Change in osmocom-bb[master]: mobile: fix unsupported data rate (UR/IR) messages
by fixeria 22 Jan '24

22 Jan '24
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/osmocom-bb/+/35638?usp=email ) Change subject: mobile: fix unsupported data rate (UR/IR) messages ...................................................................... mobile: fix unsupported data rate (UR/IR) messages Change-Id: I4f68cc999cb7bf9c5a17c8650de0411248420c1e Related: OS#4396 --- M src/host/layer23/src/mobile/mnccms.c M src/host/layer23/src/mobile/tch_data.c 2 files changed, 14 insertions(+), 4 deletions(-) Approvals: pespin: Looks good to me, but someone else must approve laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/host/layer23/src/mobile/mnccms.c b/src/host/layer23/src/mobile/mnccms.c index 8427191..c03eed5 100644 --- a/src/host/layer23/src/mobile/mnccms.c +++ b/src/host/layer23/src/mobile/mnccms.c @@ -409,8 +409,8 @@ break; default: LOGP(DMNCC, LOGL_ERROR, - "%s(): User rate 0x%02x (octets 6a) is not supported (IR=0x%02x)\n", - __func__, bcap->data.user_rate, bcap->data.interm_rate); + "%s(): IR 0x%02x / UR 0x%02x combination is not supported\n", + __func__, bcap->data.interm_rate, bcap->data.user_rate); return -ENOTSUP; } diff --git a/src/host/layer23/src/mobile/tch_data.c b/src/host/layer23/src/mobile/tch_data.c index c58f485..6ee89dc 100644 --- a/src/host/layer23/src/mobile/tch_data.c +++ b/src/host/layer23/src/mobile/tch_data.c @@ -234,8 +234,8 @@ case BCAP_RATE(GSM48_BCAP_IR_8k, GSM48_BCAP_UR_300): default: LOGP(DCC, LOGL_ERROR, - "%s(): User rate 0x%02x (octets 6a) is not supported (IR=0x%02x)\n", - __func__, bcap->data.user_rate, bcap->data.interm_rate); + "%s(): IR 0x%02x / UR 0x%02x combination is not supported\n", + __func__, bcap->data.interm_rate, bcap->data.user_rate); return NULL; } -- To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35638?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I4f68cc999cb7bf9c5a17c8650de0411248420c1e Gerrit-Change-Number: 35638 Gerrit-PatchSet: 1 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • ...
  • 156
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.