diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-12-20 18:56:47 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-12-20 18:56:47 +0100 |
commit | 3a41b80bd7868ced91abb2d48662024f5e50d1cb (patch) | |
tree | ecc972179d6f2deffe481c967e3a2e8db0bcc67d | |
parent | c751cf92cbc25a5cfca8041ef3fdcc16ed5865ad (diff) | |
parent | 2f25747e3f74dfa743363fb36069b78a19e0ce98 (diff) |
Merge branch 'zecke/abis-sw-selection'
-rw-r--r-- | openbsc/.gitignore | 1 | ||||
-rw-r--r-- | openbsc/configure.ac | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/abis_nm.h | 16 | ||||
-rw-r--r-- | openbsc/src/libbsc/abis_nm.c | 104 | ||||
-rw-r--r-- | openbsc/tests/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/tests/abis/Makefile.am | 17 | ||||
-rw-r--r-- | openbsc/tests/abis/abis_test.c | 169 | ||||
-rw-r--r-- | openbsc/tests/abis/abis_test.ok | 17 | ||||
-rw-r--r-- | openbsc/tests/testsuite.at | 6 |
9 files changed, 301 insertions, 32 deletions
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..4d6f866ee 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,8 @@ 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); +int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw, const size_t len); + #endif /* _NM_H */ diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c index e95c0a905..b74e77263 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,72 @@ 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; - } - ofs += 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; - 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; + /* final size */ + desc[desc_pos].len = &sw_descr[pos] - desc[desc_pos].start; } - 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; + return desc_pos; +} + +int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw_descr, + const size_t size) +{ + int res = 0; + int i; + + for (i = 1; i < size; ++i) { + if (memcmp(sw_descr[res].file_ver, sw_descr[i].file_ver, + OSMO_MIN(sw_descr[i].file_ver_len, sw_descr[res].file_ver_len)) < 0) { + res = i; + } } - ofs += len; - return ofs; + return res; } static int abis_nm_rx_sw_act_req(struct msgb *mb) @@ -409,7 +444,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, len; + struct abis_nm_sw_descr sw_descr[5]; abis_nm_debugp_foh(DNM, foh); @@ -439,16 +475,22 @@ 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 */ + len = abis_nm_parse_sw_config(sw_config, sw_config_len, + &sw_descr[0], ARRAY_SIZE(sw_descr)); + if (len <= 0) { + LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n"); return -EINVAL; + } + + ret = abis_nm_select_newest_sw(&sw_descr[0], len); + DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len); 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[ret].start, sw_descr[ret].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..4942a1e25 --- /dev/null +++ b/openbsc/tests/abis/abis_test.c @@ -0,0 +1,169 @@ +/* + * (C) 2012 by Holger Hans Peter Freyther <zecke@selfish.org> + * 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 <http://www.gnu.org/licenses/>. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <osmocom/core/application.h> +#include <osmocom/core/utils.h> + +#include <openbsc/gsm_data.h> +#include <openbsc/abis_nm.h> +#include <openbsc/debug.h> + +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 const uint8_t load_config[] = { + 0x42, 0x12, 0x00, 0x08, 0x31, 0x36, 0x38, 0x64, + 0x34, 0x37, 0x32, 0x00, 0x13, 0x00, 0x0b, 0x76, + 0x32, 0x30, 0x30, 0x62, 0x31, 0x34, 0x33, 0x64, + 0x30, 0x00, 0x42, 0x12, 0x00, 0x08, 0x31, 0x36, + 0x38, 0x64, 0x34, 0x37, 0x32, 0x00, 0x13, 0x00, + 0x0b, 0x76, 0x32, 0x30, 0x30, 0x62, 0x31, 0x34, + 0x33, 0x64, 0x31, 0x00 +}; + +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)); +} + +static void test_sw_selection(void) +{ + struct abis_nm_sw_descr descr[8], tmp; + int rc, pos; + + rc = abis_nm_parse_sw_config(load_config, ARRAY_SIZE(load_config), + &descr[0], ARRAY_SIZE(descr)); + if (rc != 2) { + printf("FAILED to parse the File Id/File version\n"); + 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)); + + /* start */ + pos = abis_nm_select_newest_sw(descr, rc); + if (pos != 1) { + printf("Selected the wrong version: %d\n", pos); + abort(); + } + printf("SELECTED: %d\n", pos); + + /* shuffle */ + tmp = descr[0]; + descr[0] = descr[1]; + descr[1] = tmp; + pos = abis_nm_select_newest_sw(descr, rc); + if (pos != 0) { + printf("Selected the wrong version: %d\n", pos); + abort(); + } + printf("SELECTED: %d\n", pos); +} + +int main(int argc, char **argv) +{ + osmo_init_logging(&log_info); + test_simple_sw_config(); + test_simple_sw_short(); + test_dual_sw_config(); + test_sw_selection(); + + 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..ba1da338a --- /dev/null +++ b/openbsc/tests/abis/abis_test.ok @@ -0,0 +1,17 @@ +Start: 0 len: 13 +file_id: 01 02 03 +file_ver: 03 04 05 +Start: 0 len: 13 +file_id: 01 02 03 +file_ver: 03 04 05 +Start: 13 len: 13 +file_id: 09 07 05 +file_ver: 06 07 08 +Start: 51 len: 26 +file_id: 31 36 38 64 34 37 32 00 +file_ver: 76 32 30 30 62 31 34 33 64 30 00 +Start: 77 len: 26 +file_id: 31 36 38 64 34 37 32 00 +file_ver: 76 32 30 30 62 31 34 33 64 31 00 +SELECTED: 1 +SELECTED: 0 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 |