aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-05-05 21:16:19 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-05-05 21:16:19 +0200
commit4c8e8f990a24fc5ecb24c5c21c944d8ab4dc7c1e (patch)
treeeca760e9ec46564f520252834170bedb74071eb5 /openbsc/src/gprs
parent337343d159888886eaa68476b70dbe19db93845b (diff)
parentd05e06989def81f886c673956da476e626a27af5 (diff)
Merge branch 'zecke/features/gprs-gsup-fixes'
When communicating with a GGSN that is not the OpenGGSN the PDP context activation does fail. This is because on the activation of the first PDP context we need to supply a MSISDN. Extend the protocol, parse the MSISDN and then send it to the GGSN. The second item is that we have only forwarded the requested QoS of the subscriber. In most cases this is 0x0, 0x0, ... which means one requests a rate 0 byte/sec which the GGSN will not allow. Make it possible to receive, store and use the subscribed QoS of the Subscriber.
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r--openbsc/src/gprs/gprs_gsup_messages.c21
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c15
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c23
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c41
-rw-r--r--openbsc/src/gprs/sgsn_vty.c8
5 files changed, 99 insertions, 9 deletions
diff --git a/openbsc/src/gprs/gprs_gsup_messages.c b/openbsc/src/gprs/gprs_gsup_messages.c
index 9d9b6be20..cb14fa114 100644
--- a/openbsc/src/gprs/gprs_gsup_messages.c
+++ b/openbsc/src/gprs/gprs_gsup_messages.c
@@ -2,6 +2,7 @@
/*
* (C) 2014 by Sysmocom s.f.m.c. GmbH
+ * (C) 2015 by Holger Hans Peter Freyther
* All Rights Reserved
*
* Author: Jacob Erlbeck
@@ -93,6 +94,11 @@ static int decode_pdp_info(uint8_t *data, size_t data_len,
pdp_info->apn_enc_len = value_len;
break;
+ case GPRS_GSUP_PDP_QOS_IE:
+ pdp_info->qos_enc = value;
+ pdp_info->qos_enc_len = value_len;
+ break;
+
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
@@ -291,6 +297,12 @@ int gprs_gsup_decode(const uint8_t *const_data, size_t data_len,
gsup_msg->auth_tuples[gsup_msg->num_auth_tuples++] =
auth_info;
break;
+
+ case GPRS_GSUP_MSISDN_IE:
+ gsup_msg->msisdn_enc = value;
+ gsup_msg->msisdn_enc_len = value_len;
+ break;
+
default:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d unknown\n", iei);
@@ -326,6 +338,11 @@ static void encode_pdp_info(struct msgb *msg, enum gprs_gsup_iei iei,
pdp_info->apn_enc_len, pdp_info->apn_enc);
}
+ if (pdp_info->qos_enc) {
+ msgb_tlv_put(msg, GPRS_GSUP_PDP_QOS_IE,
+ pdp_info->qos_enc_len, pdp_info->qos_enc);
+ }
+
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
@@ -374,6 +391,10 @@ void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg
msgb_tlv_put(msg, GPRS_GSUP_IMSI_IE, bcd_len - 1, &bcd_buf[1]);
/* specific parts */
+ if (gsup_msg->msisdn_enc)
+ msgb_tlv_put(msg, GPRS_GSUP_MSISDN_IE,
+ gsup_msg->msisdn_enc_len, gsup_msg->msisdn_enc);
+
if ((u8 = gsup_msg->cause))
msgb_tlv_put(msg, GPRS_GSUP_CAUSE_IE, sizeof(u8), &u8);
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 94c2b6fbe..711540e03 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -582,6 +582,17 @@ void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
sgsn_auth_update(mmctx);
}
+static void insert_qos(struct tlv_parsed *tp, struct sgsn_subscriber_pdp_data *pdp)
+{
+ tp->lv[OSMO_IE_GSM_SUB_QOS].len = pdp->qos_subscribed_len;
+ tp->lv[OSMO_IE_GSM_SUB_QOS].val = pdp->qos_subscribed;
+}
+
+/**
+ * The tlv_parsed tp parameter will be modified to insert a
+ * OSMO_IE_GSM_SUB_QOS in case the data is available in the
+ * PDP context handling.
+ */
struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
struct tlv_parsed *tp,
enum gsm48_gsm_cause *gsm_cause)
@@ -621,6 +632,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
{
allow_any_apn = 1;
selected_apn_str = "";
+ insert_qos(tp, pdp);
continue;
}
if (!llist_empty(&sgsn_apn_ctxts)) {
@@ -629,6 +641,7 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
if (apn_ctx == NULL)
continue;
}
+ insert_qos(tp, pdp);
selected_apn_str = pdp->apn_str;
break;
}
@@ -636,11 +649,13 @@ struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
/* Check whether the given APN is granted */
llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) {
if (strcmp(pdp->apn_str, "*") == 0) {
+ insert_qos(tp, pdp);
selected_apn_str = req_apn_str;
allow_any_apn = 1;
continue;
}
if (strcasecmp(pdp->apn_str, req_apn_str) == 0) {
+ insert_qos(tp, pdp);
selected_apn_str = req_apn_str;
break;
}
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 60f223a0b..c2a3ae184 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -1,6 +1,7 @@
/* MS subscriber data handling */
/* (C) 2014 by sysmocom s.f.m.c. GmbH
+ * (C) 2015 by Holger Hans Peter Freyther
*
* All Rights Reserved
*
@@ -259,9 +260,22 @@ static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
+ struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
unsigned idx;
int rc;
+ if (gsup_msg->msisdn_enc) {
+ if (gsup_msg->msisdn_enc_len > sizeof(sdata->msisdn)) {
+ LOGP(DGPRS, LOGL_ERROR, "MSISDN too long (%zu)\n",
+ gsup_msg->msisdn_enc_len);
+ sdata->msisdn_len = 0;
+ } else {
+ memcpy(sdata->msisdn, gsup_msg->msisdn_enc,
+ gsup_msg->msisdn_enc_len);
+ sdata->msisdn_len = gsup_msg->msisdn_enc_len;
+ }
+ }
+
if (gsup_msg->pdp_info_compl) {
rc = gprs_subscr_pdp_data_clear(subscr);
if (rc > 0)
@@ -281,6 +295,13 @@ static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
continue;
}
+ if (pdp_info->qos_enc_len > sizeof(pdp_data->qos_subscribed)) {
+ LOGGSUBSCRP(LOGL_ERROR, subscr,
+ "QoS info too long (%zu)\n",
+ pdp_info->qos_enc_len);
+ continue;
+ }
+
LOGGSUBSCRP(LOGL_INFO, subscr,
"Will set PDP info, context id = %zu, APN = %s\n",
ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
@@ -296,6 +317,8 @@ static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
pdp_data->pdp_type = pdp_info->pdp_type;
gprs_apn_to_str(pdp_data->apn_str,
pdp_info->apn_enc, pdp_info->apn_enc_len);
+ memcpy(pdp_data->qos_subscribed, pdp_info->qos_enc, pdp_info->qos_enc_len);
+ pdp_data->qos_subscribed_len = pdp_info->qos_enc_len;
}
}
diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c
index 455e8af39..eee3ef21c 100644
--- a/openbsc/src/gprs/sgsn_libgtp.c
+++ b/openbsc/src/gprs/sgsn_libgtp.c
@@ -3,6 +3,7 @@
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
+ * (C) 2015 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -45,6 +46,7 @@
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
+#include <openbsc/gsm_subscriber.h>
#include <gtp.h>
#include <pdp.h>
@@ -121,6 +123,8 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
struct sgsn_pdp_ctx *pctx;
struct pdp_t *pdp;
uint64_t imsi_ui64;
+ size_t qos_len;
+ const uint8_t *qos;
int rc;
LOGP(DGPRS, LOGL_ERROR, "Create PDP Context\n");
@@ -153,8 +157,14 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
/* IMSI, TEID/TEIC, FLLU/FLLC, TID, NSAPI set in pdp_newpdp */
- /* FIXME: MSISDN in BCD format from mmctx */
- //pdp->msisdn.l/.v
+ /* Put the MSISDN in case we have it */
+ if (mmctx->subscr) {
+ pdp->msisdn.l = mmctx->subscr->sgsn_data->msisdn_len;
+ if (pdp->msisdn.l > sizeof(pdp->msisdn.v))
+ pdp->msisdn.l = sizeof(pdp->msisdn.l);
+ memcpy(pdp->msisdn.v, mmctx->subscr->sgsn_data->msisdn,
+ pdp->msisdn.l);
+ }
/* End User Address from GMM requested PDP address */
pdp->eua.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_PDP_ADDR);
@@ -180,12 +190,27 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
memcpy(pdp->pco_req.v, TLVP_VAL(tp, GSM48_IE_GSM_PROTO_CONF_OPT),
pdp->pco_req.l);
- /* QoS options from GMM */
- pdp->qos_req.l = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS);
- if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
- pdp->qos_req.l = sizeof(pdp->qos_req.v);
- memcpy(pdp->qos_req.v, TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS),
- pdp->qos_req.l);
+ /* QoS options from GMM or remote */
+ if (TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS) > 0) {
+ qos_len = TLVP_LEN(tp, OSMO_IE_GSM_SUB_QOS);
+ qos = TLVP_VAL(tp, OSMO_IE_GSM_SUB_QOS);
+ } else {
+ qos_len = TLVP_LEN(tp, OSMO_IE_GSM_REQ_QOS);
+ qos = TLVP_VAL(tp, OSMO_IE_GSM_REQ_QOS);
+ }
+
+ if (qos_len <= 3) {
+ pdp->qos_req.l = qos_len + 1;
+ if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
+ pdp->qos_req.l = sizeof(pdp->qos_req.v);
+ pdp->qos_req.v[0] = 0; /* Allocation/Retention policy */
+ memcpy(&pdp->qos_req.v[1], qos, pdp->qos_req.l - 1);
+ } else {
+ pdp->qos_req.l = qos_len;
+ if (pdp->qos_req.l > sizeof(pdp->qos_req.v))
+ pdp->qos_req.l = sizeof(pdp->qos_req.v);
+ memcpy(pdp->qos_req.v, qos, pdp->qos_req.l);
+ }
/* SGSN address for control plane */
pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index 684204a1f..be575d337 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -471,6 +471,11 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr,
if (subscr->tmsi != GSM_RESERVED_TMSI)
vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
VTY_NEWLINE);
+ if (subscr->sgsn_data->msisdn_len > 0)
+ vty_out(vty, " MSISDN (BCD): %s%s",
+ osmo_hexdump(subscr->sgsn_data->msisdn,
+ subscr->sgsn_data->msisdn_len),
+ VTY_NEWLINE);
if (strlen(subscr->equipment.imei) > 0)
vty_out(vty, " IMEI: %s%s", subscr->equipment.imei, VTY_NEWLINE);
@@ -495,8 +500,9 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr,
}
llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
- vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'%s",
+ vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s' QoS: %s%s",
pdp->context_id, pdp->pdp_type, pdp->apn_str,
+ osmo_hexdump(pdp->qos_subscribed, pdp->qos_subscribed_len),
VTY_NEWLINE);
}