aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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. */