aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/sgsn_libgtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/sgsn_libgtp.c')
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c130
1 files changed, 111 insertions, 19 deletions
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index aaf7e7aa7..303fa887c 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -37,6 +37,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/crypt/auth.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
@@ -47,6 +48,11 @@
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/iu.h>
+
+#include <osmocom/ranap/ranap_ies_defs.h>
+
+#include <asn1c/asn1helpers.h>
#include <gtp.h>
#include <pdp.h>
@@ -218,7 +224,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));
@@ -239,7 +248,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
pdp->userloc_given = 1;
pdp->userloc.l = 8;
pdp->userloc.v[0] = 0; /* CGI for GERAN */
- bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->cell_id);
+ bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->gb.cell_id);
/* include the IMEI(SV) */
pdp->imeisv_given = 1;
@@ -304,6 +313,19 @@ static const struct cause_map gtp2sm_cause_map[] = {
{ 0, 0 }
};
+static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx)
+{
+ struct sgsn_signal_data sig_data;
+
+ /* Inform others about it */
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.pdp = pctx;
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
+
+ /* Send PDP CTX ACT to MS */
+ return gsm48_tx_gsm_act_pdp_acc(pctx);
+}
+
/* The GGSN has confirmed the creation of a PDP Context */
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@@ -340,16 +362,17 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
goto reject;
}
- /* Activate the SNDCP layer */
- sndcp_sm_activate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
+ if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
+ /* Activate the SNDCP layer */
+ sndcp_sm_activate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
- /* Inform others about it */
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.pdp = pctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
- /* Send PDP CTX ACT to MS */
- return gsm48_tx_gsm_act_pdp_acc(pctx);
+ return send_act_pdp_cont_acc(pctx);
+ } else {
+ /* Activate a radio bearer */
+ iu_rab_act_ps(pdp->nsapi, pctx, 1);
+ return 0;
+ }
reject:
/*
@@ -372,6 +395,70 @@ reject:
return EOF;
}
+/* 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;
+
+}
+
/* Confirmation of a PDP Context Delete */
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@@ -387,8 +474,13 @@ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_DEACT, &sig_data);
if (pctx->mm) {
- /* Deactivate the SNDCP layer */
- sndcp_sm_deactivate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
+ if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
+ /* Deactivate the SNDCP layer */
+ sndcp_sm_deactivate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
+ } else {
+ /* Dectivate a radio bearer */
+ iu_rab_deact(pctx->mm->iu.ue_ctx, 1);
+ }
/* Confirm deactivation of PDP context to MS */
rc = gsm48_tx_gsm_deact_pdp_acc(pctx);
@@ -521,9 +613,9 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
ud = msgb_put(msg, len);
memcpy(ud, packet, len);
- msgb_tlli(msg) = mm->tlli;
- msgb_bvci(msg) = mm->bvci;
- msgb_nsei(msg) = mm->nsei;
+ msgb_tlli(msg) = mm->gb.tlli;
+ msgb_bvci(msg) = mm->gb.bvci;
+ msgb_nsei(msg) = mm->gb.nsei;
switch (mm->mm_state) {
case GMM_REGISTERED_SUSPENDED:
@@ -531,12 +623,12 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
memset(&pinfo, 0, sizeof(pinfo));
pinfo.mode = BSSGP_PAGING_PS;
pinfo.scope = BSSGP_PAGING_BVCI;
- pinfo.bvci = mm->bvci;
+ pinfo.bvci = mm->gb.bvci;
pinfo.imsi = mm->imsi;
pinfo.ptmsi = &mm->p_tmsi;
pinfo.drx_params = mm->drx_parms;
pinfo.qos[0] = 0; // FIXME
- bssgp_tx_paging(mm->nsei, 0, &pinfo);
+ bssgp_tx_paging(mm->gb.nsei, 0, &pinfo);
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
/* FIXME: queue the packet we received from GTP */
break;
@@ -544,7 +636,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
break;
default:
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
- "%u\n", mm->tlli, mm->mm_state);
+ "%u\n", mm->gb.tlli, mm->mm_state);
msgb_free(msg);
return -1;
}
@@ -557,7 +649,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
/* It is easier to have a global count */
pdp->cdr_bytes_out += len;
- return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi],
+ return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
pdp->nsapi, mm);
}