aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
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);