diff --git a/lib/pfcp/types.c b/lib/pfcp/types.c index 3a8775dad..5551b2a26 100644 --- a/lib/pfcp/types.c +++ b/lib/pfcp/types.c @@ -686,3 +686,61 @@ int16_t ogs_pfcp_parse_volume_measurement( return size; } + +int16_t ogs_pfcp_build_user_id( + ogs_tlv_octet_t *octet, ogs_pfcp_user_id_t *user_id, + void *data, int data_len) +{ + ogs_pfcp_user_id_t target; + int16_t size = 0; + + ogs_assert(user_id); + ogs_assert(octet); + ogs_assert(data); + ogs_assert(data_len); + + octet->data = data; + memcpy(&target, user_id, sizeof(ogs_pfcp_user_id_t)); + + ogs_assert(size + sizeof(target.flags) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.flags, sizeof(target.flags)); + size += sizeof(target.flags); + + if (target.imsif) { + ogs_assert(size + sizeof(target.imsi_len) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.imsi_len, sizeof(target.imsi_len)); + size += sizeof(target.imsi_len); + + ogs_assert(size + user_id->imsi_len <= data_len); + memcpy((char *)octet->data + size, user_id->imsi, user_id->imsi_len); + size += user_id->imsi_len; + } + if (target.imeif) { + ogs_assert(size + sizeof(target.imeisv_len) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.imeisv_len, sizeof(target.imeisv_len)); + size += sizeof(target.imeisv_len); + + ogs_assert(size + user_id->imeisv_len <= data_len); + memcpy((char *)octet->data + size, + user_id->imeisv, user_id->imeisv_len); + size += user_id->imeisv_len; + } + if (target.msisdnf) { + ogs_assert(size + sizeof(target.msisdn_len) <= data_len); + memcpy((unsigned char *)octet->data + size, + &target.msisdn_len, sizeof(target.msisdn_len)); + size += sizeof(target.msisdn_len); + + ogs_assert(size + user_id->msisdn_len <= data_len); + memcpy((char *)octet->data + size, + user_id->msisdn, user_id->msisdn_len); + size += user_id->msisdn_len; + } + + octet->len = size; + + return octet->len; +} diff --git a/lib/pfcp/types.h b/lib/pfcp/types.h index 2b02a5e06..6ecd1c36a 100644 --- a/lib/pfcp/types.h +++ b/lib/pfcp/types.h @@ -1400,6 +1400,115 @@ int16_t ogs_pfcp_build_volume_measurement(ogs_tlv_octet_t *octet, int16_t ogs_pfcp_parse_volume_measurement( ogs_pfcp_volume_measurement_t *volume, ogs_tlv_octet_t *octet); +/* + * 8.2.101 User ID + * + * The User ID IE type shall be encoded as shown in Figure 8.2.101-1. + * + * The following flags are coded within Octet 5: + * + * -Bit 1 – IMSIF: If this bit is set to "1", + * then the Length of IMSI and IMSI fields shall be present, + * otherwise these fields shall not be present. + * -Bit 2 – IMEIF: If this bit is set to "1", + * then the Length of IMEI and IMEI fields shall be present, + * otherwise these fields shall not be present. + * -Bit 3 – MSISDNF: If this bit is set to "1", + * then the Length of MSISDN and MSISDN fields shall be present, + * otherwise these fields shall not be present. + * -Bit 4 – NAIF: If this bit is set to "1", + * then the Length of NAI and NAI fields shall be present, + * otherwise these fields shall not be present. + * -Bit 5 – SUPIF: If this bit is set to "1", + * then the Length of SUPI and SUPI fields shall be present, + * otherwise these fields shall not be present. + * -Bit 6 – GPSIF: If this bit is set to "1", + * then the Length of GPSI and GPSI fields shall be present, + * otherwise these fields shall not be present. + * -Bit 7 – PEIF: If this bit is set to "1", + * then the Length of PEI and PEI fields shall be present, + * otherwise these fields shall not be present. + * - Bit 8: Spare, for future use and set to "0". + * + * One or more flags may be set to "1". + * + * For 5GS User Identities: + * -The SUPI field shall only be used for carrying a Global Cable Identifier + * (GCI) or a Global Line Identifier (GLI). The IMSI and NAI, if received + * by the SMF in the SUPI, shall be included in the IMSI and NAI field respectively. + * -The GPSI field shall only be used for carrying an External Identifier. + * The MSISDN, if received by the SMF in the SUPI, shall be included + * in the MSISDN field. + * -The PEI field shall only be used for carrying an MAC address or + * an Extended Unique Identifier. The IMEI, if received by the SMF in the PEI, + * shall be included in the IMEI field. + * + * The coding of IMSI field, from octets 7 to 'a' shall be encoded + * as the octets 5 to n+4 of the IMSI IE type + * specified in clause 8.3 of 3GPP TS 29.274 [9]. + * + * The coding of IMEI field, in octets 'b+1' to 'c' shall be encoded + * as the octets 5 to n+4 of the MEI IE type + * specified in clause 8.10 of 3GPP TS 29.274 [9]. + * + * The coding of MSISDN field, in octets 'd+1' to 'e' shall be encoded + * as the octets 5 to n+4 of the MSISDN IE type + * specified in clause 8.11 of 3GPP TS 29.274 [9]. + * + * The coding of the SUPI field, in octets 'h+1' to 'i' shall be encoded + * as the Supi data type specified in clause 5.3.2 of 3GPP TS 29.571 [61]. + * + * The coding of the GPSI field, in octets 'j+1' to 'k' shall be encoded + * as the Gpsi data type specified in clause 5.3.2 of 3GPP TS 29.571 [61]. + * + * The coding of the PEI field, in octets 'l+1' to 'm' shall be encoded + * as the Pei data type specified in clause 5.3.2 of 3GPP TS 29.571 [61]. + * + * The NAI field, in octets 'f+1' to 'g' shall be encoded as an Octet String + * (see IETF RFC 4282 [36]). + */ +typedef struct ogs_pfcp_user_id_flags_s { + union { + struct { +ED8(uint8_t spare:1;, + uint8_t peif:1;, + uint8_t gpsif:1;, + uint8_t supif:1;, + uint8_t naif:1;, + uint8_t msisdnf:1;, + uint8_t imeif:1;, + uint8_t imsif:1;) + }; + uint8_t flags; + }; +} ogs_pfcp_user_id_flags_t; + +typedef struct ogs_pfcp_user_id_s { + union { + struct { +ED8(uint8_t spare:1;, + uint8_t peif:1;, + uint8_t gpsif:1;, + uint8_t supif:1;, + uint8_t naif:1;, + uint8_t msisdnf:1;, + uint8_t imeif:1;, + uint8_t imsif:1;) + }; + uint8_t flags; + }; + + uint8_t imsi_len; + uint8_t imsi[OGS_MAX_IMSI_LEN]; + uint8_t imeisv_len; + uint8_t imeisv[OGS_MAX_IMEISV_LEN]; + uint8_t msisdn_len; + uint8_t msisdn[OGS_MAX_MSISDN_LEN]; +} ogs_pfcp_user_id_t; + +int16_t ogs_pfcp_build_user_id( + ogs_tlv_octet_t *octet, ogs_pfcp_user_id_t *user_id, + void *data, int data_len); #ifdef __cplusplus } diff --git a/lib/proto/types.h b/lib/proto/types.h index c300d7d26..bfb4a0f0e 100644 --- a/lib/proto/types.h +++ b/lib/proto/types.h @@ -188,6 +188,7 @@ ogs_amf_id_t *ogs_amf_id_build(ogs_amf_id_t *amf_id, * SUPI/GPSI */ #define OGS_ID_SUPI_TYPE_IMSI "imsi" #define OGS_ID_GPSI_TYPE_MSISDN "msisdn" +#define OGS_ID_SUPI_TYPE_IMEISV "imeisv" char *ogs_id_get_type(char *str); char *ogs_id_get_value(char *str); diff --git a/src/amf/nudm-handler.c b/src/amf/nudm-handler.c index 6f475a50d..a9586ae01 100644 --- a/src/amf/nudm-handler.c +++ b/src/amf/nudm-handler.c @@ -57,21 +57,18 @@ int amf_nudm_sdm_handle_provisioned( char *gpsi = NULL; gpsi = ogs_id_get_type(node->data); - ogs_assert(gpsi); + if (gpsi) { + if (strncmp(gpsi, OGS_ID_GPSI_TYPE_MSISDN, + strlen(OGS_ID_GPSI_TYPE_MSISDN)) == 0) { + amf_ue->msisdn[amf_ue->num_of_msisdn] = + ogs_id_get_value(node->data); + ogs_assert(amf_ue-> + msisdn[amf_ue->num_of_msisdn]); - if (strncmp(gpsi, OGS_ID_GPSI_TYPE_MSISDN, - strlen(OGS_ID_GPSI_TYPE_MSISDN)) != 0) { - ogs_error("Unknown GPSI Type [%s]", gpsi); - - } else { - amf_ue->msisdn[amf_ue->num_of_msisdn] = - ogs_id_get_value(node->data); - ogs_assert(amf_ue->msisdn[amf_ue->num_of_msisdn]); - - amf_ue->num_of_msisdn++; + amf_ue->num_of_msisdn++; + } + ogs_free(gpsi); } - - ogs_free(gpsi); } } } diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index c9b0d4555..0b21772f4 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -35,10 +35,17 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( ogs_pfcp_node_id_t node_id; ogs_pfcp_f_seid_t f_seid; + char apn_dnn[OGS_MAX_DNN_LEN+1]; int len; + smf_ue_t *smf_ue = NULL; + ogs_pfcp_user_id_t user_id; + char user_id_buf[sizeof(ogs_pfcp_user_id_t)]; + ogs_debug("Session Establishment Request"); ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); req = &pfcp_message.pfcp_session_establishment_request; memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); @@ -102,6 +109,46 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( req->pdn_type.presence = 1; req->pdn_type.u8 = sess->session.session_type; + /* User ID */ + memset(&user_id, 0, sizeof(ogs_pfcp_user_id_t)); + if (smf_ue->imsi_len) { + user_id.imsif = 1; + user_id.imsi_len = smf_ue->imsi_len; + ogs_assert(smf_ue->imsi_len <= OGS_MAX_IMSI_LEN); + memcpy(user_id.imsi, smf_ue->imsi, smf_ue->imsi_len); + } + if (smf_ue->imeisv_len) { + user_id.imeif = 1; + user_id.imeisv_len = smf_ue->imeisv_len; + ogs_assert(smf_ue->imeisv_len <= OGS_MAX_IMEISV_LEN); + memcpy(user_id.imeisv, smf_ue->imeisv, smf_ue->imeisv_len); + } + if (smf_ue->msisdn_len) { + user_id.msisdnf = 1; + user_id.msisdn_len = smf_ue->msisdn_len; + ogs_assert(smf_ue->msisdn_len <= OGS_MAX_MSISDN_LEN); + memcpy(user_id.msisdn, smf_ue->msisdn, smf_ue->msisdn_len); + } + + if (user_id.flags) { + ogs_pfcp_build_user_id( + &req->user_id, &user_id, user_id_buf, sizeof(user_id_buf)); + req->user_id.presence = 1; + } + + /* APN/DNN */ + len = ogs_fqdn_build(apn_dnn, sess->session.name, strlen(sess->session.name)); + req->apn_dnn.presence = 1; + req->apn_dnn.len = len; + req->apn_dnn.data = apn_dnn; + + /* S-NSSAI */ + if (!sess->epc) { + req->s_nssai.presence = 1; + req->s_nssai.len = 4; + req->s_nssai.data = &sess->s_nssai; + } + pfcp_message.h.type = type; pkbuf = ogs_pfcp_build_msg(&pfcp_message); diff --git a/src/smf/nsmf-handler.c b/src/smf/nsmf-handler.c index 298c7f9f3..6e6dc85cc 100644 --- a/src/smf/nsmf-handler.c +++ b/src/smf/nsmf-handler.c @@ -28,6 +28,7 @@ bool smf_nsmf_handle_create_sm_context( { bool rc; smf_ue_t *smf_ue = NULL; + char *type = NULL; ogs_nas_5gsm_header_t *gsm_header = NULL; ogs_pkbuf_t *n1smbuf = NULL; @@ -164,6 +165,60 @@ bool smf_nsmf_handle_create_sm_context( return false; } + if (SmContextCreateData->supi) { + type = ogs_id_get_type(SmContextCreateData->supi); + if (type) { + if (strncmp(type, OGS_ID_SUPI_TYPE_IMSI, + strlen(OGS_ID_SUPI_TYPE_IMSI)) == 0) { + char *imsi_bcd = ogs_id_get_value(SmContextCreateData->supi); + + ogs_cpystrn(smf_ue->imsi_bcd, imsi_bcd, + ogs_min(strlen(imsi_bcd), OGS_MAX_IMSI_BCD_LEN)+1); + ogs_bcd_to_buffer(smf_ue->imsi_bcd, + smf_ue->imsi, &smf_ue->imsi_len); + + ogs_free(imsi_bcd); + } + ogs_free(type); + } + } + + if (SmContextCreateData->pei) { + type = ogs_id_get_type(SmContextCreateData->pei); + if (type) { + if (strncmp(type, OGS_ID_SUPI_TYPE_IMEISV, + strlen(OGS_ID_SUPI_TYPE_IMEISV)) == 0) { + char *imeisv_bcd = ogs_id_get_value(SmContextCreateData->pei); + + ogs_cpystrn(smf_ue->imeisv_bcd, imeisv_bcd, + ogs_min(strlen(imeisv_bcd), OGS_MAX_IMEISV_BCD_LEN)+1); + ogs_bcd_to_buffer(smf_ue->imeisv_bcd, + smf_ue->imeisv, &smf_ue->imeisv_len); + + ogs_free(imeisv_bcd); + } + ogs_free(type); + } + } + + if (SmContextCreateData->gpsi) { + type = ogs_id_get_type(SmContextCreateData->gpsi); + if (type) { + if (strncmp(type, OGS_ID_GPSI_TYPE_MSISDN, + strlen(OGS_ID_GPSI_TYPE_MSISDN)) == 0) { + char *msisdn_bcd = ogs_id_get_value(SmContextCreateData->gpsi); + + ogs_cpystrn(smf_ue->msisdn_bcd, msisdn_bcd, + ogs_min(strlen(msisdn_bcd), OGS_MAX_MSISDN_BCD_LEN)+1); + ogs_bcd_to_buffer(smf_ue->msisdn_bcd, + smf_ue->msisdn, &smf_ue->msisdn_len); + + ogs_free(msisdn_bcd); + } + ogs_free(type); + } + } + ogs_sbi_parse_plmn_id_nid(&sess->plmn_id, servingNetwork); sess->sbi_rat_type = SmContextCreateData->rat_type;