aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gprs_gmm.h2
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h3
-rw-r--r--openbsc/src/gprs/Makefile.am14
-rw-r--r--openbsc/src/gprs/gprs_gmm.c88
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c41
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c78
-rw-r--r--openbsc/src/gprs/sgsn_main.c16
7 files changed, 239 insertions, 3 deletions
diff --git a/openbsc/include/openbsc/gprs_gmm.h b/openbsc/include/openbsc/gprs_gmm.h
index 8a3ffea41..28467d768 100644
--- a/openbsc/include/openbsc/gprs_gmm.h
+++ b/openbsc/include/openbsc/gprs_gmm.h
@@ -14,6 +14,8 @@ int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable);
+int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
+ uint16_t *sai);
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg,
struct gprs_llc_llme *llme);
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index b0dd75f7f..18cbab834 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -226,6 +226,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
const struct gprs_ra_id *raid);
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi);
struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx);
/* look-up by matching TLLI and P-TMSI (think twice before using this) */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
@@ -234,6 +235,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
/* Allocate a new SGSN MM context */
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
const struct gprs_ra_id *raid);
+struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx);
+
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx);
struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am
index 1b6de4695..6a9531510 100644
--- a/openbsc/src/gprs/Makefile.am
+++ b/openbsc/src/gprs/Makefile.am
@@ -3,6 +3,10 @@ AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \
$(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS)
+if BUILD_IU
+AM_CFLAGS += $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
+endif
+
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS)
@@ -28,9 +32,15 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
sgsn_cdr.c sgsn_ares.c \
oap.c oap_messages.c gprs_llc_xid.c
osmo_sgsn_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
- -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
+ $(top_builddir)/src/libcommon/libcommon.a
+if BUILD_IU
+osmo_sgsn_LDADD += $(top_builddir)/src/libiu/libiu.a
+endif
+osmo_sgsn_LDADD += -lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
$(LIBCRYPTO_LIBS) -lrt
+if BUILD_IU
+osmo_sgsn_LDADD += $(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS)
+endif
osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \
gtphub_vty.c sgsn_ares.c gprs_utils.c
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index 1efada948..4c442241d 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -33,6 +33,8 @@
#include <openssl/rand.h>
+#include "bscconfig.h"
+
#include <openbsc/db.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
@@ -45,6 +47,10 @@
#include <osmocom/gprs/gprs_bssgp.h>
+#ifdef BUILD_IU
+#include <osmocom/ranap/ranap_ies_defs.h>
+#endif
+
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
@@ -58,6 +64,10 @@
#include <openbsc/sgsn.h>
#include <openbsc/signal.h>
+#ifdef BUILD_IU
+#include <openbsc/iu.h>
+#endif
+
#include <pdp.h>
#define PTMSI_ALLOC
@@ -97,6 +107,45 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = {
static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx);
+#ifdef BUILD_IU
+int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies);
+int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data)
+{
+ struct sgsn_mm_ctx *mm;
+ int rc = -1;
+
+ mm = sgsn_mm_ctx_by_ue_ctx(ctx);
+ if (!mm) {
+ LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type);
+ return rc;
+ }
+
+ switch (type) {
+ case IU_EVENT_RAB_ASSIGN:
+ rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data);
+ break;
+ case IU_EVENT_IU_RELEASE:
+ /* fall thru */
+ case IU_EVENT_LINK_INVALIDATED:
+ /* Clean up ue_conn_ctx here */
+ LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
+ rc = 0;
+ break;
+ case IU_EVENT_SECURITY_MODE_COMPLETE:
+ /* Continue authentication here */
+ mm->iu.ue_ctx->integrity_active = 1;
+ rc = gsm48_gmm_authorize(mm);
+ break;
+ default:
+ LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type);
+ rc = -1;
+ break;
+ }
+ return rc;
+}
+#endif
+
+
/* Our implementation, should be kept in SGSN */
static void mmctx_timer_cb(void *_mm);
@@ -2193,6 +2242,45 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
return rc;
}
+/* Main entry point for incoming 04.08 GPRS messages from Iu */
+int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
+ uint16_t *sai)
+{
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+ uint8_t pdisc = gsm48_hdr_pdisc(gh);
+ struct sgsn_mm_ctx *mmctx;
+ int rc = -EINVAL;
+
+ mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst);
+ if (mmctx) {
+ rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
+ if (ra_id)
+ memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
+ }
+
+ /* MMCTX can be NULL */
+
+ switch (pdisc) {
+ case GSM48_PDISC_MM_GPRS:
+ rc = gsm0408_rcv_gmm(mmctx, msg, NULL, false);
+#warning "set drop_cipherable arg for gsm0408_rcv_gmm() from IuPS?"
+ break;
+ case GSM48_PDISC_SM_GPRS:
+ rc = gsm0408_rcv_gsm(mmctx, msg, NULL);
+ break;
+ default:
+ LOGMMCTXP(LOGL_NOTICE, mmctx,
+ "Unknown GSM 04.08 discriminator 0x%02x: %s\n",
+ pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
+ /* FIXME: return status message */
+ break;
+ }
+
+ /* MMCTX can be invalid */
+
+ return rc;
+}
+
/* Main entry point for incoming 04.08 GPRS messages from Gb */
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable)
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 9cd992b49..19b0a1b7c 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -39,6 +39,7 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/signal.h>
#include "openbsc/gprs_llc.h"
+#include <openbsc/iu.h>
#include <pdp.h>
@@ -130,6 +131,20 @@ void sgsn_rate_ctr_init() {
sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0);
}
+/* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx)
+{
+ struct sgsn_mm_ctx *ctx;
+
+ llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
+ if (ctx->ran_type == MM_CTX_T_UTRAN_Iu
+ && uectx == ctx->iu.ue_ctx)
+ return ctx;
+ }
+
+ return NULL;
+}
+
/* look-up a SGSN MM context based on TLLI + RAI */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
const struct gprs_ra_id *raid)
@@ -218,6 +233,32 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
return ctx;
}
+/* Allocate a new SGSN MM context */
+struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
+{
+ struct sgsn_mm_ctx *ctx;
+
+ ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
+ if (!ctx)
+ return NULL;
+
+ ctx->ran_type = MM_CTX_T_UTRAN_Iu;
+ ctx->iu.ue_ctx = uectx;
+ ctx->mm_state = GMM_DEREGISTERED;
+ ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
+ ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0);
+
+ /* Need to get RAID from IU conn */
+ ctx->ra = ctx->iu.ue_ctx->ra_id;
+
+ INIT_LLIST_HEAD(&ctx->pdp_list);
+
+ llist_add(&ctx->list, &sgsn_mm_ctxts);
+
+ return ctx;
+}
+
+
/* this is a hard _free_ function, it doesn't clean up the PDP contexts
* in libgtp! */
static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index be7637a85..4a14cf611 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -34,6 +34,8 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include "bscconfig.h"
+
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
@@ -48,6 +50,11 @@
#include <openbsc/gprs_gmm.h>
#include <openbsc/gsm_subscriber.h>
+#ifdef BUILD_IU
+#include <openbsc/iu.h>
+#include <osmocom/ranap/ranap_ies_defs.h>
+#endif
+
#include <gtp.h>
#include <pdp.h>
@@ -218,7 +225,10 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
- /* SGSN address for user plane */
+ /* SGSN address for user plane
+ * Default to the control plane addr for now. If we are connected to a
+ * hnbgw via IuPS we'll need to send a PDP context update with the
+ * correct IP address after the RAB Assignment is complete */
pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
@@ -383,6 +393,72 @@ reject:
return EOF;
}
+#ifdef BUILD_IU
+/* Callback for RAB assignment response */
+int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
+{
+ uint8_t rab_id;
+ bool require_pdp_update = false;
+ struct sgsn_pdp_ctx *pdp = NULL;
+ RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
+
+ rab_id = item->rAB_ID.buf[0];
+
+ pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
+ if (!pdp) {
+ LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
+ return -1;
+ }
+
+ if (item->transportLayerAddress) {
+ LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
+ item->transportLayerAddress->size));
+ switch (item->transportLayerAddress->size) {
+ case 7:
+ /* It must be IPv4 inside a X213 NSAP */
+ memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
+ break;
+ case 4:
+ /* It must be a raw IPv4 address */
+ memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
+ break;
+ case 16:
+ /* TODO: It must be a raw IPv6 address */
+ case 19:
+ /* TODO: It must be IPv6 inside a X213 NSAP */
+ default:
+ LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
+ "transport layer address size %u\n",
+ item->transportLayerAddress->size);
+ return -1;
+ }
+ require_pdp_update = true;
+ }
+
+ /* The TEI on the RNC side might have changed, too */
+ if (item->iuTransportAssociation &&
+ item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
+ item->iuTransportAssociation->choice.gTP_TEI.buf &&
+ item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
+ uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
+ LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
+ pdp->lib->teid_own, tei);
+ pdp->lib->teid_own = tei;
+ require_pdp_update = true;
+ }
+
+ if (require_pdp_update)
+ gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
+
+ if (pdp->state != PDP_STATE_CR_CONF) {
+ send_act_pdp_cont_acc(pdp);
+ pdp->state = PDP_STATE_CR_CONF;
+ }
+ return 0;
+
+}
+#endif
+
/* Confirmation of a PDP Context Delete */
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index 52fc98561..7d533c060 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -56,6 +56,8 @@
#include <openbsc/sgsn.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_gmm.h>
+#include <openbsc/iu.h>
+
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
@@ -300,6 +302,13 @@ static const struct log_info gprs_log_info = {
.num_cat = ARRAY_SIZE(gprs_categories),
};
+/* Implement the extern asn_debug from libasn1c to indicate whether the ASN.1
+ * binary code decoded and encoded during Iu communication should be logged to
+ * stderr. See osmocom's libasn1c, asn_internal.h, at "if (asn_debug)":
+ * http://git.osmocom.org/libasn1c/tree/include/asn1c/asn_internal.h */
+int asn_debug = 0;
+
+int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data);
int main(int argc, char **argv)
{
@@ -326,6 +335,9 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds(&gprs_log_info);
sgsn_vty_init();
ctrl_vty_init(tall_bsc_ctx);
+#ifdef BUILD_IU
+ iu_vty_init(&asn_debug);
+#endif
handle_options(argc, argv);
@@ -417,6 +429,10 @@ int main(int argc, char **argv)
}
}
+#ifdef BUILD_IU
+ iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
+#endif
+
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {