falconia submitted this change.

View Change

Approvals: falconia: Looks good to me, approved Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve pespin: Looks good to me, but someone else must approve
nokia: add support for Flexi Multiradio

Previous support existed for Nokia MetroSite, UltraSite and InSite
models, resulting in BTS model name "nokia_site". However, there
exist newer Nokia BTS models that also support E1 Abis and can be
supported by OsmoBSC with relatively small changes: Flexi EDGE,
Flexi Multiradio and Flexi Multiradio 10. Out of these newer
models, American 2G Cooperative (the present patch author's current
organization) has only Flexi MR at the present time - hence this
model shall be the first "new" Nokia BTS to be supported.

The first change required in order to support Flexi MR is ability
to receive long OML messages that have been segmented by the BTS:
the new BTS sends a much longer BTS_CONF_REQ message, and we have
to handle it correctly.

Change-Id: Icd429552c3b5e90d6c5d3ae5f52afd6550e3cebc
---
M include/osmocom/bsc/bts.h
M src/osmo-bsc/bts_nokia_site.c
2 files changed, 138 insertions(+), 30 deletions(-)

diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h
index a10d3c4..48b84af 100644
--- a/include/osmocom/bsc/bts.h
+++ b/include/osmocom/bsc/bts.h
@@ -333,6 +333,23 @@
gsm_bts_nr_t bts_nr; /* See (struct gsm_bts *)->nr */
};

+/* Both the standard GSM 12.21 flavor of OML and Nokia's proprietary flavor
+ * use segmentation, meaning that messages longer than 256 bytes (maximum
+ * that can fit into one LAPD frame with standard N201=260, with GSM 12.21
+ * FOM header taking up 4 bytes) have to be split and transferred one segment
+ * at a time. While this mechanism appears to be not needed for any currently
+ * supported BTS that uses standard GSM 12.21 NM, we have to implement it
+ * for Nokia BTS in both Rx and Tx directions: we have to send at least one
+ * long OML message for all supported Nokia models, whereas Rx of long messages
+ * becomes a requirement with newer Flexi Multiradio BTS.
+ *
+ * In order to implement Rx of segmented OML messages, we need a reassembly
+ * buffer, and in order to size this buffer, we need an upper limit on the
+ * number of segments. The following definition tunes this limit.
+ */
+#define NOKIA_OML_MAX_SEGMENT_LEN 256
+#define NOKIA_OML_MAX_RX_SEGMENTS 5
+
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
@@ -491,6 +508,13 @@
wait_reset:2, /* we are waiting for reset to complete */
hopping_mode:1; /* hopping type selection for Nokia */
struct osmo_timer_list reset_timer;
+ /* segmented OML Rx buffer */
+ struct {
+ uint8_t buffer[NOKIA_OML_MAX_SEGMENT_LEN * NOKIA_OML_MAX_RX_SEGMENTS];
+ bool active;
+ uint8_t seg_count;
+ uint16_t byte_count;
+ } oml_seg_rx;
} nokia;
};

diff --git a/src/osmo-bsc/bts_nokia_site.c b/src/osmo-bsc/bts_nokia_site.c
index 10a4c5d..3b06d4b 100644
--- a/src/osmo-bsc/bts_nokia_site.c
+++ b/src/osmo-bsc/bts_nokia_site.c
@@ -1,4 +1,5 @@
-/* Nokia XXXsite family specific code */
+/* Nokia BTS vendor-specific code, currently supporting Site family
+ * and Flexi Multiradio. */

/* (C) 2011 by Dieter Spaar <spaar@mirider.augusta.de>
*
@@ -1410,9 +1411,9 @@
struct msgb *msg = nm_msgb_alloc();

if (seq == 0)
- max_send = 256 - sizeof(struct abis_om_nokia_hdr);
+ max_send = NOKIA_OML_MAX_SEGMENT_LEN - sizeof(struct abis_om_nokia_hdr);
else
- max_send = 256;
+ max_send = NOKIA_OML_MAX_SEGMENT_LEN;

if (len_remain > max_send) {
len_to_send = max_send;
@@ -1761,17 +1762,18 @@
* - receive ACK, start RSL link(s)
* ACK some other messages received from the BTS.
*
- * Probably its also possible to configure the BTS without a reset, this
- * has not been tested yet.
+ * It is also possible to configure the BTS without a reset, but in this case
+ * the BTS does not accept any changes in configuration - therefore, the mode
+ * of skipping BSC-driven BTS reset is only for use during osmo-bsc development,
+ * when the developer-operator resets the BTS manually before each test run.
*/

#define FIND_ELEM(data, data_len, ei, var, len) (find_element(data, data_len, ei, var, len) == len)
-static int abis_nm_rcvmsg_fom(struct msgb *mb)
+static int abis_nm_rcvmsg_fom(struct e1inp_sign_link *sign_link,
+ uint8_t *l3_msg, unsigned l3_msg_len)
{
- struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)mb->dst;
struct gsm_bts *bts = sign_link->trx->bts;
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_nokia_hdr *noh = msgb_l3(mb);
+ struct abis_om_nokia_hdr *noh = (struct abis_om_nokia_hdr *) l3_msg;
uint8_t mt = noh->msg_type;
int ret = 0;
uint16_t ref = ntohs(noh->reference);
@@ -1787,18 +1789,13 @@
int ei_alarm_detail_len = 0;
int len_data;

-
- if (bts->nokia.wait_reset) {
- LOG_BTS(bts, DNM, LOGL_INFO, "Ignoring message while waiting for reset: %s\n", msgb_hexdump(mb));
- return ret;
- }
-
- if (oh->length < sizeof(struct abis_om_nokia_hdr)) {
- LOG_BTS(bts, DNM, LOGL_ERROR, "Message too short: %s\n", msgb_hexdump(mb));
+ if (l3_msg_len < sizeof(struct abis_om_nokia_hdr)) {
+ LOG_BTS(bts, DNM, LOGL_ERROR, "Message too short: %s\n",
+ osmo_hexdump(l3_msg, l3_msg_len));
return -EINVAL;
}

- len_data = oh->length - sizeof(struct abis_om_nokia_hdr);
+ len_data = l3_msg_len - sizeof(struct abis_om_nokia_hdr);
LOG_BTS(bts, DNM, LOGL_INFO, "Rx (0x%02X) %s\n", mt, get_msg_type_name_string(mt));
#if 0 /* debugging */
dump_elements(noh->data, len_data);
@@ -1839,8 +1836,11 @@
LOG_BTS(bts, DNM, LOGL_ERROR, "Rx No ACK (%u): don't know how to proceed\n", ack);
/* TODO: properly handle failures (NACK) */
}
- } else
- LOG_BTS(bts, DNM, LOGL_ERROR, "Rx MSG_ACK but no EI_ACK found: %s\n", msgb_hexdump(mb));
+ } else {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Rx MSG_ACK but no EI_ACK found: %s\n",
+ osmo_hexdump(l3_msg, l3_msg_len));
+ }

/* TODO: the assumption for the following is that no NACK was received */

@@ -1997,7 +1997,87 @@
return ret;
}

-/* TODO: put in a separate file ? */
+static int abis_nm_rcvmsg_fom_seg(struct msgb *msg)
+{
+ struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
+ struct gsm_bts *bts = sign_link->trx->bts;
+ struct abis_om_hdr *oh = msgb_l2(msg);
+ unsigned seg_len = oh->length;
+ uint8_t expect_seq;
+
+ /* 0 length segments aren't possible, valid range for segment length
+ * is [1,256] bytes, with code of 0 meaning 256. */
+ if (seg_len == 0)
+ seg_len = NOKIA_OML_MAX_SEGMENT_LEN;
+ if (msgb_l3len(msg) < seg_len) {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Message too short per FOM header: %s\n",
+ msgb_hexdump(msg));
+ return -EINVAL;
+ }
+
+ switch (oh->placement) {
+ case ABIS_OM_PLACEMENT_ONLY:
+ case ABIS_OM_PLACEMENT_FIRST:
+ /* clear any previous reassembly */
+ bts->nokia.oml_seg_rx.active = false;
+ expect_seq = 0;
+ break;
+ case ABIS_OM_PLACEMENT_MIDDLE:
+ case ABIS_OM_PLACEMENT_LAST:
+ if (!bts->nokia.oml_seg_rx.active) {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Rx ABIS OML fragment without prior part(s)\n");
+ return -EINVAL;
+ }
+ expect_seq = bts->nokia.oml_seg_rx.seg_count;
+ break;
+ default:
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Rx ABIS OML placement 0x%x is invalid\n",
+ oh->placement);
+ bts->nokia.oml_seg_rx.active = false;
+ return -EINVAL;
+ }
+ if (oh->sequence != expect_seq) {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Rx ABIS OML sequence 0x%x != expected 0x%x\n",
+ oh->sequence, expect_seq);
+ bts->nokia.oml_seg_rx.active = false;
+ return -EINVAL;
+ }
+
+ switch (oh->placement) {
+ case ABIS_OM_PLACEMENT_ONLY:
+ return abis_nm_rcvmsg_fom(sign_link, msgb_l3(msg), seg_len);
+ case ABIS_OM_PLACEMENT_FIRST:
+ bts->nokia.oml_seg_rx.active = true;
+ bts->nokia.oml_seg_rx.seg_count = 0;
+ bts->nokia.oml_seg_rx.byte_count = 0;
+ break;
+ case ABIS_OM_PLACEMENT_MIDDLE:
+ case ABIS_OM_PLACEMENT_LAST:
+ if (bts->nokia.oml_seg_rx.seg_count >= NOKIA_OML_MAX_RX_SEGMENTS) {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "segmented OML message exceeds current limit of %d segments\n",
+ NOKIA_OML_MAX_RX_SEGMENTS);
+ bts->nokia.oml_seg_rx.active = false;
+ return -EMSGSIZE;
+ }
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+ memcpy(bts->nokia.oml_seg_rx.buffer + bts->nokia.oml_seg_rx.byte_count,
+ msgb_l3(msg), seg_len);
+ bts->nokia.oml_seg_rx.byte_count += seg_len;
+ bts->nokia.oml_seg_rx.seg_count++;
+ if (oh->placement != ABIS_OM_PLACEMENT_LAST)
+ return 0;
+ bts->nokia.oml_seg_rx.active = false;
+ return abis_nm_rcvmsg_fom(sign_link, bts->nokia.oml_seg_rx.buffer,
+ bts->nokia.oml_seg_rx.byte_count);
+}

int abis_nokia_rcvmsg(struct msgb *msg)
{
@@ -2006,14 +2086,18 @@
struct abis_om_hdr *oh = msgb_l2(msg);
int rc = 0;

- /* Various consistency checks */
- if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
- LOG_BTS(bts, DNM, LOGL_ERROR, "Rx ABIS OML placement 0x%x not supported\n", oh->placement);
- if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
- return -EINVAL;
+ if (bts->nokia.wait_reset) {
+ LOG_BTS(bts, DNM, LOGL_INFO, "Ignoring message while waiting for reset: %s\n", msgb_hexdump(msg));
+ msgb_free(msg);
+ return 0;
}
- if (oh->sequence != 0) {
- LOG_BTS(bts, DNM, LOGL_ERROR, "Rx ABIS OML sequence 0x%x != 0x00\n", oh->sequence);
+
+ /* Various consistency checks */
+ if (msgb_l2len(msg) < sizeof(*oh)) {
+ LOG_BTS(bts, DNM, LOGL_ERROR,
+ "Message too short for FOM header: %s\n",
+ msgb_hexdump(msg));
+ msgb_free(msg);
return -EINVAL;
}
msg->l3h = (unsigned char *)oh + sizeof(*oh);
@@ -2021,7 +2105,7 @@
switch (oh->mdisc) {
case ABIS_OM_MDISC_FOM:
LOG_BTS(bts, DNM, LOGL_INFO, "Rx ABIS_OM_MDISC_FOM\n");
- rc = abis_nm_rcvmsg_fom(msg);
+ rc = abis_nm_rcvmsg_fom_seg(msg);
break;
case ABIS_OM_MDISC_MANUF:
LOG_BTS(bts, DNM, LOGL_INFO, "Rx ABIS_OM_MDISC_MANUF: ignoring\n");
@@ -2032,7 +2116,7 @@
break;
default:
LOG_BTS(bts, DNM, LOGL_ERROR, "Rx unknown ABIS OML message discriminator 0x%x\n", oh->mdisc);
- return -EINVAL;
+ rc = -EINVAL;
}

msgb_free(msg);

To view, visit change 42712. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: Icd429552c3b5e90d6c5d3ae5f52afd6550e3cebc
Gerrit-Change-Number: 42712
Gerrit-PatchSet: 3
Gerrit-Owner: falconia <falcon@freecalypso.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: falconia <falcon@freecalypso.org>
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>
Gerrit-CC: osmith <osmith@sysmocom.de>