diff options
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 12 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 85 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 7 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 10 |
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); |