diff options
-rw-r--r-- | include/osmo-bts/Makefile.am | 2 | ||||
-rw-r--r-- | include/osmo-bts/msg_utils.h | 20 | ||||
-rw-r--r-- | include/osmo-bts/oml.h | 4 | ||||
-rw-r--r-- | src/common/Makefile.am | 2 | ||||
-rw-r--r-- | src/common/msg_utils.c | 174 | ||||
-rw-r--r-- | src/common/oml.c | 12 | ||||
-rw-r--r-- | src/osmo-bts-sysmo/oml_router.c | 18 | ||||
-rw-r--r-- | tests/misc/Makefile.am | 3 | ||||
-rw-r--r-- | tests/misc/misc_test.c | 75 | ||||
-rw-r--r-- | tests/misc/misc_test.ok | 2 |
10 files changed, 302 insertions, 10 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am index d7f9421f..68d63e09 100644 --- a/include/osmo-bts/Makefile.am +++ b/include/osmo-bts/Makefile.am @@ -1,3 +1,3 @@ noinst_HEADERS = abis.h bts.h bts_model.h gsm_data.h logging.h measurement.h \ oml.h paging.h rsl.h signal.h vty.h amr.h pcu_if.h pcuif_proto.h \ - handover.h + handover.h msg_utils.h diff --git a/include/osmo-bts/msg_utils.h b/include/osmo-bts/msg_utils.h new file mode 100644 index 00000000..f63c0964 --- /dev/null +++ b/include/osmo-bts/msg_utils.h @@ -0,0 +1,20 @@ +/* + * Routines to check the structurally integrity of messages + */ + +#pragma once + +struct msgb; + +/** + * Classification of OML message. ETSI for plain GSM 12.21 + * messages and IPA/Osmo for manufacturer messages. + */ +enum { + OML_MSG_TYPE_ETSI, + OML_MSG_TYPE_IPA, + OML_MSG_TYPE_OSMO, +}; + +int msg_verify_ipa_structure(struct msgb *msg); +int msg_verify_oml_structure(struct msgb *msg); diff --git a/include/osmo-bts/oml.h b/include/osmo-bts/oml.h index dfbc5549..d7092780 100644 --- a/include/osmo-bts/oml.h +++ b/include/osmo-bts/oml.h @@ -5,6 +5,10 @@ struct gsm_bts; struct gsm_abis_mo; struct msgb; + +extern const char oml_ipa_magic[13]; +extern const char oml_osmo_magic[12]; + int oml_init(void); int down_oml(struct gsm_bts *bts, struct msgb *msg); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 716fad94..ea2a742b 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -5,4 +5,4 @@ LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOTRAU_LIBS) noinst_LIBRARIES = libbts.a libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c \ rsl.c vty.c paging.c measurement.c amr.c lchan.c \ - load_indication.c pcu_sock.c handover.c
\ No newline at end of file + load_indication.c pcu_sock.c handover.c msg_utils.c diff --git a/src/common/msg_utils.c b/src/common/msg_utils.c new file mode 100644 index 00000000..2d5ebd9b --- /dev/null +++ b/src/common/msg_utils.c @@ -0,0 +1,174 @@ +/* (C) 2014 by sysmocom s.f.m.c. GmbH + * + * 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 <osmo-bts/msg_utils.h> +#include <osmo-bts/logging.h> +#include <osmo-bts/oml.h> + +#include <osmocom/gsm/protocol/ipaccess.h> +#include <osmocom/gsm/protocol/gsm_12_21.h> +#include <osmocom/core/msgb.h> + +#include <arpa/inet.h> + + +static int check_fom(struct abis_om_hdr *omh, size_t len) +{ + if (omh->length != len) { + LOGP(DL1C, LOGL_ERROR, "Incorrect OM hdr length value %d %zu\n", + omh->length, len); + return -1; + } + + if (len < sizeof(struct abis_om_fom_hdr)) { + LOGP(DL1C, LOGL_ERROR, "FOM header insufficient space %zu %zu\n", + len, sizeof(struct abis_om_fom_hdr)); + return -1; + } + + return 0; +} + +static int check_manuf(struct msgb *msg, struct abis_om_hdr *omh, size_t msg_size) +{ + int type; + size_t size; + + if (msg_size < 1) { + LOGP(DL1C, LOGL_ERROR, "No ManId Length Indicator %zu\n", + msg_size); + return -1; + } + + if (omh->data[0] >= msg_size - 1) { + LOGP(DL1C, LOGL_ERROR, + "Insufficient message space for this ManId Length %d %zu\n", + omh->data[0], msg_size - 1); + return -1; + } + + if (omh->data[0] == sizeof(oml_ipa_magic) && + strncmp(oml_ipa_magic, (const char *)omh->data + 1, + sizeof(oml_ipa_magic)) == 0) { + type = OML_MSG_TYPE_IPA; + size = sizeof(oml_ipa_magic) + 1; + } else if (omh->data[0] == sizeof(oml_osmo_magic) && + strncmp(oml_osmo_magic, (const char *) omh->data + 1, + sizeof(oml_osmo_magic)) == 0) { + type = OML_MSG_TYPE_OSMO; + size = sizeof(oml_osmo_magic) + 1; + } else { + LOGP(DL1C, LOGL_ERROR, "Manuf Label Unknown\n"); + return -1; + } + + /* we have verified that the vendor string fits */ + msg->l3h = omh->data + size; + if (check_fom(omh, msgb_l3len(msg)) != 0) + return -1; + return type; +} + +/** + * Return 0 in case the IPA structure is okay and in this + * case the l2h will be set to the beginning of the data. + */ +int msg_verify_ipa_structure(struct msgb *msg) +{ + struct ipaccess_head *hh; + + if (msgb_l1len(msg) < sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, + "Ipa header insufficient space %d %d\n", + msgb_l1len(msg), sizeof(struct ipaccess_head)); + return -1; + } + + hh = (struct ipaccess_head *) msg->l1h; + + if (hh->proto != IPAC_PROTO_OML) { + LOGP(DL1C, LOGL_ERROR, + "Incorrect ipa header protocol 0x%x 0x%x\n", + hh->proto, IPAC_PROTO_OML); + return -1; + } + + if (ntohs(hh->len) != msgb_l1len(msg) - sizeof(struct ipaccess_head)) { + LOGP(DL1C, LOGL_ERROR, + "Incorrect ipa header msg size %d %d\n", + ntohs(hh->len), msgb_l1len(msg) - sizeof(struct ipaccess_head)); + return -1; + } + + msg->l2h = hh->data; + return 0; +} + +/** + * \brief Verify the structure of the OML message and set l3h + * + * This function verifies that the data in \param in msg is a proper + * OML message. This code assumes that msg->l2h points to the + * beginning of the OML message. In the successful case the msg->l3h + * will be set and will point to the FOM header. The value is undefined + * in all other cases. + * + * \param msg The message to analyze starting from msg->l2h. + * \return In case the structure is correct a positive number will be + * returned and msg->l3h will point to the FOM. The number is a + * classification of the vendor type of the message. + */ +int msg_verify_oml_structure(struct msgb *msg) +{ + struct abis_om_hdr *omh; + + if (msgb_l2len(msg) < sizeof(*omh)) { + LOGP(DL1C, LOGL_ERROR, "Om header insufficient space %d %d\n", + msgb_l2len(msg), sizeof(*omh)); + return -1; + } + + omh = (struct abis_om_hdr *) msg->l2h; + if (omh->mdisc != ABIS_OM_MDISC_FOM && + omh->mdisc != ABIS_OM_MDISC_MANUF) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om mdisc value %x\n", + omh->mdisc); + return -1; + } + + if (omh->placement != ABIS_OM_PLACEMENT_ONLY) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om placement value %x %x\n", + omh->placement, ABIS_OM_PLACEMENT_ONLY); + return -1; + } + + if (omh->sequence != 0) { + LOGP(DL1C, LOGL_ERROR, "Incorrect om sequence value %d\n", + omh->sequence); + return -1; + } + + if (omh->mdisc == ABIS_OM_MDISC_MANUF) + return check_manuf(msg, omh, msgb_l2len(msg) - sizeof(*omh)); + + msg->l3h = omh->data; + if (check_fom(omh, msgb_l3len(msg)) != 0) + return -1; + return OML_MSG_TYPE_ETSI; +} diff --git a/src/common/oml.c b/src/common/oml.c index b7c12f7c..2d690d63 100644 --- a/src/common/oml.c +++ b/src/common/oml.c @@ -92,7 +92,9 @@ static struct tlv_definition abis_nm_att_tlvdef_ipa = { }; /* ip.access nanoBTS specific commands */ -static const char ipaccess_magic[] = "com.ipaccess"; +const char oml_ipa_magic[] = "com.ipaccess"; +const char oml_osmo_magic[] = "org.osmocom"; + static int oml_ipa_set_attr(struct gsm_bts *bts, struct msgb *msg); /* @@ -165,9 +167,9 @@ int oml_send_msg(struct msgb *msg, int is_manuf) if (is_manuf) { /* length byte, string + 0 termination */ - uint8_t *manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic)); - manuf[0] = strlen(ipaccess_magic)+1; - memcpy(manuf+1, ipaccess_magic, strlen(ipaccess_magic)); + uint8_t *manuf = msgb_push(msg, 1 + sizeof(oml_ipa_magic)); + manuf[0] = strlen(oml_ipa_magic)+1; + memcpy(manuf+1, oml_ipa_magic, strlen(oml_ipa_magic)); } /* Push the main OML header and send it off */ @@ -1048,7 +1050,7 @@ static int down_mom(struct gsm_bts *bts, struct msgb *msg) return -EIO; } - if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) { + if (strncmp((char *)&oh->data[1], oml_ipa_magic, idstrlen)) { LOGP(DOML, LOGL_ERROR, "Manufacturer OML message != ipaccess not supported\n"); return -EINVAL; } diff --git a/src/osmo-bts-sysmo/oml_router.c b/src/osmo-bts-sysmo/oml_router.c index 64b36840..4af20d50 100644 --- a/src/osmo-bts-sysmo/oml_router.c +++ b/src/osmo-bts-sysmo/oml_router.c @@ -24,6 +24,7 @@ #include <osmo-bts/bts.h> #include <osmo-bts/logging.h> #include <osmo-bts/oml.h> +#include <osmo-bts/msg_utils.h> #include <osmocom/core/socket.h> #include <osmocom/core/select.h> @@ -51,9 +52,22 @@ static int oml_router_read_cb(struct osmo_fd *fd, unsigned int what) goto err; } - msgb_put(msg, rc); + msg->l1h = msgb_put(msg, rc); + rc = msg_verify_ipa_structure(msg); + if (rc < 0) { + LOGP(DL1C, LOGL_ERROR, + "OML Router: Invalid IPA message rc(%d)\n", rc); + goto err; + } + + rc = msg_verify_oml_structure(msg); + if (rc < 0) { + LOGP(DL1C, LOGL_ERROR, + "OML Router: Invalid OML message rc(%d)\n", rc); + goto err; + } - /* todo analyze and dispatch message */ + /* todo dispatch message */ err: msgb_free(msg); diff --git a/tests/misc/Makefile.am b/tests/misc/Makefile.am index 4091bc6a..f60325b0 100644 --- a/tests/misc/Makefile.am +++ b/tests/misc/Makefile.am @@ -5,4 +5,5 @@ noinst_PROGRAMS = misc_test EXTRA_DIST = misc_test.ok misc_test_SOURCES = misc_test.c $(srcdir)/../stubs.c -misc_test_LDADD = $(top_builddir)/src/common/libbts.a $(LDADD) +misc_test_LDADD = $(top_builddir)/src/common/libbts.a \ + $(LIBOSMOABIS_LIBS) $(LIBOSMOTRAU_LIBS) $(LDADD) diff --git a/tests/misc/misc_test.c b/tests/misc/misc_test.c index 91fd73a1..f1b7ce3c 100644 --- a/tests/misc/misc_test.c +++ b/tests/misc/misc_test.c @@ -21,10 +21,81 @@ */ #include <osmo-bts/bts.h> +#include <osmo-bts/msg_utils.h> +#include <osmo-bts/logging.h> + +#include <osmocom/gsm/protocol/ipaccess.h> #include <stdlib.h> #include <stdio.h> +static const uint8_t ipa_rsl_connect[] = { + 0x00, 0x1c, 0xff, 0x10, 0x80, 0x00, 0x0a, 0x0d, + 0x63, 0x6f, 0x6d, 0x2e, 0x69, 0x70, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x00, 0xe0, 0x04, 0x00, + 0x00, 0xff, 0x85, 0x00, 0x81, 0x0b, 0xbb +}; + +static void test_msg_utils_ipa(void) +{ + struct msgb *msg; + int rc, size; + + printf("Testing IPA structure\n"); + + msg = msgb_alloc(sizeof(ipa_rsl_connect), "IPA test"); + msg->l1h = msgb_put(msg, sizeof(ipa_rsl_connect)); + memcpy(msg->l1h, ipa_rsl_connect, sizeof(ipa_rsl_connect)); + rc = msg_verify_ipa_structure(msg); + OSMO_ASSERT(rc == 0); + msgb_free(msg); + + /* test truncated messages and they should fail */ + for (size = sizeof(ipa_rsl_connect) - 1; size >= 0; --size) { + msg = msgb_alloc(sizeof(ipa_rsl_connect) - 1, "IPA test"); + msg->l1h = msgb_put(msg, size); + memcpy(msg->l1h, ipa_rsl_connect, size); + rc = msg_verify_ipa_structure(msg); + OSMO_ASSERT(rc == -1); + msgb_free(msg); + } + + /* change the type of the message */ + msg = msgb_alloc(sizeof(ipa_rsl_connect), "IPA test"); + msg->l1h = msgb_put(msg, sizeof(ipa_rsl_connect)); + memcpy(msg->l1h, ipa_rsl_connect, sizeof(ipa_rsl_connect)); + msg->l1h[2] = 0x23; + rc = msg_verify_ipa_structure(msg); + OSMO_ASSERT(rc == -1); + msgb_free(msg); +} + +static void test_msg_utils_oml(void) +{ + static const size_t hh_size = sizeof(struct ipaccess_head); + struct msgb *msg; + int rc, size; + + printf("Testing OML structure\n"); + + msg = msgb_alloc(sizeof(ipa_rsl_connect) - hh_size, "IPA test"); + msg->l2h = msgb_put(msg, sizeof(ipa_rsl_connect) - hh_size); + memcpy(msg->l2h, ipa_rsl_connect + hh_size, sizeof(ipa_rsl_connect) - hh_size); + rc = msg_verify_oml_structure(msg); + OSMO_ASSERT(rc == OML_MSG_TYPE_IPA); + msgb_free(msg); + + /* test truncated messages and they should fail */ + for (size = sizeof(ipa_rsl_connect) - hh_size - 1; size >=0; --size) { + msg = msgb_alloc(size, "IPA test"); + msg->l2h = msgb_put(msg, size); + memcpy(msg->l2h, ipa_rsl_connect + hh_size, size); + rc = msg_verify_oml_structure(msg); + OSMO_ASSERT(rc == -1); + msgb_free(msg); + } +} + static void test_sacch_get(void) { struct gsm_lchan lchan; @@ -53,6 +124,10 @@ static void test_sacch_get(void) int main(int argc, char **argv) { + bts_log_init(NULL); + test_sacch_get(); + test_msg_utils_ipa(); + test_msg_utils_oml(); return EXIT_SUCCESS; } diff --git a/tests/misc/misc_test.ok b/tests/misc/misc_test.ok index c8187a10..58aa3ea1 100644 --- a/tests/misc/misc_test.ok +++ b/tests/misc/misc_test.ok @@ -1 +1,3 @@ Testing lchan_sacch_get +Testing IPA structure +Testing OML structure |