aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2021-06-08 18:38:23 +0200
committerlaforge <laforge@osmocom.org>2021-06-30 08:13:21 +0000
commit8bf5cbea49275c5cd21873e05e896dfeea73b9b1 (patch)
tree639120ed0e9946fd9f757ba3391757d13618d17c
parent80ce85295b35874e853517e8fc77776b3424350d (diff)
Support forwarding proto IPAC_PROTO_EXT_PCU BSC<->PCU
This new extension protocol is used to forward Osmocom PCUIF messages BSC<->BTS<->PCU. It will be sent re-using the IPA multiplex of the OML link between BSC and BTS. BTS is responsible for forwarding the message over the unix socket to the PCU. PCUIF existing RX path needs to be reworked in order to accept variable-size messages, in order to be able to transparently forward messages without knowing about them (the new container message is variable-length). Related: SYS#5303 Change-Id: I73fdb17107494ade9263a62d1f729e67303fce87
-rw-r--r--include/osmo-bts/Makefile.am1
-rw-r--r--include/osmo-bts/abis_osmo.h10
-rw-r--r--include/osmo-bts/bts.h2
-rw-r--r--include/osmo-bts/pcu_if.h5
-rw-r--r--src/common/Makefile.am1
-rw-r--r--src/common/abis.c13
-rw-r--r--src/common/abis_osmo.c136
-rw-r--r--src/common/bts.c1
-rw-r--r--src/common/pcu_sock.c42
9 files changed, 201 insertions, 10 deletions
diff --git a/include/osmo-bts/Makefile.am b/include/osmo-bts/Makefile.am
index 84dc6671..d52c9aa4 100644
--- a/include/osmo-bts/Makefile.am
+++ b/include/osmo-bts/Makefile.am
@@ -1,5 +1,6 @@
noinst_HEADERS = \
abis.h \
+ abis_osmo.h \
bts.h \
bts_model.h \
bts_shutdown_fsm.h \
diff --git a/include/osmo-bts/abis_osmo.h b/include/osmo-bts/abis_osmo.h
new file mode 100644
index 00000000..be2817f0
--- /dev/null
+++ b/include/osmo-bts/abis_osmo.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <osmocom/core/msgb.h>
+#include <osmo-bts/pcuif_proto.h>
+
+struct gsm_bts;
+
+int down_osmo(struct gsm_bts *bts, struct msgb *msg);
+
+int abis_osmo_pcu_tx_container(struct gsm_bts *bts, const struct gsm_pcu_if_container *container);
diff --git a/include/osmo-bts/bts.h b/include/osmo-bts/bts.h
index 978a5481..a891fb75 100644
--- a/include/osmo-bts/bts.h
+++ b/include/osmo-bts/bts.h
@@ -167,6 +167,8 @@ struct gsm_bts {
/* how do we talk OML with this TRX? */
struct e1inp_sign_link *oml_link;
struct timespec oml_conn_established_timestamp;
+ /* OSMO extenion link associated to same line as oml_link: */
+ struct e1inp_sign_link *osmo_link;
/* Abis network management O&M handle */
struct gsm_abis_mo mo;
diff --git a/include/osmo-bts/pcu_if.h b/include/osmo-bts/pcu_if.h
index 6ef8dc57..12a8abc9 100644
--- a/include/osmo-bts/pcu_if.h
+++ b/include/osmo-bts/pcu_if.h
@@ -1,8 +1,12 @@
#ifndef _PCU_IF_H
#define _PCU_IF_H
+#include <osmo-bts/pcuif_proto.h>
+
extern int pcu_direct;
+#define PCUIF_HDR_SIZE ( sizeof(struct gsm_pcu_if) - sizeof(((struct gsm_pcu_if *)0)->u) )
+
int pcu_tx_info_ind(void);
int pcu_tx_si(const struct gsm_bts *bts, enum osmo_sysinfo_type si_type, bool enable);
int pcu_tx_app_info_req(struct gsm_bts *bts, uint8_t app_type, uint8_t len, const uint8_t *app_data);
@@ -20,6 +24,7 @@ int pcu_tx_interf_ind(uint8_t bts_nr, uint8_t trx_nr, uint32_t fn,
int pcu_tx_pag_req(const uint8_t *identity_lv, uint8_t chan_needed);
int pcu_tx_pch_data_cnf(uint32_t fn, uint8_t *data, uint8_t len);
int pcu_tx_susp_req(struct gsm_lchan *lchan, uint32_t tlli, const uint8_t *ra_id, uint8_t cause);
+int pcu_sock_send(struct gsm_network *net, struct msgb *msg);
int pcu_sock_init(const char *path);
void pcu_sock_exit(void);
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index d979bc0e..72438c67 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -12,6 +12,7 @@ libbts_a_SOURCES = \
sysinfo.c \
logging.c \
abis.c \
+ abis_osmo.c \
oml.c \
bts.c \
bts_trx.c \
diff --git a/src/common/abis.c b/src/common/abis.c
index 17a244c7..abef8264 100644
--- a/src/common/abis.c
+++ b/src/common/abis.c
@@ -48,6 +48,7 @@
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/abis_osmo.h>
#include <osmo-bts/bts_model.h>
#include <osmo-bts/bts_trx.h>
@@ -113,6 +114,8 @@ static struct e1inp_sign_link *sign_link_up(void *unit, struct e1inp_line *line,
if (clock_gettime(CLOCK_MONOTONIC, &g_bts->oml_conn_established_timestamp) != 0)
memset(&g_bts->oml_conn_established_timestamp, 0,
sizeof(g_bts->oml_conn_established_timestamp));
+ g_bts->osmo_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OSMO,
+ g_bts->c0, IPAC_PROTO_OSMO, 0);
drain_oml_queue(g_bts);
bts_link_estab(g_bts);
return g_bts->oml_link;
@@ -158,10 +161,15 @@ static void sign_link_down(struct e1inp_line *line)
"A common error is a mismatch between unit_id configuration parameters of BTS and BSC.\n",
(uint64_t)(now.tv_sec - g_bts->oml_conn_established_timestamp.tv_sec));
}
+ g_bts->oml_link = NULL;
}
- g_bts->oml_link = NULL;
memset(&g_bts->oml_conn_established_timestamp, 0, sizeof(g_bts->oml_conn_established_timestamp));
+ if (g_bts->osmo_link) {
+ e1inp_sign_link_destroy(g_bts->osmo_link);
+ g_bts->osmo_link = NULL;
+ }
+
/* Then iterate over the RSL signalling links */
llist_for_each_entry(trx, &g_bts->trx_list, list) {
if (trx->rsl_link) {
@@ -191,6 +199,9 @@ static int sign_link_cb(struct msgb *msg)
case E1INP_SIGN_RSL:
down_rsl(link->trx, msg);
break;
+ case E1INP_SIGN_OSMO:
+ down_osmo(link->trx->bts, msg);
+ break;
default:
msgb_free(msg);
break;
diff --git a/src/common/abis_osmo.c b/src/common/abis_osmo.c
new file mode 100644
index 00000000..46dc5fa9
--- /dev/null
+++ b/src/common/abis_osmo.c
@@ -0,0 +1,136 @@
+/* OSMO extenion link associated to same line as oml_link: */
+
+/* (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin@sysmocom.de>
+ *
+ * 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 <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/ipa.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/pcu_if.h>
+#include <osmo-bts/pcuif_proto.h>
+
+extern struct gsm_network bts_gsmnet;
+
+#define OM_HEADROOM_SIZE 128
+
+////////////////////////////////////////
+// OSMO ABIS extensions (PCU)
+///////////////////////////////////////
+
+static struct msgb *abis_osmo_pcu_msgb_alloc(uint8_t msg_type, uint8_t bts_nr, size_t extra_size)
+{
+ struct msgb *msg;
+ struct gsm_pcu_if *pcu_prim;
+ msg = msgb_alloc_headroom(OM_HEADROOM_SIZE + sizeof(struct gsm_pcu_if) + extra_size,
+ OM_HEADROOM_SIZE, "IPA/ABIS/OSMO");
+ /* Only header is filled, caller is responible for reserving + filling
+ * message type specific contents: */
+ msgb_put(msg, PCUIF_HDR_SIZE);
+ pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ pcu_prim->msg_type = msg_type;
+ pcu_prim->bts_nr = bts_nr;
+ return msg;
+}
+
+/* Send a OML NM Message from BSC to BTS */
+int abis_osmo_sendmsg(struct gsm_bts *bts, struct msgb *msg)
+{
+ msg->dst = bts->osmo_link;
+ msg->l2h = msg->data;
+ return abis_sendmsg(msg);
+}
+
+
+/* Send IPA/OSMO/PCU extension Abis message from PCU to BSC */
+static int abis_osmo_pcu_sendmsg(struct gsm_bts *bts, struct msgb *msg)
+{
+ ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_PCU);
+ return abis_osmo_sendmsg(bts, msg);
+}
+
+int abis_osmo_pcu_tx_container(struct gsm_bts *bts, const struct gsm_pcu_if_container *container)
+{
+ uint16_t data_length = osmo_load16be(&container->length);
+ struct msgb *msg = abis_osmo_pcu_msgb_alloc(PCU_IF_MSG_CONTAINER, bts->nr, data_length);
+ struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *) msgb_data(msg);
+ struct gsm_pcu_if_container *tx_cont = &pcu_prim->u.container;
+
+ msgb_put(msg, sizeof(*tx_cont) + data_length);
+ tx_cont->msg_type = container->msg_type;
+ tx_cont->length = container->length;
+ if (data_length)
+ memcpy(tx_cont->data, container->data, data_length);
+
+ return abis_osmo_pcu_sendmsg(bts, msg);
+}
+
+
+/* incoming IPA/OSMOEXT/PCU Abis message from BSC */
+static int rx_down_osmo_pcu(struct gsm_bts *bts, struct msgb *msg)
+{
+ struct gsm_pcu_if *pcu_prim;
+ if (msgb_l2len(msg) < PCUIF_HDR_SIZE) {
+ LOGP(DPCU, LOGL_ERROR, "ABIS_OSMO_PCU message too short\n");
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "ABIS_OSMO_PCU message too short\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+ pcu_prim = msgb_l2(msg);
+ LOGP(DPCU, LOGL_INFO, "Rx BSC->BTS%d ABIS_OSMO_PCU msg type %u\n",
+ pcu_prim->bts_nr, pcu_prim->msg_type);
+ /* we patch the bts_nr received from BTS with the bts_nr we used to set up in the local PCU */
+ pcu_prim->bts_nr = bts->nr;
+ /* Trim Abis lower layers: */
+ msgb_pull_to_l2(msg);
+ /* we simply forward it to PCUIF: */
+ return pcu_sock_send(&bts_gsmnet, msg);
+}
+
+/* incoming IPA/OSMO extension Abis message from BSC */
+int down_osmo(struct gsm_bts *bts, struct msgb *msg)
+{
+ uint8_t *type;
+
+ if (msgb_l2len(msg) < 1) {
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "OSMO message too short\n");
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ type = msgb_l2(msg);
+ msg->l2h = type + 1;
+
+ switch (*type) {
+ case IPAC_PROTO_EXT_PCU:
+ return rx_down_osmo_pcu(bts, msg);
+ default:
+ oml_tx_failure_event_rep(&bts->mo, NM_SEVER_MAJOR, OSMO_EVT_MAJ_UKWN_MSG,
+ "OSMO message unknown extension %u\n", *type);
+ msgb_free(msg);
+ return -EIO;
+ }
+}
diff --git a/src/common/bts.c b/src/common/bts.c
index bf291135..7d5732b3 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -371,6 +371,7 @@ int bts_init(struct gsm_bts *bts)
/* features implemented in 'common', available for all models */
osmo_bts_set_feature(bts->features, BTS_FEAT_ETWS_PN);
osmo_bts_set_feature(bts->features, BTS_FEAT_IPV6_NSVC);
+ osmo_bts_set_feature(bts->features, BTS_FEAT_ABIS_OSMO_PCU);
rc = bts_model_init(bts);
if (rc < 0) {
diff --git a/src/common/pcu_sock.c b/src/common/pcu_sock.c
index 5a04bf08..f40dd42a 100644
--- a/src/common/pcu_sock.c
+++ b/src/common/pcu_sock.c
@@ -45,6 +45,7 @@
#include <osmo-bts/signal.h>
#include <osmo-bts/l1sap.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/abis_osmo.h>
uint32_t trx_get_hlayer1(const struct gsm_bts_trx *trx);
@@ -62,8 +63,6 @@ static const char *sapi_string[] = {
[PCU_IF_SAPI_PTCCH] = "PTCCH",
};
-static int pcu_sock_send(struct gsm_network *net, struct msgb *msg);
-
/*
* PCU messages
*/
@@ -884,11 +883,21 @@ static int pcu_rx_act_req(struct gsm_bts *bts,
return 0;
}
+#define CHECK_IF_MSG_SIZE(prim_len, prim_msg) \
+ do { \
+ size_t _len = PCUIF_HDR_SIZE + sizeof(prim_msg); \
+ if (prim_len < _len) { \
+ LOGP(DPCU, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive %s " \
+ "size is %zu, discarding\n", prim_len, #prim_msg, _len); \
+ return -EINVAL; \
+ } \
+ } while(0);
static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
- struct gsm_pcu_if *pcu_prim)
+ struct gsm_pcu_if *pcu_prim, size_t prim_len)
{
int rc = 0;
struct gsm_bts *bts;
+ size_t exp_len;
if ((bts = gsm_bts_num(net, pcu_prim->bts_nr)) == NULL) {
LOGP(DPCU, LOGL_ERROR, "Received PCU Prim for non-existent BTS %u\n", pcu_prim->bts_nr);
@@ -897,17 +906,32 @@ static int pcu_rx(struct gsm_network *net, uint8_t msg_type,
switch (msg_type) {
case PCU_IF_MSG_DATA_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.data_req);
rc = pcu_rx_data_req(bts, msg_type, &pcu_prim->u.data_req);
break;
case PCU_IF_MSG_PAG_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.pag_req);
rc = pcu_rx_pag_req(bts, msg_type, &pcu_prim->u.pag_req);
break;
case PCU_IF_MSG_ACT_REQ:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.act_req);
rc = pcu_rx_act_req(bts, &pcu_prim->u.act_req);
break;
case PCU_IF_MSG_TXT_IND:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.txt_ind);
rc = pcu_rx_txt_ind(bts, &pcu_prim->u.txt_ind);
break;
+ case PCU_IF_MSG_CONTAINER:
+ CHECK_IF_MSG_SIZE(prim_len, pcu_prim->u.container);
+ /* ^ check if we can access container fields, v check with container data length */
+ exp_len = PCUIF_HDR_SIZE + sizeof(pcu_prim->u.container) + osmo_load16be(&pcu_prim->u.container.length);
+ if (prim_len < exp_len) {
+ LOGP(DPCU, LOGL_ERROR, "Received %zu bytes on PCU Socket, but primitive "
+ "container size is %zu, discarding\n", prim_len, exp_len);
+ return -EINVAL;
+ }
+ rc = abis_osmo_pcu_tx_container(bts, &pcu_prim->u.container);
+ break;
default:
LOGP(DPCU, LOGL_ERROR, "Received unknown PCU msg type %d\n",
msg_type);
@@ -928,7 +952,7 @@ struct pcu_sock_state {
struct llist_head upqueue; /* queue for sending messages */
};
-static int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
+int pcu_sock_send(struct gsm_network *net, struct msgb *msg)
{
struct pcu_sock_state *state = net->pcu_state;
struct osmo_fd *conn_bfd;
@@ -1019,7 +1043,7 @@ static int pcu_sock_read(struct osmo_fd *bfd)
struct msgb *msg;
int rc;
- msg = msgb_alloc(sizeof(*pcu_prim), "pcu_sock_rx");
+ msg = msgb_alloc(sizeof(*pcu_prim) + 1000, "pcu_sock_rx");
if (!msg)
return -ENOMEM;
@@ -1037,14 +1061,14 @@ static int pcu_sock_read(struct osmo_fd *bfd)
goto close;
}
- if (rc < sizeof(*pcu_prim)) {
- LOGP(DPCU, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive size "
- "is %zu, discarding\n", rc, sizeof(*pcu_prim));
+ if (rc < PCUIF_HDR_SIZE) {
+ LOGP(DPCU, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive hdr size "
+ "is %zu, discarding\n", rc, PCUIF_HDR_SIZE);
msgb_free(msg);
return 0;
}
- rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim);
+ rc = pcu_rx(state->net, pcu_prim->msg_type, pcu_prim, rc);
/* as we always synchronously process the message in pcu_rx() and
* its callbacks, we can free the message here. */