aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-05-25 16:21:35 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-07-31 16:58:26 +0200
commit0655cac6f1fbb0a669f064780a171a363ce8ef83 (patch)
tree17bda895ab0b476e73d74e9fdb6deb21dd38689b
parentb05d72d21b8cc91126cf45525f9010df6142e1c2 (diff)
sysmobts: Verify the structure of IPA and OML messages
Extend the router to verify that the message received is properly encoded. The code can deal with the basic structure of ETSI OML and vendor specific messages for ip.access and the osmocom project.
-rw-r--r--include/osmo-bts/Makefile.am2
-rw-r--r--include/osmo-bts/msg_utils.h20
-rw-r--r--include/osmo-bts/oml.h4
-rw-r--r--src/common/Makefile.am2
-rw-r--r--src/common/msg_utils.c174
-rw-r--r--src/common/oml.c12
-rw-r--r--src/osmo-bts-sysmo/oml_router.c18
-rw-r--r--tests/misc/Makefile.am3
-rw-r--r--tests/misc/misc_test.c75
-rw-r--r--tests/misc/misc_test.ok2
10 files changed, 302 insertions, 10 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index d7f9421..68d63e0 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 0000000..f63c096
--- /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 dfbc554..d709278 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 716fad9..ea2a742 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 0000000..2d5ebd9
--- /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 b7c12f7..2d690d6 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 64b3684..4af20d5 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 4091bc6..f60325b 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 91fd73a..f1b7ce3 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 c8187a1..58aa3ea 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