Hi,
This a respin of my old series of patches[1], to add decoding of SMSCB messages on the MS side.
The series defines a new smscb_entity, which can be fed L1 messages from a CBCH, performs reassembly, and constructs equivalent SMS Broadcast Command (RSL_MT_SMS_BC_CMD) messages for L3.
I also have a follow-up patch for bb/cell_log which makes use of this functionality.
Please review and consider for merging, thanks.
[1] http://lists.osmocom.org/pipermail/baseband-devel/2010-November/000834.html
Alex Badea (8): gsm: add skeleton smscb module smscb: add unit test for smscb_entity smscb: process Null messages smscb test: support a list of L1 messages to test smscb: add test-case for reassembling a normal message smscb: add test-case for reassembling a Schedule message smscb: implement reassembly smscb: hook into LAPDm
include/Makefile.am | 1 + include/osmocom/gsm/lapdm.h | 3 + include/osmocom/gsm/smscb.h | 37 ++++++++ src/gsm/Makefile.am | 1 + src/gsm/lapdm.c | 13 +++ src/gsm/libosmogsm.map | 5 + src/gsm/smscb.c | 209 +++++++++++++++++++++++++++++++++++++++++++ tests/smscb/smscb_test.c | 118 ++++++++++++++++++++++++ tests/smscb/smscb_test.ok | 9 ++ tests/testsuite.at | 2 +- 10 files changed, 397 insertions(+), 1 deletions(-) create mode 100644 include/osmocom/gsm/smscb.h create mode 100644 src/gsm/smscb.c
Header files and skeleton functions for a SMSCB entity.
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- include/Makefile.am | 1 + include/osmocom/gsm/smscb.h | 28 ++++++++++++++++++ src/gsm/Makefile.am | 1 + src/gsm/libosmogsm.map | 5 +++ src/gsm/smscb.c | 65 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 0 deletions(-) create mode 100644 include/osmocom/gsm/smscb.h create mode 100644 src/gsm/smscb.c
diff --git a/include/Makefile.am b/include/Makefile.am index 60b9ea9..560fc54 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -66,6 +66,7 @@ nobase_include_HEADERS = \ osmocom/gsm/protocol/ipaccess.h \ osmocom/gsm/rsl.h \ osmocom/gsm/rxlev_stat.h \ + osmocom/gsm/smscb.h \ osmocom/gsm/sysinfo.h \ osmocom/gsm/tlv.h
diff --git a/include/osmocom/gsm/smscb.h b/include/osmocom/gsm/smscb.h new file mode 100644 index 0000000..88ba6e2 --- /dev/null +++ b/include/osmocom/gsm/smscb.h @@ -0,0 +1,28 @@ +#ifndef _OSMOCOM_SMSCB_H +#define _OSMOCOM_SMSCB_H + +/*! \defgroup smscb SMSCB implementation according to GSM TS 03.41 + * @{ + */ + +/*! \file smscb.h */ + +struct msgb; +struct smscb_entity; + +typedef int (*smscb_cb_t)(struct msgb *msg, struct smscb_entity *se, void *ctx); + +/*! \brief a SMSCB Entity */ +struct smscb_entity { + smscb_cb_t l3_cb; /*!< \brief callback for sending stuff to L3 */ + void *l3_ctx; /*!< \brief context for layer3 instance */ +}; + +void smscb_init(struct smscb_entity *se); +void smscb_exit(struct smscb_entity *se); +void smscb_set_l3(struct smscb_entity *se, smscb_cb_t cb, void *ctx); +int smscb_ph_data_ind(struct smscb_entity *se, struct msgb *msg); + +/*! @} */ + +#endif /* _OSMOCOM_SMSCB_H */ diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am index 6e2a785..3d79f7e 100644 --- a/src/gsm/Makefile.am +++ b/src/gsm/Makefile.am @@ -16,6 +16,7 @@ libosmogsm_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c gsm_utils.c \ gprs_cipher_core.c gsm0480.c abis_nm.c gsm0502.c \ gsm0411_utils.c gsm0411_smc.c gsm0411_smr.c \ lapd_core.c lapdm.c \ + smscb.c \ auth_core.c auth_comp128v1.c auth_milenage.c \ milenage/aes-encblock.c milenage/aes-internal.c \ milenage/aes-internal-enc.c milenage/milenage.c gan.c diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index b2278f1..674a85f 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -223,6 +223,11 @@ rxlev_stat_get_next; rxlev_stat_input; rxlev_stat_reset;
+smscb_init; +smscb_exit; +smscb_set_l3; +smscb_ph_data_ind; + tlv_def_patch; tlv_dump; tlv_parse; diff --git a/src/gsm/smscb.c b/src/gsm/smscb.c new file mode 100644 index 0000000..a9f38eb --- /dev/null +++ b/src/gsm/smscb.c @@ -0,0 +1,65 @@ +/* GSM SMSCB (TS 04.12) implementation */ + +/* (C) 2010,2013 by Alex Badea vamposdecampos@gmail.com + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +/*! \addtogroup smscb + * @{ + */ + +/*! \file smscb.c */ + +#include <osmocom/gsm/smscb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h> + +/*! \brief Initialize a SMSCB entity */ +void smscb_init(struct smscb_entity *se) +{ +} + +/*! \brief Deinitialize a smscb entity */ +void smscb_exit(struct smscb_entity *se) +{ +} + +/*! \brief Set the L3 callback and context of a SMSCB entity */ +void smscb_set_l3(struct smscb_entity *se, smscb_cb_t cb, void *ctx) +{ + se->l3_cb = cb; + se->l3_ctx = ctx; +} + +/*! \brief Input data from layer 1 */ +int smscb_ph_data_ind(struct smscb_entity *se, struct msgb *msg) +{ + uint8_t addr = msg->l2h[0]; + uint8_t seq = addr & 0x0f; + + LOGP(DLLAPD, LOGL_NOTICE, "SMSCB: received message: seq=%d len=%d\n", + seq, msg->len); + + msgb_free(msg); + return 0; +} + +/*! @} */ +
Since we've enabled logging, we now ignore stderr.
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- tests/smscb/smscb_test.c | 71 +++++++++++++++++++++++++++++++++++++++++++++ tests/smscb/smscb_test.ok | 3 ++ tests/testsuite.at | 2 +- 3 files changed, 75 insertions(+), 1 deletions(-)
diff --git a/tests/smscb/smscb_test.c b/tests/smscb/smscb_test.c index e10e12d..de88b0a 100644 --- a/tests/smscb/smscb_test.c +++ b/tests/smscb/smscb_test.c @@ -19,8 +19,76 @@ */
#include <osmocom/gsm/protocol/gsm_03_41.h> +#include <osmocom/gsm/smscb.h> +#include <osmocom/gsm/rsl.h> +#include <osmocom/gsm/tlv.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h>
#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define ASSERT(exp) \ + if (!(exp)) { \ + printf("Assert failed %s %s:%d\n", #exp, __FILE__, __LINE__); \ + abort(); \ + } + + +static struct log_info info = {}; + +static uint8_t smscb_null_l1_msg[] = { + 0x2f, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, +}; + +static int l3_cb(struct msgb *msg, struct smscb_entity *se, void *ctx) +{ + struct abis_rsl_cchan_hdr *ch; + struct tlv_parsed tv; + struct rsl_ie_cb_cmd_type *cmd_type; + struct gsm341_ms_message *cbmsg; + unsigned int cbmsglen; + + printf("smscb l3 cb\n"); + + ch = msgb_l2(msg); + ASSERT(ch != NULL); + ASSERT(ch->c.msg_discr == ABIS_RSL_MDISC_COM_CHAN | ABIS_RSL_MDISC_TRANSP); + ASSERT(ch->c.msg_type == RSL_MT_SMS_BC_CMD); + + rsl_tlv_parse(&tv, ch->data, msgb_l2len(msg) - sizeof(*ch)); + ASSERT(TLVP_PRESENT(&tv, RSL_IE_CB_CMD_TYPE)); + ASSERT(TLVP_PRESENT(&tv, RSL_IE_SMSCB_MSG)); + + cmd_type = (struct rsl_ie_cb_cmd_type *) TLVP_VAL(&tv, RSL_IE_CB_CMD_TYPE); + cbmsg = (struct gsm341_ms_message *) TLVP_VAL(&tv, RSL_IE_SMSCB_MSG); + cbmsglen = TLVP_LEN(&tv, RSL_IE_SMSCB_MSG); + + printf("cmd_type: %u\n", cmd_type->command); + printf("cbmsg:\t%s\n", osmo_hexdump((uint8_t *) cbmsg, cbmsglen)); +} + +static int smscb_send(struct smscb_entity *se, const void *data, size_t len) +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "data"); + msg->l2h = msgb_put(msg, len); + memcpy(msg->l2h, data, len); + return smscb_ph_data_ind(se, msg); +} + +static void test_reassembly(void) +{ + struct smscb_entity se; + + smscb_init(&se); + smscb_set_l3(&se, l3_cb, NULL); + smscb_send(&se, smscb_null_l1_msg, sizeof(smscb_null_l1_msg)); + smscb_exit(&se); +} +
static uint8_t smscb_msg[] = { 0x40, 0x10, 0x05, 0x0d, 0x01, 0x11 };
@@ -37,5 +105,8 @@ int main(int argc, char **argv) printf("(pge) page total: %d current: %d\n", msg->page.total, msg->page.current);
+ osmo_init_logging(&info); + test_reassembly(); + return 0; } diff --git a/tests/smscb/smscb_test.ok b/tests/smscb/smscb_test.ok index 347037f..5954fc6 100644 --- a/tests/smscb/smscb_test.ok +++ b/tests/smscb/smscb_test.ok @@ -2,3 +2,6 @@ (msg) msg_id: 1293 (dcs) group: 1 language: 0 (pge) page total: 1 current: 1 +smscb l3 cb +cmd_type: 15 +cbmsg: diff --git a/tests/testsuite.at b/tests/testsuite.at index 1cfae03..0f5b721 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -46,7 +46,7 @@ AT_CLEANUP AT_SETUP([smscb]) AT_KEYWORDS([smscb]) cat $abs_srcdir/smscb/smscb_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/smscb/smscb_test], [], [expout]) +AT_CHECK([$abs_top_builddir/tests/smscb/smscb_test], [], [expout], [ignore]) AT_CLEANUP
AT_SETUP([timer])
Pick smscb messages with a sequence-number of "null". For these, construct a RSL_MT_SMS_BC_CMD message and send it upstream.
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- src/gsm/smscb.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/src/gsm/smscb.c b/src/gsm/smscb.c index a9f38eb..db7f1cc 100644 --- a/src/gsm/smscb.c +++ b/src/gsm/smscb.c @@ -28,9 +28,21 @@ /*! \file smscb.c */
#include <osmocom/gsm/smscb.h> +#include <osmocom/gsm/rsl.h> +#include <osmocom/gsm/tlv.h> +#include <osmocom/gsm/protocol/gsm_04_12.h> +#include <osmocom/gsm/protocol/gsm_08_58.h> #include <osmocom/core/logging.h> #include <osmocom/core/msgb.h>
+#include <errno.h> + +#define SMSCB_ALLOC_SIZE 256 +#define SMSCB_ALLOC_HEADROOM 64 + +/* Link Protocol Discriminator for SMSCB */ +#define SMSCB_LPD 1 + /*! \brief Initialize a SMSCB entity */ void smscb_init(struct smscb_entity *se) { @@ -48,14 +60,65 @@ void smscb_set_l3(struct smscb_entity *se, smscb_cb_t cb, void *ctx) se->l3_ctx = ctx; }
+static int rslms_sendmsg(struct msgb *msg, struct smscb_entity *se) +{ + if (!se->l3_cb) { + msgb_free(msg); + return -EIO; + } + return se->l3_cb(msg, se, se->l3_ctx); +} + +static int smscb_rx_null_msg(struct smscb_entity *se) +{ + struct msgb *msg; + struct abis_rsl_cchan_hdr *ch; + struct rsl_ie_cb_cmd_type cmd_type = {}; + + msg = msgb_alloc_headroom( + SMSCB_ALLOC_HEADROOM + SMSCB_ALLOC_SIZE, + SMSCB_ALLOC_HEADROOM, "smscb_data"); + if (!msg) + return -ENOMEM; + + msg->l2h = msgb_put(msg, sizeof(*ch)); + ch = (struct abis_rsl_cchan_hdr *) msg->l2h; + rsl_init_cchan_hdr(ch, RSL_MT_SMS_BC_CMD); + ch->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; + /* TODO: we need ->chan_nr from L1: */ + ch->chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH8_ACCH, 2, 2); + + cmd_type.command = RSL_CB_CMD_TYPE_NULL; + msgb_tv_put(msg, RSL_IE_CB_CMD_TYPE, *((uint8_t *) &cmd_type)); + msgb_tlv_put(msg, RSL_IE_SMSCB_MSG, 0, NULL); + + /* + * TODO: we need ->frame_nr from L1: + * gsm_fn2gsmtime(&tm, ntohl(l1i->frame_nr)); + * msgb_tv_put(msg, RSL_IE_SMSCB_CHAN_INDICATOR, !(tm.tc < 4)); + */ + + return rslms_sendmsg(msg, se); +} + + + /*! \brief Input data from layer 1 */ int smscb_ph_data_ind(struct smscb_entity *se, struct msgb *msg) { - uint8_t addr = msg->l2h[0]; - uint8_t seq = addr & 0x0f; + struct gsm412_block_type *bt = (struct gsm412_block_type *) msg->l2h; + + LOGP(DLLAPD, LOGL_NOTICE, "SMSCB: received message: len=%d" + " seq=%d lb=%d lpd=%d spare=%d\n", + msg->len, bt->seq_nr, bt->lb, bt->lpd, bt->spare); + + if (bt->lpd != SMSCB_LPD) { + msgb_free(msg); + return -EINVAL; + }
- LOGP(DLLAPD, LOGL_NOTICE, "SMSCB: received message: seq=%d len=%d\n", - seq, msg->len); + if (bt->seq_nr == GSM412_SEQ_NULL_MSG) + smscb_rx_null_msg(se);
msgb_free(msg); return 0;
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- tests/smscb/smscb_test.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/tests/smscb/smscb_test.c b/tests/smscb/smscb_test.c index de88b0a..80cf69c 100644 --- a/tests/smscb/smscb_test.c +++ b/tests/smscb/smscb_test.c @@ -38,10 +38,13 @@
static struct log_info info = {};
-static uint8_t smscb_null_l1_msg[] = { - 0x2f, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, +static uint8_t smscb_test_messages[][23] = { + /* NULL message */ + { + 0x2f, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + }, };
static int l3_cb(struct msgb *msg, struct smscb_entity *se, void *ctx) @@ -82,10 +85,12 @@ static int smscb_send(struct smscb_entity *se, const void *data, size_t len) static void test_reassembly(void) { struct smscb_entity se; + int k;
smscb_init(&se); smscb_set_l3(&se, l3_cb, NULL); - smscb_send(&se, smscb_null_l1_msg, sizeof(smscb_null_l1_msg)); + for (k = 0; k < ARRAY_SIZE(smscb_test_messages); k++) + smscb_send(&se, smscb_test_messages[k], sizeof(smscb_test_messages[k])); smscb_exit(&se); }
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- tests/smscb/smscb_test.c | 21 +++++++++++++++++++++ tests/smscb/smscb_test.ok | 3 +++ 2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/tests/smscb/smscb_test.c b/tests/smscb/smscb_test.c index 80cf69c..9948f5f 100644 --- a/tests/smscb/smscb_test.c +++ b/tests/smscb/smscb_test.c @@ -45,6 +45,27 @@ static uint8_t smscb_test_messages[][23] = { 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, }, + /* 4 blocks with a normal message */ + { + 0x20, 0x00, 0x70, 0x00, 0x32, 0x01, 0x11, 0x3c, + 0xaa, 0xaf, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, + 0xa3, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, + }, + { + 0x21, 0xa3, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, + 0xa3, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, + 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, + }, + { + 0x22, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, + 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, + 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, + }, + { + 0x23, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, + 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, 0x68, + 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, 0x00, + }, };
static int l3_cb(struct msgb *msg, struct smscb_entity *se, void *ctx) diff --git a/tests/smscb/smscb_test.ok b/tests/smscb/smscb_test.ok index 5954fc6..c4dd4b8 100644 --- a/tests/smscb/smscb_test.ok +++ b/tests/smscb/smscb_test.ok @@ -5,3 +5,6 @@ smscb l3 cb cmd_type: 15 cbmsg: +smscb l3 cb +cmd_type: 0 +cbmsg: 00 70 00 32 01 11 3c aa af d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 00
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- tests/smscb/smscb_test.c | 21 +++++++++++++++++++++ tests/smscb/smscb_test.ok | 3 +++ 2 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/tests/smscb/smscb_test.c b/tests/smscb/smscb_test.c index 9948f5f..779c2af 100644 --- a/tests/smscb/smscb_test.c +++ b/tests/smscb/smscb_test.c @@ -66,6 +66,27 @@ static uint8_t smscb_test_messages[][23] = { 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, 0x68, 0x34, 0x1a, 0x8d, 0x46, 0xa3, 0xd1, 0x00, }, + /* 4 blocks with a Schedule message */ + { + 0x28, 0x01, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x32, 0x40, 0x40, 0x40, 0x01, 0x40, + 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, 0x01, + }, + { + 0x21, 0x40, 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, + 0x01, 0x40, 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, + 0x01, 0x40, 0x40, 0x2b, 0x2b, 0x2b, 0x2b, + }, + { + 0x22, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + }, + { + 0x23, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + }, };
static int l3_cb(struct msgb *msg, struct smscb_entity *se, void *ctx) diff --git a/tests/smscb/smscb_test.ok b/tests/smscb/smscb_test.ok index c4dd4b8..f28ab5b 100644 --- a/tests/smscb/smscb_test.ok +++ b/tests/smscb/smscb_test.ok @@ -8,3 +8,6 @@ cbmsg: smscb l3 cb cmd_type: 0 cbmsg: 00 70 00 32 01 11 3c aa af d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 68 34 1a 8d 46 a3 d1 00 +smscb l3 cb +cmd_type: 8 +cbmsg: 01 1f 00 00 00 00 00 00 80 32 40 40 40 01 40 40 40 01 40 40 40 01 40 40 40 01 40 40 40 01 40 40 40 01 40 40 40 01 40 40 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
Signed-off-by: Alex Badea vamposdecampos@gmail.com --- include/osmocom/gsm/smscb.h | 9 ++++ src/gsm/smscb.c | 95 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 7 deletions(-)
diff --git a/include/osmocom/gsm/smscb.h b/include/osmocom/gsm/smscb.h index 88ba6e2..05f33ef 100644 --- a/include/osmocom/gsm/smscb.h +++ b/include/osmocom/gsm/smscb.h @@ -1,12 +1,16 @@ #ifndef _OSMOCOM_SMSCB_H #define _OSMOCOM_SMSCB_H
+#include <stdint.h> + /*! \defgroup smscb SMSCB implementation according to GSM TS 03.41 * @{ */
/*! \file smscb.h */
+#define SMSCB_MAX_BLOCKS 4 + struct msgb; struct smscb_entity;
@@ -16,8 +20,13 @@ typedef int (*smscb_cb_t)(struct msgb *msg, struct smscb_entity *se, void *ctx); struct smscb_entity { smscb_cb_t l3_cb; /*!< \brief callback for sending stuff to L3 */ void *l3_ctx; /*!< \brief context for layer3 instance */ + + uint8_t seq_next; /*!< \brief next expected sequence number */ + uint8_t sched:1; /*!< \brief 1 if we're processing a Schedule message */ + struct msgb *blocks[SMSCB_MAX_BLOCKS]; /*!< \brief stored blocks for reassembly */ };
+ void smscb_init(struct smscb_entity *se); void smscb_exit(struct smscb_entity *se); void smscb_set_l3(struct smscb_entity *se, smscb_cb_t cb, void *ctx); diff --git a/src/gsm/smscb.c b/src/gsm/smscb.c index db7f1cc..d9a0ccf 100644 --- a/src/gsm/smscb.c +++ b/src/gsm/smscb.c @@ -43,14 +43,28 @@ /* Link Protocol Discriminator for SMSCB */ #define SMSCB_LPD 1
+static void smscb_reset(struct smscb_entity *se) +{ + int k; + + for (k = 0; k < SMSCB_MAX_BLOCKS; k++) { + msgb_free(se->blocks[k]); + se->blocks[k] = NULL; + } + se->sched = 0; + se->seq_next = 0; +} + /*! \brief Initialize a SMSCB entity */ void smscb_init(struct smscb_entity *se) { + memset(se, 0, sizeof(*se)); }
/*! \brief Deinitialize a smscb entity */ void smscb_exit(struct smscb_entity *se) { + smscb_reset(se); }
/*! \brief Set the L3 callback and context of a SMSCB entity */ @@ -69,11 +83,13 @@ static int rslms_sendmsg(struct msgb *msg, struct smscb_entity *se) return se->l3_cb(msg, se, se->l3_ctx); }
-static int smscb_rx_null_msg(struct smscb_entity *se) +static int smscb_rx_msg(struct smscb_entity *se) { struct msgb *msg; struct abis_rsl_cchan_hdr *ch; struct rsl_ie_cb_cmd_type cmd_type = {}; + int k; + uint8_t msglen, *tlv;
msg = msgb_alloc_headroom( SMSCB_ALLOC_HEADROOM + SMSCB_ALLOC_SIZE, @@ -81,6 +97,9 @@ static int smscb_rx_null_msg(struct smscb_entity *se) if (!msg) return -ENOMEM;
+ for (k = 0, msglen = 0; se->blocks[k] && k < SMSCB_MAX_BLOCKS; k++) + msglen += se->blocks[k]->len; + msg->l2h = msgb_put(msg, sizeof(*ch)); ch = (struct abis_rsl_cchan_hdr *) msg->l2h; rsl_init_cchan_hdr(ch, RSL_MT_SMS_BC_CMD); @@ -88,9 +107,24 @@ static int smscb_rx_null_msg(struct smscb_entity *se) /* TODO: we need ->chan_nr from L1: */ ch->chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH8_ACCH, 2, 2);
- cmd_type.command = RSL_CB_CMD_TYPE_NULL; + cmd_type.command = + se->sched ? RSL_CB_CMD_TYPE_SCHEDULE : + msglen ? RSL_CB_CMD_TYPE_NORMAL : + RSL_CB_CMD_TYPE_NULL; + cmd_type.last_block = + se->blocks[3] ? RSL_CB_CMD_LASTBLOCK_4 : + se->blocks[2] ? RSL_CB_CMD_LASTBLOCK_3 : + se->blocks[1] ? RSL_CB_CMD_LASTBLOCK_2 : + RSL_CB_CMD_LASTBLOCK_1; msgb_tv_put(msg, RSL_IE_CB_CMD_TYPE, *((uint8_t *) &cmd_type)); - msgb_tlv_put(msg, RSL_IE_SMSCB_MSG, 0, NULL); + + tlv = msgb_put(msg, TLV_GROSS_LEN(msglen)); + *tlv++ = RSL_IE_SMSCB_MSG; + *tlv++ = msglen; + for (k = 0; se->blocks[k] && k < SMSCB_MAX_BLOCKS; k++) { + memcpy(tlv, se->blocks[k]->data, se->blocks[k]->len); + tlv += se->blocks[k]->len; + }
/* * TODO: we need ->frame_nr from L1: @@ -107,6 +141,8 @@ static int smscb_rx_null_msg(struct smscb_entity *se) int smscb_ph_data_ind(struct smscb_entity *se, struct msgb *msg) { struct gsm412_block_type *bt = (struct gsm412_block_type *) msg->l2h; + uint8_t seq; + uint8_t last;
LOGP(DLLAPD, LOGL_NOTICE, "SMSCB: received message: len=%d" " seq=%d lb=%d lpd=%d spare=%d\n", @@ -117,11 +153,56 @@ int smscb_ph_data_ind(struct smscb_entity *se, struct msgb *msg) return -EINVAL; }
- if (bt->seq_nr == GSM412_SEQ_NULL_MSG) - smscb_rx_null_msg(se); + msgb_pull(msg, sizeof(*bt)); + seq = bt->seq_nr & 3; + last = bt->lb; + + if (bt->seq_nr == GSM412_SEQ_NULL_MSG) { + smscb_reset(se); + smscb_rx_msg(se); + msgb_free(msg); + return 0; + } + + if (seq != se->seq_next) { + LOGP(DLLAPD, LOGL_ERROR, "SMSCB: got sequence %d (expected %d)\n", + bt->seq_nr, se->seq_next); + smscb_reset(se); + if (seq) { + msgb_free(msg); + return -EINVAL; + } + }
- msgb_free(msg); - return 0; + switch (bt->seq_nr) { + case GSM412_SEQ_FST_SCHED_BLOCK: + se->sched = 1; + break; + case GSM412_SEQ_FTH_BLOCK: + last = 1; + break; + } + + switch (bt->seq_nr) { + case GSM412_SEQ_FST_SCHED_BLOCK: + case GSM412_SEQ_FST_BLOCK: + case GSM412_SEQ_SND_BLOCK: + case GSM412_SEQ_TRD_BLOCK: + case GSM412_SEQ_FTH_BLOCK: + msgb_free(se->blocks[seq]); + se->blocks[seq] = msg; + se->seq_next = seq + 1; + if (!last) + return 0; + smscb_rx_msg(se); + smscb_reset(se); + return 0; + default: + LOGP(DLLAPD, LOGL_ERROR, "SMSCB: unhandled sequence number %d\n", + bt->seq_nr); + msgb_free(msg); + return -EINVAL; + } }
/*! @} */
Add a smscb_entity to each lapdm_entity. Pass LAPDm messages having LPD=01 up to SMSCB. Pass L3 messages output by SMSCB to the L3 entity registered with LAPDm.
Signed-off-by: Alex Badea vamposdecampos@gmail.com ---
This makes L3 get SMSCB decoding for free. It worksforme, but I'm not sure how it might interact with e.g. the BTS side. An alternative is to hook smscb_entity into the bb layer3 apps themselves; suggestions are welcome.
include/osmocom/gsm/lapdm.h | 3 +++ src/gsm/lapdm.c | 13 +++++++++++++ 2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/osmocom/gsm/lapdm.h b/include/osmocom/gsm/lapdm.h index 571fd46..e1fd4f0 100644 --- a/include/osmocom/gsm/lapdm.h +++ b/include/osmocom/gsm/lapdm.h @@ -2,6 +2,7 @@ #define _OSMOCOM_LAPDM_H
#include <osmocom/gsm/lapd_core.h> +#include <osmocom/gsm/smscb.h>
/*! \defgroup lapdm LAPDm implementation according to GSM TS 04.06 * @{ @@ -113,6 +114,8 @@ struct lapdm_entity {
/*! \brief pointer to \ref lapdm_channel of which we're part */ struct lapdm_channel *lapdm_ch; + /*! \brief SMSCB entity associated with this LAPDm entity */ + struct smscb_entity smscb;
uint8_t ta; /* TA used and indicated to network */ uint8_t tx_power; /* MS power used and indicated to network */ diff --git a/src/gsm/lapdm.c b/src/gsm/lapdm.c index 2bda48a..fcce526 100644 --- a/src/gsm/lapdm.c +++ b/src/gsm/lapdm.c @@ -114,6 +114,7 @@ enum lapdm_format { static int lapdm_send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg); static int send_rslms_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); +static int lapdm_smscb_cb(struct msgb *msg, struct smscb_entity *se, void *ctx);
static void lapdm_dl_init(struct lapdm_datalink *dl, struct lapdm_entity *entity, int t200) @@ -142,6 +143,8 @@ void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode, int t200) lapdm_dl_init(&le->datalink[i], le, t200);
lapdm_entity_set_mode(le, mode); + smscb_init(&le->smscb); + smscb_set_l3(&le->smscb, lapdm_smscb_cb, le); }
/*! \brief initialize a LAPDm channel and all its channels @@ -168,6 +171,7 @@ void lapdm_entity_exit(struct lapdm_entity *le) dl = &le->datalink[i]; lapd_dl_exit(&dl->dl); } + smscb_exit(&le->smscb); }
/* \brief lfush and release all resources in LAPDm channel @@ -229,6 +233,12 @@ static int rslms_sendmsg(struct msgb *msg, struct lapdm_entity *le) return le->l3_cb(msg, le, le->l3_ctx); }
+/* input function from smscb up to L3 */ +static int lapdm_smscb_cb(struct msgb *msg, struct smscb_entity *se, void *ctx) +{ + return rslms_sendmsg(msg, ctx); +} + /* write a frame into the tx queue */ static int tx_ph_data_enqueue(struct lapdm_datalink *dl, struct msgb *msg, uint8_t chan_nr, uint8_t link_id, uint8_t pad) @@ -543,6 +553,9 @@ static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, LOGP(DLLAPD, LOGL_INFO, "fmt=B\n"); n201 = N201_AB_SDCCH; sapi = (msg->l2h[0] >> 2) & 7; + + if (LAPDm_ADDR_LPD(msg->l2h[0]) == LAPDm_LPD_SMSCB) + return smscb_ph_data_ind(&le->smscb, msg); } }
Hi,
This a respin of my old series of patches[1], to add decoding of SMSCB messages on the MS side.
Before I dig deeper, a quick question:
Why in libosmocore ? This implementation is MS side only right ? so can't be re-used to implement smscb in OpenBSC or OsmoBTS.
Cheers,
Sylvain
Hi,
On Sun, Jan 6, 2013 at 12:34 AM, Sylvain Munaut 246tnt@gmail.com wrote:
Hi,
This a respin of my old series of patches[1], to add decoding of SMSCB messages on the MS side.
Before I dig deeper, a quick question:
Why in libosmocore ? This implementation is MS side only right ? so can't be re-used to implement smscb in OpenBSC or OsmoBTS.
Inertia would be one reason -- since my first patchset, LAPDm has moved from BB into libosmocore, so I just tagged along.
On the practical side, I see two reasons now:
i) if we want to hook it into LAPDm, it needs to be where lapdm.c is
ii) libosmocore has a testsuite, so I could just stuff some testcases in there
In the future, we can also add the BTS-side implementation. I don't think they can share much code, but it might make sense to have both in the same place.
I can spin a patch series directly on top of osmocom-bb, but the testcases will probably not make it.
Thanks, Alex
Hi,
Inertia would be one reason -- since my first patchset, LAPDm has moved from BB into libosmocore, so I just tagged along.
On the practical side, I see two reasons now:
i) if we want to hook it into LAPDm, it needs to be where lapdm.c is
After starting to read the spec (not done yet, so further comments my come afterwards), I don't think "hooking" LAPDm is the right way.
On Sun, Jan 6, 2013 at 5:10 PM, Sylvain Munaut 246tnt@gmail.com wrote:
i) if we want to hook it into LAPDm, it needs to be where lapdm.c is
After starting to read the spec (not done yet, so further comments my come afterwards), I don't think "hooking" LAPDm is the right way.
From the specs, LAPDm and the SMSCB link layer are not one above the other but rather completely separate. And again from the spec, should you expect one or the other on a channel, you must ignore any packets with the wrong LPD. So AFAIK on a CBCH channel if you ever get a LPD=00 it should be ignored and not fed to a LAPDm processor. Same thing for a BTS side LAPDm instance if it receives a LPD=01 it should be ignored.
I did get confused by that. I parsed that the LPD field is specified by LAPDm (TS 04.06), and it indicates a possible sublayer.
Now that I re-read 04.06, it does say that only LPD=00 is valid for LAPDm, so other values must be other protocols.
[...]
That all makes sense, I'll give it a try.
Thanks for the feedback.
baseband-devel@lists.osmocom.org