aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2021-01-07 21:55:48 +0100
committerPhilipp Maier <pmaier@sysmocom.de>2021-01-19 17:38:31 +0100
commit9e667c5065e42c59021e90b4924fe7c8dd4f4af8 (patch)
treefe66ad08258e65722cb643673ac152cc8742ab36
parentaca31b8b2ddd63bc5f9f8db020cffb699672477b (diff)
gprs_bssgp: add utilities to send and parse BSSGP rim PDUspmaier/rim2
At the moment libosmogb offers no convinient way to send RIM PDUs. Also parsing an incoming RIM messages into destination, source routing info and RIM container is not available. Change-Id: I18134fd9938040d2facb6beee3732628b167ce8c Related: SYS#5103
-rw-r--r--include/osmocom/gprs/gprs_bssgp.h35
-rw-r--r--include/osmocom/gprs/gprs_bssgp_rim.h4
-rw-r--r--src/gb/gprs_bssgp.c4
-rw-r--r--src/gb/gprs_bssgp_rim.c13
-rw-r--r--src/gb/gprs_bssgp_util.c211
-rw-r--r--src/gb/libosmogb.map2
6 files changed, 265 insertions, 4 deletions
diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h
index 92556615..a7b363bd 100644
--- a/include/osmocom/gprs/gprs_bssgp.h
+++ b/include/osmocom/gprs/gprs_bssgp.h
@@ -11,6 +11,7 @@
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/gprs/protocol/gsm_24_301.h>
+#include <osmocom/gprs/gprs_bssgp_rim.h>
/* gprs_bssgp_util.c */
@@ -41,6 +42,39 @@ int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei,
/* Chapter 10.4.14: Status */
int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg);
+/* Chapter 10.6.1: RAN-INFORMATION-REQUEST */
+struct bssgp_ran_information_pdu {
+ struct bssgp_rim_routing_info routing_info_dest;
+ struct bssgp_rim_routing_info routing_info_src;
+
+ /* Encoded variant of the RIM container */
+ uint8_t rim_cont_iei;
+ const uint8_t *rim_cont;
+ unsigned int rim_cont_len;
+
+ /* Decoded variant of the RIM container */
+ bool decoded_present;
+ union {
+ struct bssgp_ran_inf_req_rim_cont req_rim_cont;
+ struct bssgp_ran_inf_rim_cont rim_cont;
+ struct bssgp_ran_inf_ack_rim_cont ack_rim_cont;
+ struct bssgp_ran_inf_err_rim_cont err_rim_cont;
+ struct bssgp_ran_inf_app_err_rim_cont app_err_rim_cont;
+ } decoded;
+
+ /* When receiving a PDU from BSSGP the encoded variant of the RIM
+ * container will always be present. The decoded variant will be
+ * present in addition whenever BSSGP was able to decode the container.
+ *
+ * When sending a PDU to BSSGP, then the decoded variant is used when
+ * it is available. The encoded variant (if present) will be ignored
+ * then. */
+};
+int bssgp_tx_rim(const struct bssgp_ran_information_pdu *pdu, uint16_t nsei);
+
+int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb *msg);
+struct msgb *bssgp_encode_rim_pdu(const struct bssgp_ran_information_pdu *pdu);
+
enum bssgp_prim {
PRIM_BSSGP_DL_UD,
PRIM_BSSGP_UL_UD,
@@ -75,6 +109,7 @@ struct osmo_bssgp_prim {
struct {
uint8_t suspend_ref;
} resume;
+ struct bssgp_ran_information_pdu rim_pdu;
} u;
};
diff --git a/include/osmocom/gprs/gprs_bssgp_rim.h b/include/osmocom/gprs/gprs_bssgp_rim.h
index 7f3a0e43..7e9efcd7 100644
--- a/include/osmocom/gprs/gprs_bssgp_rim.h
+++ b/include/osmocom/gprs/gprs_bssgp_rim.h
@@ -54,6 +54,10 @@ struct bssgp_rim_routing_info {
};
};
+/* The encoded result of the rim routing information is, depending on the
+ * address type (discr) of variable length. */
+#define BSSGP_RIM_ROUTING_INFO_MAXLEN 14
+
int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf, unsigned int len);
int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri);
diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c
index 45514275..6fdacce6 100644
--- a/src/gb/gprs_bssgp.c
+++ b/src/gb/gprs_bssgp.c
@@ -675,6 +675,8 @@ static int bssgp_rx_rim(struct msgb *msg, struct tlv_parsed *tp, uint16_t bvci)
nmp.nsei = nsei;
nmp.bvci = bvci;
nmp.tp = tp;
+ if (bssgp_parse_rim_pdu(&nmp.u.rim_pdu, msg) < 0)
+ return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
osmo_prim_init(&nmp.oph, SAP_BSSGP_RIM, prim, PRIM_OP_INDICATION, msg);
bssgp_prim_cb(&nmp.oph, NULL);
@@ -1111,7 +1113,7 @@ static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
case BSSGP_PDUT_RAN_INFO_ACK:
case BSSGP_PDUT_RAN_INFO_ERROR:
case BSSGP_PDUT_RAN_INFO_APP_ERROR:
- bssgp_rx_rim(msg, tp, bvci);
+ rc = bssgp_rx_rim(msg, tp, bvci);
break;
/* those only exist in the SGSN -> BSS direction */
diff --git a/src/gb/gprs_bssgp_rim.c b/src/gb/gprs_bssgp_rim.c
index 0dc6d215..7094f5f4 100644
--- a/src/gb/gprs_bssgp_rim.c
+++ b/src/gb/gprs_bssgp_rim.c
@@ -96,6 +96,7 @@ int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
{
int rc;
struct gprs_ra_id raid_temp;
+ int len;
buf[0] = ri->discr & 0x0f;
buf++;
@@ -105,11 +106,13 @@ int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
rc = bssgp_create_cell_id(buf, &ri->geran.raid, ri->geran.cid);
if (rc < 0)
return -EINVAL;
- return rc + 1;
+ len = rc + 1;
+ break;
case BSSGP_RIM_ROUTING_INFO_UTRAN:
gsm48_encode_ra((struct gsm48_ra_id *)buf, &ri->utran.raid);
osmo_store16be(ri->utran.rncid, buf + 6);
- return 9;
+ len = 9;
+ break;
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
/* Note: 3GPP TS 24.301 Figure 9.9.3.32.1 and 3GPP TS 24.008
* Figure 10.5.130 specify MCC/MNC encoding in the same way,
@@ -126,10 +129,14 @@ int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri)
sizeof(ri->eutran.global_enb_id));
memcpy(buf + 5, ri->eutran.global_enb_id,
ri->eutran.global_enb_id_len);
- return ri->eutran.global_enb_id_len + 6;
+ len = ri->eutran.global_enb_id_len + 6;
+ break;
default:
return -EINVAL;
}
+
+ OSMO_ASSERT(len <= BSSGP_RIM_ROUTING_INFO_MAXLEN);
+ return len;
}
/*! Decode a RAN Information Request Application Container for NACC (3GPP TS 48.018, section 11.3.63.1.1).
diff --git a/src/gb/gprs_bssgp_util.c b/src/gb/gprs_bssgp_util.c
index 92896c1f..fc00fcfc 100644
--- a/src/gb/gprs_bssgp_util.c
+++ b/src/gb/gprs_bssgp_util.c
@@ -588,3 +588,214 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg)
return bssgp_ns_send(bssgp_ns_send_data, msg);
}
+
+/* Chapter 10.6.1: RAN-INFORMATION-REQUEST */
+int bssgp_tx_rim(const struct bssgp_ran_information_pdu *pdu, uint16_t nsei)
+{
+ struct msgb *msg;
+ struct bssgp_normal_hdr *bgph;
+
+ /* Encode RIM PDU into mesage buffer */
+ msg = bssgp_encode_rim_pdu(pdu);
+ if (!msg) {
+ LOGP(DLBSSGP, LOGL_ERROR,
+ "BSSGP RIM (NSEI=%u) unable to encode BSSGP RIM PDU\n", nsei);
+ return -EINVAL;
+ }
+
+ msgb_nsei(msg) = nsei;
+ msgb_bvci(msg) = 0; /* Signalling */
+
+ bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
+ DEBUGP(DLBSSGP, "BSSGP BVCI=0 Tx RIM-PDU:%s\n", bssgp_pdu_str(bgph->pdu_type));
+
+ return bssgp_ns_send(bssgp_ns_send_data, msg);
+}
+
+/* Parse a given message buffer into a rim-pdu struct */
+int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb *msg)
+{
+ struct tlv_parsed tp[2];
+ struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_bssgph(msg);
+ int data_len;
+ int rc;
+ uint16_t nsei = msgb_nsei(msg);
+
+ memset(pdu, 0, sizeof(*pdu));
+
+ data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
+ if (data_len < 0)
+ return -EINVAL;
+
+ rc = osmo_tlv_prot_parse(&osmo_pdef_bssgp, tp, ARRAY_SIZE(tp), bgph->pdu_type, bgph->data, data_len, 0, 0,
+ DLBSSGP, __func__);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (TLVP_PRESENT(&tp[0], BSSGP_IE_RIM_ROUTING_INFO)) {
+ rc = bssgp_parse_rim_ri(&pdu->routing_info_dest, TLVP_VAL(&tp[0], BSSGP_IE_RIM_ROUTING_INFO),
+ TLVP_LEN(&tp[0], BSSGP_IE_RIM_ROUTING_INFO));
+ if (rc < 0) {
+ LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
+ return -EINVAL;
+ }
+ } else {
+ LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Destination Cell Identifier IE\n", nsei);
+ return -EINVAL;
+ }
+
+ if (TLVP_PRESENT(&tp[1], BSSGP_IE_RIM_ROUTING_INFO)) {
+ rc = bssgp_parse_rim_ri(&pdu->routing_info_src, TLVP_VAL(&tp[1], BSSGP_IE_RIM_ROUTING_INFO),
+ TLVP_LEN(&tp[1], BSSGP_IE_RIM_ROUTING_INFO));
+ if (rc < 0) {
+ LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) invalid Destination Cell Identifier IE\n", nsei);
+ return -EINVAL;
+ }
+ } else {
+ LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing Source Cell Identifier IE\n", nsei);
+ return -EINVAL;
+ }
+
+ if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_REQ_RIM_CONTAINER))
+ pdu->rim_cont_iei = BSSGP_IE_RI_REQ_RIM_CONTAINER;
+ else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_RIM_CONTAINER))
+ pdu->rim_cont_iei = BSSGP_IE_RI_RIM_CONTAINER;
+ else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_APP_ERROR_RIM_CONT))
+ pdu->rim_cont_iei = BSSGP_IE_RI_APP_ERROR_RIM_CONT;
+ else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ACK_RIM_CONTAINER))
+ pdu->rim_cont_iei = BSSGP_IE_RI_ACK_RIM_CONTAINER;
+ else if (TLVP_PRESENT(&tp[0], BSSGP_IE_RI_ERROR_RIM_COINTAINER))
+ pdu->rim_cont_iei = BSSGP_IE_RI_ERROR_RIM_COINTAINER;
+ else {
+ LOGP(DLBSSGP, LOGL_ERROR, "BSSGP RIM (NSEI=%u) missing or wrong RIM Container IE\n", nsei);
+ return -EINVAL;
+ }
+
+ pdu->rim_cont = TLVP_VAL(&tp[0], pdu->rim_cont_iei);
+ pdu->rim_cont_len = TLVP_LEN(&tp[0], pdu->rim_cont_iei);
+
+ /* Make sure the rim container field is not empty */
+ if (pdu->rim_cont_len < 1)
+ return -EINVAL;
+ if (!pdu->rim_cont)
+ return -EINVAL;
+
+ /* Note: It is not an error if we fail to parse the RIM container,
+ * since there are applications where parsing the RIM container
+ * is not necessary (routing). It is up to the API user to check
+ * the results. */
+ switch (pdu->rim_cont_iei) {
+ case BSSGP_IE_RI_REQ_RIM_CONTAINER:
+ rc = bssgp_dec_ran_inf_req_rim_cont(&pdu->decoded.req_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
+ break;
+ case BSSGP_IE_RI_RIM_CONTAINER:
+ rc = bssgp_dec_ran_inf_rim_cont(&pdu->decoded.rim_cont, pdu->rim_cont, pdu->rim_cont_len);
+ break;
+ case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
+ rc = bssgp_dec_ran_inf_app_err_rim_cont(&pdu->decoded.app_err_rim_cont, pdu->rim_cont,
+ pdu->rim_cont_len);
+ break;
+ case BSSGP_IE_RI_ACK_RIM_CONTAINER:
+ rc = bssgp_dec_ran_inf_ack_rim_cont(&pdu->decoded.ack_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
+ break;
+ case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
+ rc = bssgp_dec_ran_inf_err_rim_cont(&pdu->decoded.err_rim_cont, pdu->rim_cont, pdu->rim_cont_len);
+ break;
+ default:
+ LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) cannot parse unknown RIM container.\n", nsei);
+ return 0;
+ }
+ if (rc < 0) {
+ LOGP(DLBSSGP, LOGL_DEBUG, "BSSGP RIM (NSEI=%u) unable to parse RIM container.\n", nsei);
+ return 0;
+ }
+ pdu->decoded_present = true;
+
+ return 0;
+}
+
+/* Encode a given rim-pdu struct into a message buffer */
+struct msgb *bssgp_encode_rim_pdu(const struct bssgp_ran_information_pdu *pdu)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *)msgb_put(msg, sizeof(*bgph));
+ uint8_t rim_ri_buf[BSSGP_RIM_ROUTING_INFO_MAXLEN];
+ uint8_t *rim_cont_buf;
+ int rc;
+
+ /* Set PDU type based on RIM container type */
+ switch (pdu->rim_cont_iei) {
+ case BSSGP_IE_RI_REQ_RIM_CONTAINER:
+ bgph->pdu_type = BSSGP_PDUT_RAN_INFO_REQ;
+ break;
+ case BSSGP_IE_RI_RIM_CONTAINER:
+ bgph->pdu_type = BSSGP_PDUT_RAN_INFO;
+ break;
+ case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
+ bgph->pdu_type = BSSGP_PDUT_RAN_INFO_APP_ERROR;
+ break;
+ case BSSGP_IE_RI_ACK_RIM_CONTAINER:
+ bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ACK;
+ break;
+ case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
+ bgph->pdu_type = BSSGP_PDUT_RAN_INFO_ERROR;
+ break;
+ default:
+ /* The caller must correctly specify the container type! */
+ OSMO_ASSERT(false);
+ }
+
+ /* Put RIM routing information */
+ rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_dest);
+ if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
+ goto error;
+ msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
+ rc = bssgp_create_rim_ri(rim_ri_buf, &pdu->routing_info_src);
+ if (rc < 0 || rc > BSSGP_RIM_ROUTING_INFO_MAXLEN)
+ goto error;
+ msgb_tvlv_put(msg, BSSGP_IE_RIM_ROUTING_INFO, rc, rim_ri_buf);
+
+ /* Put RIM container */
+ if (pdu->decoded_present) {
+ rim_cont_buf = talloc_zero_size(msg, msg->data_len);
+ if (!rim_cont_buf)
+ goto error;
+
+ switch (pdu->rim_cont_iei) {
+ case BSSGP_IE_RI_REQ_RIM_CONTAINER:
+ rc = bssgp_enc_ran_inf_req_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.req_rim_cont);
+ break;
+ case BSSGP_IE_RI_RIM_CONTAINER:
+ rc = bssgp_enc_ran_inf_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.rim_cont);
+ break;
+ case BSSGP_IE_RI_APP_ERROR_RIM_CONT:
+ rc = bssgp_enc_ran_inf_app_err_rim_cont(rim_cont_buf, msg->data_len,
+ &pdu->decoded.app_err_rim_cont);
+ break;
+ case BSSGP_IE_RI_ACK_RIM_CONTAINER:
+ rc = bssgp_enc_ran_inf_ack_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.ack_rim_cont);
+ break;
+ case BSSGP_IE_RI_ERROR_RIM_COINTAINER:
+ rc = bssgp_enc_ran_inf_err_rim_cont(rim_cont_buf, msg->data_len, &pdu->decoded.err_rim_cont);
+ break;
+ default:
+ /* The API user must set the iei properly! */
+ OSMO_ASSERT(false);
+ }
+ if (rc < 0)
+ goto error;
+
+ msgb_tvlv_put(msg, pdu->rim_cont_iei, rc, rim_cont_buf);
+ talloc_free(rim_cont_buf);
+ } else {
+ /* Make sure the RIM container is actually present. */
+ OSMO_ASSERT(pdu->rim_cont_iei != 0 && pdu->rim_cont_len > 0 && pdu->rim_cont);
+ msgb_tvlv_put(msg, pdu->rim_cont_iei, pdu->rim_cont_len, pdu->rim_cont);
+ }
+
+ return msg;
+error:
+ talloc_free(rim_cont_buf);
+ msgb_free(msg);
+ return 0;
+}
diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map
index b012184e..763ddc6c 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -30,6 +30,7 @@ bssgp_msgb_copy;
bssgp_msgb_tlli_put;
bssgp_msgb_ra_put;
bssgp_parse_cell_id;
+bssgp_parse_rim_pdu;
bssgp_parse_rim_ri;
bssgp_set_bssgp_callback;
bssgp_tx_bvc_block;
@@ -48,6 +49,7 @@ bssgp_tx_radio_status_tmsi;
bssgp_tx_resume;
bssgp_tx_resume_ack;
bssgp_tx_resume_nack;
+bssgp_tx_rim;
bssgp_tx_simple_bvci;
bssgp_tx_status;
bssgp_tx_suspend;