aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2021-01-19 23:58:39 +0100
committerPhilipp Maier <pmaier@sysmocom.de>2021-01-20 20:34:58 +0100
commitd1b1f694292b13b52a027f08b7250fcb6e8372b4 (patch)
treec0e6279acf0848b731494fe2ee81711c0057108e
parent2e6b60df455ad35c296460e0ad38e2dbe8ae511e (diff)
-rw-r--r--include/osmocom/pcu/pcuif_proto.h10
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bts.h4
-rw-r--r--src/gprs_bssgp_pcu.c26
-rw-r--r--src/gprs_bssgp_rim.c203
-rw-r--r--src/gprs_bssgp_rim.h5
-rw-r--r--src/gprs_debug.cpp6
-rw-r--r--src/gprs_debug.h1
-rw-r--r--src/pcu_l1_if.cpp27
9 files changed, 283 insertions, 1 deletions
diff --git a/include/osmocom/pcu/pcuif_proto.h b/include/osmocom/pcu/pcuif_proto.h
index cdd73d9..6ac9a02 100644
--- a/include/osmocom/pcu/pcuif_proto.h
+++ b/include/osmocom/pcu/pcuif_proto.h
@@ -1,12 +1,13 @@
#ifndef _PCUIF_PROTO_H
#define _PCUIF_PROTO_H
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/l1sap.h>
#include <arpa/inet.h>
#define PCU_SOCK_DEFAULT "/tmp/pcu_bts"
-#define PCU_IF_VERSION 0x0a
+#define PCU_IF_VERSION 0x0b
#define TXT_MAX_LEN 128
/* msg_type */
@@ -177,6 +178,13 @@ struct gsm_pcu_if_info_ind {
struct in_addr v4;
struct in6_addr v6;
} remote_ip[PCU_IF_NUM_NSVC];
+ /* RIM */
+ uint8_t si1[GSM_MACBLOCK_LEN];
+ uint8_t si1_is_set;
+ uint8_t si3[GSM_MACBLOCK_LEN];
+ uint8_t si3_is_set;
+ uint8_t si13[GSM_MACBLOCK_LEN];
+ uint8_t si13_is_set;
} __attribute__ ((packed));
struct gsm_pcu_if_act_req {
diff --git a/src/Makefile.am b/src/Makefile.am
index de924a6..f85a456 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,7 @@ libgprs_la_SOURCES = \
csn1.c \
gsm_rlcmac.c \
gprs_bssgp_pcu.c \
+ gprs_bssgp_rim.c \
gprs_rlcmac.cpp \
gprs_rlcmac_sched.cpp \
gprs_rlcmac_meas.cpp \
@@ -81,6 +82,7 @@ noinst_HEADERS = \
csn1.h \
gsm_rlcmac.h \
gprs_bssgp_pcu.h \
+ gprs_bssgp_rim.h \
gprs_rlcmac.h \
gprs_ms.h \
gprs_ms_storage.h \
diff --git a/src/bts.h b/src/bts.h
index 7f437e3..195c44f 100644
--- a/src/bts.h
+++ b/src/bts.h
@@ -215,6 +215,10 @@ struct gprs_rlcmac_bts {
uint8_t n3105;
struct gprs_rlcmac_trx trx[8];
+ uint8_t si1[GSM_MACBLOCK_LEN];
+ bool si1_is_set;
+ uint8_t si3[GSM_MACBLOCK_LEN];
+ bool si3_is_set;
uint8_t si13[GSM_MACBLOCK_LEN];
bool si13_is_set;
diff --git a/src/gprs_bssgp_pcu.c b/src/gprs_bssgp_pcu.c
index 956fb66..c5163a3 100644
--- a/src/gprs_bssgp_pcu.c
+++ b/src/gprs_bssgp_pcu.c
@@ -20,6 +20,7 @@
#include <gprs_rlcmac.h>
#include <gprs_bssgp_pcu.h>
+#include <gprs_bssgp_rim.h>
#include <pcu_l1_if.h>
#include <gprs_debug.h>
#include <bts.h>
@@ -424,6 +425,20 @@ static int gprs_bssgp_pcu_rcvmsg(struct msgb *msg)
* STATUS and RESET messages in either direction. */
return bssgp_rcvmsg(msg);
+ switch (pdu_type) {
+ /* Also pass all RIM related messages to the generic BSSGP
+ * parser so that it can deliver primitive to the RIM SAP
+ * (SAP_BSSGP_RIM) */
+ case BSSGP_PDUT_RAN_INFO:
+ case BSSGP_PDUT_RAN_INFO_REQ:
+ case BSSGP_PDUT_RAN_INFO_ACK:
+ case BSSGP_PDUT_RAN_INFO_ERROR:
+ case BSSGP_PDUT_RAN_INFO_APP_ERROR:
+ return bssgp_rcvmsg(msg);
+ default:
+ break;
+ }
+
/* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */
/* UNITDATA BSSGP headers have TLLI in front */
@@ -544,14 +559,25 @@ static void handle_nm_status(struct osmo_bssgp_prim *bp)
int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
{
+ struct gprs_rlcmac_bts *bts;
struct osmo_bssgp_prim *bp;
bp = container_of(oph, struct osmo_bssgp_prim, oph);
+ /* FIXME: This calculation needs to be redone to support multiple BTS */
+ bts = llist_first_entry_or_null(&the_pcu->bts_list, struct gprs_rlcmac_bts, list);
+ if (!bts) {
+ LOGP(DBSSGP, LOGL_ERROR, "No bts\n");
+ return -EIO;
+ }
+
switch (oph->sap) {
case SAP_BSSGP_NM:
if (oph->primitive == PRIM_NM_STATUS)
handle_nm_status(bp);
break;
+ case SAP_BSSGP_RIM:
+ sgsn_rim_rx(bp, oph->msg, bts);
+ break;
default:
break;
}
diff --git a/src/gprs_bssgp_rim.c b/src/gprs_bssgp_rim.c
new file mode 100644
index 0000000..cd7b275
--- /dev/null
+++ b/src/gprs_bssgp_rim.c
@@ -0,0 +1,203 @@
+#include <gprs_rlcmac.h>
+#include <gprs_bssgp_rim.h>
+#include <pcu_l1_if.h>
+#include <gprs_debug.h>
+#include <bts.h>
+#include <gprs_bssgp_pcu.h>
+
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_bssgp_rim.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gprs/gprs_ns.h>
+
+/* Match the destination ran information in the request PDU to the cell id / routing area id of the local bvc ctx */
+static bool match_destination_ran_info(struct bssgp_ran_information_pdu *req_pdu, uint16_t nsei)
+{
+ struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
+
+ if (req_pdu->routing_info_dest.geran.cid != bctx->cell_id) {
+ LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) cell id (%04x != %04x) unknown to this pcu\n",
+ nsei, req_pdu->routing_info_dest.geran.cid, bctx->cell_id);
+ return false;
+ }
+
+ if (memcmp
+ (&req_pdu->routing_info_dest.geran.raid, &bctx->ra_id,
+ sizeof(req_pdu->routing_info_dest.geran.raid) != 0)) {
+ LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) routing area id (%s != %s) unknown to this pcu\n", nsei,
+ osmo_rai_name(&req_pdu->routing_info_dest.geran.raid), osmo_rai_name(&bctx->ra_id));
+ return false;
+ }
+
+ return true;
+}
+
+/* Check if the application ID in the request PDU is actually BSSGP_RAN_INF_APP_ID_NACC */
+static bool match_app_id(struct bssgp_ran_information_pdu *req_pdu)
+{
+ switch (req_pdu->rim_cont_iei) {
+ case BSSGP_IE_RI_REQ_RIM_CONTAINER:
+ if (req_pdu->decoded.req_rim_cont.app_id == BSSGP_RAN_INF_APP_ID_NACC)
+ return true;
+ case BSSGP_IE_RI_RIM_CONTAINER:
+ if (req_pdu->decoded.rim_cont.app_id == BSSGP_RAN_INF_APP_ID_NACC)
+ return true;
+ case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
+ if (req_pdu->decoded.app_err_rim_cont.app_id == BSSGP_RAN_INF_APP_ID_NACC)
+ return true;
+ case BSSGP_IE_RI_ACK_RIM_CONTAINER:
+ if (req_pdu->decoded.ack_rim_cont.app_id == BSSGP_RAN_INF_APP_ID_NACC)
+ return true;
+ case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
+ if (req_pdu->decoded.err_rim_cont.app_id == BSSGP_RAN_INF_APP_ID_NACC)
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Mirror RIM routing information of a given PDU, see also 3GPP TS 48.018, section 8c.1.4.3 */
+static void mirror_rim_routing_info(struct bssgp_ran_information_pdu *resp_pdu,
+ struct bssgp_ran_information_pdu *req_pdu)
+{
+ memcpy(&resp_pdu->routing_info_dest, &req_pdu->routing_info_src, sizeof(resp_pdu->routing_info_dest));
+ memcpy(&resp_pdu->routing_info_src, &req_pdu->routing_info_dest, sizeof(resp_pdu->routing_info_src));
+}
+
+/* Fill NACC application container with data (cell identifier, sysinfo) */
+static void fill_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *app_cont, const struct gprs_rlcmac_bts *bts)
+{
+ struct bssgp_bvc_ctx *bctx = gprs_bssgp_pcu_current_bctx();
+
+ app_cont->reprt_cell.rai.lac.plmn.mcc = bctx->ra_id.mcc;
+ app_cont->reprt_cell.rai.lac.plmn.mnc = bctx->ra_id.mnc;
+ app_cont->reprt_cell.rai.lac.plmn.mnc_3_digits = bctx->ra_id.mnc_3_digits;
+ app_cont->reprt_cell.rai.lac.lac = bctx->ra_id.lac;
+ app_cont->reprt_cell.rai.rac = bctx->ra_id.rac;
+ app_cont->reprt_cell.cell_identity = bctx->cell_id;
+ app_cont->num_si = 0;
+
+ if (bts->si1_is_set) {
+ app_cont->si[app_cont->num_si] = bts->si1 + 2;
+ app_cont->num_si++;
+ }
+
+ if (bts->si3_is_set) {
+ app_cont->si[app_cont->num_si] = bts->si3 + 2;
+ app_cont->num_si++;
+ }
+
+ if (bts->si13_is_set) {
+ app_cont->si[app_cont->num_si] = bts->si13 + 2;
+ app_cont->num_si++;
+ }
+
+ /* Note: It is possible that the resulting PDU will not contain any system information, even if this is
+ * an unlikely case since the BTS immediately updates the system information after startup. The
+ * specification permits to send zero system information, see also: 3GPP TS 48.018 section 11.3.63.2.1 */
+}
+
+/* Format a RAN INFORMATION PDU that contains the requested system information */
+static void format_response_pdu(struct bssgp_ran_information_pdu *resp_pdu, struct bssgp_ran_information_pdu *req_pdu,
+ const struct gprs_rlcmac_bts *bts)
+{
+ memset(resp_pdu, 0, sizeof(*resp_pdu));
+ mirror_rim_routing_info(resp_pdu, req_pdu);
+
+ resp_pdu->decoded.rim_cont = (struct bssgp_ran_inf_rim_cont) {
+ .app_id = BSSGP_RAN_INF_APP_ID_NACC,
+ .seq_num = 1, /* single report has only one message in response */
+ .pdu_ind = {
+ .pdu_type_ext = RIM_PDU_TYPE_SING_REP,
+ },
+ .prot_ver = 1,
+ };
+
+ fill_app_cont_nacc(&resp_pdu->decoded.rim_cont.u.app_cont_nacc, bts);
+ resp_pdu->decoded_present = true;
+ resp_pdu->rim_cont_iei = BSSGP_IE_RI_RIM_CONTAINER;
+}
+
+/* Format a RAN INFORMATION ERROR PDU */
+static void format_response_pdu_err(struct bssgp_ran_information_pdu *resp_pdu,
+ struct bssgp_ran_information_pdu *req_pdu)
+{
+ memset(resp_pdu, 0, sizeof(*resp_pdu));
+ mirror_rim_routing_info(resp_pdu, req_pdu);
+
+ resp_pdu->decoded.err_rim_cont = (struct bssgp_ran_inf_err_rim_cont) {
+ .app_id = BSSGP_RAN_INF_APP_ID_NACC,
+ .prot_ver = 1,
+ .err_pdu = req_pdu->rim_cont,
+ .err_pdu_len = req_pdu->rim_cont_len,
+ };
+
+ resp_pdu->decoded_present = true;
+ resp_pdu->rim_cont_iei = BSSGP_IE_RI_ERROR_RIM_COINTAINER;
+}
+
+int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg, struct gprs_rlcmac_bts *bts)
+{
+ uint16_t nsei = msgb_nsei(msg);
+ struct bssgp_ran_information_pdu *req_pdu = &bp->u.rim_pdu;
+ struct bssgp_ran_information_pdu resp_pdu;
+
+ /* At the moment we only support GERAN, so we block all other network
+ * types here. */
+ if (req_pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
+ LOGP(DRIM, LOGL_ERROR,
+ "BSSGP RIM (NSEI=%u) only GERAN supported, destination cell is not a GERAN cell -- rejected.\n",
+ nsei);
+ return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ }
+ if (req_pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
+ LOGP(DRIM, LOGL_ERROR,
+ "BSSGP RIM (NSEI=%u) only GERAN supported, source cell is not a GERAN cell -- rejected.\n", nsei);
+ return bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
+ }
+
+ /* Check if the RIM pdu is really addressed to this PCU, see also
+ * 3GPP TS 48.018, section 8c.3.1.2 */
+ if (!match_destination_ran_info(req_pdu, nsei))
+ return bssgp_tx_status(BSSGP_CAUSE_UNKN_DST, NULL, msg);
+
+ /* Check if the incoming RIM PDU is parseable, if not we must report
+ * an error to the controlling BSS 3GPP TS 48.018, 8c.3.4 and 8c.3.4.2 */
+ if (!req_pdu->decoded_present) {
+ LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) errornous RIM PDU received -- rejected.\n", nsei);
+ format_response_pdu_err(&resp_pdu, req_pdu);
+ return 0;
+ }
+
+ /* Check if the RIM container inside the incoming RIM PDU has the correct
+ * application ID */
+ if (!match_app_id(req_pdu)) {
+ LOGP(DRIM, LOGL_ERROR,
+ "BSSGP RIM (NSEI=%u) RIM PDU with unknown/wrong application ID received -- rejected.\n", nsei);
+ format_response_pdu_err(&resp_pdu, req_pdu);
+ return 0;
+ }
+
+ /* Handle incoming RIM container */
+ switch (req_pdu->rim_cont_iei) {
+ case BSSGP_IE_RI_REQ_RIM_CONTAINER:
+ LOGP(DRIM, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) responding to RAN INFORMATION REQUEST ...\n", nsei);
+ format_response_pdu(&resp_pdu, req_pdu, bts);
+ bssgp_tx_rim(&resp_pdu, nsei);
+ break;
+ case BSSGP_IE_RI_RIM_CONTAINER:
+ case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
+ case BSSGP_IE_RI_ACK_RIM_CONTAINER:
+ case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
+ LOGP(DRIM, LOGL_ERROR, "BSSGP RIM (NSEI=%u) RIM PDU not handled by this application\n", nsei);
+ return -EINVAL;
+ default:
+ /* This should never happen. If the RIM PDU is parsed correctly, then the rim_cont_iei will
+ * be set to one of the cases above and if parsing failes this switch statement is guarded
+ * by the check on decoded_present above */
+ OSMO_ASSERT(false);
+ }
+
+ return 0;
+}
diff --git a/src/gprs_bssgp_rim.h b/src/gprs_bssgp_rim.h
new file mode 100644
index 0000000..a34377d
--- /dev/null
+++ b/src/gprs_bssgp_rim.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <osmocom/gprs/gprs_bssgp.h>
+
+int sgsn_rim_rx(struct osmo_bssgp_prim *bp, struct msgb *msg, struct gprs_rlcmac_bts *bts);
diff --git a/src/gprs_debug.cpp b/src/gprs_debug.cpp
index a790e3f..9f3b1b8 100644
--- a/src/gprs_debug.cpp
+++ b/src/gprs_debug.cpp
@@ -119,6 +119,12 @@ static const struct log_info_cat default_categories[] = {
.loglevel = LOGL_NOTICE,
.enabled = 1,
},
+ [DRIM] = {
+ .name = "DRIM",
+ .description = "RAN Information Management (RIM)",
+ .loglevel = LOGL_NOTICE,
+ .enabled = 1,
+ },
};
static int filter_fn(const struct log_context *ctx,
diff --git a/src/gprs_debug.h b/src/gprs_debug.h
index 84a0a07..8df405a 100644
--- a/src/gprs_debug.h
+++ b/src/gprs_debug.h
@@ -46,6 +46,7 @@ enum {
DTBFUL,
DNS,
DPCU,
+ DRIM,
aDebug_LastEntry
};
diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp
index 8ae74d5..7054d1b 100644
--- a/src/pcu_l1_if.cpp
+++ b/src/pcu_l1_if.cpp
@@ -656,6 +656,33 @@ bssgp_failed:
goto bssgp_failed;
}
+ if (info_ind->si1_is_set) {
+ LOGP(DL1IF, LOGL_DEBUG, " si1=%s\n", osmo_hexdump_nospc(info_ind->si1, GSM_MACBLOCK_LEN));
+ memcpy(bts->si1, info_ind->si1, GSM_MACBLOCK_LEN);
+ bts->si1_is_set = true;
+ } else {
+ LOGP(DL1IF, LOGL_DEBUG, " si1=(not set)\n");
+ bts->si1_is_set = false;
+ }
+
+ if (info_ind->si3_is_set) {
+ LOGP(DL1IF, LOGL_DEBUG, " si3=%s\n", osmo_hexdump_nospc(info_ind->si3, GSM_MACBLOCK_LEN));
+ memcpy(bts->si3, info_ind->si3, GSM_MACBLOCK_LEN);
+ bts->si3_is_set = true;
+ } else {
+ LOGP(DL1IF, LOGL_DEBUG, " si3=(not set)\n");
+ bts->si3_is_set = false;
+ }
+
+ if (info_ind->si13_is_set) {
+ LOGP(DL1IF, LOGL_DEBUG, " si13=%s\n", osmo_hexdump_nospc(info_ind->si13, GSM_MACBLOCK_LEN));
+ memcpy(bts->si13, info_ind->si13, GSM_MACBLOCK_LEN);
+ bts->si13_is_set = true;
+ } else {
+ LOGP(DL1IF, LOGL_DEBUG, " si13=(not set)\n");
+ bts->si13_is_set = false;
+ }
+
if (info_ind->t3142) { /* if timer values are set */
osmo_tdef_set(bts->T_defs_bts, 3142, info_ind->t3142, OSMO_TDEF_S);
osmo_tdef_set(bts->T_defs_bts, 3169, info_ind->t3169, OSMO_TDEF_S);