From bce5675e5fa1eb4bcbe0dd24d503456eaeb58a0d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Nov 2012 14:59:46 +0100 Subject: [PATCH] abis: Create a routine that can parse all SW Descriptions of a SW Config Be able to parse the entire SW Config IE. Parse the SW Descruption into a struct provided by the caller. --- openbsc/.gitignore | 1 + openbsc/configure.ac | 1 + openbsc/include/openbsc/abis_nm.h | 15 ++++ openbsc/src/libbsc/abis_nm.c | 91 ++++++++++++++--------- openbsc/tests/Makefile.am | 2 +- openbsc/tests/abis/Makefile.am | 17 +++++ openbsc/tests/abis/abis_test.c | 118 ++++++++++++++++++++++++++++++ openbsc/tests/abis/abis_test.ok | 9 +++ openbsc/tests/testsuite.at | 6 ++ 9 files changed, 225 insertions(+), 35 deletions(-) create mode 100644 openbsc/tests/abis/Makefile.am create mode 100644 openbsc/tests/abis/abis_test.c create mode 100644 openbsc/tests/abis/abis_test.ok diff --git a/openbsc/.gitignore b/openbsc/.gitignore index f345baccd..bf909f59f 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -58,6 +58,7 @@ tests/sccp/sccp_test tests/sms/sms_test tests/timer/timer_test tests/gprs/gprs_test +tests/abis/abis_test tests/atconfig tests/atlocal diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 1bb660fab..91ae08aeb 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -151,6 +151,7 @@ AC_OUTPUT( tests/mgcp/Makefile tests/gprs/Makefile tests/si/Makefile + tests/abis/Makefile doc/Makefile doc/examples/Makefile Makefile) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 9c4cc3309..51f11e975 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -66,6 +66,18 @@ struct abis_nm_cfg { int (*sw_act_req)(struct msgb *); }; +struct abis_nm_sw_descr { + /* where does it start? how long is it? */ + const uint8_t *start; + size_t len; + + /* the parsed data */ + const uint8_t *file_id; + uint16_t file_id_len; + const uint8_t *file_ver; + uint16_t file_ver_len; +}; + extern int abis_nm_rcvmsg(struct msgb *msg); int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_t *buf, int len); @@ -167,4 +179,7 @@ int _abis_nm_sendmsg(struct msgb *msg); void abis_nm_queue_send_next(struct gsm_bts *bts); /* for bs11_config. */ +int abis_nm_parse_sw_config(const uint8_t *data, const size_t len, + struct abis_nm_sw_descr *res, const int res_len); + #endif /* _NM_H */ diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c index e95c0a905..7485a6cce 100644 --- a/openbsc/src/libbsc/abis_nm.c +++ b/openbsc/src/libbsc/abis_nm.c @@ -359,7 +359,8 @@ static int ipacc_sw_activate(struct gsm_bts *bts, uint8_t obj_class, uint8_t i0, return abis_nm_sendmsg(bts, msg); } -static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len) +int abis_nm_parse_sw_config(const uint8_t *sw_descr, const size_t sw_descr_len, + struct abis_nm_sw_descr *desc, const int res_len) { static const struct tlv_definition sw_descr_def = { .def = { @@ -368,38 +369,56 @@ static int abis_nm_parse_sw_descr(const uint8_t *sw_descr, int sw_descr_len) }, }; - uint8_t tag; - uint16_t tag_len; - const uint8_t *val; - int ofs = 0, len; + size_t pos = 0; + int desc_pos = 0; - /* Classic TLV parsing doesn't work well with SW_DESCR because of it's - * nested nature and the fact you have to assume it contains only two sub - * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */ + for (pos = 0; pos < sw_descr_len && desc_pos < res_len; ++desc_pos) { + uint8_t tag; + uint16_t tag_len; + const uint8_t *val; + int len; - if (sw_descr[0] != NM_ATT_SW_DESCR) { - DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n"); - return -1; + memset(&desc[desc_pos], 0, sizeof(desc[desc_pos])); + desc[desc_pos].start = &sw_descr[pos]; + + /* Classic TLV parsing doesn't work well with SW_DESCR because of it's + * nested nature and the fact you have to assume it contains only two sub + * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */ + if (sw_descr[pos] != NM_ATT_SW_DESCR) { + LOGP(DNM, LOGL_ERROR, + "SW_DESCR attribute identifier not found!\n"); + return -1; + } + + pos += 1; + len = tlv_parse_one(&tag, &tag_len, &val, + &sw_descr_def, &sw_descr[pos], sw_descr_len - pos); + if (len < 0 || (tag != NM_ATT_FILE_ID)) { + LOGP(DNM, LOGL_ERROR, + "FILE_ID attribute identifier not found!\n"); + return -2; + } + desc[desc_pos].file_id = val; + desc[desc_pos].file_id_len = tag_len; + pos += len; + + + len = tlv_parse_one(&tag, &tag_len, &val, + &sw_descr_def, &sw_descr[pos], sw_descr_len - pos); + if (len < 0 || (tag != NM_ATT_FILE_VERSION)) { + LOGP(DNM, LOGL_ERROR, + "FILE_VERSION attribute identifier not found!\n"); + return -3; + } + desc[desc_pos].file_ver = val; + desc[desc_pos].file_ver_len = tag_len; + pos += len; + + /* final size */ + desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start; } - ofs += 1; - len = tlv_parse_one(&tag, &tag_len, &val, - &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs); - if (len < 0 || (tag != NM_ATT_FILE_ID)) { - DEBUGP(DNM, "FILE_ID attribute identifier not found!\n"); - return -2; - } - ofs += len; - - len = tlv_parse_one(&tag, &tag_len, &val, - &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs); - if (len < 0 || (tag != NM_ATT_FILE_VERSION)) { - DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n"); - return -3; - } - ofs += len; - - return ofs; + return desc_pos; } static int abis_nm_rx_sw_act_req(struct msgb *mb) @@ -409,7 +428,8 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) struct e1inp_sign_link *sign_link = mb->dst; struct tlv_parsed tp; const uint8_t *sw_config; - int ret, sw_config_len, sw_descr_len; + int ret, sw_config_len; + struct abis_nm_sw_descr sw_descr[1]; abis_nm_debugp_foh(DNM, foh); @@ -439,16 +459,19 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len)); } - /* Use the first SW_DESCR present in SW config */ - sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len); - if (sw_descr_len < 0) + /* Parse up to two sw descriptions from the data */ + ret = abis_nm_parse_sw_config(sw_config, sw_config_len, + &sw_descr[0], ARRAY_SIZE(sw_descr)); + if (ret <= 0) { + LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n"); return -EINVAL; + } return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr, - sw_config, sw_descr_len); + sw_descr[0].start, sw_descr[0].len); } /* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */ diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index cede8e824..7ea4cff67 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gsm0408 db channel mgcp gprs si +SUBDIRS = gsm0408 db channel mgcp gprs si abis if BUILD_NAT SUBDIRS += bsc-nat diff --git a/openbsc/tests/abis/Makefile.am b/openbsc/tests/abis/Makefile.am new file mode 100644 index 000000000..3255ecf55 --- /dev/null +++ b/openbsc/tests/abis/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) $(COVERAGE_CFLAGS) + +EXTRA_DIST = abis_test.ok + +noinst_PROGRAMS = abis_test + +abis_test_SOURCES = abis_test.c + +abis_test_LDADD = \ + $(top_builddir)/src/libbsc/libbsc.a \ + $(top_builddir)/src/libcommon/libcommon.a \ + $(top_builddir)/src/libbsc/libbsc.a \ + $(top_builddir)/src/libtrau/libtrau.a \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOABIS_LIBS) \ + $(LIBOSMOGSM_LIBS) diff --git a/openbsc/tests/abis/abis_test.c b/openbsc/tests/abis/abis_test.c new file mode 100644 index 000000000..a2f6a05c2 --- /dev/null +++ b/openbsc/tests/abis/abis_test.c @@ -0,0 +1,118 @@ +/* + * (C) 2012 by Holger Hans Peter Freyther + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include + +#include +#include + +#include +#include +#include + +static const uint8_t simple_config[] = { + /*0, 13, */ + 66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5, +}; + +static const uint8_t dual_config[] = { + /*0, 26, */ + 66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5, + 66, 18, 0, 3, 9, 7, 5, 19, 0, 3, 6, 7, 8, +}; + +static void test_simple_sw_config(void) +{ + struct abis_nm_sw_descr descr[1]; + int rc; + + rc = abis_nm_parse_sw_config(simple_config, ARRAY_SIZE(simple_config), + &descr[0], ARRAY_SIZE(descr)); + if (rc != 1) { + printf("FAILED to parse the File Id/File version\n"); + abort(); + } + + if (descr[0].len != 13) { + printf("WRONG SIZE: %d\n", descr[0].len); + abort(); + } + + printf("Start: %u len: %zu\n", descr[0].start - simple_config, descr[0].len); + printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); + printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len)); +} + +static void test_simple_sw_short(void) +{ + struct abis_nm_sw_descr descr[1]; + int i; + + for (i = 1; i < ARRAY_SIZE(simple_config); ++i) { + int rc = abis_nm_parse_sw_config(simple_config, + ARRAY_SIZE(simple_config) - i, &descr[0], + ARRAY_SIZE(descr)); + if (rc >= 1) { + printf("SHOULD not have parsed: %d\n", rc); + abort(); + } + } +} + +static void test_dual_sw_config(void) +{ + struct abis_nm_sw_descr descr[2]; + int rc; + + rc = abis_nm_parse_sw_config(dual_config, ARRAY_SIZE(dual_config), + &descr[0], ARRAY_SIZE(descr)); + if (rc != 2) { + printf("FAILED to parse the File Id/File version\n"); + abort(); + } + + if (descr[0].len != 13) { + printf("WRONG SIZE0: %d\n", descr[0].len); + abort(); + } + + if (descr[1].len != 13) { + printf("WRONG SIZE1: %d\n", descr[1].len); + abort(); + } + + printf("Start: %u len: %zu\n", descr[0].start - dual_config, descr[0].len); + printf("file_id: %s\n", osmo_hexdump(descr[0].file_id, descr[0].file_id_len)); + printf("file_ver: %s\n", osmo_hexdump(descr[0].file_ver, descr[0].file_ver_len)); + + printf("Start: %u len: %zu\n", descr[1].start - dual_config, descr[1].len); + printf("file_id: %s\n", osmo_hexdump(descr[1].file_id, descr[1].file_id_len)); + printf("file_ver: %s\n", osmo_hexdump(descr[1].file_ver, descr[1].file_ver_len)); +} + +int main(int argc, char **argv) +{ + osmo_init_logging(&log_info); + test_simple_sw_config(); + test_simple_sw_short(); + test_dual_sw_config(); + + return EXIT_SUCCESS; +} diff --git a/openbsc/tests/abis/abis_test.ok b/openbsc/tests/abis/abis_test.ok new file mode 100644 index 000000000..64019880c --- /dev/null +++ b/openbsc/tests/abis/abis_test.ok @@ -0,0 +1,9 @@ +Start: 0 len: 13 +file_id: 01 02 03 +file_ver: 03 04 05 +Start: 13 len: 26 +file_id: 01 02 03 +file_ver: 03 04 05 +Start: 26 len: 13 +file_id: 09 07 05 +file_ver: 06 07 08 diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 8e1277312..4c5de8d6a 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -43,3 +43,9 @@ AT_KEYWORDS([si]) cat $abs_srcdir/si/si_test.ok > expout AT_CHECK([$abs_top_builddir/tests/si/si_test], [], [expout], [ignore]) AT_CLEANUP + +AT_SETUP([abis]) +AT_KEYWORDS([abis]) +cat $abs_srcdir/abis/abis_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/abis/abis_test], [], [expout], [ignore]) +AT_CLEANUP