blob: f28ba60bfb14552d151338016d719b11447768ec [file] [log] [blame]
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/vty/logging.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gprs/gprs_bssgp_rim.h>
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/gtp_mme.h>
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/sgsn.h>
static int sgsn_bssgp_fwd_rim_to_geran(const struct bssgp_ran_information_pdu *pdu)
{
struct bssgp_bvc_ctx *bvc_ctx;
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_GERAN);
bvc_ctx = btsctx_by_raid_cid(&pdu->routing_info_dest.geran.raid, pdu->routing_info_dest.geran.cid);
if (!bvc_ctx) {
LOGP(DRIM, LOGL_ERROR, "Unable to find NSEI for destination cell %s\n",
bssgp_rim_ri_name(&pdu->routing_info_dest));
return -EINVAL;
}
/* Forward PDU as it is to the correct interface */
return bssgp_tx_rim(pdu, bvc_ctx->nsei);
}
static int sgsn_bssgp_fwd_rim_to_eutran(const struct bssgp_ran_information_pdu *pdu)
{
struct sgsn_mme_ctx *mme;
OSMO_ASSERT(pdu->routing_info_dest.discr == BSSGP_RIM_ROUTING_INFO_EUTRAN);
mme = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_dest.eutran.tai);
if (!mme) { /* See if we have a default route configured */
mme = sgsn_mme_ctx_by_default_route(sgsn);
if (!mme) {
LOGP(DRIM, LOGL_ERROR, "Unable to find MME for destination cell %s\n",
bssgp_rim_ri_name(&pdu->routing_info_dest));
return -EINVAL;
}
}
return sgsn_mme_ran_info_req(mme, pdu);
}
/* Receive a RIM PDU from BSSGP (GERAN) */
int sgsn_rim_rx_from_gb(struct osmo_bssgp_prim *bp, struct msgb *msg)
{
uint16_t nsei = msgb_nsei(msg);
struct bssgp_ran_information_pdu *pdu = &bp->u.rim_pdu;
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGP(DRIM, LOGL_ERROR,
"Rx BSSGP RIM (NSEI=%u): Expected src %s, got %s\n", nsei,
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
goto err;
}
switch (pdu->routing_info_dest.discr) {
case BSSGP_RIM_ROUTING_INFO_GERAN:
return sgsn_bssgp_fwd_rim_to_geran(pdu);
case BSSGP_RIM_ROUTING_INFO_EUTRAN:
return sgsn_bssgp_fwd_rim_to_eutran(pdu);
default:
/* At the moment we can only handle GERAN/EUTRAN addresses, any
* other type of address will be considered as an invalid
* address. see also: 3GPP TS 48.018, section 8c.3.1.3
*/
LOGP(DRIM, LOGL_ERROR,
"Rx BSSGP RIM (NSEI=%u): Unsupported dst %s\n", nsei,
bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));
}
LOGP(DRIM, LOGL_INFO, "Rx BSSGP RIM (NSEI=%u): for dest cell %s\n", nsei,
bssgp_rim_ri_name(&pdu->routing_info_dest));
err:
/* In case of an invalid destination address we respond with
* a BSSGP STATUS PDU, see also: 3GPP TS 48.018, section 8c.3.1.3 */
bssgp_tx_status(BSSGP_CAUSE_UNKN_RIM_AI, NULL, msg);
return -1;
}
/* Receive a RIM PDU from GTPvC1 (EUTRAN) */
int sgsn_rim_rx_from_gtp(struct bssgp_ran_information_pdu *pdu, struct sgsn_mme_ctx *mme)
{
struct sgsn_mme_ctx *mme_tmp;
if (pdu->routing_info_src.discr != BSSGP_RIM_ROUTING_INFO_EUTRAN) {
LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected src %s, got %s\n",
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_EUTRAN),
bssgp_rim_routing_info_discr_str(pdu->routing_info_src.discr));
return -EINVAL;
}
if (pdu->routing_info_dest.discr != BSSGP_RIM_ROUTING_INFO_GERAN) {
LOGMME(mme, DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: Expected dst %s, got %s\n",
bssgp_rim_routing_info_discr_str(BSSGP_RIM_ROUTING_INFO_GERAN),
bssgp_rim_routing_info_discr_str(pdu->routing_info_dest.discr));
return -EINVAL;
}
mme_tmp = sgsn_mme_ctx_by_route(sgsn, &pdu->routing_info_src.eutran.tai);
if (!mme_tmp)/* See if we have a default route configured */
mme_tmp = sgsn_mme_ctx_by_default_route(sgsn);
if (mme != mme_tmp) {
LOGP(DRIM, LOGL_ERROR, "Rx GTP RAN Information Relay: "
"Source MME doesn't have RIM routing configured for TAI: %s\n",
bssgp_rim_ri_name(&pdu->routing_info_src));
return -EINVAL;
}
LOGMME(mme, DRIM, LOGL_INFO, "Rx GTP RAN Information Relay for dest cell %s\n",
bssgp_rim_ri_name(&pdu->routing_info_dest));
return sgsn_bssgp_fwd_rim_to_geran(pdu);
}