diff --git a/lib/core/include/3gpp_types.h b/lib/core/include/3gpp_types.h index b63b10afa..c007e4cca 100644 --- a/lib/core/include/3gpp_types.h +++ b/lib/core/include/3gpp_types.h @@ -121,7 +121,7 @@ typedef struct _paa_t { /* 8.34 PDN Type */ #define GTP_PDN_TYPE_IPV4 1 #define GTP_PDN_TYPE_IPV6 2 -#define GTP_PDN_TYPE_BOTH 3 +#define GTP_PDN_TYPE_IPV4V6 3 #define GTP_PDN_TYPE_NON_IP 4 ED2(c_uint8_t spare:5;, c_uint8_t pdn_type:3;) @@ -138,7 +138,6 @@ ED2(c_uint8_t spare:5;, /* GTP_PDN_TYPE_BOTH */ struct { c_uint32_t addr; - struct { c_uint8_t len; c_uint8_t addr6[IPV6_LEN]; @@ -217,10 +216,10 @@ typedef struct _pcc_rule_t { typedef struct _pdn_t { c_uint32_t context_identifier; c_int8_t apn[MAX_APN_LEN+1]; -#define S6A_PDN_TYPE_IPV4 0 -#define S6A_PDN_TYPE_IPV6 1 -#define S6A_PDN_TYPE_IPV4_AND_IPV6 2 -#define S6A_PDN_TYPE_IPV4_OR_IPV6 3 +#define HSS_PDN_TYPE_IPV4 0 +#define HSS_PDN_TYPE_IPV6 1 +#define HSS_PDN_TYPE_IPV4V6 2 +#define HSS_PDN_TYPE_IPV4_OR_IPV6 3 c_int8_t pdn_type; qos_t qos; diff --git a/lib/nas/nas_types.h b/lib/nas/nas_types.h index 2476b5e45..294aa2784 100644 --- a/lib/nas/nas_types.h +++ b/lib/nas/nas_types.h @@ -1152,10 +1152,24 @@ ED3(c_uint8_t type:4;, /* 9.9.4.9 PDN address * M LV 6-14 */ +#define NAS_PDN_ADDRESS_IPV4_LEN 5 +#define NAS_PDN_ADDRESS_IPV6_LEN 9 +#define NAS_PDN_ADDRESS_IPV4V6_LEN 13 typedef struct _nas_pdn_address_t { c_uint8_t length; - paa_t paa; -} nas_pdn_address_t; +ED2(c_uint8_t reserved:5;, + c_uint8_t pdn_type:3;) + union { + c_uint32_t addr; + struct { + c_uint8_t addr6[IPV6_LEN/2]; /* Interface Identifer Only */ + }; + struct { + c_uint8_t addr6[IPV6_LEN/2]; /* Interface Identifer Only */ + c_uint32_t addr; + } both; + }; +} __attribute__ ((packed)) nas_pdn_address_t; /* 9.9.4.11 Protocol configuration options * See subclause 10.5.6.3 in 3GPP TS 24.008 [13]. @@ -1197,9 +1211,9 @@ ED3(c_uint8_t spare:3;, /* allowed in A/Gb mode or Iu mode */ #define NAS_PDN_CONNECTIVITY_PDN_TYPE_NON_IP 5 typedef struct _nas_request_type_t { ED4(c_uint8_t spare1:1;, - c_uint8_t request_type:3;, + c_uint8_t pdn_type:3;, c_uint8_t spare2:1;, - c_uint8_t pdn_type:3;) + c_uint8_t request_type:3;) } __attribute__ ((packed)) nas_request_type_t; /* 9.9.4.15 Traffic flow aggregate description diff --git a/src/mme/esm_build.c b/src/mme/esm_build.c index ab6eaf793..590b9d58e 100644 --- a/src/mme/esm_build.c +++ b/src/mme/esm_build.c @@ -132,8 +132,27 @@ status_t esm_build_activate_default_bearer_context_request( core_cpystrn(access_point_name->apn, pdn->apn, c_min(access_point_name->length, MAX_APN_LEN) + 1); - pdn_address->length = PAA_IPV4_LEN; - memcpy(&pdn_address->paa, &pdn->paa, pdn_address->length); + pdn_address->pdn_type = pdn->paa.pdn_type; + if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV4) + { + pdn_address->addr = pdn->paa.addr; + pdn_address->length = NAS_PDN_ADDRESS_IPV4_LEN; + } + else if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV6) + { + memcpy(pdn_address->addr6, pdn->paa.addr6+IPV6_LEN/2, IPV6_LEN/2); + pdn_address->length = NAS_PDN_ADDRESS_IPV6_LEN; + } + else if (pdn_address->pdn_type == GTP_PDN_TYPE_IPV4V6) + { + pdn_address->both.addr = pdn->paa.both.addr; + memcpy(pdn_address->both.addr6, + pdn->paa.both.addr6+IPV6_LEN/2, IPV6_LEN/2); + pdn_address->length = NAS_PDN_ADDRESS_IPV4V6_LEN; + } + else + d_assert(0, return CORE_ERROR, + "Invalid PDN_TYPE(%d)", pdn->paa.pdn_type); if (pdn->ambr.downlink || pdn->ambr.uplink) { diff --git a/src/mme/esm_handler.c b/src/mme/esm_handler.c index 69276b586..0db4654f6 100644 --- a/src/mme/esm_handler.c +++ b/src/mme/esm_handler.c @@ -18,17 +18,22 @@ status_t esm_handle_pdn_connectivity_request(mme_bearer_t *bearer, mme_sess_t *sess = NULL; c_uint8_t security_protected_required = 0; - d_assert(bearer, return CORE_ERROR, "Null param"); + d_assert(bearer, return CORE_ERROR,); sess = bearer->sess; - d_assert(sess, return CORE_ERROR, "Null param"); + d_assert(sess, return CORE_ERROR,); mme_ue = sess->mme_ue; - d_assert(mme_ue, return CORE_ERROR, "Null param"); + d_assert(mme_ue, return CORE_ERROR,); + + d_assert(pdn_connectivity_request, return CORE_ERROR,); d_assert(MME_UE_HAVE_IMSI(mme_ue), return CORE_ERROR, "No IMSI in PDN_CPNNECTIVITY_REQUEST"); d_assert(SECURITY_CONTEXT_IS_VALID(mme_ue), return CORE_ERROR, "No Security Context in PDN_CPNNECTIVITY_REQUEST"); + memcpy(&sess->request_type, &pdn_connectivity_request->request_type, + sizeof(sess->request_type)); + security_protected_required = 0; if (pdn_connectivity_request->presencemask & NAS_PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT) diff --git a/src/mme/mme_context.h b/src/mme/mme_context.h index 05f3cf0d1..f65f12e1a 100644 --- a/src/mme/mme_context.h +++ b/src/mme/mme_context.h @@ -345,6 +345,9 @@ typedef struct _mme_sess_t { c_uint8_t pti; /* Procedure Trasaction Identity */ + /* PDN Connectivity Request */ + nas_request_type_t request_type; + /* mme_bearer_first(sess) : Default Bearer Context */ list_t bearer_list; diff --git a/src/mme/mme_s11_build.c b/src/mme/mme_s11_build.c index 91ef11e68..9026b15c3 100644 --- a/src/mme/mme_s11_build.c +++ b/src/mme/mme_s11_build.c @@ -107,13 +107,42 @@ status_t mme_s11_build_create_session_request( req->selection_mode.u8 = GTP_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN | 0xfc; + d_assert(sess->request_type.pdn_type == + NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV4 || + sess->request_type.pdn_type == + NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV6 || + sess->request_type.pdn_type == + NAS_PDN_CONNECTIVITY_PDN_TYPE_IPV4V6, return CORE_ERROR, + "UE PDN Configuration Error(%d)", sess->request_type.pdn_type); + if (pdn->pdn_type == HSS_PDN_TYPE_IPV4 || + pdn->pdn_type == HSS_PDN_TYPE_IPV6 || + pdn->pdn_type == HSS_PDN_TYPE_IPV4V6) + { + req->pdn_type.u8 = ((pdn->pdn_type + 1) & sess->request_type.pdn_type); + d_assert(req->pdn_type.u8 != 0, return CORE_ERROR, + "PDN Configuration Error:(%d, %d)", + pdn->pdn_type, sess->request_type.pdn_type); + } + else if (pdn->pdn_type == HSS_PDN_TYPE_IPV4_OR_IPV6) + { + req->pdn_type.u8 = sess->request_type.pdn_type; + } + else + d_assert(0, return CORE_ERROR, + "HSS PDN Confiugration Error(%d)", pdn->pdn_type); req->pdn_type.presence = 1; - req->pdn_type.u8 = GTP_PDN_TYPE_IPV4; - pdn->paa.pdn_type = GTP_PDN_TYPE_IPV4; - req->pdn_address_allocation.presence = 1; + pdn->paa.pdn_type = req->pdn_type.u8; req->pdn_address_allocation.data = &pdn->paa; - req->pdn_address_allocation.len = PAA_IPV4_LEN; + if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV4) + req->pdn_address_allocation.len = PAA_IPV4_LEN; + else if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV6) + req->pdn_address_allocation.len = PAA_IPV6_LEN; + else if (req->pdn_type.u8 == GTP_PDN_TYPE_IPV4V6) + req->pdn_address_allocation.len = PAA_IPV4V6_LEN; + else + d_assert(0, return CORE_ERROR, "Not supported(%d)", req->pdn_type.u8); + req->pdn_address_allocation.presence = 1; req->maximum_apn_restriction.presence = 1; req->maximum_apn_restriction.u8 = GTP_APN_NO_RESTRICTION; diff --git a/src/pgw/pgw_context.c b/src/pgw/pgw_context.c index 1a1b45e6f..f7b3df2b8 100644 --- a/src/pgw/pgw_context.c +++ b/src/pgw/pgw_context.c @@ -727,7 +727,8 @@ static void *sess_hash_keygen(c_uint8_t *out, int *out_len, } pgw_sess_t *pgw_sess_add( - c_uint8_t *imsi, int imsi_len, c_int8_t *apn, c_uint8_t ebi) + c_uint8_t *imsi, int imsi_len, c_int8_t *apn, + c_uint8_t pdn_type, c_uint8_t ebi) { pgw_sess_t *sess = NULL; pgw_bearer_t *bearer = NULL; @@ -754,9 +755,29 @@ pgw_sess_t *pgw_sess_add( "Can't add default bearer context"); bearer->ebi = ebi; - sess->ue_ip = pgw_ue_ip_alloc(AF_INET, apn); - d_assert(sess->ue_ip, pgw_sess_remove(sess); return NULL, - "Can't add default bearer context"); + if (pdn_type == GTP_PDN_TYPE_IPV4) + { + sess->ipv4 = pgw_ue_ip_alloc(AF_INET, apn); + d_assert(sess->ipv4, pgw_sess_remove(sess); return NULL, + "Can't allocate IPv4 Pool"); + } + else if (pdn_type == GTP_PDN_TYPE_IPV6) + { + sess->ipv6 = pgw_ue_ip_alloc(AF_INET6, apn); + d_assert(sess->ipv6, pgw_sess_remove(sess); return NULL, + "Can't allocate IPv6 Pool"); + } + else if (pdn_type == GTP_PDN_TYPE_IPV4V6) + { + sess->ipv4 = pgw_ue_ip_alloc(AF_INET, apn); + d_assert(sess->ipv4, pgw_sess_remove(sess); return NULL, + "Can't allocate IPv4 Pool"); + sess->ipv6 = pgw_ue_ip_alloc(AF_INET6, apn); + d_assert(sess->ipv6, pgw_sess_remove(sess); return NULL, + "Can't allocate IPv6 Pool"); + } + else + d_assert(0, return NULL, "Unsupported PDN Type(%d)", pdn_type); /* Generate Hash Key : IMSI + APN */ sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen, @@ -773,7 +794,10 @@ status_t pgw_sess_remove(pgw_sess_t *sess) hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL); - pgw_ue_ip_free(sess->ue_ip); + if (sess->ipv4) + pgw_ue_ip_free(sess->ipv4); + if (sess->ipv6) + pgw_ue_ip_free(sess->ipv6); pgw_bearer_remove_all(sess); @@ -874,12 +898,18 @@ pgw_sess_t *pgw_sess_add_by_message(gtp_message_t *message) d_error("No EPS Bearer ID"); return NULL; } + if (req->pdn_type.presence == 0) + { + d_error("No PDN Type"); + return NULL; + } apn_parse(apn, req->access_point_name.data, req->access_point_name.len); sess = pgw_sess_find_by_imsi_apn(req->imsi.data, req->imsi.len, apn); if (!sess) { sess = pgw_sess_add(req->imsi.data, req->imsi.len, apn, + req->pdn_type.u8, req->bearer_contexts_to_be_created.eps_bearer_id.u8); d_assert(sess, return NULL, "No Session Context"); } diff --git a/src/pgw/pgw_context.h b/src/pgw/pgw_context.h index 4507c277a..18fc51130 100644 --- a/src/pgw/pgw_context.h +++ b/src/pgw/pgw_context.h @@ -86,7 +86,8 @@ typedef struct _pgw_sess_t { /* APN Configuration */ pdn_t pdn; - pgw_ue_ip_t* ue_ip; + pgw_ue_ip_t* ipv4; + pgw_ue_ip_t* ipv6; /* User-Lication-Info */ tai_t tai; @@ -169,7 +170,8 @@ CORE_DECLARE(gtp_node_t *) pgw_sgw_add_by_message(gtp_message_t *message); CORE_DECLARE(pgw_sess_t *) pgw_sess_add_by_message(gtp_message_t *message); CORE_DECLARE(pgw_sess_t*) pgw_sess_add( - c_uint8_t *imsi, int imsi_len, c_int8_t *apn, c_uint8_t ebi); + c_uint8_t *imsi, int imsi_len, c_int8_t *apn, + c_uint8_t pdn_type, c_uint8_t ebi); CORE_DECLARE(status_t ) pgw_sess_remove(pgw_sess_t *sess); CORE_DECLARE(status_t ) pgw_sess_remove_all(); CORE_DECLARE(pgw_sess_t*) pgw_sess_find(index_t index); diff --git a/src/pgw/pgw_fd_path.c b/src/pgw/pgw_fd_path.c index c501724c9..4855e8335 100644 --- a/src/pgw/pgw_fd_path.c +++ b/src/pgw/pgw_fd_path.c @@ -39,7 +39,7 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess, struct session *session = NULL; d_assert(sess, return, "Null param"); - d_assert(sess->ue_ip, return, "Null param"); + d_assert(sess->ipv4 || sess->ipv6, return, "Null param"); /* Create the random value to store with the session */ pool_alloc_node(&pgw_gx_sess_pool, &mi); @@ -138,8 +138,16 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess, /* Set Framed-IP-Address */ CHECK_FCT_DO( fd_msg_avp_new(gx_framed_ip_address, 0, &avp), goto out ); - val.os.data = (c_uint8_t*)&sess->ue_ip->addr[0]; - val.os.len = sizeof(sess->ue_ip->addr[0]); + if (sess->ipv6) + { + val.os.data = (c_uint8_t*)&sess->ipv6->addr; + val.os.len = 16; + } + else + { + val.os.data = (c_uint8_t*)&sess->ipv4->addr; + val.os.len = 4; + } CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), goto out ); CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp), goto out ); diff --git a/src/pgw/pgw_s5c_build.c b/src/pgw/pgw_s5c_build.c index 28e3a0263..51979f1ea 100644 --- a/src/pgw/pgw_s5c_build.c +++ b/src/pgw/pgw_s5c_build.c @@ -59,13 +59,31 @@ status_t pgw_s5c_build_create_session_response( len = len; /* PDN Address Allocation */ - d_assert(sess->ue_ip, return CORE_ERROR, "No IP Pool"); - sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV4; - sess->pdn.paa.addr = sess->ue_ip->addr[0]; - - rsp->pdn_address_allocation.presence = 1; rsp->pdn_address_allocation.data = &sess->pdn.paa; - rsp->pdn_address_allocation.len = PAA_IPV4_LEN; + if (sess->ipv4 && sess->ipv6) + { + sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV4V6; + sess->pdn.paa.both.addr = sess->ipv4->addr[0]; + sess->pdn.paa.both.len = IPV6_LEN; + memcpy(sess->pdn.paa.both.addr6, sess->ipv6->addr, IPV6_LEN); + rsp->pdn_address_allocation.len = PAA_IPV4V6_LEN; + } + else if (sess->ipv4) + { + sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV4; + sess->pdn.paa.addr = sess->ipv4->addr[0]; + rsp->pdn_address_allocation.len = PAA_IPV4_LEN; + } + else if (sess->ipv6) + { + sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV6; + sess->pdn.paa.len = IPV6_LEN; + memcpy(sess->pdn.paa.addr6, sess->ipv6->addr, IPV6_LEN); + rsp->pdn_address_allocation.len = PAA_IPV6_LEN; + } + else + d_assert(0, return CORE_ERROR, "No IP Pool"); + rsp->pdn_address_allocation.presence = 1; /* APN Restriction */ rsp->apn_restriction.presence = 1; diff --git a/test/testpacket.c b/test/testpacket.c index b5411891a..b7daaede1 100644 --- a/test/testpacket.c +++ b/test/testpacket.c @@ -450,7 +450,7 @@ status_t tests1ap_build_initial_ue_msg(pkbuf_t **pkbuf, int i) { char *payload[TESTS1AP_MAX_MESSAGE] = { "000c405800000500 0800020001001a00 302f177ca0b38802 0741020809101010" - "3254869104e060c0 4000050221d011d1 5c0a003103e5e034 9011035758a65d01" + "3254869104e060c0 4000050221d031d1 5c0a003103e5e034 9011035758a65d01" "00004300060000f1 1030390064400800 00f1101079baf000 86400130", "000c40809c00"