aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-12-17 14:03:35 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-02-06 09:55:39 +0100
commit0e8add601da35188eb155c8c279a9bdcaf4ba41b (patch)
tree734feace1bd63992e0d31d0a0414df79552a8cb8 /openbsc
parentf6f86b0eec18da165db136b14bf2db87fde4b4ac (diff)
sgsn: Add PDP info to subscriber data
Currently the PDP info that is transmitted via GSUP is just parsed and then discarded. This commit adds a new data structure sgsn_subscriber_pdp_data and maintains a list of those in sgsn_subscriber_data. The PDP data is copied from an incoming GSUP UpdateLocationResult message. If that message contains the PDPInfoComplete flag, the list is cleared before new entries are added. The 'show subscriber cache' output now also shows the PDP data entries. Note that the InsertSubscriberData message is still not supported. [hfreyther: Added talloc_free in gprs_subscr_pdp_data_clear] Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h12
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c85
-rw-r--r--openbsc/src/gprs/sgsn_vty.c7
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c10
4 files changed, 105 insertions, 9 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index f566ab9f9..516b6cda9 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -15,6 +15,7 @@
#define GSM_IMSI_LENGTH 17
#define GSM_IMEI_LENGTH 17
#define GSM_EXTENSION_LENGTH 15
+#define GSM_APN_LENGTH 102
struct gprs_llc_lle;
struct ctrl_handle;
@@ -273,6 +274,16 @@ struct imsi_acl_entry {
char imsi[16+1];
};
+/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
+/* see GSM 09.02, B.1, gprsSubscriptionData */
+struct sgsn_subscriber_pdp_data {
+ struct llist_head list;
+
+ unsigned int context_id;
+ uint16_t pdp_type;
+ char apn_str[GSM_APN_LENGTH];
+};
+
enum sgsn_subscriber_proc {
SGSN_SUBSCR_PROC_NONE = 0,
SGSN_SUBSCR_PROC_PURGE,
@@ -284,6 +295,7 @@ struct sgsn_subscriber_data {
struct sgsn_mm_ctx *mm;
struct gsm_auth_tuple auth_triplets[5];
int auth_triplets_updated;
+ struct llist_head pdp_list;
int error_cause;
enum sgsn_subscriber_proc blocked_by;
};
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 0009685b1..24603403d 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -26,6 +26,7 @@
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gprs_gsup_messages.h>
+#include <openbsc/gprs_utils.h>
#include <openbsc/debug.h>
@@ -111,9 +112,23 @@ static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
+ INIT_LLIST_HEAD(&sdata->pdp_list);
+
return sdata;
}
+struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
+ struct sgsn_subscriber_data *sdata)
+{
+ struct sgsn_subscriber_pdp_data* pdata;
+
+ pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data);
+
+ llist_add_tail(&pdata->list, &sdata->pdp_list);
+
+ return pdata;
+}
+
struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
{
struct gsm_subscriber *subscr;
@@ -229,27 +244,81 @@ static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
return 0;
}
-static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
- struct gprs_gsup_message *gsup_msg)
+static int gprs_subscr_pdp_data_clear(struct gsm_subscriber *subscr)
+{
+ struct sgsn_subscriber_pdp_data *pdp, *pdp2;
+ int count = 0;
+
+ llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) {
+ llist_del(&pdp->list);
+ talloc_free(pdp);
+ count += 1;
+ }
+
+ return count;
+}
+
+static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
+ struct gsm_subscriber *subscr, unsigned context_id)
+{
+ struct sgsn_subscriber_pdp_data *pdp;
+
+ llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
+ if (pdp->context_id == context_id)
+ return pdp;
+ }
+
+ return NULL;
+}
+
+
+static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
+ struct gprs_gsup_message *gsup_msg)
{
unsigned idx;
+ int rc;
if (gsup_msg->pdp_info_compl) {
- LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
-
- /* TODO: clear existing PDP info entries */
+ rc = gprs_subscr_pdp_data_clear(subscr);
+ if (rc > 0)
+ LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n");
}
for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
size_t ctx_id = pdp_info->context_id;
+ struct sgsn_subscriber_pdp_data *pdp_data;
- LOGP(DGPRS, LOGL_INFO,
- "Would set PDP info, context id = %d, APN = %s\n",
+ if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
+ LOGGSUBSCRP(LOGL_ERROR, subscr,
+ "APN too long, context id = %d, APN = %s\n",
+ ctx_id, osmo_hexdump(pdp_info->apn_enc,
+ pdp_info->apn_enc_len));
+ continue;
+ }
+
+ LOGGSUBSCRP(LOGL_INFO, subscr,
+ "Will set PDP info, context id = %d, APN = %s\n",
ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
- /* TODO: set PDP info [ctx_id] */
+ /* Set PDP info [ctx_id] */
+ pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id);
+ if (!pdp_data) {
+ pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data);
+ pdp_data->context_id = ctx_id;
+ }
+
+ OSMO_ASSERT(pdp_data != NULL);
+ 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);
}
+}
+
+static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
+ struct gprs_gsup_message *gsup_msg)
+{
+ gprs_subscr_gsup_insert_data(subscr, gsup_msg);
subscr->authorized = 1;
subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index ba71555ec..81b9d7f67 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -402,6 +402,7 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr,
char expire_time[200];
struct gsm_auth_tuple *at;
int at_idx;
+ struct sgsn_subscriber_pdp_data *pdp;
vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
subscr->authorized, VTY_NEWLINE);
@@ -439,6 +440,12 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr,
VTY_NEWLINE);
}
+ llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
+ vty_out(vty, " PDP info: Id: %d, Type: 0x%04x, APN: '%s'%s",
+ pdp->context_id, pdp->pdp_type, pdp->apn_str,
+ VTY_NEWLINE);
+ }
+
/* print the expiration time of a subscriber */
if (subscr->expire_lu) {
strftime(expire_time, sizeof(expire_time),
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index 425cf63ff..7a14cdefa 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -383,6 +383,7 @@ static void test_subscriber_gsup(void)
struct sgsn_mm_ctx *ctx;
struct gprs_ra_id raid = { 0, };
uint32_t local_tlli = 0xffeeddcc;
+ struct sgsn_subscriber_pdp_data *pdpd;
int rc;
static const uint8_t send_auth_info_res[] = {
@@ -520,12 +521,19 @@ static void test_subscriber_gsup(void)
OSMO_ASSERT(s1->sgsn_data->auth_triplets[1].key_seq == GSM_KEY_SEQ_INVAL);
OSMO_ASSERT(s1->sgsn_data->auth_triplets[2].key_seq == GSM_KEY_SEQ_INVAL);
- /* Inject UpdateLocReq GSUP message */
+ /* Inject UpdateLocRes GSUP message */
rc = rx_gsup_message(update_location_res, sizeof(update_location_res));
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(last_updated_subscr == s1);
OSMO_ASSERT(s1->flags & GPRS_SUBSCRIBER_ENABLE_PURGE);
OSMO_ASSERT(s1->sgsn_data->error_cause == SGSN_ERROR_CAUSE_NONE);
+ OSMO_ASSERT(!llist_empty(&s1->sgsn_data->pdp_list));
+ pdpd = llist_entry(s1->sgsn_data->pdp_list.next,
+ struct sgsn_subscriber_pdp_data, list);
+ OSMO_ASSERT(strcmp(pdpd->apn_str, "test.apn") == 0);
+ pdpd = llist_entry(pdpd->list.next,
+ struct sgsn_subscriber_pdp_data, list);
+ OSMO_ASSERT(strcmp(pdpd->apn_str, "foo.apn") == 0);
/* Check authorization */
OSMO_ASSERT(s1->authorized == 1);