diff options
-rw-r--r-- | openbsc/doc/sgsn-remote-protocol.txt | 45 | ||||
-rw-r--r-- | openbsc/include/openbsc/gprs_gsup_messages.h | 7 | ||||
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 5 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_04_08_gprs.h | 1 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_gsup_messages.c | 21 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_sgsn.c | 15 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_subscriber.c | 23 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_libgtp.c | 41 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 8 | ||||
-rw-r--r-- | openbsc/tests/gprs/gprs_test.c | 5 | ||||
-rw-r--r-- | openbsc/tests/sgsn/sgsn_test.c | 9 |
11 files changed, 170 insertions, 10 deletions
diff --git a/openbsc/doc/sgsn-remote-protocol.txt b/openbsc/doc/sgsn-remote-protocol.txt index 3369d19b1..acb24a5ef 100644 --- a/openbsc/doc/sgsn-remote-protocol.txt +++ b/openbsc/doc/sgsn-remote-protocol.txt @@ -119,6 +119,7 @@ Network peer -> SGSN IEI Info Element Type Pres. Format Length Message type 4.2.1 M V 1 01 IMSI 4.2.9 M TLV 2-10 + 08 MSISDN 4.2.10 O TLV 0-9 04 PDP info complete 4.2.8 O TLV 2 05 PDP info 4.2.3 1-10 TLV @@ -279,6 +280,7 @@ This is a container for information elements describing a single PDP. 10 PDP context id big endian int, 1-N C TLV 3 11 PDP type 4.2.4 C TLV 4 12 Access point name 04.08, 10.5.6.1 C TLV 3-102 + 13 Quality of Service 4.2.11 O TLV 1-20 The conditional IE are mandantory unless mentioned otherwise. @@ -354,9 +356,11 @@ IEI that shall be used for the encoding. | 0x05 PDP info 4.2.3 | | 0x06 Cancel type 4.2.6 | | 0x07 Freeze P-TMSI 4.2.8 | + | 0x08 MSISDN ISDN-AddressString/octet, 4.2.10 | | 0x10 PDP context id big endian int | | 0x11 PDP type 4.2.4 | | 0x12 APN 04.08, 10.5.6.1 | + | 0x13 QoS 4.2.11 | | 0x20 RAND octet string | | 0x21 SRES octet string | | 0x22 Kc octet string | @@ -397,3 +401,44 @@ The IMSI is encoded like in octet 4-N of the Called Party BCD Number defined in Note 1) Either '1 1 1 1 | Number digit N' (N odd) or 'Number digit N | Number digit N-1' (N even), where N is the number of digits. + +4.2.10. ISDN-AddressString / MSISDN / Called Party BCD Number + +The MSISDN is encoded as an ISDN-AddressString in GSM 09.02 and Called Party +BCD Number in GSM 04.08. It will be stored by the SGSN and then passed as is +to the GGSN during the activation of the primary PDP Context. + + 8 7 6 5 4 3 2 1 + +-----------------------------------------------------+ + | | IEI | octet 1 + +-----------------------------------------------------+ + | Length of IE contents | octet 2 + +-----------------------------------------------------+ + | ext | Type of num | Numbering plan | octet 2 + +-----------------------------------------------------+ + | Number digit 2 | Number digit 1 | octet 3 + +-----------------------------------------------------+ + | Number digit 4 | Number digit 3 | octet 4 + +-----------------------------------------------------+ + : : : + +-----------------------------------------------------+ + + +4.2.11 Quality of Service Subscribed Service + +This encodes the subscribed QoS of a subscriber. It will be used by the +SGSN during the PDP Context activation. If the length of the QoS data +is 3 (three) octets it is assumed that these are octets 3-5 of the TS +3GPP TS 24.008 Quality of Service Octets. If it is more than three then +then it is assumed that the first octet is the Allocation/Retention +Priority and the reset are encoded as octets 3-N of 24.008. + + + 8 7 6 5 4 3 2 1 + +-----------------------------------------------------+ + | | IEI | octet 1 + +-----------------------------------------------------+ + | Length of IE contents | octet 2 + +-----------------------------------------------------+ + : : : + +-----------------------------------------------------+ diff --git a/openbsc/include/openbsc/gprs_gsup_messages.h b/openbsc/include/openbsc/gprs_gsup_messages.h index 9857b979d..123e1fc05 100644 --- a/openbsc/include/openbsc/gprs_gsup_messages.h +++ b/openbsc/include/openbsc/gprs_gsup_messages.h @@ -29,6 +29,7 @@ #define GPRS_GSUP_MAX_NUM_PDP_INFO 10 /* GSM 09.02 limits this to 50 */ #define GPRS_GSUP_MAX_NUM_AUTH_INFO 5 +#define GPRS_GSUP_MAX_MSISDN_LEN 9 #define GPRS_GSUP_PDP_TYPE_SIZE 2 @@ -40,9 +41,11 @@ enum gprs_gsup_iei { GPRS_GSUP_PDP_INFO_IE = 0x05, GPRS_GSUP_CANCEL_TYPE_IE = 0x06, GPRS_GSUP_FREEZE_PTMSI_IE = 0x07, + GPRS_GSUP_MSISDN_IE = 0x08, GPRS_GSUP_PDP_CONTEXT_ID_IE = 0x10, GPRS_GSUP_PDP_TYPE_IE = 0x11, GPRS_GSUP_ACCESS_POINT_NAME_IE = 0x12, + GPRS_GSUP_PDP_QOS_IE = 0x13, GPRS_GSUP_RAND_IE = 0x20, GPRS_GSUP_SRES_IE = 0x21, GPRS_GSUP_KC_IE = 0x22 @@ -89,6 +92,8 @@ struct gprs_gsup_pdp_info { uint16_t pdp_type; const uint8_t *apn_enc; size_t apn_enc_len; + const uint8_t *qos_enc; + size_t qos_enc_len; }; struct gprs_gsup_message { @@ -102,6 +107,8 @@ struct gprs_gsup_message { size_t num_auth_tuples; struct gprs_gsup_pdp_info pdp_infos[GPRS_GSUP_MAX_NUM_PDP_INFO]; size_t num_pdp_infos; + const uint8_t *msisdn_enc; + size_t msisdn_enc_len; }; int gprs_gsup_decode(const uint8_t *data, size_t data_len, diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 2572ead52..7a429cdab 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -294,6 +294,8 @@ struct sgsn_subscriber_pdp_data { unsigned int context_id; uint16_t pdp_type; char apn_str[GSM_APN_LENGTH]; + uint8_t qos_subscribed[20]; + size_t qos_subscribed_len; }; struct sgsn_subscriber_data { @@ -302,6 +304,9 @@ struct sgsn_subscriber_data { int auth_triplets_updated; struct llist_head pdp_list; int error_cause; + + uint8_t msisdn[9]; + size_t msisdn_len; }; #define SGSN_ERROR_CAUSE_NONE (-1) diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index 3eec98365..f35d11b60 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -100,6 +100,7 @@ enum gsm48_gprs_ie_sm { * but which we use to simplify internal APIs */ OSMO_IE_GSM_REQ_QOS = 0xfd, OSMO_IE_GSM_REQ_PDP_ADDR = 0xfe, + OSMO_IE_GSM_SUB_QOS = 0xff, }; /* Chapter 9.4.15 / Table 9.4.15 */ 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); } diff --git a/openbsc/tests/gprs/gprs_test.c b/openbsc/tests/gprs/gprs_test.c index 0ae06e780..bbd1d8ab3 100644 --- a/openbsc/tests/gprs/gprs_test.c +++ b/openbsc/tests/gprs/gprs_test.c @@ -443,11 +443,14 @@ static void test_gsup_messages_dec_enc(void) static const uint8_t update_location_res[] = { 0x06, TEST_IMSI_IE, + 0x08, 0x07, /* MSISDN of the subscriber */ + 0x91, 0x94, 0x61, 0x46, 0x32, 0x24, 0x43, 0x04, 0x00, /* PDP info complete */ - 0x05, 0x12, + 0x05, 0x15, 0x10, 0x01, 0x01, 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n', + 0x13, 0x01, 0x02, 0x05, 0x11, 0x10, 0x01, 0x02, 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 197be9da4..d9b162dc2 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -414,9 +414,14 @@ static void test_subscriber_gsup(void) 0x02, 0x01, 0x07 /* GPRS not allowed */ }; +#define MSISDN 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 + + static const uint8_t s1_msisdn[] = { MSISDN }; + static const uint8_t update_location_res[] = { 0x06, TEST_GSUP_IMSI1_IE, + 0x08, 0x09, MSISDN, 0x04, 0x00, /* PDP info complete */ 0x05, 0x12, 0x10, 0x01, 0x01, @@ -428,6 +433,8 @@ static void test_subscriber_gsup(void) 0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n', }; +#undef MSISDN + static const uint8_t update_location_err[] = { 0x05, TEST_GSUP_IMSI1_IE, @@ -534,6 +541,8 @@ static void test_subscriber_gsup(void) 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(s1->sgsn_data->msisdn_len == sizeof(s1_msisdn)); + OSMO_ASSERT(memcmp(s1->sgsn_data->msisdn, s1_msisdn, sizeof(s1_msisdn)) == 0); OSMO_ASSERT(!llist_empty(&s1->sgsn_data->pdp_list)); pdpd = llist_entry(s1->sgsn_data->pdp_list.next, struct sgsn_subscriber_pdp_data, list); |