diff options
-rw-r--r-- | include/osmocom/gprs/gprs_bssgp.h | 35 | ||||
-rw-r--r-- | include/osmocom/gprs/gprs_bssgp_rim.h | 4 | ||||
-rw-r--r-- | src/gb/gprs_bssgp.c | 4 | ||||
-rw-r--r-- | src/gb/gprs_bssgp_rim.c | 13 | ||||
-rw-r--r-- | src/gb/gprs_bssgp_util.c | 215 | ||||
-rw-r--r-- | src/gb/libosmogb.map | 2 |
6 files changed, 269 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..d93c9df9 100644 --- a/src/gb/gprs_bssgp_util.c +++ b/src/gb/gprs_bssgp_util.c @@ -588,3 +588,218 @@ 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; + uint8_t rim_ri_buf[BSSGP_RIM_ROUTING_INFO_MAXLEN]; + uint8_t *rim_cont_buf; + int rc; + + if (!msg) + return NULL; + bgph = (struct bssgp_normal_hdr *)msgb_put(msg, sizeof(*bgph)); + + /* 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; |