diff --git a/lib/gtp/v2/message.c b/lib/gtp/v2/message.c index 070d042e1..07f469cb4 100644 --- a/lib/gtp/v2/message.c +++ b/lib/gtp/v2/message.c @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by gtp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2022-04-22 03:19:22.029355 by acetcom + * Created on: 2022-05-01 15:20:04.462265 by acetcom * from 29274-g30.docx ******************************************************************************/ @@ -2063,6 +2063,7 @@ ogs_tlv_desc_t ogs_gtp2_tlv_desc_create_session_request = &ogs_gtp2_tlv_desc_twmi_0, &ogs_gtp2_tlv_desc_pco_0, &ogs_gtp2_tlv_desc_bearer_context_0, + &ogs_tlv_desc_more8, &ogs_gtp2_tlv_desc_bearer_context_1, &ogs_gtp2_tlv_desc_trace_information_0, &ogs_gtp2_tlv_desc_recovery_0, @@ -2128,6 +2129,7 @@ ogs_tlv_desc_t ogs_gtp2_tlv_desc_create_session_response = &ogs_gtp2_tlv_desc_ebi_0, &ogs_gtp2_tlv_desc_pco_0, &ogs_gtp2_tlv_desc_bearer_context_0, + &ogs_tlv_desc_more8, &ogs_gtp2_tlv_desc_bearer_context_1, &ogs_gtp2_tlv_desc_recovery_0, &ogs_gtp2_tlv_desc_fqdn_0, diff --git a/lib/gtp/v2/message.h b/lib/gtp/v2/message.h index cd3d09186..5f051a04f 100644 --- a/lib/gtp/v2/message.h +++ b/lib/gtp/v2/message.h @@ -20,7 +20,7 @@ /******************************************************************************* * This file had been created by gtp-tlv.py script v0.1.0 * Please do not modify this file but regenerate it via script. - * Created on: 2022-04-22 03:19:22.024556 by acetcom + * Created on: 2022-05-01 15:20:04.456902 by acetcom * from 29274-g30.docx ******************************************************************************/ @@ -758,7 +758,7 @@ typedef struct ogs_gtp2_create_session_request_s { ogs_gtp2_tlv_ebi_t linked_eps_bearer_id; ogs_gtp2_tlv_twmi_t trusted_wlan_mode_indication; ogs_gtp2_tlv_pco_t protocol_configuration_options; - ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_created; + ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_created[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_removed; ogs_gtp2_tlv_trace_information_t trace_information; ogs_gtp2_tlv_recovery_t recovery; @@ -818,7 +818,7 @@ typedef struct ogs_gtp2_create_session_response_s { ogs_gtp2_tlv_ambr_t aggregate_maximum_bit_rate; ogs_gtp2_tlv_ebi_t linked_eps_bearer_id; ogs_gtp2_tlv_pco_t protocol_configuration_options; - ogs_gtp2_tlv_bearer_context_t bearer_contexts_created; + ogs_gtp2_tlv_bearer_context_t bearer_contexts_created[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_bearer_context_t bearer_contexts_marked_for_removal; ogs_gtp2_tlv_recovery_t recovery; ogs_gtp2_tlv_fqdn_t charging_gateway_name; @@ -851,7 +851,7 @@ typedef struct ogs_gtp2_modify_bearer_request_s { ogs_gtp2_tlv_f_teid_t sender_f_teid_for_control_plane; ogs_gtp2_tlv_ambr_t aggregate_maximum_bit_rate; ogs_gtp2_tlv_delay_value_t delay_downlink_packet_notification_request; - ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_modified[8]; + ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_modified[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_bearer_context_t bearer_contexts_to_be_removed; ogs_gtp2_tlv_recovery_t recovery; ogs_gtp2_tlv_ue_time_zone_t ue_time_zone; @@ -884,7 +884,7 @@ typedef struct ogs_gtp2_modify_bearer_response_s { ogs_gtp2_tlv_ebi_t linked_eps_bearer_id; ogs_gtp2_tlv_apn_restriction_t apn_restriction; ogs_gtp2_tlv_pco_t protocol_configuration_options; - ogs_gtp2_tlv_bearer_context_t bearer_contexts_modified[8]; + ogs_gtp2_tlv_bearer_context_t bearer_contexts_modified[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_bearer_context_t bearer_contexts_marked_for_removal; ogs_gtp2_tlv_change_reporting_action_t change_reporting_action; ogs_gtp2_tlv_csg_information_reporting_action_t csg_information_reporting_action; @@ -1160,14 +1160,14 @@ typedef struct ogs_gtp2_create_indirect_data_forwarding_tunnel_request_s { ogs_gtp2_tlv_mei_t me_identity; ogs_gtp2_tlv_indication_t indication_flags; ogs_gtp2_tlv_f_teid_t sender_f_teid_for_control_plane; - ogs_gtp2_tlv_bearer_context_t bearer_contexts[8]; + ogs_gtp2_tlv_bearer_context_t bearer_contexts[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_recovery_t recovery; } ogs_gtp2_create_indirect_data_forwarding_tunnel_request_t; typedef struct ogs_gtp2_create_indirect_data_forwarding_tunnel_response_s { ogs_gtp2_tlv_cause_t cause; ogs_gtp2_tlv_f_teid_t sender_f_teid_for_control_plane; - ogs_gtp2_tlv_bearer_context_t bearer_contexts[8]; + ogs_gtp2_tlv_bearer_context_t bearer_contexts[OGS_BEARER_PER_UE]; ogs_gtp2_tlv_recovery_t recovery; } ogs_gtp2_create_indirect_data_forwarding_tunnel_response_t; diff --git a/lib/gtp/v2/path.c b/lib/gtp/v2/path.c index 44a9b56d9..3f7cd470f 100644 --- a/lib/gtp/v2/path.c +++ b/lib/gtp/v2/path.c @@ -252,6 +252,7 @@ void ogs_gtp2_send_error_message( tlv = &errmsg.bearer_resource_failure_indication.cause; break; default: + ogs_fatal("Invalid message[%d]", type); ogs_assert_if_reached(); return; } diff --git a/lib/gtp/v2/support/gtp-tlv.py b/lib/gtp/v2/support/gtp-tlv.py index 8a4e0614e..ab0380174 100644 --- a/lib/gtp/v2/support/gtp-tlv.py +++ b/lib/gtp/v2/support/gtp-tlv.py @@ -580,9 +580,9 @@ for (k, v) in sorted_msg_list: if "ies" in msg_list[k]: f.write("typedef struct ogs_gtp2_" + v_lower(k) + "_s {\n") for ies in msg_list[k]["ies"]: - if ((k == 'Create Indirect Data Forwarding Tunnel Request' or k == 'Create Indirect Data Forwarding Tunnel Response') and ies["ie_value"] == 'Bearer Contexts') or (k == 'Modify Bearer Request' and ies["ie_value"] == 'Bearer Contexts to be modified') or (k == 'Modify Bearer Response' and ies["ie_value"] == 'Bearer Contexts modified'): + if ((k == 'Create Indirect Data Forwarding Tunnel Request' or k == 'Create Indirect Data Forwarding Tunnel Response') and ies["ie_value"] == 'Bearer Contexts') or (k == 'Create Session Request' and ies["ie_value"] == 'Bearer Contexts to be created') or (k == 'Create Session Response' and ies["ie_value"] == 'Bearer Contexts created') or (k == 'Modify Bearer Request' and ies["ie_value"] == 'Bearer Contexts to be modified') or (k == 'Modify Bearer Response' and ies["ie_value"] == 'Bearer Contexts modified'): f.write(" ogs_gtp2_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ - v_lower(ies["ie_value"]) + "[8];\n") + v_lower(ies["ie_value"]) + "[OGS_BEARER_PER_UE];\n") else: f.write(" ogs_gtp2_tlv_" + v_lower(ies["ie_type"]) + "_t " + \ v_lower(ies["ie_value"]) + ";\n") @@ -671,7 +671,7 @@ for (k, v) in sorted_msg_list: f.write(" 0, 0, 0, 0, {\n") for ies in msg_list[k]["ies"]: f.write(" &ogs_gtp2_tlv_desc_%s_%s,\n" % (v_lower(ies["ie_type"]), v_lower(ies["instance"]))) - if ((k == 'Create Indirect Data Forwarding Tunnel Request' or k == 'Create Indirect Data Forwarding Tunnel Response') and ies["ie_value"] == 'Bearer Contexts') or (k == 'Modify Bearer Request' and ies["ie_value"] == 'Bearer Contexts to be modified') or (k == 'Modify Bearer Response' and ies["ie_value"] == 'Bearer Contexts modified'): + if ((k == 'Create Indirect Data Forwarding Tunnel Request' or k == 'Create Indirect Data Forwarding Tunnel Response') and ies["ie_value"] == 'Bearer Contexts') or (k == 'Create Session Request' and ies["ie_value"] == 'Bearer Contexts to be created') or (k == 'Create Session Response' and ies["ie_value"] == 'Bearer Contexts created') or (k == 'Modify Bearer Request' and ies["ie_value"] == 'Bearer Contexts to be modified') or (k == 'Modify Bearer Response' and ies["ie_value"] == 'Bearer Contexts modified'): f.write(" &ogs_tlv_desc_more8,\n") f.write(" NULL,\n") f.write("}};\n\n") diff --git a/lib/gtp/xact.h b/lib/gtp/xact.h index be6a31dcd..89a453efe 100644 --- a/lib/gtp/xact.h +++ b/lib/gtp/xact.h @@ -99,6 +99,7 @@ typedef struct ogs_gtp_xact_s { #define OGS_GTP_DELETE_SEND_UE_CONTEXT_RELEASE_COMMAND 4 #define OGS_GTP_DELETE_HANDLE_PDN_CONNECTIVITY_REQUEST 5 #define OGS_GTP_DELETE_UE_CONTEXT_REMOVE 6 +#define OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST 7 int delete_action; #define OGS_GTP_RELEASE_SEND_UE_CONTEXT_RELEASE_COMMAND 1 diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 993de0ca7..31e0c65c7 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -138,6 +138,7 @@ typedef struct ogs_pfcp_pdr_s { uint32_t index; ogs_lnode_t to_create_node; + ogs_lnode_t to_modify_node; struct { struct { diff --git a/lib/pfcp/handler.c b/lib/pfcp/handler.c index ee86c81f5..982b83af5 100644 --- a/lib/pfcp/handler.c +++ b/lib/pfcp/handler.c @@ -170,7 +170,7 @@ bool ogs_pfcp_up_handle_association_setup_response( } bool ogs_pfcp_up_handle_pdr( - ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf, + ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *recvbuf, ogs_pfcp_user_plane_report_t *report) { ogs_pfcp_far_t *far = NULL; @@ -178,6 +178,7 @@ bool ogs_pfcp_up_handle_pdr( bool buffering; ogs_assert(recvbuf); + ogs_assert(type); ogs_assert(pdr); ogs_assert(report); @@ -198,7 +199,7 @@ bool ogs_pfcp_up_handle_pdr( if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { /* Forward packet */ - ogs_pfcp_send_g_pdu(pdr, sendbuf); + ogs_pfcp_send_g_pdu(pdr, type, sendbuf); } else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) { diff --git a/lib/pfcp/handler.h b/lib/pfcp/handler.h index 590711fe9..f87b789b0 100644 --- a/lib/pfcp/handler.h +++ b/lib/pfcp/handler.h @@ -46,7 +46,7 @@ bool ogs_pfcp_up_handle_association_setup_response( ogs_pfcp_association_setup_response_t *req); bool ogs_pfcp_up_handle_pdr( - ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *recvbuf, + ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *recvbuf, ogs_pfcp_user_plane_report_t *report); bool ogs_pfcp_up_handle_error_indication( ogs_pfcp_far_t *far, ogs_pfcp_user_plane_report_t *report); diff --git a/lib/pfcp/path.c b/lib/pfcp/path.c index b9569fb53..a110e3ac8 100644 --- a/lib/pfcp/path.c +++ b/lib/pfcp/path.c @@ -283,7 +283,8 @@ int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact, return rv; } -void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) +void ogs_pfcp_send_g_pdu( + ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *sendbuf) { ogs_gtp_node_t *gnode = NULL; ogs_pfcp_far_t *far = NULL; @@ -292,6 +293,7 @@ void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) ogs_gtp2_extension_header_t ext_hdesc; ogs_assert(pdr); + ogs_assert(type); ogs_assert(sendbuf); far = pdr->far; @@ -314,7 +316,7 @@ void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf) memset(>p_hdesc, 0, sizeof(gtp_hdesc)); memset(&ext_hdesc, 0, sizeof(ext_hdesc)); - gtp_hdesc.type = OGS_GTPU_MSGTYPE_GPDU; + gtp_hdesc.type = type; gtp_hdesc.teid = far->outer_header_creation.teid; if (pdr->qer && pdr->qer->qfi) ext_hdesc.qos_flow_identifier = pdr->qer->qfi; @@ -374,7 +376,8 @@ void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr) if (far && far->gnode) { if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) { for (i = 0; i < far->num_of_buffered_packet; i++) { - ogs_pfcp_send_g_pdu(pdr, far->buffered_packet[i]); + ogs_pfcp_send_g_pdu( + pdr, OGS_GTPU_MSGTYPE_GPDU, far->buffered_packet[i]); } far->num_of_buffered_packet = 0; } diff --git a/lib/pfcp/path.h b/lib/pfcp/path.h index 88d1bd57e..689175c26 100644 --- a/lib/pfcp/path.h +++ b/lib/pfcp/path.h @@ -78,7 +78,8 @@ int ogs_pfcp_up_send_association_setup_request(ogs_pfcp_node_t *node, int ogs_pfcp_up_send_association_setup_response(ogs_pfcp_xact_t *xact, uint8_t cause); -void ogs_pfcp_send_g_pdu(ogs_pfcp_pdr_t *pdr, ogs_pkbuf_t *sendbuf); +void ogs_pfcp_send_g_pdu( + ogs_pfcp_pdr_t *pdr, uint8_t type, ogs_pkbuf_t *sendbuf); int ogs_pfcp_send_end_marker(ogs_pfcp_pdr_t *pdr); void ogs_pfcp_send_buffered_packet(ogs_pfcp_pdr_t *pdr); diff --git a/src/amf/context.h b/src/amf/context.h index b851b1e84..1f17da32a 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -754,7 +754,7 @@ void amf_sess_select_nf(amf_sess_t *sess, OpenAPI_nf_type_e nf_type); void amf_sess_select_smf(amf_sess_t *sess); -#define SESSION_SYNC_DONE(__aMF, __sTATE) \ +#define AMF_SESSION_SYNC_DONE(__aMF, __sTATE) \ (amf_sess_xact_state_count(__aMF, __sTATE) == 0) int amf_sess_xact_count(amf_ue_t *amf_ue); int amf_sess_xact_state_count(amf_ue_t *amf_ue, int state); diff --git a/src/amf/nsmf-handler.c b/src/amf/nsmf-handler.c index 13924483c..4000cc89c 100644 --- a/src/amf/nsmf-handler.c +++ b/src/amf/nsmf-handler.c @@ -223,9 +223,9 @@ int amf_nsmf_pdusession_handle_update_sm_context( sess, pdu_session_resource_setup_request, ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue, + if (AMF_SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) && - SESSION_SYNC_DONE(amf_ue, + AMF_SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) { if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) { @@ -247,9 +247,9 @@ int amf_nsmf_pdusession_handle_update_sm_context( sess, pdu_session_resource_setup_request, ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue, + if (AMF_SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && - SESSION_SYNC_DONE(amf_ue, + AMF_SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST)) { ogs_assert(OGS_OK == nas_5gs_send_service_accept(amf_ue)); @@ -261,7 +261,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( AMF_SESS_STORE_N2_TRANSFER( sess, handover_request, ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue, + if (AMF_SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED)) { ogs_assert(OGS_OK == ngap_send_handover_request(amf_ue)); @@ -367,7 +367,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( sess, path_switch_request_ack, ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ogs_assert(OGS_OK == ngap_send_path_switch_ack(sess)); @@ -390,7 +390,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( AMF_SESS_STORE_N2_TRANSFER( sess, handover_command, ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ogs_assert(OGS_OK == ngap_send_handover_command(amf_ue)); @@ -497,7 +497,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( * 6. UEContextReleaseComplete */ - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ogs_assert(amf_ue->deactivation.group); ogs_assert(OGS_OK == @@ -573,7 +573,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL) { - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *source_ue = NULL, *target_ue = NULL; source_ue = amf_ue->ran_ue; @@ -593,7 +593,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( /* Nothing to do */ } else if (state == AMF_REMOVE_S1_CONTEXT_BY_LO_CONNREFUSED) { - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); amf_ue_deassociate(amf_ue); @@ -608,7 +608,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( } } else if (state == AMF_REMOVE_S1_CONTEXT_BY_RESET_ALL) { - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); amf_ue_deassociate(amf_ue); @@ -631,7 +631,7 @@ int amf_nsmf_pdusession_handle_update_sm_context( } } else if (state == AMF_REMOVE_S1_CONTEXT_BY_RESET_PARTIAL) { - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *iter = NULL; ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); @@ -797,9 +797,9 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state) * 2. Release All SM contexts * 3. Registration accept */ - if (SESSION_SYNC_DONE( + if (AMF_SESSION_SYNC_DONE( amf_ue, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) && - SESSION_SYNC_DONE( + AMF_SESSION_SYNC_DONE( amf_ue, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) { if (!PCF_AM_POLICY_ASSOCIATED(amf_ue)) { @@ -820,14 +820,14 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state) * 2. Release All SM contexts * 3. Service accept */ - if (SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && - SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST)) + if (AMF_SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && + AMF_SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST)) ogs_assert(OGS_OK == nas_5gs_send_service_accept(amf_ue)); } else { - if (SESSION_SYNC_DONE(amf_ue, state)) { + if (AMF_SESSION_SYNC_DONE(amf_ue, state)) { if (state == AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE) { /* diff --git a/src/mme/esm-sm.c b/src/mme/esm-sm.c index 3db8d012c..0ec58b983 100644 --- a/src/mme/esm-sm.c +++ b/src/mme/esm-sm.c @@ -119,7 +119,7 @@ void esm_state_inactive(ogs_fsm_t *s, mme_event_t *e) mme_ue->imsi_bcd, sess->pti, bearer->ebi); if (MME_HAVE_SGW_S1U_PATH(sess)) { ogs_assert(OGS_OK == - mme_gtp_send_delete_session_request(sess, + mme_gtp_send_delete_session_request(mme_ue->sgw_ue, sess, OGS_GTP_DELETE_SEND_DEACTIVATE_BEARER_CONTEXT_REQUEST)); } else { ogs_assert(OGS_OK == @@ -306,7 +306,7 @@ void esm_state_active(ogs_fsm_t *s, mme_event_t *e) mme_ue->imsi_bcd, sess->pti, bearer->ebi); if (MME_HAVE_SGW_S1U_PATH(sess)) { ogs_assert(OGS_OK == - mme_gtp_send_delete_session_request(sess, + mme_gtp_send_delete_session_request(mme_ue->sgw_ue, sess, OGS_GTP_DELETE_SEND_DEACTIVATE_BEARER_CONTEXT_REQUEST)); } else { ogs_assert(OGS_OK == diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index c6ff06969..be857df69 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -2039,14 +2039,9 @@ sgw_ue_t *sgw_ue_add(mme_sgw_t *sgw) ogs_assert(sgw_ue); memset(sgw_ue, 0, sizeof *sgw_ue); - sgw_ue->index = ogs_pool_index(&sgw_ue_pool, sgw_ue); - ogs_assert(sgw_ue->index > 0 && sgw_ue->index <= ogs_app()->max.ue); - - sgw_ue->mme_s11_teid = sgw_ue->index; - - sgw_ue->t_gtp2_holding = ogs_timer_add( + sgw_ue->t_s11_holding = ogs_timer_add( ogs_app()->timer_mgr, mme_timer_s11_holding_timer_expire, sgw_ue); - ogs_assert(sgw_ue->t_gtp2_holding); + ogs_assert(sgw_ue->t_s11_holding); sgw_ue->sgw = sgw; @@ -2065,8 +2060,8 @@ void sgw_ue_remove(sgw_ue_t *sgw_ue) ogs_list_remove(&sgw->sgw_ue_list, sgw_ue); - ogs_assert(sgw_ue->t_gtp2_holding); - ogs_timer_delete(sgw_ue->t_gtp2_holding); + ogs_assert(sgw_ue->t_s11_holding); + ogs_timer_delete(sgw_ue->t_s11_holding); ogs_pool_free(&sgw_ue_pool, sgw_ue); } @@ -2092,11 +2087,6 @@ sgw_ue_t *sgw_ue_find(uint32_t index) return ogs_pool_find(&sgw_ue_pool, index); } -sgw_ue_t *sgw_ue_find_by_mme_s11_teid(uint32_t mme_s11_teid) -{ - return sgw_ue_find(mme_s11_teid); -} - sgw_ue_t *sgw_ue_cycle(sgw_ue_t *sgw_ue) { return ogs_pool_cycle(&sgw_ue_pool, sgw_ue); @@ -2105,7 +2095,7 @@ sgw_ue_t *sgw_ue_cycle(sgw_ue_t *sgw_ue) sgw_relocation_e sgw_ue_check_if_relocated(mme_ue_t *mme_ue) { enb_ue_t *enb_ue = NULL; - sgw_ue_t *source_ue, *target_ue = NULL; + sgw_ue_t *old_source_ue = NULL, *source_ue = NULL, *target_ue = NULL; mme_sgw_t *current = NULL, *changed = NULL; ogs_assert(mme_ue); @@ -2120,6 +2110,13 @@ sgw_relocation_e sgw_ue_check_if_relocated(mme_ue_t *mme_ue) changed = changed_sgw_node(current, enb_ue); if (!changed) return SGW_WITHOUT_RELOCATION; + /* Check if Old Source UE */ + old_source_ue = sgw_ue_cycle(source_ue->source_ue); + if (old_source_ue) { + sgw_ue_source_deassociate_target(old_source_ue); + sgw_ue_remove(old_source_ue); + } + target_ue = sgw_ue_cycle(source_ue->target_ue); if (target_ue) { ogs_error("SGW-UE source has already been associated with target"); @@ -2260,6 +2257,10 @@ mme_ue_t *mme_ue_add(enb_ue_t *enb_ue) ogs_list_init(&mme_ue->sess_list); + mme_ue->mme_s11_teid = ogs_pool_index(&mme_ue_pool, mme_ue); + ogs_assert(mme_ue->mme_s11_teid > 0 && + mme_ue->mme_s11_teid <= ogs_app()->max.ue); + /* * When used for the first time, if last node is set, * the search is performed from the first SGW in a round-robin manner. @@ -2438,6 +2439,11 @@ mme_ue_t *mme_ue_find_by_guti(ogs_nas_eps_guti_t *guti) self.guti_ue_hash, guti, sizeof(ogs_nas_eps_guti_t)); } +mme_ue_t *mme_ue_find_by_teid(uint32_t teid) +{ + return ogs_pool_find(&mme_ue_pool, teid); +} + mme_ue_t *mme_ue_find_by_message(ogs_nas_eps_message_t *message) { mme_ue_t *mme_ue = NULL; diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 26422b826..96efe7e4b 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -277,7 +277,6 @@ struct sgw_ue_s { sgw_ue_t *target_ue; /* UE identity */ - uint32_t mme_s11_teid; /* MME-S11-TEID is derived from INDEX */ uint32_t sgw_s11_teid; /* SGW-S11-TEID is received from SGW */ /* @@ -288,8 +287,8 @@ struct sgw_ue_s { */ int session_context_will_deleted; - /* GTPv2-C Holding timer for removing this context */ - ogs_timer_t *t_gtp2_holding; + /* S11 Holding timer for removing this context */ + ogs_timer_t *t_s11_holding; /* Related Context */ union { @@ -351,6 +350,8 @@ struct mme_ue_s { ogs_nas_eps_guti_t guti; } current, next; + uint32_t mme_s11_teid; /* MME-S11-TEID is derived from INDEX */ + uint16_t vlr_ostream_id; /* SCTP output stream id for VLR */ /* UE Info */ @@ -533,8 +534,8 @@ struct mme_ue_s { #define MAX_NUM_OF_GTP_COUNTER 16 -#define GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH 1 -#define GTP_COUNTER_MODIFY_BEARER_BY_E_RAB_MODIFICATION 2 +#define GTP_COUNTER_CREATE_SESSION_BY_PATH_SWITCH 1 +#define GTP_COUNTER_DELETE_SESSION_BY_PATH_SWITCH 2 struct { uint8_t request; uint8_t response; @@ -638,6 +639,8 @@ typedef struct mme_bearer_s { ogs_ip_t enb_s1u_ip; uint32_t sgw_s1u_teid; ogs_ip_t sgw_s1u_ip; + uint32_t pgw_s5u_teid; + ogs_ip_t pgw_s5u_ip; uint32_t target_s1u_teid; /* Target S1U TEID from HO-Req-Ack */ ogs_ip_t target_s1u_ip; /* Target S1U ADDR from HO-Req-Ack */ @@ -734,7 +737,6 @@ sgw_ue_t *sgw_ue_add(mme_sgw_t *sgw); void sgw_ue_remove(sgw_ue_t *sgw_ue); void sgw_ue_switch_to_sgw(sgw_ue_t *sgw_ue, mme_sgw_t *new_sgw); sgw_ue_t *sgw_ue_find(uint32_t index); -sgw_ue_t *sgw_ue_find_by_mme_s11_teid(uint32_t mme_s11_teid); sgw_ue_t *sgw_ue_cycle(sgw_ue_t *sgw_ue); typedef enum { @@ -758,6 +760,7 @@ void mme_ue_fsm_fini(mme_ue_t *mme_ue); mme_ue_t *mme_ue_find_by_imsi(uint8_t *imsi, int imsi_len); mme_ue_t *mme_ue_find_by_imsi_bcd(char *imsi_bcd); mme_ue_t *mme_ue_find_by_guti(ogs_nas_eps_guti_t *nas_guti); +mme_ue_t *mme_ue_find_by_teid(uint32_t teid); mme_ue_t *mme_ue_find_by_message(ogs_nas_eps_message_t *message); int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd); diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 6bf1db30c..c03c3f6d2 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -747,10 +747,10 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); ogs_assert(ret == 0); - if (hdr->avp_value->os.len) { + if (hdr->avp_value->os.data && hdr->avp_value->os.len) { mme_ue->msisdn_len = hdr->avp_value->os.len; - memcpy(mme_ue->msisdn, - hdr->avp_value->os.data, mme_ue->msisdn_len); + memcpy(mme_ue->msisdn, hdr->avp_value->os.data, + ogs_min(mme_ue->msisdn_len, OGS_MAX_MSISDN_LEN)); ogs_buffer_to_bcd(mme_ue->msisdn, mme_ue->msisdn_len, mme_ue->msisdn_bcd); } @@ -769,10 +769,10 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) if (avpch1) { ret = fd_msg_avp_hdr(avpch1, &hdr); ogs_assert(ret == 0); - if (hdr->avp_value->os.len) { + if (hdr->avp_value->os.data && hdr->avp_value->os.len) { mme_ue->a_msisdn_len = hdr->avp_value->os.len; - memcpy(mme_ue->a_msisdn, - hdr->avp_value->os.data, mme_ue->a_msisdn_len); + memcpy(mme_ue->a_msisdn, hdr->avp_value->os.data, + ogs_min(mme_ue->a_msisdn_len, OGS_MAX_MSISDN_LEN)); ogs_buffer_to_bcd(mme_ue->a_msisdn, mme_ue->a_msisdn_len, mme_ue->a_msisdn_bcd); } diff --git a/src/mme/mme-gtp-path.c b/src/mme/mme-gtp-path.c index 291d11f13..99d27f655 100644 --- a/src/mme/mme-gtp-path.c +++ b/src/mme/mme-gtp-path.c @@ -267,27 +267,26 @@ int mme_gtp_send_modify_bearer_request( return rv; } -int mme_gtp_send_delete_session_request(mme_sess_t *sess, int action) +int mme_gtp_send_delete_session_request( + sgw_ue_t *sgw_ue, mme_sess_t *sess, int action) { int rv; ogs_pkbuf_t *s11buf = NULL; ogs_gtp2_header_t h; ogs_gtp_xact_t *xact = NULL; mme_ue_t *mme_ue = NULL; - sgw_ue_t *sgw_ue = NULL; ogs_assert(action); ogs_assert(sess); mme_ue = sess->mme_ue; ogs_assert(mme_ue); - sgw_ue = mme_ue->sgw_ue; ogs_assert(sgw_ue); memset(&h, 0, sizeof(ogs_gtp2_header_t)); h.type = OGS_GTP2_DELETE_SESSION_REQUEST_TYPE; h.teid = sgw_ue->sgw_s11_teid; - s11buf = mme_s11_build_delete_session_request(h.type, sess); + s11buf = mme_s11_build_delete_session_request(h.type, sess, action); ogs_expect_or_return_val(s11buf, OGS_ERROR); xact = ogs_gtp_xact_local_create(sgw_ue->gnode, &h, s11buf, timeout, sess); @@ -330,7 +329,7 @@ void mme_gtp_send_delete_all_sessions(mme_ue_t *mme_ue, int action) OGS_FSM_CHECK(&bearer->sm, esm_state_pdn_will_disconnect)) { ogs_warn("PDN will disconnect[EBI:%d]", bearer->ebi); } else { - mme_gtp_send_delete_session_request(sess, action); + mme_gtp_send_delete_session_request(sgw_ue, sess, action); } } else { mme_sess_remove(sess); diff --git a/src/mme/mme-gtp-path.h b/src/mme/mme-gtp-path.h index a20733902..839a11fed 100644 --- a/src/mme/mme-gtp-path.h +++ b/src/mme/mme-gtp-path.h @@ -32,7 +32,8 @@ void mme_gtp_close(void); int mme_gtp_send_create_session_request(mme_sess_t *sess, int create_action); int mme_gtp_send_modify_bearer_request( mme_ue_t *mme_ue, int uli_presence, int modify_action); -int mme_gtp_send_delete_session_request(mme_sess_t *sess, int action); +int mme_gtp_send_delete_session_request( + sgw_ue_t *sgw_ue, mme_sess_t *sess, int action); void mme_gtp_send_delete_all_sessions(mme_ue_t *mme_ue, int action); int mme_gtp_send_create_bearer_response( mme_bearer_t *bearer, uint8_t cause_value); diff --git a/src/mme/mme-s11-build.c b/src/mme/mme-s11-build.c index 986412d14..da21d3a3c 100644 --- a/src/mme/mme-s11-build.c +++ b/src/mme/mme-s11-build.c @@ -37,9 +37,13 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( char uli_buf[OGS_GTP2_MAX_ULI_LEN]; ogs_gtp2_f_teid_t mme_s11_teid, pgw_s5c_teid; int len; + ogs_gtp2_f_teid_t enb_s1u_teid[OGS_BEARER_PER_UE]; + int enb_s1u_len[OGS_BEARER_PER_UE]; + ogs_gtp2_f_teid_t pgw_s5u_teid[OGS_BEARER_PER_UE]; + int pgw_s5u_len[OGS_BEARER_PER_UE]; ogs_gtp2_ambr_t ambr; ogs_gtp2_bearer_qos_t bearer_qos; - char bearer_qos_buf[GTP2_BEARER_QOS_LEN]; + char bearer_qos_buf[OGS_BEARER_PER_UE][GTP2_BEARER_QOS_LEN]; ogs_gtp2_ue_timezone_t ue_timezone; struct timeval now; struct tm time_exp; @@ -51,8 +55,6 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( session = sess->session; ogs_assert(session); ogs_assert(session->name); - bearer = mme_default_bearer_in_sess(sess); - ogs_assert(bearer); mme_ue = sess->mme_ue; ogs_assert(mme_ue); sgw_ue = mme_ue->sgw_ue; @@ -65,7 +67,7 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( ogs_debug("Create Session Request"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); ogs_assert(mme_ue->imsi_len); @@ -105,7 +107,7 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( memset(&mme_s11_teid, 0, sizeof(ogs_gtp2_f_teid_t)); mme_s11_teid.interface_type = OGS_GTP2_F_TEID_S11_MME_GTP_C; - mme_s11_teid.teid = htobe32(sgw_ue->mme_s11_teid); + mme_s11_teid.teid = htobe32(mme_ue->mme_s11_teid); rv = ogs_gtp2_sockaddr_to_f_teid( ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6, &mme_s11_teid, &len); @@ -257,20 +259,58 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( req->protocol_configuration_options.len = sess->ue_pco.length; } - req->bearer_contexts_to_be_created.presence = 1; - req->bearer_contexts_to_be_created.eps_bearer_id.presence = 1; - req->bearer_contexts_to_be_created.eps_bearer_id.u8 = bearer->ebi; + int i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); - memset(&bearer_qos, 0, sizeof(bearer_qos)); - bearer_qos.qci = session->qos.index; - bearer_qos.priority_level = session->qos.arp.priority_level; - bearer_qos.pre_emption_capability = session->qos.arp.pre_emption_capability; - bearer_qos.pre_emption_vulnerability = - session->qos.arp.pre_emption_vulnerability; - req->bearer_contexts_to_be_created.bearer_level_qos.presence = 1; - ogs_gtp2_build_bearer_qos( - &req->bearer_contexts_to_be_created.bearer_level_qos, - &bearer_qos, bearer_qos_buf, GTP2_BEARER_QOS_LEN); + /* Bearer Context : EBI */ + req->bearer_contexts_to_be_created[i].presence = 1; + req->bearer_contexts_to_be_created[i].eps_bearer_id.presence = 1; + req->bearer_contexts_to_be_created[i].eps_bearer_id.u8 = bearer->ebi; + + if (create_action == OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST) { + + /* Data Plane(DL) : ENB-S1U */ + memset(&enb_s1u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + enb_s1u_teid[i].interface_type = OGS_GTP2_F_TEID_S1_U_ENODEB_GTP_U; + enb_s1u_teid[i].teid = htobe32(bearer->enb_s1u_teid); + ogs_assert(OGS_OK == ogs_gtp2_ip_to_f_teid( + &bearer->enb_s1u_ip, &enb_s1u_teid[i], &enb_s1u_len[i])); + req->bearer_contexts_to_be_created[i].s1_u_enodeb_f_teid. + presence = 1; + req->bearer_contexts_to_be_created[i].s1_u_enodeb_f_teid.data = + &enb_s1u_teid[i]; + req->bearer_contexts_to_be_created[i].s1_u_enodeb_f_teid.len = + enb_s1u_len[i]; + + /* Data Plane(DL) : PGW-S5U */ + memset(&pgw_s5u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + pgw_s5u_teid[i].interface_type = OGS_GTP2_F_TEID_S5_S8_PGW_GTP_U; + pgw_s5u_teid[i].teid = htobe32(bearer->pgw_s5u_teid); + ogs_assert(OGS_OK == ogs_gtp2_ip_to_f_teid( + &bearer->pgw_s5u_ip, &pgw_s5u_teid[i], &pgw_s5u_len[i])); + req->bearer_contexts_to_be_created[i].s5_s8_u_sgw_f_teid. + presence = 1; + req->bearer_contexts_to_be_created[i].s5_s8_u_sgw_f_teid.data = + &pgw_s5u_teid[i]; + req->bearer_contexts_to_be_created[i].s5_s8_u_sgw_f_teid.len = + pgw_s5u_len[i]; + } + + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = session->qos.index; + bearer_qos.priority_level = session->qos.arp.priority_level; + bearer_qos.pre_emption_capability = + session->qos.arp.pre_emption_capability; + bearer_qos.pre_emption_vulnerability = + session->qos.arp.pre_emption_vulnerability; + req->bearer_contexts_to_be_created[i].bearer_level_qos.presence = 1; + ogs_gtp2_build_bearer_qos( + &req->bearer_contexts_to_be_created[i].bearer_level_qos, + &bearer_qos, bearer_qos_buf[i], GTP2_BEARER_QOS_LEN); + + i++; + } /* UE Time Zone */ memset(&ue_timezone, 0, sizeof(ue_timezone)); @@ -305,7 +345,7 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( ogs_gtp2_modify_bearer_request_t *req = NULL; ogs_gtp2_f_teid_t enb_s1u_teid[OGS_BEARER_PER_UE]; - int len, i; + int enb_s1u_len[OGS_BEARER_PER_UE], i; ogs_gtp2_uli_t uli; char uli_buf[OGS_GTP2_MAX_ULI_LEN]; @@ -326,7 +366,7 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( req = >p_message.modify_bearer_request; ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); i = 0; ogs_list_for_each_entry( @@ -345,12 +385,13 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( memset(&enb_s1u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); enb_s1u_teid[i].interface_type = OGS_GTP2_F_TEID_S1_U_ENODEB_GTP_U; enb_s1u_teid[i].teid = htobe32(bearer->enb_s1u_teid); - ogs_assert(OGS_OK == - ogs_gtp2_ip_to_f_teid(&bearer->enb_s1u_ip, &enb_s1u_teid[i], &len)); + ogs_assert(OGS_OK == ogs_gtp2_ip_to_f_teid( + &bearer->enb_s1u_ip, &enb_s1u_teid[i], &enb_s1u_len[i])); req->bearer_contexts_to_be_modified[i].s1_u_enodeb_f_teid.presence = 1; req->bearer_contexts_to_be_modified[i].s1_u_enodeb_f_teid.data = &enb_s1u_teid[i]; - req->bearer_contexts_to_be_modified[i].s1_u_enodeb_f_teid.len = len; + req->bearer_contexts_to_be_modified[i].s1_u_enodeb_f_teid.len = + enb_s1u_len[i]; i++; } @@ -409,7 +450,7 @@ ogs_pkbuf_t *mme_s11_build_modify_bearer_request( } ogs_pkbuf_t *mme_s11_build_delete_session_request( - uint8_t type, mme_sess_t *sess) + uint8_t type, mme_sess_t *sess, int action) { ogs_gtp2_message_t gtp_message; ogs_gtp2_delete_session_request_t *req = @@ -421,19 +462,14 @@ ogs_pkbuf_t *mme_s11_build_delete_session_request( mme_bearer_t *bearer = NULL; mme_ue_t *mme_ue = NULL; - sgw_ue_t *sgw_ue = NULL; ogs_assert(sess); mme_ue = sess->mme_ue; ogs_assert(mme_ue); - sgw_ue = mme_ue->sgw_ue; - ogs_assert(sgw_ue); bearer = mme_default_bearer_in_sess(sess); ogs_assert(bearer); ogs_debug("Delete Session Request"); - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -453,7 +489,11 @@ ogs_pkbuf_t *mme_s11_build_delete_session_request( uli_buf, OGS_GTP2_MAX_ULI_LEN); memset(&indication, 0, sizeof(ogs_gtp2_indication_t)); - indication.operation_indication = 1; + if (action == OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST) { + indication.scope_indication = 1; + } else { + indication.operation_indication = 1; + } req->indication_flags.presence = 1; req->indication_flags.data = &indication; req->indication_flags.len = sizeof(ogs_gtp2_indication_t); @@ -490,7 +530,7 @@ ogs_pkbuf_t *mme_s11_build_create_bearer_response( ogs_debug("Create Bearer Response"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -591,7 +631,7 @@ ogs_pkbuf_t *mme_s11_build_update_bearer_response( ogs_debug("Update Bearer Response"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -670,7 +710,7 @@ ogs_pkbuf_t *mme_s11_build_delete_bearer_response( ogs_debug("Delete Bearer Response"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -824,7 +864,7 @@ ogs_pkbuf_t *mme_s11_build_create_indirect_data_forwarding_tunnel_request( ogs_debug("Create Indirect Data Forwarding Tunnel Request"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -906,7 +946,7 @@ ogs_pkbuf_t *mme_s11_build_bearer_resource_command( ogs_debug("Bearer Resource Command"); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); ogs_assert(nas_message); switch (nas_message->esm.h.message_type) { diff --git a/src/mme/mme-s11-build.h b/src/mme/mme-s11-build.h index c5dae8e16..f979cd12c 100644 --- a/src/mme/mme-s11-build.h +++ b/src/mme/mme-s11-build.h @@ -29,7 +29,7 @@ ogs_pkbuf_t *mme_s11_build_create_session_request( ogs_pkbuf_t *mme_s11_build_modify_bearer_request( uint8_t type, mme_ue_t *mme_ue, int uli_presense); ogs_pkbuf_t *mme_s11_build_delete_session_request( - uint8_t type, mme_sess_t *sess); + uint8_t type, mme_sess_t *sess, int action); ogs_pkbuf_t *mme_s11_build_create_bearer_response( uint8_t type, mme_bearer_t *bearer, uint8_t cause_value); ogs_pkbuf_t *mme_s11_build_update_bearer_response( diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 2f5fe61be..338adfb82 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -20,6 +20,7 @@ #include "mme-event.h" #include "mme-sm.h" #include "mme-context.h" +#include "mme-timer.h" #include "s1ap-path.h" #include "mme-gtp-path.h" @@ -77,19 +78,21 @@ void mme_s11_handle_echo_response( } void mme_s11_handle_create_session_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_create_session_response_t *rsp) { - int rv; + int rv, i; uint8_t cause_value = 0; ogs_gtp2_cause_t *cause = NULL; ogs_gtp2_f_teid_t *sgw_s11_teid = NULL; ogs_gtp2_f_teid_t *pgw_s5c_teid = NULL; ogs_gtp2_f_teid_t *sgw_s1u_teid = NULL; + ogs_gtp2_f_teid_t *pgw_s5u_teid = NULL; mme_bearer_t *bearer = NULL; mme_sess_t *sess = NULL; mme_ue_t *mme_ue = NULL; + sgw_ue_t *source_ue = NULL, *target_ue = NULL; ogs_session_t *session = NULL; ogs_gtp2_bearer_qos_t bearer_qos; ogs_gtp2_ambr_t *ambr = NULL; @@ -109,38 +112,28 @@ void mme_s11_handle_create_session_response( ogs_assert(sess); mme_ue = sess->mme_ue; ogs_assert(mme_ue); + source_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(source_ue); + + if (create_action == OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST) { + target_ue = sgw_ue_cycle(source_ue->target_ue); + ogs_assert(target_ue); + } else { + target_ue = source_ue; + ogs_assert(target_ue); + } rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; - } else { - if (rsp->bearer_contexts_created.presence == 0) { - ogs_error("No Bearer"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } - if (rsp->bearer_contexts_created.eps_bearer_id.presence == 0) { - ogs_error("No EPS Bearer ID"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } - - if (cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - bearer = mme_bearer_find_by_ue_ebi(mme_ue, - rsp->bearer_contexts_created.eps_bearer_id.u8); - - if (!bearer) { - ogs_error("No Context for EPS Bearer ID[%d]", - rsp->bearer_contexts_created.eps_bearer_id.u8); - cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; - } - } } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { @@ -162,38 +155,46 @@ void mme_s11_handle_create_session_response( ogs_error("No S11 TEID"); cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; } - if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.presence == 0) { - ogs_error("No S5C TEID"); - cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; - } - if (rsp->bearer_contexts_created.s1_u_enodeb_f_teid.presence == 0) { - ogs_error("No S1U TEID"); - cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; - } - if (rsp->pdn_address_allocation.presence) { - ogs_paa_t paa; + if (create_action == OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST) { - memcpy(&paa, rsp->pdn_address_allocation.data, - rsp->pdn_address_allocation.len); + /* No need S5C TEID in PathSwitchRequest */ - if (!OGS_PDU_SESSION_TYPE_IS_VALID(paa.session_type)) { - ogs_error("Unknown PDN Type[%u]", paa.session_type); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_INCORRECT; - } } else { - ogs_error("No PDN Address Allocation"); - cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; + + if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.presence == 0) { + ogs_error("No S5C TEID"); + cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; + } + + } + + if (create_action == OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST) { + + /* No need S5C TEID in PathSwitchRequest */ + + } else { + + if (rsp->pdn_address_allocation.presence) { + ogs_paa_t paa; + + memcpy(&paa, rsp->pdn_address_allocation.data, + rsp->pdn_address_allocation.len); + + if (!OGS_PDU_SESSION_TYPE_IS_VALID(paa.session_type)) { + ogs_error("Unknown PDN Type[%u]", paa.session_type); + cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_INCORRECT; + } + } else { + ogs_error("No PDN Address Allocation"); + cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; + } } if (rsp->cause.presence == 0) { ogs_error("No Cause"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (rsp->bearer_contexts_created.cause.presence == 0) { - ogs_error("No Bearer Cause"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { @@ -210,18 +211,24 @@ void mme_s11_handle_create_session_response( ********************/ ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); - cause = rsp->bearer_contexts_created.cause.data; - ogs_assert(cause); - cause_value = cause->value; - if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); - if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { - ogs_error("[%s] Attach reject", mme_ue->imsi_bcd); - ogs_assert(OGS_OK == nas_eps_send_attach_reject(mme_ue, - EMM_CAUSE_NETWORK_FAILURE, ESM_CAUSE_NETWORK_FAILURE)); + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (rsp->bearer_contexts_created[i].cause.presence == 0) { + break; + } + + cause = rsp->bearer_contexts_created[i].cause.data; + ogs_assert(cause); + cause_value = cause->value; + if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { + ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { + ogs_error("[%s] Attach reject", mme_ue->imsi_bcd); + ogs_assert(OGS_OK == nas_eps_send_attach_reject(mme_ue, + EMM_CAUSE_NETWORK_FAILURE, ESM_CAUSE_NETWORK_FAILURE)); + } + mme_send_delete_session_or_mme_ue_context_release(mme_ue); + return; } - mme_send_delete_session_or_mme_ue_context_release(mme_ue); - return; } cause = rsp->cause.data; @@ -246,25 +253,87 @@ void mme_s11_handle_create_session_response( /******************** * Check ALL Context ********************/ - ogs_assert(mme_ue); - ogs_assert(sgw_ue); - - ogs_assert(bearer); - sess = bearer->sess; ogs_assert(sess); session = sess->session; ogs_assert(session); + ogs_assert(mme_ue); + ogs_assert(source_ue); + ogs_assert(target_ue); + + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + mme_ue->mme_s11_teid, target_ue->sgw_s11_teid); + + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (rsp->bearer_contexts_created[i].presence == 0) { + break; + } + if (rsp->bearer_contexts_created[i].eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + if (rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.presence == 0) { + ogs_error("No SGW-S1U TEID"); + break; + } + if (rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.presence == 0) { + ogs_error("No PGW-S5U TEID"); + break; + } + + /* EPS Bearer ID */ + bearer = mme_bearer_find_by_ue_ebi(mme_ue, + rsp->bearer_contexts_created[i].eps_bearer_id.u8); + if (!bearer) { + mme_send_delete_session_or_mme_ue_context_release(mme_ue); + return; + } + + /* Data Plane(UL) : SGW-S1U */ + sgw_s1u_teid = rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.data; + bearer->sgw_s1u_teid = be32toh(sgw_s1u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip)); + + /* Data Plane(UL) : PGW-S5U */ + pgw_s5u_teid = rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.data; + bearer->pgw_s5u_teid = be32toh(pgw_s5u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(pgw_s5u_teid, &bearer->pgw_s5u_ip)); + + ogs_debug(" ENB_S1U_TEID[%d] SGW_S1U_TEID[%d] PGW_S5U_TEID[%d]", + bearer->enb_s1u_teid, bearer->sgw_s1u_teid, bearer->pgw_s5u_teid); + } + + /* Bearer Level QoS */ + if (rsp->bearer_contexts_created[0].bearer_level_qos.presence) { + decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, + &rsp->bearer_contexts_created[0].bearer_level_qos); + ogs_assert(decoded == + rsp->bearer_contexts_created[0].bearer_level_qos.len); + session->qos.index = bearer_qos.qci; + session->qos.arp.priority_level = bearer_qos.priority_level; + session->qos.arp.pre_emption_capability = + bearer_qos.pre_emption_capability; + session->qos.arp.pre_emption_vulnerability = + bearer_qos.pre_emption_vulnerability; + } + /* Control Plane(UL) : SGW-S11 */ sgw_s11_teid = rsp->sender_f_teid_for_control_plane.data; - sgw_ue->sgw_s11_teid = be32toh(sgw_s11_teid->teid); + target_ue->sgw_s11_teid = be32toh(sgw_s11_teid->teid); /* Control Plane(UL) : PGW-S5C */ - pgw_s5c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.data; - sess->pgw_s5c_teid = be32toh(pgw_s5c_teid->teid); + if (rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.presence) { + pgw_s5c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.data; + sess->pgw_s5c_teid = be32toh(pgw_s5c_teid->teid); + } - memcpy(&session->paa, rsp->pdn_address_allocation.data, - rsp->pdn_address_allocation.len); + /* PDN Addresss Allocation */ + if (rsp->pdn_address_allocation.presence) { + memcpy(&session->paa, rsp->pdn_address_allocation.data, + rsp->pdn_address_allocation.len); + } /* PCO */ if (rsp->protocol_configuration_options.presence) { @@ -273,10 +342,10 @@ void mme_s11_handle_create_session_response( } /* Bearer QoS */ - if (rsp->bearer_contexts_created.bearer_level_qos.presence) { + if (rsp->bearer_contexts_created[0].bearer_level_qos.presence) { decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, - &rsp->bearer_contexts_created.bearer_level_qos); - ogs_assert(rsp->bearer_contexts_created.bearer_level_qos.len == + &rsp->bearer_contexts_created[0].bearer_level_qos); + ogs_assert(rsp->bearer_contexts_created[0].bearer_level_qos.len == decoded); session->qos.index = bearer_qos.qci; session->qos.arp.priority_level = bearer_qos.priority_level; @@ -293,18 +362,6 @@ void mme_s11_handle_create_session_response( session->ambr.uplink = be32toh(ambr->uplink) * 1000; } - /* Data Plane(UL) : SGW-S1U */ - sgw_s1u_teid = rsp->bearer_contexts_created.s1_u_enodeb_f_teid.data; - bearer->sgw_s1u_teid = be32toh(sgw_s1u_teid->teid); - - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); - ogs_debug(" ENB_S1U_TEID[%d] SGW_S1U_TEID[%d]", - bearer->enb_s1u_teid, bearer->sgw_s1u_teid); - - rv = ogs_gtp2_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip); - ogs_assert(rv == OGS_OK); - if (create_action == OGS_GTP_CREATE_IN_ATTACH_REQUEST) { mme_csmap_t *csmap = mme_csmap_find_by_tai(&mme_ue->tai); mme_ue->csmap = csmap; @@ -327,7 +384,15 @@ void mme_s11_handle_create_session_response( nas_eps_send_activate_default_bearer_context_request( bearer, create_action)); } else if (create_action == OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST) { - ogs_error("OK"); + + GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_CREATE_SESSION_BY_PATH_SWITCH, + ogs_timer_start(source_ue->t_s11_holding, + mme_timer_cfg(MME_TIMER_S11_HOLDING)->duration); + + sgw_ue_associate_mme_ue(target_ue, mme_ue); + ogs_assert(OGS_OK == s1ap_send_path_switch_ack(mme_ue, true)); + ); + } else { ogs_fatal("Invalid Create Session Action[%d]", create_action); ogs_assert_if_reached(); @@ -335,7 +400,7 @@ void mme_s11_handle_create_session_response( } void mme_s11_handle_modify_bearer_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_modify_bearer_response_t *rsp) { int rv; @@ -344,6 +409,7 @@ void mme_s11_handle_modify_bearer_response( ogs_gtp2_cause_t *cause = NULL; mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_assert(rsp); @@ -353,19 +419,21 @@ void mme_s11_handle_modify_bearer_response( * Check Transaction ********************/ ogs_assert(xact); + modify_action = xact->modify_action; mme_ue = xact->data; ogs_assert(mme_ue); - modify_action = xact->modify_action; + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } @@ -411,11 +479,11 @@ void mme_s11_handle_modify_bearer_response( ogs_assert(sgw_ue); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); switch (modify_action) { case OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST: - ogs_assert(OGS_OK == s1ap_send_path_switch_ack(mme_ue)); + ogs_assert(OGS_OK == s1ap_send_path_switch_ack(mme_ue, false)); break; case OGS_GTP_MODIFY_IN_E_RAB_MODIFICATION: ogs_assert(OGS_OK == s1ap_send_e_rab_modification_confirm(mme_ue)); @@ -426,14 +494,15 @@ void mme_s11_handle_modify_bearer_response( } void mme_s11_handle_delete_session_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_delete_session_response_t *rsp) { int rv; uint8_t cause_value = 0; int action = 0; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *source_ue = NULL, *target_ue = NULL; mme_sess_t *sess = NULL; + mme_ue_t *mme_ue = NULL; ogs_assert(rsp); @@ -449,15 +518,26 @@ void mme_s11_handle_delete_session_response( ogs_assert(sess); mme_ue = sess->mme_ue; ogs_assert(mme_ue); + target_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(target_ue); + + if (action == OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST) { + source_ue = sgw_ue_cycle(target_ue->source_ue); + ogs_assert(source_ue); + } else { + source_ue = target_ue; + ogs_assert(source_ue); + } rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ - if (!sgw_ue) + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); + } /******************** * Check Cause Value @@ -474,12 +554,13 @@ void mme_s11_handle_delete_session_response( /******************** * Check ALL Context ********************/ - ogs_assert(mme_ue); ogs_assert(sess); + ogs_assert(mme_ue); + ogs_assert(target_ue); + ogs_assert(source_ue); - if (sgw_ue) - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + mme_ue->mme_s11_teid, source_ue->sgw_s11_teid); if (action == OGS_GTP_DELETE_SEND_AUTHENTICATION_REQUEST) { if (mme_sess_count(mme_ue) == 1) /* Last Session */ { @@ -541,6 +622,20 @@ void mme_s11_handle_delete_session_response( mme_ue_remove(mme_ue); return; + } else if (action == OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST) { + + /* Don't have to remove Session in X2 Handover with SGW relocation */ + ogs_assert(source_ue); + + GTP_COUNTER_CHECK(mme_ue, GTP_COUNTER_DELETE_SESSION_BY_PATH_SWITCH, + + sgw_ue_source_deassociate_target(source_ue); + sgw_ue_remove(source_ue); + + ); + + return; + } else { ogs_fatal("Invalid action = %d", action); ogs_assert_if_reached(); @@ -553,16 +648,16 @@ void mme_s11_handle_delete_session_response( } void mme_s11_handle_create_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_create_bearer_request_t *req) { - int rv; uint8_t cause_value = 0; mme_bearer_t *bearer = NULL, *default_bearer = NULL; mme_sess_t *sess = NULL; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_gtp2_f_teid_t *sgw_s1u_teid = NULL; + ogs_gtp2_f_teid_t *pgw_s5u_teid = NULL; ogs_gtp2_bearer_qos_t bearer_qos; ogs_assert(xact); @@ -571,16 +666,16 @@ void mme_s11_handle_create_bearer_request( ogs_debug("Create Bearer Response"); /*********************** - * Check SGW-UE Context + * Check MME-UE Context ***********************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } else { - mme_ue = sgw_ue->mme_ue; - ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); if (req->linked_eps_bearer_id.presence == 0) { ogs_error("No Linked EBI"); @@ -617,7 +712,11 @@ void mme_s11_handle_create_bearer_request( cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } if (req->bearer_contexts.s1_u_enodeb_f_teid.presence == 0) { - ogs_error("No GTP TEID"); + ogs_error("No SGW-S1U TEID"); + cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; + } + if (req->bearer_contexts.s4_u_sgsn_f_teid.presence == 0) { + ogs_error("No PGW-S5U TEID"); cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; } if (req->bearer_contexts.bearer_level_qos.presence == 0) { @@ -646,7 +745,7 @@ void mme_s11_handle_create_bearer_request( ogs_assert(bearer); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); /* Set PTI */ sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; @@ -658,8 +757,14 @@ void mme_s11_handle_create_bearer_request( /* Data Plane(UL) : SGW-S1U */ sgw_s1u_teid = req->bearer_contexts.s1_u_enodeb_f_teid.data; bearer->sgw_s1u_teid = be32toh(sgw_s1u_teid->teid); - rv = ogs_gtp2_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip); - ogs_assert(rv == OGS_OK); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(sgw_s1u_teid, &bearer->sgw_s1u_ip)); + + /* Data Plane(UL) : PGW-S5U */ + pgw_s5u_teid = req->bearer_contexts.s4_u_sgsn_f_teid.data; + bearer->pgw_s5u_teid = be32toh(pgw_s5u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(pgw_s5u_teid, &bearer->pgw_s5u_ip)); /* Bearer QoS */ ogs_expect_or_return(ogs_gtp2_parse_bearer_qos(&bearer_qos, @@ -721,13 +826,13 @@ void mme_s11_handle_create_bearer_request( } void mme_s11_handle_update_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_update_bearer_request_t *req) { uint8_t cause_value = 0; mme_bearer_t *bearer = NULL; mme_sess_t *sess = NULL; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_gtp2_bearer_qos_t bearer_qos; ogs_assert(xact); @@ -736,16 +841,16 @@ void mme_s11_handle_update_bearer_request( ogs_debug("Update Bearer Request"); /*********************** - * Check SGW-UE Context + * Check MME-UE Context ***********************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } else { - mme_ue = sgw_ue->mme_ue; - ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); if (req->bearer_contexts.presence == 0) { ogs_error("No Bearer"); @@ -783,7 +888,7 @@ void mme_s11_handle_update_bearer_request( ogs_assert(sess); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); /* Set PTI */ sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; @@ -856,14 +961,14 @@ void mme_s11_handle_update_bearer_request( } void mme_s11_handle_delete_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_delete_bearer_request_t *req) { uint8_t cause_value = 0; mme_bearer_t *bearer = NULL; mme_sess_t *sess = NULL; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_assert(xact); ogs_assert(req); @@ -871,16 +976,16 @@ void mme_s11_handle_delete_bearer_request( ogs_debug("Delete Bearer Request"); /*********************** - * Check SGW-UE Context + * Check MME-UE Context ***********************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } else { - mme_ue = sgw_ue->mme_ue; - ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); if (req->linked_eps_bearer_id.presence == 1) { /* @@ -943,7 +1048,7 @@ void mme_s11_handle_delete_bearer_request( ogs_assert(sess); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); /* Set PTI */ sess->pti = OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; @@ -971,7 +1076,7 @@ void mme_s11_handle_delete_bearer_request( } void mme_s11_handle_release_access_bearers_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_release_access_bearers_response_t *rsp) { int rv; @@ -979,7 +1084,8 @@ void mme_s11_handle_release_access_bearers_response( int action = 0; enb_ue_t *enb_ue = NULL; - mme_ue_t *mme_ue = NULL;; + sgw_ue_t *sgw_ue = NULL;; + mme_ue_t *mme_ue = NULL; mme_sess_t *sess = NULL; mme_bearer_t *bearer = NULL; @@ -995,15 +1101,18 @@ void mme_s11_handle_release_access_bearers_response( ogs_assert(action); mme_ue = xact->data; ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /*********************** - * Check SGW-UE Context + * Check MME-UE Context ***********************/ - if (!sgw_ue) + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); + } /******************** * Check Cause Value @@ -1021,10 +1130,10 @@ void mme_s11_handle_release_access_bearers_response( * Check ALL Context ********************/ ogs_assert(mme_ue); + ogs_assert(sgw_ue); - if (sgw_ue) - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); ogs_list_for_each(&mme_ue->sess_list, sess) { ogs_list_for_each(&sess->bearer_list, bearer) { @@ -1125,13 +1234,13 @@ void mme_s11_handle_release_access_bearers_response( } void mme_s11_handle_downlink_data_notification( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_downlink_data_notification_t *noti) { uint8_t cause_value = 0; mme_bearer_t *bearer = NULL; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_assert(xact); ogs_assert(noti); @@ -1139,16 +1248,16 @@ void mme_s11_handle_downlink_data_notification( ogs_debug("Downlink Data Notification"); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue) { ogs_error("No UE Context"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } else { - mme_ue = sgw_ue->mme_ue; - ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); if (noti->eps_bearer_id.presence == 0) { ogs_error("No Bearer ID"); @@ -1181,7 +1290,7 @@ void mme_s11_handle_downlink_data_notification( ogs_assert(bearer); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); /* * Save Transaction. It will be handled after ECM-Connected @@ -1263,14 +1372,15 @@ void mme_s11_handle_downlink_data_notification( } void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_create_indirect_data_forwarding_tunnel_response_t *rsp) { int rv; uint8_t cause_value = 0; ogs_gtp2_cause_t *cause = NULL; - mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; mme_bearer_t *bearer = NULL; + mme_ue_t *mme_ue = NULL; enb_ue_t *source_ue = NULL; int i; @@ -1286,16 +1396,18 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( ogs_assert(xact); mme_ue = xact->data; ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } @@ -1341,7 +1453,7 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( ogs_assert(sgw_ue); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); for (i = 0; rsp->bearer_contexts[i].presence; i++) { if (rsp->bearer_contexts[i].eps_bearer_id.presence == 0) { @@ -1378,7 +1490,7 @@ void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( } void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_delete_indirect_data_forwarding_tunnel_response_t *rsp) { int rv; @@ -1386,6 +1498,7 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( ogs_gtp2_cause_t *cause = NULL; int action = 0; mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_assert(rsp); @@ -1399,16 +1512,18 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( ogs_assert(action); mme_ue = xact->data; ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); /************************ - * Check SGW-UE Context + * Check MME-UE Context ************************/ cause_value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - if (!sgw_ue) { + if (!mme_ue_from_teid) { ogs_error("No Context in TEID"); cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; } @@ -1454,7 +1569,7 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( ogs_assert(sgw_ue); ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); mme_ue_clear_indirect_tunnel(mme_ue); @@ -1470,7 +1585,7 @@ void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( } void mme_s11_handle_bearer_resource_failure_indication( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue_from_teid, ogs_gtp2_bearer_resource_failure_indication_t *ind) { int rv; @@ -1479,6 +1594,7 @@ void mme_s11_handle_bearer_resource_failure_indication( mme_bearer_t *bearer = NULL; mme_sess_t *sess = NULL; mme_ue_t *mme_ue = NULL; + sgw_ue_t *sgw_ue = NULL; ogs_debug("Bearer Resource Failure Indication"); @@ -1492,11 +1608,13 @@ void mme_s11_handle_bearer_resource_failure_indication( ogs_assert(sess); mme_ue = sess->mme_ue; ogs_assert(mme_ue); + sgw_ue = sgw_ue_cycle(mme_ue->sgw_ue); + ogs_assert(sgw_ue); rv = ogs_gtp_xact_commit(xact); ogs_expect_or_return(rv == OGS_OK); - if (!sgw_ue) + if (!mme_ue_from_teid) ogs_error("No Context in TEID"); /******************** @@ -1516,10 +1634,10 @@ void mme_s11_handle_bearer_resource_failure_indication( * Check ALL Context ********************/ ogs_assert(mme_ue); + ogs_assert(sgw_ue); - if (sgw_ue) - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgw_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + mme_ue->mme_s11_teid, sgw_ue->sgw_s11_teid); ogs_assert(OGS_OK == nas_eps_send_bearer_resource_modification_reject( diff --git a/src/mme/mme-s11-handler.h b/src/mme/mme-s11-handler.h index faa06a57b..63126bcbc 100644 --- a/src/mme/mme-s11-handler.h +++ b/src/mme/mme-s11-handler.h @@ -31,39 +31,39 @@ void mme_s11_handle_echo_request( void mme_s11_handle_echo_response( ogs_gtp_xact_t *xact, ogs_gtp2_echo_response_t *rsp); void mme_s11_handle_create_session_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_create_session_response_t *rsp); void mme_s11_handle_modify_bearer_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_modify_bearer_response_t *rsp); void mme_s11_handle_delete_session_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_delete_session_response_t *rsp); void mme_s11_handle_create_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_create_bearer_request_t *rsp); void mme_s11_handle_update_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_update_bearer_request_t *rsp); void mme_s11_handle_delete_bearer_request( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_delete_bearer_request_t *rsp); void mme_s11_handle_release_access_bearers_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_release_access_bearers_response_t *rsp); void mme_s11_handle_downlink_data_notification( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_downlink_data_notification_t *noti); void mme_s11_handle_create_indirect_data_forwarding_tunnel_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_create_indirect_data_forwarding_tunnel_response_t *rsp); void mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_delete_indirect_data_forwarding_tunnel_response_t *rsp); void mme_s11_handle_bearer_resource_failure_indication( - ogs_gtp_xact_t *xact, sgw_ue_t *sgw_ue, + ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_bearer_resource_failure_indication_t *ind); #ifdef __cplusplus diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index b9c42337c..424252d3f 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -521,6 +521,15 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) break; } + gnode = e->gnode; + ogs_assert(gnode); + + rv = ogs_gtp_xact_receive(gnode, >p_message.h, &xact); + if (rv != OGS_OK) { + ogs_pkbuf_free(pkbuf); + break; + } + /* * 5.5.2 in spec 29.274 * @@ -552,21 +561,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) */ if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { /* Cause is not "Context not found" */ - sgw_ue = sgw_ue_find_by_mme_s11_teid(gtp_message.h.teid); - } - - if (sgw_ue) { - gnode = sgw_ue->gnode; - ogs_assert(gnode); - } else { - gnode = e->gnode; - ogs_assert(gnode); - } - - rv = ogs_gtp_xact_receive(gnode, >p_message.h, &xact); - if (rv != OGS_OK) { - ogs_pkbuf_free(pkbuf); - break; + mme_ue = mme_ue_find_by_teid(gtp_message.h.teid); } switch (gtp_message.h.type) { @@ -578,49 +573,49 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) break; case OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE: mme_s11_handle_create_session_response( - xact, sgw_ue, >p_message.create_session_response); + xact, mme_ue, >p_message.create_session_response); break; case OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE: mme_s11_handle_modify_bearer_response( - xact, sgw_ue, >p_message.modify_bearer_response); + xact, mme_ue, >p_message.modify_bearer_response); break; case OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE: mme_s11_handle_delete_session_response( - xact, sgw_ue, >p_message.delete_session_response); + xact, mme_ue, >p_message.delete_session_response); break; case OGS_GTP2_CREATE_BEARER_REQUEST_TYPE: mme_s11_handle_create_bearer_request( - xact, sgw_ue, >p_message.create_bearer_request); + xact, mme_ue, >p_message.create_bearer_request); break; case OGS_GTP2_UPDATE_BEARER_REQUEST_TYPE: mme_s11_handle_update_bearer_request( - xact, sgw_ue, >p_message.update_bearer_request); + xact, mme_ue, >p_message.update_bearer_request); break; case OGS_GTP2_DELETE_BEARER_REQUEST_TYPE: mme_s11_handle_delete_bearer_request( - xact, sgw_ue, >p_message.delete_bearer_request); + xact, mme_ue, >p_message.delete_bearer_request); break; case OGS_GTP2_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE: mme_s11_handle_release_access_bearers_response( - xact, sgw_ue, >p_message.release_access_bearers_response); + xact, mme_ue, >p_message.release_access_bearers_response); break; case OGS_GTP2_DOWNLINK_DATA_NOTIFICATION_TYPE: mme_s11_handle_downlink_data_notification( - xact, sgw_ue, >p_message.downlink_data_notification); + xact, mme_ue, >p_message.downlink_data_notification); break; case OGS_GTP2_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE: mme_s11_handle_create_indirect_data_forwarding_tunnel_response( - xact, sgw_ue, + xact, mme_ue, >p_message.create_indirect_data_forwarding_tunnel_response); break; case OGS_GTP2_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE_TYPE: mme_s11_handle_delete_indirect_data_forwarding_tunnel_response( - xact, sgw_ue, + xact, mme_ue, >p_message.delete_indirect_data_forwarding_tunnel_response); break; case OGS_GTP2_BEARER_RESOURCE_FAILURE_INDICATION_TYPE: mme_s11_handle_bearer_resource_failure_indication( - xact, sgw_ue, + xact, mme_ue, >p_message.bearer_resource_failure_indication); break; default: @@ -630,6 +625,37 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) ogs_pkbuf_free(pkbuf); break; + case MME_EVT_S11_TIMER: + sgw_ue = e->sgw_ue; + ogs_assert(sgw_ue); + mme_ue = sgw_ue->mme_ue; + ogs_assert(mme_ue); + + switch (e->timer_id) { + case MME_TIMER_S11_HOLDING: + + GTP_COUNTER_CLEAR(mme_ue, + GTP_COUNTER_DELETE_SESSION_BY_PATH_SWITCH); + + ogs_list_for_each(&mme_ue->sess_list, sess) { + + GTP_COUNTER_INCREMENT( + mme_ue, GTP_COUNTER_DELETE_SESSION_BY_PATH_SWITCH); + + ogs_assert(OGS_OK == + mme_gtp_send_delete_session_request( + sgw_ue, sess, + OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST)); + } + break; + + default: + ogs_error("Unknown timer[%s:%d]", + mme_timer_get_name(e->timer_id), e->timer_id); + } + break; + + case MME_EVT_SGSAP_LO_SCTP_COMM_UP: sock = e->sock; ogs_assert(sock); diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index 61c5f37a0..f99b77fa7 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -1556,7 +1556,8 @@ ogs_pkbuf_t *s1ap_build_mme_configuration_transfer( return ogs_s1ap_encode(&pdu); } -ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue) +ogs_pkbuf_t *s1ap_build_path_switch_ack( + mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list) { S1AP_S1AP_PDU_t pdu; S1AP_SuccessfulOutcome_t *successfulOutcome = NULL; @@ -1565,8 +1566,11 @@ ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue) S1AP_PathSwitchRequestAcknowledgeIEs_t *ie = NULL; S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL; S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL; + S1AP_E_RABToBeSwitchedULList_t *E_RABToBeSwitchedULList = NULL; S1AP_SecurityContext_t *SecurityContext = NULL; + mme_sess_t *sess = NULL; + mme_bearer_t *bearer = NULL; enb_ue_t *enb_ue = NULL; ogs_assert(mme_ue); @@ -1608,6 +1612,18 @@ ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue) ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID; + if (e_rab_to_switched_in_uplink_list == true) { + ie = CALLOC(1, sizeof(S1AP_PathSwitchRequestAcknowledgeIEs_t)); + ASN_SEQUENCE_ADD(&PathSwitchRequestAcknowledge->protocolIEs, ie); + + ie->id = S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedULList; + ie->criticality = S1AP_Criticality_ignore; + ie->value.present = + S1AP_PathSwitchRequestAcknowledgeIEs__value_PR_E_RABToBeSwitchedULList; + + E_RABToBeSwitchedULList = &ie->value.choice.E_RABToBeSwitchedULList; + } + ie = CALLOC(1, sizeof(S1AP_PathSwitchRequestAcknowledgeIEs_t)); ASN_SEQUENCE_ADD(&PathSwitchRequestAcknowledge->protocolIEs, ie); @@ -1624,6 +1640,31 @@ ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue) *MME_UE_S1AP_ID = enb_ue->mme_ue_s1ap_id; *ENB_UE_S1AP_ID = enb_ue->enb_ue_s1ap_id; + if (e_rab_to_switched_in_uplink_list == true) { + ogs_list_for_each(&mme_ue->sess_list, sess) { + ogs_list_for_each(&sess->bearer_list, bearer) { + S1AP_E_RABToBeSwitchedULItemIEs_t *item = NULL; + S1AP_E_RABToBeSwitchedULItem_t *e_rab = NULL; + + item = CALLOC(1, sizeof(S1AP_E_RABToBeSwitchedULItemIEs_t)); + ASN_SEQUENCE_ADD(&E_RABToBeSwitchedULList->list, item); + + item->id = S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedULItem; + item->criticality = S1AP_Criticality_ignore; + item->value.present = S1AP_E_RABToBeSwitchedULItemIEs__value_PR_E_RABToBeSwitchedULItem; + + e_rab = &item->value.choice.E_RABToBeSwitchedULItem; + + e_rab->e_RAB_ID = bearer->ebi; + + ogs_assert(OGS_OK == ogs_asn_ip_to_BIT_STRING( + &bearer->sgw_s1u_ip, &e_rab->transportLayerAddress)); + ogs_asn_uint32_to_OCTET_STRING( + bearer->sgw_s1u_teid, &e_rab->gTP_TEID); + } + } + } + SecurityContext->nextHopChainingCount = mme_ue->nhcc; SecurityContext->nextHopParameter.size = OGS_SHA256_DIGEST_SIZE; SecurityContext->nextHopParameter.buf = diff --git a/src/mme/s1ap-build.h b/src/mme/s1ap-build.h index 27d350079..e62a5db8d 100644 --- a/src/mme/s1ap-build.h +++ b/src/mme/s1ap-build.h @@ -56,7 +56,8 @@ ogs_pkbuf_t *s1ap_build_paging( ogs_pkbuf_t *s1ap_build_mme_configuration_transfer( S1AP_SONConfigurationTransfer_t *son_configuration_transfer); -ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue); +ogs_pkbuf_t *s1ap_build_path_switch_ack( + mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list); ogs_pkbuf_t *s1ap_build_path_switch_failure( uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, S1AP_Cause_PR group, long cause); diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index a44c8e7d6..539df1a4d 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -1927,69 +1927,64 @@ void s1ap_handle_path_switch_request( mme_ue->nhcc++; ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->nh, mme_ue->nh); -#if 0 - relocation = sgw_ue_check_if_relocated(mme_ue); -#else - relocation = SGW_WITHOUT_RELOCATION; -#endif - if (relocation == SGW_WITHOUT_RELOCATION) { + ogs_list_init(&mme_ue->bearer_to_modify_list); - ogs_list_init(&mme_ue->bearer_to_modify_list); + for (i = 0; i < E_RABToBeSwitchedDLList->list.count; i++) { + S1AP_E_RABToBeSwitchedDLItemIEs_t *item = NULL; + S1AP_E_RABToBeSwitchedDLItem_t *e_rab = NULL; - for (i = 0; i < E_RABToBeSwitchedDLList->list.count; i++) { - S1AP_E_RABToBeSwitchedDLItemIEs_t *item = NULL; - S1AP_E_RABToBeSwitchedDLItem_t *e_rab = NULL; + mme_bearer_t *bearer = NULL; - mme_bearer_t *bearer = NULL; - - item = (S1AP_E_RABToBeSwitchedDLItemIEs_t *) - E_RABToBeSwitchedDLList->list.array[i]; - if (!item) { - ogs_error("No S1AP_E_RABToBeSwitchedDLItemIEs_t"); - ogs_assert(OGS_OK == - s1ap_send_error_indication2(mme_ue, - S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error)); - return; - } - - e_rab = &item->value.choice.E_RABToBeSwitchedDLItem; - if (!e_rab) { - ogs_error("No E_RABToBeSwitchedDLItem"); - ogs_assert(OGS_OK == - s1ap_send_error_indication2(mme_ue, - S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error)); - return; - } - - bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID); - if (!bearer) { - ogs_error("No Bearer [%d]", (int)e_rab->e_RAB_ID); - ogs_assert(OGS_OK == - s1ap_send_error_indication2(mme_ue, - S1AP_Cause_PR_radioNetwork, - S1AP_CauseRadioNetwork_unknown_E_RAB_ID)); - return; - } - - memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf, - sizeof(bearer->enb_s1u_teid)); - bearer->enb_s1u_teid = be32toh(bearer->enb_s1u_teid); - rv = ogs_asn_BIT_STRING_to_ip( - &e_rab->transportLayerAddress, &bearer->enb_s1u_ip); - if (rv != OGS_OK) { - ogs_error("No transportLayerAddress [%d]", - (int)e_rab->e_RAB_ID); - ogs_assert(OGS_OK == - s1ap_send_error_indication2(mme_ue, - S1AP_Cause_PR_protocol, - S1AP_CauseProtocol_abstract_syntax_error_falsely_constructed_message)); - return; - } - - ogs_list_add( - &mme_ue->bearer_to_modify_list, &bearer->to_modify_node); + item = (S1AP_E_RABToBeSwitchedDLItemIEs_t *) + E_RABToBeSwitchedDLList->list.array[i]; + if (!item) { + ogs_error("No S1AP_E_RABToBeSwitchedDLItemIEs_t"); + ogs_assert(OGS_OK == + s1ap_send_error_indication2(mme_ue, + S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error)); + return; } + e_rab = &item->value.choice.E_RABToBeSwitchedDLItem; + if (!e_rab) { + ogs_error("No E_RABToBeSwitchedDLItem"); + ogs_assert(OGS_OK == + s1ap_send_error_indication2(mme_ue, + S1AP_Cause_PR_protocol, S1AP_CauseProtocol_semantic_error)); + return; + } + + bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID); + if (!bearer) { + ogs_error("No Bearer [%d]", (int)e_rab->e_RAB_ID); + ogs_assert(OGS_OK == + s1ap_send_error_indication2(mme_ue, + S1AP_Cause_PR_radioNetwork, + S1AP_CauseRadioNetwork_unknown_E_RAB_ID)); + return; + } + + memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf, + sizeof(bearer->enb_s1u_teid)); + bearer->enb_s1u_teid = be32toh(bearer->enb_s1u_teid); + rv = ogs_asn_BIT_STRING_to_ip( + &e_rab->transportLayerAddress, &bearer->enb_s1u_ip); + if (rv != OGS_OK) { + ogs_error("No transportLayerAddress [%d]", + (int)e_rab->e_RAB_ID); + ogs_assert(OGS_OK == + s1ap_send_error_indication2(mme_ue, + S1AP_Cause_PR_protocol, + S1AP_CauseProtocol_abstract_syntax_error_falsely_constructed_message)); + return; + } + + ogs_list_add( + &mme_ue->bearer_to_modify_list, &bearer->to_modify_node); + } + + relocation = sgw_ue_check_if_relocated(mme_ue); + if (relocation == SGW_WITHOUT_RELOCATION) { if (ogs_list_count(&mme_ue->bearer_to_modify_list)) { ogs_assert(OGS_OK == mme_gtp_send_modify_bearer_request( mme_ue, 1, OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST)); @@ -1998,6 +1993,9 @@ void s1ap_handle_path_switch_request( mme_sess_t *sess = NULL; ogs_list_for_each(&mme_ue->sess_list, sess) { + GTP_COUNTER_INCREMENT( + mme_ue, GTP_COUNTER_CREATE_SESSION_BY_PATH_SWITCH); + ogs_assert(OGS_OK == mme_gtp_send_create_session_request( sess, OGS_GTP_CREATE_IN_PATH_SWITCH_REQUEST)); diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index fbe2e7495..f43c093d7 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -415,7 +415,8 @@ int s1ap_send_e_rab_modification_confirm(mme_ue_t *mme_ue) return rv; } -int s1ap_send_path_switch_ack(mme_ue_t *mme_ue) +int s1ap_send_path_switch_ack( + mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list) { int rv; ogs_pkbuf_t *s1apbuf = NULL; @@ -423,7 +424,8 @@ int s1ap_send_path_switch_ack(mme_ue_t *mme_ue) ogs_assert(mme_ue); ogs_debug("PathSwitchAcknowledge"); - s1apbuf = s1ap_build_path_switch_ack(mme_ue); + s1apbuf = s1ap_build_path_switch_ack( + mme_ue, e_rab_to_switched_in_uplink_list); ogs_expect_or_return_val(s1apbuf, OGS_ERROR); rv = nas_eps_send_to_enb(mme_ue, s1apbuf); diff --git a/src/mme/s1ap-path.h b/src/mme/s1ap-path.h index 7ec2f5210..c30b7c0a6 100644 --- a/src/mme/s1ap-path.h +++ b/src/mme/s1ap-path.h @@ -66,7 +66,8 @@ int s1ap_send_mme_configuration_transfer( int s1ap_send_e_rab_modification_confirm(mme_ue_t *mme_ue); -int s1ap_send_path_switch_ack(mme_ue_t *mme_ue); +int s1ap_send_path_switch_ack( + mme_ue_t *mme_ue, bool e_rab_to_switched_in_uplink_list); int s1ap_send_handover_command(enb_ue_t *source_ue); int s1ap_send_handover_preparation_failure( diff --git a/src/sgwc/context.h b/src/sgwc/context.h index 524208a87..efa3a6461 100644 --- a/src/sgwc/context.h +++ b/src/sgwc/context.h @@ -155,7 +155,7 @@ sgwc_sess_t *sgwc_sess_find_by_apn(sgwc_ue_t *sgwc_ue, char *apn); sgwc_sess_t *sgwc_sess_find_by_ebi(sgwc_ue_t *sgwc_ue, uint8_t ebi); sgwc_sess_t *sgwc_sess_cycle(sgwc_sess_t *sess); -#define SESSION_SYNC_DONE(__sGWC, __tYPE, __fLAGS) \ +#define SGWC_SESSION_SYNC_DONE(__sGWC, __tYPE, __fLAGS) \ (sgwc_sess_pfcp_xact_count(__sGWC, __tYPE, __fLAGS) == 0) int sgwc_sess_pfcp_xact_count( sgwc_ue_t *sgwc_ue, uint8_t pfcp_type, uint64_t modify_flags); diff --git a/src/sgwc/gtp-path.c b/src/sgwc/gtp-path.c index e25d43a0b..7a66790ec 100644 --- a/src/sgwc/gtp-path.c +++ b/src/sgwc/gtp-path.c @@ -159,6 +159,37 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) } } +int sgwc_gtp_send_create_session_response( + sgwc_sess_t *sess, ogs_gtp_xact_t *xact) +{ + int rv; + + sgwc_ue_t *sgwc_ue = NULL; + + ogs_gtp2_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(sess); + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_gtp2_header_t)); + h.type = OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE; + h.teid = sgwc_ue->mme_s11_teid; + + pkbuf = sgwc_s11_build_create_session_response(h.type, sess); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + int sgwc_gtp_send_downlink_data_notification( uint8_t cause_value, sgwc_bearer_t *bearer) { @@ -169,8 +200,8 @@ int sgwc_gtp_send_downlink_data_notification( ogs_gtp_xact_t *gtp_xact = NULL; - ogs_pkbuf_t *pkbuf = NULL; ogs_gtp2_header_t h; + ogs_pkbuf_t *pkbuf = NULL; ogs_assert(bearer); diff --git a/src/sgwc/gtp-path.h b/src/sgwc/gtp-path.h index 81b4633e0..e4e6b575e 100644 --- a/src/sgwc/gtp-path.h +++ b/src/sgwc/gtp-path.h @@ -29,6 +29,9 @@ extern "C" { int sgwc_gtp_open(void); void sgwc_gtp_close(void); +int sgwc_gtp_send_create_session_response( + sgwc_sess_t *sess, ogs_gtp_xact_t *xact); + int sgwc_gtp_send_downlink_data_notification( uint8_t cause_value, sgwc_bearer_t *bearer); diff --git a/src/sgwc/pfcp-path.c b/src/sgwc/pfcp-path.c index c8290ef15..598c4b932 100644 --- a/src/sgwc/pfcp-path.c +++ b/src/sgwc/pfcp-path.c @@ -202,6 +202,32 @@ static void bearer_timeout(ogs_pfcp_xact_t *xact, void *data) } } +int sgwc_pfcp_send_bearer_to_modify_list( + sgwc_sess_t *sess, ogs_pfcp_xact_t *xact) +{ + int rv; + ogs_pkbuf_t *sxabuf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(sess); + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; + h.seid = sess->sgwu_sxa_seid; + + sxabuf = sgwc_sxa_build_bearer_to_modify_list(h.type, sess, xact); + ogs_expect_or_return_val(sxabuf, OGS_ERROR); + + rv = ogs_pfcp_xact_update_tx(xact, &h, sxabuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + int sgwc_pfcp_send_session_establishment_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf) { @@ -212,10 +238,6 @@ int sgwc_pfcp_send_session_establishment_request( ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; - h.seid = sess->sgwu_sxa_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -225,6 +247,10 @@ int sgwc_pfcp_send_session_establishment_request( ogs_expect_or_return_val(xact->gtpbuf, OGS_ERROR); } + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + h.seid = sess->sgwu_sxa_seid; + sxabuf = sgwc_sxa_build_session_establishment_request(h.type, sess); ogs_expect_or_return_val(sxabuf, OGS_ERROR); @@ -237,55 +263,7 @@ int sgwc_pfcp_send_session_establishment_request( return rv; } -ogs_pfcp_xact_t *sgwc_pfcp_xact_create( - sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, - ogs_pkbuf_t *gtpbuf, uint64_t flags) -{ - ogs_pfcp_xact_t *xact = NULL; - - ogs_assert(sess); - - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_timeout, sess); - ogs_expect_or_return_val(xact, NULL); - - xact->assoc_xact = gtp_xact; - xact->modify_flags = flags | OGS_PFCP_MODIFY_SESSION; - if (gtpbuf) { - xact->gtpbuf = ogs_pkbuf_copy(gtpbuf); - ogs_expect_or_return_val(xact->gtpbuf, NULL); - } - - return xact; -} - -int sgwc_pfcp_xact_commit(ogs_pfcp_xact_t *xact) -{ - int rv; - sgwc_sess_t *sess = NULL; - ogs_pkbuf_t *sxabuf = NULL; - ogs_pfcp_header_t h; - - ogs_assert(xact); - sess = xact->data; - ogs_assert(sess); - - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; - h.seid = sess->sgwu_sxa_seid; - - sxabuf = sgwc_sxa_build_session_modification_request(h.type, sess, xact); - ogs_expect_or_return_val(sxabuf, OGS_ERROR); - - rv = ogs_pfcp_xact_update_tx(xact, &h, sxabuf); - ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); - - rv = ogs_pfcp_xact_commit(xact); - ogs_expect(rv == OGS_OK); - - return rv; -} - -int sgwc_pfcp_send_sess_modification_request( +int sgwc_pfcp_send_session_modification_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags) { @@ -294,13 +272,20 @@ int sgwc_pfcp_send_sess_modification_request( ogs_assert(sess); - xact = sgwc_pfcp_xact_create(sess, gtp_xact, gtpbuf, flags); + xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); + xact->assoc_xact = gtp_xact; + xact->modify_flags = flags | OGS_PFCP_MODIFY_SESSION; + if (gtpbuf) { + xact->gtpbuf = ogs_pkbuf_copy(gtpbuf); + ogs_expect_or_return_val(xact->gtpbuf, OGS_ERROR); + } + ogs_list_for_each(&sess->bearer_list, bearer) ogs_list_add(&xact->bearer_to_modify_list, &bearer->to_modify_node); - return sgwc_pfcp_xact_commit(xact); + return sgwc_pfcp_send_bearer_to_modify_list(sess, xact); } int sgwc_pfcp_send_bearer_modification_request( @@ -333,7 +318,7 @@ int sgwc_pfcp_send_bearer_modification_request( h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; h.seid = sess->sgwu_sxa_seid; - sxabuf = sgwc_sxa_build_session_modification_request(h.type, sess, xact); + sxabuf = sgwc_sxa_build_bearer_to_modify_list(h.type, sess, xact); ogs_expect_or_return_val(sxabuf, OGS_ERROR); rv = ogs_pfcp_xact_update_tx(xact, &h, sxabuf); @@ -355,10 +340,6 @@ int sgwc_pfcp_send_session_deletion_request( ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; - h.seid = sess->sgwu_sxa_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -368,6 +349,10 @@ int sgwc_pfcp_send_session_deletion_request( ogs_expect_or_return_val(xact->gtpbuf, OGS_ERROR); } + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; + h.seid = sess->sgwu_sxa_seid; + sxabuf = sgwc_sxa_build_session_deletion_request(h.type, sess); ogs_expect_or_return_val(sxabuf, OGS_ERROR); diff --git a/src/sgwc/pfcp-path.h b/src/sgwc/pfcp-path.h index daef6b695..82bbbb0c8 100644 --- a/src/sgwc/pfcp-path.h +++ b/src/sgwc/pfcp-path.h @@ -29,31 +29,19 @@ extern "C" { int sgwc_pfcp_open(void); void sgwc_pfcp_close(void); +int sgwc_pfcp_send_bearer_to_modify_list( + sgwc_sess_t *sess, ogs_pfcp_xact_t *xact); + int sgwc_pfcp_send_session_establishment_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf); -/* - * sgwc_pfcp_xact_create()/sgwc_pfcp_xact_commit() can only be used - * with sgwc_pfcp_send_sess_modification_request() - * - * You should not use the following functions - * - sgwc_pfcp_send_session_establishment_request() - * - sgwc_pfcp_send_bearer_modification_request() - * - sgwc_pfcp_send_session_deletion_request() - * - sgwc_pfcp_send_session_report_response() - */ -ogs_pfcp_xact_t *sgwc_pfcp_xact_create( +int sgwc_pfcp_send_session_modification_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags); -int sgwc_pfcp_xact_commit(ogs_pfcp_xact_t *xact); - -int sgwc_pfcp_send_sess_modification_request( - sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, - ogs_pkbuf_t *gtpbuf, uint64_t flags); - int sgwc_pfcp_send_bearer_modification_request( sgwc_bearer_t *bearer, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags); + int sgwc_pfcp_send_session_deletion_request( sgwc_sess_t *sess, ogs_gtp_xact_t *gtp_xact, ogs_pkbuf_t *gtpbuf); diff --git a/src/sgwc/s11-build.c b/src/sgwc/s11-build.c index e267a1f56..f16a79b3d 100644 --- a/src/sgwc/s11-build.c +++ b/src/sgwc/s11-build.c @@ -19,6 +19,118 @@ #include "s11-build.h" +ogs_pkbuf_t *sgwc_s11_build_create_session_response( + uint8_t type, sgwc_sess_t *sess) +{ + int rv, i; + sgwc_bearer_t *bearer = NULL; + sgwc_tunnel_t *ul_tunnel = NULL; + sgwc_ue_t *sgwc_ue = NULL; + + ogs_gtp2_message_t gtp_message; + ogs_gtp2_create_session_response_t *rsp = NULL; + + ogs_gtp2_cause_t cause; + + ogs_gtp2_f_teid_t sgw_s11_teid; + int len; + + ogs_gtp2_cause_t bearer_cause[OGS_BEARER_PER_UE]; + ogs_gtp2_f_teid_t sgw_s1u_teid[OGS_BEARER_PER_UE]; + int sgw_s1u_len[OGS_BEARER_PER_UE]; + ogs_gtp2_f_teid_t pgw_s5u_teid[OGS_BEARER_PER_UE]; + int pgw_s5u_len[OGS_BEARER_PER_UE]; + + ogs_debug("[SGWC] Create Session Response"); + + ogs_assert(sess); + sgwc_ue = sess->sgwc_ue; + ogs_assert(sgwc_ue); + + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->pgw_s5c_teid); + + rsp = >p_message.create_session_response; + memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); + + /* Set Cause */ + memset(&cause, 0, sizeof(cause)); + rsp->cause.presence = 1; + rsp->cause.len = sizeof(cause); + rsp->cause.data = &cause; + + cause.value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + + /* Send Control Plane(UL) : SGW-S11 */ + memset(&sgw_s11_teid, 0, sizeof(ogs_gtp2_f_teid_t)); + sgw_s11_teid.interface_type = OGS_GTP2_F_TEID_S11_S4_SGW_GTP_C; + sgw_s11_teid.teid = htobe32(sgwc_ue->sgw_s11_teid); + rv = ogs_gtp2_sockaddr_to_f_teid( + ogs_gtp_self()->gtpc_addr, ogs_gtp_self()->gtpc_addr6, + &sgw_s11_teid, &len); + ogs_assert(rv == OGS_OK); + rsp->sender_f_teid_for_control_plane.presence = 1; + rsp->sender_f_teid_for_control_plane.data = &sgw_s11_teid; + rsp->sender_f_teid_for_control_plane.len = len; + + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); + + /* Bearer EBI */ + rsp->bearer_contexts_created[i].presence = 1; + rsp->bearer_contexts_created[i].eps_bearer_id.presence = 1; + rsp->bearer_contexts_created[i].eps_bearer_id.u8 = bearer->ebi; + + /* Bearer Cause */ + memset(&bearer_cause[i], 0, sizeof(bearer_cause[i])); + rsp->bearer_contexts_created[i].cause.presence = 1; + rsp->bearer_contexts_created[i].cause.len = sizeof(bearer_cause[i]); + rsp->bearer_contexts_created[i].cause.data = &bearer_cause[i]; + bearer_cause[i].value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + + /* Data Plane(UL) */ + ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer); + ogs_assert(ul_tunnel); + + ogs_debug(" SGW_S1U_TEID[0x%x] PGW_S5U_TEID[0x%x]", + ul_tunnel->local_teid, ul_tunnel->remote_teid); + + /* Data Plane(UL) : SGW-S1U */ + memset(&sgw_s1u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + sgw_s1u_teid[i].interface_type = ul_tunnel->interface_type; + sgw_s1u_teid[i].teid = htobe32(ul_tunnel->local_teid); + ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6); + rv = ogs_gtp2_sockaddr_to_f_teid( + ul_tunnel->local_addr, ul_tunnel->local_addr6, + &sgw_s1u_teid[i], &sgw_s1u_len[i]); + ogs_assert(rv == OGS_OK); + rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.presence = 1; + rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.data = + &sgw_s1u_teid[i]; + rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid.len = + sgw_s1u_len[i]; + + /* Data Plane(UL) : PGW-S5U */ + memset(&pgw_s5u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + pgw_s5u_teid[i].interface_type = OGS_GTP2_F_TEID_S5_S8_PGW_GTP_U; + pgw_s5u_teid[i].teid = htobe32(ul_tunnel->remote_teid); + rv = ogs_gtp2_ip_to_f_teid(&ul_tunnel->remote_ip, + &pgw_s5u_teid[i], &pgw_s5u_len[i]); + ogs_assert(rv == OGS_OK); + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.presence = 1; + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.data = + &pgw_s5u_teid[i]; + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.len = + pgw_s5u_len[i]; + + i++; + } + + gtp_message.h.type = type; + return ogs_gtp2_build_msg(>p_message); +} + ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification( uint8_t cause_value, sgwc_bearer_t *bearer) { diff --git a/src/sgwc/s11-build.h b/src/sgwc/s11-build.h index 54c9c3f9b..ff3dcdc61 100644 --- a/src/sgwc/s11-build.h +++ b/src/sgwc/s11-build.h @@ -26,6 +26,9 @@ extern "C" { #endif +ogs_pkbuf_t *sgwc_s11_build_create_session_response( + uint8_t type, sgwc_sess_t *sess); + ogs_pkbuf_t *sgwc_s11_build_downlink_data_notification( uint8_t cause_value, sgwc_bearer_t *bearer); diff --git a/src/sgwc/s11-handler.c b/src/sgwc/s11-handler.c index bd3ba3b0b..1b580ed29 100644 --- a/src/sgwc/s11-handler.c +++ b/src/sgwc/s11-handler.c @@ -22,7 +22,7 @@ #include "s11-handler.h" -static void sess_timeout(ogs_gtp_xact_t *xact, void *data) +static void gtp_sess_timeout(ogs_gtp_xact_t *xact, void *data) { sgwc_sess_t *sess = data; sgwc_ue_t *sgwc_ue = NULL; @@ -52,7 +52,7 @@ static void sess_timeout(ogs_gtp_xact_t *xact, void *data) } } -static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) +static void gtp_bearer_timeout(ogs_gtp_xact_t *xact, void *data) { sgwc_bearer_t *bearer = data; sgwc_sess_t *sess = NULL; @@ -72,6 +72,29 @@ static void bearer_timeout(ogs_gtp_xact_t *xact, void *data) sgwc_ue->imsi_bcd, type); } +static void pfcp_sess_timeout(ogs_pfcp_xact_t *xact, void *data) +{ + uint8_t type; + + ogs_assert(xact); + type = xact->seq[0].type; + + switch (type) { + case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE: + ogs_error("No PFCP session establishment response"); + break; + case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE: + ogs_error("No PFCP session modification response"); + break; + case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE: + ogs_error("No PFCP session deletion response"); + break; + default: + ogs_error("Not implemented [type:%d]", type); + break; + } +} + /* This code was created in case it will be used later, * and is currently not being used. */ static uint8_t pfcp_cause_from_gtp(uint8_t gtp_cause) @@ -116,6 +139,7 @@ void sgwc_s11_handle_create_session_request( sgwc_ue_t *sgwc_ue, ogs_gtp_xact_t *s11_xact, ogs_pkbuf_t *gtpbuf, ogs_gtp2_message_t *message) { + int i; uint8_t cause_value = 0; sgwc_sess_t *sess = NULL; @@ -164,15 +188,15 @@ void sgwc_s11_handle_create_session_request( ogs_error("No IMSI"); cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; } - if (req->bearer_contexts_to_be_created.presence == 0) { + if (req->bearer_contexts_to_be_created[0].presence == 0) { ogs_error("No Bearer"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) { + if (req->bearer_contexts_to_be_created[0].eps_bearer_id.presence == 0) { ogs_error("No EPS Bearer ID"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) { + if (req->bearer_contexts_to_be_created[0].bearer_level_qos.presence == 0) { ogs_error("No Bearer QoS"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } @@ -201,7 +225,7 @@ void sgwc_s11_handle_create_session_request( req->access_point_name.data, ogs_min(req->access_point_name.len, OGS_MAX_APN_LEN))); sess = sgwc_sess_find_by_ebi(sgwc_ue, - req->bearer_contexts_to_be_created.eps_bearer_id.u8); + req->bearer_contexts_to_be_created[0].eps_bearer_id.u8); if (sess) { ogs_info("OLD Session Release [IMSI:%s,APN:%s]", sgwc_ue->imsi_bcd, sess->session.name); @@ -243,27 +267,100 @@ void sgwc_s11_handle_create_session_request( return; } - /* Set Bearer QoS */ - decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, - &req->bearer_contexts_to_be_created.bearer_level_qos); - ogs_assert(req->bearer_contexts_to_be_created.bearer_level_qos.len == - decoded); - sess->session.qos.index = bearer_qos.qci; - sess->session.qos.arp.priority_level = bearer_qos.priority_level; - sess->session.qos.arp.pre_emption_capability = - bearer_qos.pre_emption_capability; - sess->session.qos.arp.pre_emption_vulnerability = - bearer_qos.pre_emption_vulnerability; - /* Remove all previous bearer */ sgwc_bearer_remove_all(sess); - /* Setup Default Bearer */ - bearer = sgwc_bearer_add(sess); - ogs_assert(bearer); + /* Setup Bearer */ + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (req->bearer_contexts_to_be_created[i].presence == 0) + break; + if (req->bearer_contexts_to_be_created[i].eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + if (req->bearer_contexts_to_be_created[i]. + bearer_level_qos.presence == 0) { + ogs_error("No Bearer QoS"); + break; + } - /* Set Bearer EBI */ - bearer->ebi = req->bearer_contexts_to_be_created.eps_bearer_id.u8; + decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, + &req->bearer_contexts_to_be_created[i].bearer_level_qos); + ogs_assert(decoded == + req->bearer_contexts_to_be_created[i].bearer_level_qos.len); + + bearer = sgwc_bearer_add(sess); + ogs_assert(bearer); + + /* Set Bearer EBI */ + bearer->ebi = req->bearer_contexts_to_be_created[i].eps_bearer_id.u8; + + if (req->bearer_contexts_to_be_created[i].s1_u_enodeb_f_teid.presence) { + + sgwc_tunnel_t *dl_tunnel = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_gtp2_f_teid_t *enb_s1u_teid = NULL; + + dl_tunnel = sgwc_dl_tunnel_in_bearer(bearer); + ogs_assert(dl_tunnel); + + /* Data Plane(DL) : eNB-S1U */ + enb_s1u_teid = req->bearer_contexts_to_be_created[i]. + s1_u_enodeb_f_teid.data; + dl_tunnel->remote_teid = be32toh(enb_s1u_teid->teid); + + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(enb_s1u_teid, &dl_tunnel->remote_ip)); + + far = dl_tunnel->far; + ogs_assert(far); + + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + + ogs_assert(OGS_OK == ogs_pfcp_ip_to_outer_header_creation( + &dl_tunnel->remote_ip, &far->outer_header_creation, + &far->outer_header_creation_len)); + far->outer_header_creation.teid = dl_tunnel->remote_teid; + } + + if (req->bearer_contexts_to_be_created[i].s5_s8_u_sgw_f_teid.presence) { + + sgwc_tunnel_t *ul_tunnel = NULL; + ogs_pfcp_far_t *far = NULL; + ogs_gtp2_f_teid_t *pgw_s5u_teid = NULL; + + ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer); + ogs_assert(ul_tunnel); + + /* Data Plane(UL) : PGW-S5U */ + pgw_s5u_teid = req->bearer_contexts_to_be_created[i]. + s5_s8_u_sgw_f_teid.data; + ul_tunnel->remote_teid = be32toh(pgw_s5u_teid->teid); + + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(pgw_s5u_teid, &ul_tunnel->remote_ip)); + + far = ul_tunnel->far; + ogs_assert(far); + + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + + ogs_assert(OGS_OK == ogs_pfcp_ip_to_outer_header_creation( + &ul_tunnel->remote_ip, &far->outer_header_creation, + &far->outer_header_creation_len)); + far->outer_header_creation.teid = ul_tunnel->remote_teid; + } + + /* Set Session QoS from Default Bearer Level QoS */ + if (i == 0) { + sess->session.qos.index = bearer_qos.qci; + sess->session.qos.arp.priority_level = bearer_qos.priority_level; + sess->session.qos.arp.pre_emption_capability = + bearer_qos.pre_emption_capability; + sess->session.qos.arp.pre_emption_vulnerability = + bearer_qos.pre_emption_vulnerability; + } + } /* Receive Control Plane(DL) : MME-S11 */ mme_s11_teid = req->sender_f_teid_for_control_plane.data; @@ -334,7 +431,7 @@ void sgwc_s11_handle_modify_bearer_request( *****************************************/ ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); - for (i = 0; i < 8 /* Max number of Bearer Contexts in Message */ ; i++) { + for (i = 0; i < OGS_BEARER_PER_UE; i++) { ogs_pfcp_xact_t *current_xact = NULL; if (req->bearer_contexts_to_be_modified[i].presence == 0) { @@ -372,10 +469,18 @@ void sgwc_s11_handle_modify_bearer_request( } if (!current_xact) { - current_xact = sgwc_pfcp_xact_create(sess, s11_xact, gtpbuf, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE); + current_xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, pfcp_sess_timeout, sess); ogs_assert(current_xact); + current_xact->assoc_xact = s11_xact; + current_xact->modify_flags = OGS_PFCP_MODIFY_SESSION| + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE; + if (gtpbuf) { + current_xact->gtpbuf = ogs_pkbuf_copy(gtpbuf); + ogs_assert(current_xact->gtpbuf); + } + ogs_list_add(&pfcp_xact_list, ¤t_xact->tmpnode); } @@ -453,7 +558,7 @@ void sgwc_s11_handle_modify_bearer_request( dl_tunnel->remote_teid, dl_tunnel->local_teid); ogs_list_for_each_entry(&pfcp_xact_list, pfcp_xact, tmpnode) - sgwc_pfcp_xact_commit(pfcp_xact); + sgwc_pfcp_send_bearer_to_modify_list(pfcp_xact->data, pfcp_xact); } void sgwc_s11_handle_delete_session_request( @@ -465,6 +570,7 @@ void sgwc_s11_handle_delete_session_request( sgwc_sess_t *sess = NULL; ogs_gtp_xact_t *s5c_xact = NULL; ogs_gtp2_delete_session_request_t *req = NULL; + ogs_gtp2_indication_t *indication = NULL; ogs_assert(s11_xact); ogs_assert(gtpbuf); @@ -505,6 +611,27 @@ void sgwc_s11_handle_delete_session_request( return; } + /***************************************** + * Check Mandatory/Conditional IE Missing + *****************************************/ + ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); + + if (req->indication_flags.presence && + req->indication_flags.data && req->indication_flags.len) { + indication = req->indication_flags.data; + } + + if (indication && + indication->operation_indication == 1 && + indication->scope_indication == 1) { + ogs_error("Invalid Indication"); + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE, + OGS_GTP2_CAUSE_INVALID_MESSAGE_FORMAT); + return; + } + /******************** * Check ALL Context ********************/ @@ -516,20 +643,29 @@ void sgwc_s11_handle_delete_session_request( ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); - message->h.type = OGS_GTP2_DELETE_SESSION_REQUEST_TYPE; - message->h.teid = sess->pgw_s5c_teid; + if (indication && + indication->operation_indication == 0 && + indication->scope_indication == 1) { - gtpbuf = ogs_gtp2_build_msg(message); - ogs_expect_or_return(gtpbuf); + ogs_assert(OGS_OK == + sgwc_pfcp_send_session_deletion_request(sess, s11_xact, gtpbuf)); - s5c_xact = ogs_gtp_xact_local_create( - sess->gnode, &message->h, gtpbuf, sess_timeout, sess); - ogs_expect_or_return(s5c_xact); + } else { + message->h.type = OGS_GTP2_DELETE_SESSION_REQUEST_TYPE; + message->h.teid = sess->pgw_s5c_teid; - ogs_gtp_xact_associate(s11_xact, s5c_xact); + gtpbuf = ogs_gtp2_build_msg(message); + ogs_expect_or_return(gtpbuf); - rv = ogs_gtp_xact_commit(s5c_xact); - ogs_expect(rv == OGS_OK); + s5c_xact = ogs_gtp_xact_local_create( + sess->gnode, &message->h, gtpbuf, gtp_sess_timeout, sess); + ogs_expect_or_return(s5c_xact); + + ogs_gtp_xact_associate(s11_xact, s5c_xact); + + rv = ogs_gtp_xact_commit(s5c_xact); + ogs_expect(rv == OGS_OK); + } } void sgwc_s11_handle_create_bearer_response( @@ -1032,7 +1168,7 @@ void sgwc_s11_handle_release_access_bearers_request( ogs_list_for_each(&sgwc_ue->sess_list, sess) { ogs_assert(OGS_OK == - sgwc_pfcp_send_sess_modification_request( + sgwc_pfcp_send_session_modification_request( sess, s11_xact, gtpbuf, OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE)); } @@ -1224,7 +1360,7 @@ void sgwc_s11_handle_create_indirect_data_forwarding_tunnel_request( ogs_list_for_each(&sgwc_ue->sess_list, sess) { ogs_assert(OGS_OK == - sgwc_pfcp_send_sess_modification_request( + sgwc_pfcp_send_session_modification_request( sess, s11_xact, gtpbuf, OGS_PFCP_MODIFY_INDIRECT|OGS_PFCP_MODIFY_CREATE)); } @@ -1270,7 +1406,7 @@ void sgwc_s11_handle_delete_indirect_data_forwarding_tunnel_request( ogs_list_for_each(&sgwc_ue->sess_list, sess) { ogs_assert(OGS_OK == - sgwc_pfcp_send_sess_modification_request( + sgwc_pfcp_send_session_modification_request( sess, s11_xact, gtpbuf, OGS_PFCP_MODIFY_INDIRECT| OGS_PFCP_MODIFY_REMOVE)); } @@ -1375,7 +1511,7 @@ void sgwc_s11_handle_bearer_resource_command( ogs_expect_or_return(pkbuf); s5c_xact = ogs_gtp_xact_local_create( - sess->gnode, &message->h, pkbuf, bearer_timeout, bearer); + sess->gnode, &message->h, pkbuf, gtp_bearer_timeout, bearer); ogs_expect_or_return(s5c_xact); ogs_gtp_xact_associate(s11_xact, s5c_xact); diff --git a/src/sgwc/s5c-handler.c b/src/sgwc/s5c-handler.c index 9e7e12131..f0ec8c877 100644 --- a/src/sgwc/s5c-handler.c +++ b/src/sgwc/s5c-handler.c @@ -63,7 +63,7 @@ void sgwc_s5c_handle_create_session_response( sgwc_sess_t *sess, ogs_gtp_xact_t *s5c_xact, ogs_pkbuf_t *gtpbuf, ogs_gtp2_message_t *message) { - int rv; + int rv, i; uint8_t cause_value; ogs_gtp2_cause_t *cause = NULL; @@ -106,25 +106,6 @@ void sgwc_s5c_handle_create_session_response( } else { sgwc_ue = sess->sgwc_ue; ogs_assert(sgwc_ue); - - if (rsp->bearer_contexts_created.presence == 0) { - ogs_error("No Bearer"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } - if (rsp->bearer_contexts_created.eps_bearer_id.presence == 0) { - ogs_error("No EPS Bearer ID"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } - - if (cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - bearer = sgwc_bearer_find_by_sess_ebi(sess, - rsp->bearer_contexts_created.eps_bearer_id.u8); - if (!bearer) { - ogs_error("No Context for EPS Bearer ID[%d]", - rsp->bearer_contexts_created.eps_bearer_id.u8); - cause_value = OGS_GTP2_CAUSE_CONTEXT_NOT_FOUND; - } - } } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { @@ -143,10 +124,6 @@ void sgwc_s5c_handle_create_session_response( ogs_error("No GTP TEID"); cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; } - if (rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence == 0) { - ogs_error("No GTP TEID"); - cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; - } if (rsp->pdn_address_allocation.presence) { ogs_paa_t paa; @@ -165,11 +142,7 @@ void sgwc_s5c_handle_create_session_response( if (rsp->cause.presence == 0) { ogs_error("No Cause"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; - } - if (rsp->bearer_contexts_created.cause.presence == 0) { - ogs_error("No Bearer Cause"); - cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; + cause_value = OGS_GTP2_CAUSE_CONDITIONAL_IE_MISSING; } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { @@ -184,15 +157,21 @@ void sgwc_s5c_handle_create_session_response( ********************/ ogs_assert(cause_value == OGS_GTP2_CAUSE_REQUEST_ACCEPTED); - cause = rsp->bearer_contexts_created.cause.data; - ogs_assert(cause); - cause_value = cause->value; - if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); - return; + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (rsp->bearer_contexts_created[i].cause.presence == 0) { + break; + } + + cause = rsp->bearer_contexts_created[i].cause.data; + ogs_assert(cause); + cause_value = cause->value; + if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { + ogs_error("GTP Failed [Bearer-CAUSE:%d]", cause_value); + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + return; + } } cause = rsp->cause.data; @@ -216,49 +195,75 @@ void sgwc_s5c_handle_create_session_response( ********************/ ogs_assert(sgwc_ue); ogs_assert(sess); - ogs_assert(bearer); - ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer); - ogs_assert(ul_tunnel); - /* Receive Data Plane(UL) : PGW-S5U */ - pgw_s5u_teid = rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data; - ogs_assert(pgw_s5u_teid); - ul_tunnel->remote_teid = be32toh(pgw_s5u_teid->teid); + ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", + sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->pgw_s5c_teid); - rv = ogs_gtp2_f_teid_to_ip(pgw_s5u_teid, &ul_tunnel->remote_ip); - if (rv != OGS_OK) { - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, - OGS_GTP2_CAUSE_MANDATORY_IE_MISSING); - return; + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (rsp->bearer_contexts_created[i].presence == 0) { + break; + } + if (rsp->bearer_contexts_created[i].eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + if (rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.presence == 0) { + ogs_error("No GTP TEID"); + break; + } + + /* EPS Bearer ID */ + bearer = sgwc_bearer_find_by_sess_ebi(sess, + rsp->bearer_contexts_created[i].eps_bearer_id.u8); + if (!bearer) { + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP2_CAUSE_MANDATORY_IE_MISSING); + return; + } + + ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer); + ogs_assert(ul_tunnel); + + ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", + ul_tunnel->local_teid, ul_tunnel->remote_teid); + + /* Receive Data Plane(UL) : PGW-S5U */ + pgw_s5u_teid = rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.data; + ogs_assert(pgw_s5u_teid); + ul_tunnel->remote_teid = be32toh(pgw_s5u_teid->teid); + + rv = ogs_gtp2_f_teid_to_ip(pgw_s5u_teid, &ul_tunnel->remote_ip); + if (rv != OGS_OK) { + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP2_CAUSE_MANDATORY_IE_MISSING); + return; + } + + far = ul_tunnel->far; + ogs_assert(far); + + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + + ogs_assert(OGS_OK == + ogs_pfcp_ip_to_outer_header_creation(&ul_tunnel->remote_ip, + &far->outer_header_creation, &far->outer_header_creation_len)); + far->outer_header_creation.teid = ul_tunnel->remote_teid; } - far = ul_tunnel->far; - ogs_assert(far); - - far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; - - ogs_assert(OGS_OK == - ogs_pfcp_ip_to_outer_header_creation(&ul_tunnel->remote_ip, - &far->outer_header_creation, &far->outer_header_creation_len)); - far->outer_header_creation.teid = ul_tunnel->remote_teid; - /* Receive Control Plane(UL) : PGW-S5C */ pgw_s5c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.data; ogs_assert(pgw_s5c_teid); sess->pgw_s5c_teid = be32toh(pgw_s5c_teid->teid); - ogs_debug(" MME_S11_TEID[%d] SGW_S11_TEID[%d]", - sgwc_ue->mme_s11_teid, sgwc_ue->sgw_s11_teid); - ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", - sess->sgw_s5c_teid, sess->pgw_s5c_teid); - ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", - ul_tunnel->local_teid, ul_tunnel->remote_teid); - ogs_assert(OGS_OK == - sgwc_pfcp_send_bearer_modification_request( - bearer, s11_xact, gtpbuf, + sgwc_pfcp_send_session_modification_request( + sess, s11_xact, gtpbuf, OGS_PFCP_MODIFY_UL_ONLY|OGS_PFCP_MODIFY_ACTIVATE)); } @@ -371,6 +376,7 @@ void sgwc_s5c_handle_modify_bearer_response( int rv; ogs_gtp2_cause_t *cause = NULL; uint8_t cause_value; + int modify_action; sgwc_ue_t *sgwc_ue = NULL; ogs_pkbuf_t *pkbuf = NULL; @@ -390,6 +396,7 @@ void sgwc_s5c_handle_modify_bearer_response( ogs_assert(s5c_xact); s11_xact = s5c_xact->assoc_xact; ogs_assert(s11_xact); + modify_action = s5c_xact->modify_action; rv = ogs_gtp_xact_commit(s5c_xact); ogs_expect(rv == OGS_OK); @@ -408,9 +415,14 @@ void sgwc_s5c_handle_modify_bearer_response( } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + else + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); return; } @@ -425,9 +437,14 @@ void sgwc_s5c_handle_modify_bearer_response( } if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + else + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); return; } @@ -441,9 +458,14 @@ void sgwc_s5c_handle_modify_bearer_response( cause_value = cause->value; if (cause_value != OGS_GTP2_CAUSE_REQUEST_ACCEPTED) { ogs_error("GTP Failed [CAUSE:%d]", cause_value); - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); + if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, cause_value); + else + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE, cause_value); return; } @@ -458,17 +480,22 @@ void sgwc_s5c_handle_modify_bearer_response( ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", sess->sgw_s5c_teid, sess->pgw_s5c_teid); - message->h.type = OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE; - message->h.teid = sgwc_ue->mme_s11_teid; + if (modify_action == OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST) { + ogs_assert(OGS_OK == + sgwc_gtp_send_create_session_response(sess, s11_xact)); + } else { + message->h.type = OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE; + message->h.teid = sgwc_ue->mme_s11_teid; - pkbuf = ogs_gtp2_build_msg(message); - ogs_expect_or_return(pkbuf); + pkbuf = ogs_gtp2_build_msg(message); + ogs_expect_or_return(pkbuf); - rv = ogs_gtp_xact_update_tx(s11_xact, &message->h, pkbuf); - ogs_expect_or_return(rv == OGS_OK); + rv = ogs_gtp_xact_update_tx(s11_xact, &message->h, pkbuf); + ogs_expect_or_return(rv == OGS_OK); - rv = ogs_gtp_xact_commit(s11_xact); - ogs_expect(rv == OGS_OK); + rv = ogs_gtp_xact_commit(s11_xact); + ogs_expect(rv == OGS_OK); + } } void sgwc_s5c_handle_create_bearer_request( diff --git a/src/sgwc/sgwc-sm.c b/src/sgwc/sgwc-sm.c index 8fd2de8f6..2dc8ab197 100644 --- a/src/sgwc/sgwc-sm.c +++ b/src/sgwc/sgwc-sm.c @@ -145,18 +145,8 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e) break; } - if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { - /* Cause is not "Context not found" */ - sgwc_ue = sgwc_ue_find_by_teid(gtp_message.h.teid); - } - - if (sgwc_ue) { - gnode = sgwc_ue->gnode; - ogs_assert(gnode); - } else { - gnode = e->gnode; - ogs_assert(gnode); - } + gnode = e->gnode; + ogs_assert(gnode); rv = ogs_gtp_xact_receive(gnode, >p_message.h, >p_xact); if (rv != OGS_OK) { @@ -164,6 +154,11 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e) break; } + if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { + /* Cause is not "Context not found" */ + sgwc_ue = sgwc_ue_find_by_teid(gtp_message.h.teid); + } + switch(gtp_message.h.type) { case OGS_GTP2_ECHO_REQUEST_TYPE: sgwc_handle_echo_request(gtp_xact, >p_message.echo_request); @@ -239,17 +234,8 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e) break; } - if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { - sess = sgwc_sess_find_by_teid(gtp_message.h.teid); - } - - if (sess) { - gnode = sess->gnode; - ogs_assert(gnode); - } else { - gnode = e->gnode; - ogs_assert(gnode); - } + gnode = e->gnode; + ogs_assert(gnode); rv = ogs_gtp_xact_receive(gnode, >p_message.h, >p_xact); if (rv != OGS_OK) { @@ -257,6 +243,10 @@ void sgwc_state_operational(ogs_fsm_t *s, sgwc_event_t *e) break; } + if (gtp_message.h.teid_presence && gtp_message.h.teid != 0) { + sess = sgwc_sess_find_by_teid(gtp_message.h.teid); + } + switch(gtp_message.h.type) { case OGS_GTP2_ECHO_REQUEST_TYPE: sgwc_handle_echo_request(gtp_xact, >p_message.echo_request); diff --git a/src/sgwc/sxa-build.c b/src/sgwc/sxa-build.c index 2dae7a3d2..503f51511 100644 --- a/src/sgwc/sxa-build.c +++ b/src/sgwc/sxa-build.c @@ -105,7 +105,7 @@ ogs_pkbuf_t *sgwc_sxa_build_session_establishment_request( return pkbuf; } -ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( +ogs_pkbuf_t *sgwc_sxa_build_bearer_to_modify_list( uint8_t type, sgwc_sess_t *sess, ogs_pfcp_xact_t *xact) { ogs_pfcp_message_t pfcp_message; @@ -135,12 +135,6 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( req = &pfcp_message.pfcp_session_modification_request; memset(&pfcp_message, 0, sizeof(ogs_pfcp_message_t)); - num_of_remove_pdr = 0; - num_of_remove_far = 0; - num_of_create_pdr = 0; - num_of_create_far = 0; - num_of_update_far = 0; - if (modify_flags & OGS_PFCP_MODIFY_CREATE) { ogs_pfcp_pdrbuf_init(); } @@ -166,6 +160,7 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( OGS_GTP2_F_TEID_SGW_GTP_U_FOR_UL_DATA_FORWARDING))))) { if (modify_flags & OGS_PFCP_MODIFY_REMOVE) { + pdr = tunnel->pdr; if (pdr) { ogs_pfcp_tlv_remove_pdr_t *message = @@ -193,6 +188,7 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( ogs_assert_if_reached(); } else if (modify_flags & OGS_PFCP_MODIFY_CREATE) { + pdr = tunnel->pdr; if (pdr) { ogs_pfcp_build_create_pdr( @@ -214,7 +210,10 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( num_of_create_far++; } else ogs_assert_if_reached(); - } else if (modify_flags & OGS_PFCP_MODIFY_DEACTIVATE) { + } + + if (modify_flags & OGS_PFCP_MODIFY_DEACTIVATE) { + far = tunnel->far; if (far) { ogs_pfcp_build_update_far_deactivate( @@ -224,7 +223,9 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( num_of_update_far++; } else ogs_assert_if_reached(); + } else if (modify_flags & OGS_PFCP_MODIFY_ACTIVATE) { + far = tunnel->far; if (far) { if (modify_flags & OGS_PFCP_MODIFY_END_MARKER) { @@ -241,6 +242,7 @@ ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( tunnel->far->smreq_flags.value = 0; } else ogs_assert_if_reached(); + } } } diff --git a/src/sgwc/sxa-build.h b/src/sgwc/sxa-build.h index e51ba089e..fad9391ae 100644 --- a/src/sgwc/sxa-build.h +++ b/src/sgwc/sxa-build.h @@ -28,7 +28,7 @@ extern "C" { ogs_pkbuf_t *sgwc_sxa_build_session_establishment_request( uint8_t type, sgwc_sess_t *sess); -ogs_pkbuf_t *sgwc_sxa_build_session_modification_request( +ogs_pkbuf_t *sgwc_sxa_build_bearer_to_modify_list( uint8_t type, sgwc_sess_t *sess, ogs_pfcp_xact_t *xact); ogs_pkbuf_t *sgwc_sxa_build_session_deletion_request( uint8_t type, sgwc_sess_t *sess); diff --git a/src/sgwc/sxa-handler.c b/src/sgwc/sxa-handler.c index d7477f71d..36154bd4c 100644 --- a/src/sgwc/sxa-handler.c +++ b/src/sgwc/sxa-handler.c @@ -134,10 +134,15 @@ void sgwc_sxa_handle_session_establishment_response( ogs_pfcp_f_seid_t *up_f_seid = NULL; - int sgw_s5c_len, sgw_s5u_len; - ogs_gtp2_f_teid_t sgw_s5c_teid, sgw_s5u_teid; + int sgw_s5c_len; + ogs_gtp2_f_teid_t sgw_s5c_teid; ogs_gtp2_f_teid_t *pgw_s5c_teid = NULL; + int i, num_of_sgw_s5u; + uint8_t ebi[OGS_BEARER_PER_UE]; + int sgw_s5u_len[OGS_BEARER_PER_UE]; + ogs_gtp2_f_teid_t sgw_s5u_teid[OGS_BEARER_PER_UE]; + ogs_gtp_xact_t *s11_xact = NULL, *s5c_xact = NULL; ogs_gtp_node_t *pgw = NULL; @@ -248,24 +253,44 @@ void sgwc_sxa_handle_session_establishment_response( ogs_assert(sess); - bearer = sgwc_default_bearer_in_sess(sess); - ogs_assert(bearer); - dl_tunnel = sgwc_dl_tunnel_in_bearer(bearer); - ogs_assert(dl_tunnel); + ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", + sess->sgw_s5c_teid, sess->pgw_s5c_teid); - if (dl_tunnel->local_addr == NULL && dl_tunnel->local_addr6 == NULL) { - ogs_error("No UP F-TEID"); - ogs_gtp_send_error_message( - s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, - OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, - OGS_GTP2_CAUSE_GRE_KEY_NOT_FOUND); - return; + /* Data Plane(DL) : SGW-S5U */ + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); + + dl_tunnel = sgwc_dl_tunnel_in_bearer(bearer); + ogs_assert(dl_tunnel); + + ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", + dl_tunnel->local_teid, dl_tunnel->remote_teid); + + if (dl_tunnel->local_addr == NULL && dl_tunnel->local_addr6 == NULL) { + ogs_error("No UP F-TEID"); + ogs_gtp_send_error_message( + s11_xact, sgwc_ue ? sgwc_ue->mme_s11_teid : 0, + OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE, + OGS_GTP2_CAUSE_GRE_KEY_NOT_FOUND); + return; + } + + ebi[i] = bearer->ebi; + + memset(&sgw_s5u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + sgw_s5u_teid[i].teid = htobe32(dl_tunnel->local_teid); + sgw_s5u_teid[i].interface_type = dl_tunnel->interface_type; + ogs_assert(dl_tunnel->local_addr || dl_tunnel->local_addr6); + rv = ogs_gtp2_sockaddr_to_f_teid( + dl_tunnel->local_addr, dl_tunnel->local_addr6, + &sgw_s5u_teid[i], &sgw_s5u_len[i]); + ogs_assert(rv == OGS_OK); + + i++; } - /* UP F-SEID */ - up_f_seid = pfcp_rsp->up_f_seid.data; - ogs_assert(up_f_seid); - sess->sgwu_sxa_seid = be64toh(up_f_seid->seid); + num_of_sgw_s5u = i; /* Send Control Plane(DL) : SGW-S5C */ memset(&sgw_s5c_teid, 0, sizeof(ogs_gtp2_f_teid_t)); @@ -276,10 +301,10 @@ void sgwc_sxa_handle_session_establishment_response( &sgw_s5c_teid, &sgw_s5c_len); ogs_assert(rv == OGS_OK); - ogs_debug(" SGW_S5C_TEID[0x%x] PGW_S5C_TEID[0x%x]", - sess->sgw_s5c_teid, sess->pgw_s5c_teid); - ogs_debug(" SGW_S5U_TEID[%d] PGW_S5U_TEID[%d]", - dl_tunnel->local_teid, dl_tunnel->remote_teid); + /* UP F-SEID */ + up_f_seid = pfcp_rsp->up_f_seid.data; + ogs_assert(up_f_seid); + sess->sgwu_sxa_seid = be64toh(up_f_seid->seid); pgw_s5c_teid = create_session_request-> pgw_s5_s8_address_for_control_plane_or_pmip.data; @@ -299,16 +324,6 @@ void sgwc_sxa_handle_session_establishment_response( /* Setup GTP Node */ OGS_SETUP_GTP_NODE(sess, pgw); - /* Data Plane(DL) : SGW-S5U */ - memset(&sgw_s5u_teid, 0, sizeof(ogs_gtp2_f_teid_t)); - sgw_s5u_teid.teid = htobe32(dl_tunnel->local_teid); - sgw_s5u_teid.interface_type = dl_tunnel->interface_type; - ogs_assert(dl_tunnel->local_addr || dl_tunnel->local_addr6); - rv = ogs_gtp2_sockaddr_to_f_teid( - dl_tunnel->local_addr, dl_tunnel->local_addr6, - &sgw_s5u_teid, &sgw_s5u_len); - ogs_assert(rv == OGS_OK); - /* Check Indication */ if (create_session_request->indication_flags.presence && create_session_request->indication_flags.data && @@ -340,20 +355,24 @@ void sgwc_sxa_handle_session_establishment_response( modify_bearer_request->sender_f_teid_for_control_plane. len = sgw_s5c_len; - /* Bearer Context : EBI */ - modify_bearer_request->bearer_contexts_to_be_modified[0].presence = 1; - modify_bearer_request->bearer_contexts_to_be_modified[0]. - eps_bearer_id.presence = 1; - modify_bearer_request->bearer_contexts_to_be_modified[0]. - eps_bearer_id.u8 = bearer->ebi; + for (i = 0; i < num_of_sgw_s5u; i++) { + modify_bearer_request->bearer_contexts_to_be_modified[i]. + presence = 1; + modify_bearer_request->bearer_contexts_to_be_modified[i]. + eps_bearer_id.presence = 1; - /* Data Plane(DL) : SGW-S5U */ - modify_bearer_request->bearer_contexts_to_be_modified[0]. - s4_u_sgsn_f_teid.presence = 1; - modify_bearer_request->bearer_contexts_to_be_modified[0]. - s4_u_sgsn_f_teid.data = &sgw_s5u_teid; - modify_bearer_request->bearer_contexts_to_be_modified[0]. - s4_u_sgsn_f_teid.len = sgw_s5u_len; + /* Bearer Context : EBI */ + modify_bearer_request->bearer_contexts_to_be_modified[i]. + eps_bearer_id.u8 = ebi[i]; + + /* Data Plane(DL) : SGW-S5U */ + modify_bearer_request->bearer_contexts_to_be_modified[i]. + s4_u_sgsn_f_teid.presence = 1; + modify_bearer_request->bearer_contexts_to_be_modified[i]. + s4_u_sgsn_f_teid.data = &sgw_s5u_teid[i]; + modify_bearer_request->bearer_contexts_to_be_modified[i]. + s4_u_sgsn_f_teid.len = sgw_s5u_len[i]; + } pkbuf = ogs_gtp2_build_msg(&send_message); ogs_expect_or_return(pkbuf); @@ -362,7 +381,11 @@ void sgwc_sxa_handle_session_establishment_response( s5c_xact = ogs_gtp_xact_local_create( sess->gnode, &send_message.h, pkbuf, sess_timeout, sess); ogs_expect_or_return(s5c_xact); + + s5c_xact->modify_action = OGS_GTP_MODIFY_IN_PATH_SWITCH_REQUEST; + } else { + /* Create Session Request */ recv_message->h.type = OGS_GTP2_CREATE_SESSION_REQUEST_TYPE; recv_message->h.teid = sess->pgw_s5c_teid; @@ -379,12 +402,14 @@ void sgwc_sxa_handle_session_establishment_response( presence = 0; /* Bearer Contexts */ - create_session_request->bearer_contexts_to_be_created. - s5_s8_u_sgw_f_teid.presence = 1; - create_session_request->bearer_contexts_to_be_created. - s5_s8_u_sgw_f_teid.data = &sgw_s5u_teid; - create_session_request->bearer_contexts_to_be_created. - s5_s8_u_sgw_f_teid.len = sgw_s5u_len; + for (i = 0; i < num_of_sgw_s5u; i++) { + create_session_request->bearer_contexts_to_be_created[i]. + s5_s8_u_sgw_f_teid.presence = 1; + create_session_request->bearer_contexts_to_be_created[i]. + s5_s8_u_sgw_f_teid.data = &sgw_s5u_teid[i]; + create_session_request->bearer_contexts_to_be_created[i]. + s5_s8_u_sgw_f_teid.len = sgw_s5u_len[i]; + } pkbuf = ogs_gtp2_build_msg(recv_message); ogs_expect_or_return(pkbuf); @@ -617,7 +642,7 @@ void sgwc_sxa_handle_session_modification_response( ogs_pfcp_xact_commit(pfcp_xact); ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); - if (SESSION_SYNC_DONE(sgwc_ue, + if (SGWC_SESSION_SYNC_DONE(sgwc_ue, OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE, flags)) { sgwc_tunnel_t *tunnel = NULL, *next_tunnel = NULL; @@ -702,9 +727,6 @@ void sgwc_sxa_handle_session_modification_response( gtp_req = &recv_message->create_bearer_request; ogs_assert(gtp_req); - /* Remove S5U-F-TEID */ - gtp_req->bearer_contexts.s4_u_sgsn_f_teid.presence = 0; - /* Send Data Plane(UL) : SGW-S1U */ memset(&sgw_s1u_teid, 0, sizeof(ogs_gtp2_f_teid_t)); sgw_s1u_teid.interface_type = ul_tunnel->interface_type; @@ -797,7 +819,7 @@ void sgwc_sxa_handle_session_modification_response( ogs_pfcp_xact_commit(pfcp_xact); ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); - if (SESSION_SYNC_DONE(sgwc_ue, + if (SGWC_SESSION_SYNC_DONE(sgwc_ue, OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE, flags)) { sgwc_tunnel_t *tunnel = NULL; @@ -921,10 +943,12 @@ void sgwc_sxa_handle_session_modification_response( ogs_pfcp_xact_commit(pfcp_xact); + ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); if (flags & OGS_PFCP_MODIFY_UL_ONLY) { ogs_gtp2_create_session_response_t *gtp_rsp = NULL; ogs_gtp2_f_teid_t sgw_s11_teid; - ogs_gtp2_f_teid_t sgw_s1u_teid; + ogs_gtp2_f_teid_t sgw_s1u_teid[OGS_BEARER_PER_UE]; + int sgw_s1u_len[OGS_BEARER_PER_UE]; ogs_assert(recv_message); gtp_rsp = &recv_message->create_session_response; @@ -943,19 +967,30 @@ void sgwc_sxa_handle_session_modification_response( gtp_rsp->sender_f_teid_for_control_plane.len = len; /* Send Data Plane(UL) : SGW-S1U */ - ogs_assert(ul_tunnel); - memset(&sgw_s1u_teid, 0, sizeof(ogs_gtp2_f_teid_t)); - sgw_s1u_teid.interface_type = ul_tunnel->interface_type; - sgw_s1u_teid.teid = htobe32(ul_tunnel->local_teid); - ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6); - rv = ogs_gtp2_sockaddr_to_f_teid( - ul_tunnel->local_addr, ul_tunnel->local_addr6, - &sgw_s1u_teid, &len); - ogs_assert(rv == OGS_OK); - gtp_rsp->bearer_contexts_created.s1_u_enodeb_f_teid.presence = 1; - gtp_rsp->bearer_contexts_created.s1_u_enodeb_f_teid.data = - &sgw_s1u_teid; - gtp_rsp->bearer_contexts_created.s1_u_enodeb_f_teid.len = len; + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); + + ul_tunnel = sgwc_ul_tunnel_in_bearer(bearer); + ogs_assert(ul_tunnel); + + memset(&sgw_s1u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + sgw_s1u_teid[i].interface_type = ul_tunnel->interface_type; + sgw_s1u_teid[i].teid = htobe32(ul_tunnel->local_teid); + ogs_assert(ul_tunnel->local_addr || ul_tunnel->local_addr6); + rv = ogs_gtp2_sockaddr_to_f_teid( + ul_tunnel->local_addr, ul_tunnel->local_addr6, + &sgw_s1u_teid[i], &sgw_s1u_len[i]); + ogs_assert(rv == OGS_OK); + gtp_rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid. + presence = 1; + gtp_rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid. + data = &sgw_s1u_teid[i]; + gtp_rsp->bearer_contexts_created[i].s1_u_enodeb_f_teid. + len = sgw_s1u_len[i]; + + i++; + } recv_message->h.type = OGS_GTP2_CREATE_SESSION_RESPONSE_TYPE; recv_message->h.teid = sgwc_ue->mme_s11_teid; @@ -970,10 +1005,7 @@ void sgwc_sxa_handle_session_modification_response( ogs_expect(rv == OGS_OK); } else if (flags & OGS_PFCP_MODIFY_DL_ONLY) { -#if 0 /* FIXME */ - ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); -#endif - if (SESSION_SYNC_DONE(sgwc_ue, + if (SGWC_SESSION_SYNC_DONE(sgwc_ue, OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE, flags)) { ogs_gtp2_modify_bearer_request_t *gtp_req = NULL; ogs_gtp2_modify_bearer_response_t *gtp_rsp = NULL; @@ -1023,7 +1055,7 @@ void sgwc_sxa_handle_session_modification_response( /* Copy Bearer-Contexts-Modified from Modify-Bearer-Request * - * TS 29.274 Table 7.2.7-2 + * TS 29.274 Table 7.2.8-2 * NOTE 1: The SGW shall not change its F-TEID for a given interface * during the Handover, Service Request, E-UTRAN Initial Attach, * UE Requested PDN connectivity and PDP Context Activation procedures. @@ -1083,12 +1115,10 @@ void sgwc_sxa_handle_session_modification_response( ogs_expect(rv == OGS_OK); } } - } else { ogs_fatal("Invalid modify_flags[0x%llx]", (long long)flags); ogs_assert_if_reached(); } - } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) { if (flags & OGS_PFCP_MODIFY_ERROR_INDICATION) { /* It's faked method for receiving `bearer` context */ @@ -1098,7 +1128,7 @@ void sgwc_sxa_handle_session_modification_response( ogs_pfcp_xact_commit(pfcp_xact); ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); - if (SESSION_SYNC_DONE(sgwc_ue, + if (SGWC_SESSION_SYNC_DONE(sgwc_ue, OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE, flags)) { ogs_assert(OGS_OK == sgwc_gtp_send_downlink_data_notification( @@ -1112,7 +1142,7 @@ void sgwc_sxa_handle_session_modification_response( ogs_pfcp_xact_commit(pfcp_xact); ogs_assert(flags & OGS_PFCP_MODIFY_SESSION); - if (SESSION_SYNC_DONE(sgwc_ue, + if (SGWC_SESSION_SYNC_DONE(sgwc_ue, OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE, flags)) { ogs_gtp2_release_access_bearers_response_t *gtp_rsp = NULL; @@ -1194,6 +1224,15 @@ void sgwc_sxa_handle_session_deletion_response( goto cleanup; } + if (gtp_message->h.type == OGS_GTP2_DELETE_SESSION_REQUEST_TYPE) { + /* + * X2-based Handover with SGW change + * 1. MME sends Delete Session Request to SGW-C + * 2. SGW-C sends Delete Session Response to MME. + */ + gtp_message->h.type = OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE; + } + switch (gtp_message->h.type) { case OGS_GTP2_DELETE_SESSION_RESPONSE_TYPE: /* @@ -1350,7 +1389,7 @@ void sgwc_sxa_handle_session_report_request( ogs_list_for_each(&sgwc_ue->sess_list, sess) { ogs_assert(OGS_OK == - sgwc_pfcp_send_sess_modification_request(sess, + sgwc_pfcp_send_session_modification_request(sess, /* We only use the `assoc_xact` parameter temporarily here * to pass the `bearer` context. */ (ogs_gtp_xact_t *)bearer, diff --git a/src/sgwu/gtp-path.c b/src/sgwu/gtp-path.c index 1526ea7b0..f572ef5ef 100644 --- a/src/sgwu/gtp-path.c +++ b/src/sgwu/gtp-path.c @@ -133,7 +133,33 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_assert(ogs_pkbuf_pull(pkbuf, len)); if (gtp_h->type == OGS_GTPU_MSGTYPE_END_MARKER) { - /* Nothing */ + ogs_pfcp_object_t *pfcp_object = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + ogs_pkbuf_t *sendbuf = NULL; + + pfcp_object = ogs_pfcp_object_find_by_teid(teid); + if (!pfcp_object) { + /* TODO : Send Error Indication */ + goto cleanup; + } + + switch(pfcp_object->type) { + case OGS_PFCP_OBJ_PDR_TYPE: + pdr = (ogs_pfcp_pdr_t *)pfcp_object; + ogs_assert(pdr); + break; + default: + ogs_fatal("Unknown type [%d]", pfcp_object->type); + ogs_assert_if_reached(); + } + + ogs_assert(pdr); + + sendbuf = ogs_pkbuf_copy(pkbuf); + ogs_assert(sendbuf); + + /* Forward packet */ + ogs_pfcp_send_g_pdu(pdr, gtp_h->type, sendbuf); } else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) { ogs_pfcp_far_t *far = NULL; @@ -209,7 +235,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) } ogs_assert(pdr); - ogs_assert(true == ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report)); + ogs_assert(true == ogs_pfcp_up_handle_pdr( + pdr, gtp_h->type, pkbuf, &report)); if (report.type.downlink_data_report) { ogs_assert(pdr->sess); diff --git a/src/smf/binding.c b/src/smf/binding.c index 196a7a752..b76082e36 100644 --- a/src/smf/binding.c +++ b/src/smf/binding.c @@ -394,7 +394,7 @@ void smf_bearer_binding(smf_sess_t *sess) } } -int smf_gtp_send_create_bearer_request(smf_bearer_t *bearer) +int smf_gtp2_send_create_bearer_request(smf_bearer_t *bearer) { int rv; diff --git a/src/smf/binding.h b/src/smf/binding.h index eec2fd1ed..511028e3b 100644 --- a/src/smf/binding.h +++ b/src/smf/binding.h @@ -27,7 +27,7 @@ extern "C" { #endif void smf_bearer_binding(smf_sess_t *sess); -int smf_gtp_send_create_bearer_request(smf_bearer_t *bearer); +int smf_gtp2_send_create_bearer_request(smf_bearer_t *bearer); void smf_qos_flow_binding(smf_sess_t *sess); diff --git a/src/smf/context.h b/src/smf/context.h index f2980be91..c809836d9 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -169,7 +169,7 @@ ED3(uint8_t spare:2;, typedef struct smf_bearer_s { ogs_lnode_t lnode; /**< A node of list_t */ - ogs_lnode_t to_update_node; + ogs_lnode_t to_modify_node; ogs_lnode_t to_delete_node; uint32_t index; @@ -391,6 +391,9 @@ typedef struct smf_sess_s { ogs_list_t bearer_list; + ogs_list_t pdr_to_modify_list; + ogs_list_t qos_flow_to_modify_list; + ogs_gtp_node_t *gnode; ogs_pfcp_node_t *pfcp_node; diff --git a/src/smf/gn-handler.c b/src/smf/gn-handler.c index 27556e98f..62257e06f 100644 --- a/src/smf/gn-handler.c +++ b/src/smf/gn-handler.c @@ -364,7 +364,7 @@ void smf_gn_handle_update_pdp_context_request( sess->sgw_s5c_teid, sess->smf_n4_teid); } - /* User Plane(DL) : SGW-S5C */ + /* User Plane(DL) : SGW-S5U */ bearer->sgw_s5u_teid = req->tunnel_endpoint_identifier_data_i.u32; rv = ogs_gtp1_gsn_addr_to_ip(req->sgsn_address_for_user_traffic.data, req->sgsn_address_for_user_traffic.len, @@ -405,7 +405,7 @@ void smf_gn_handle_update_pdp_context_request( } } - rv = smf_epc_pfcp_send_session_modification_request(sess, xact, + rv = smf_epc_pfcp_send_session_modification_request(sess, xact, NULL, OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, OGS_GTP1_CAUSE_REACTIACTION_REQUESTED); diff --git a/src/smf/gsm-handler.c b/src/smf/gsm-handler.c index 88adf91e4..3054fc04c 100644 --- a/src/smf/gsm-handler.c +++ b/src/smf/gsm-handler.c @@ -307,7 +307,7 @@ int gsm_handle_pdu_session_modification_request( pfcp_flags |= OGS_PFCP_MODIFY_TFT_REPLACE; qos_flow_find_or_add( - &update_list, qos_flow, to_update_node); + &update_list, qos_flow, to_modify_node); ogs_list_add( &qos_flow->pf_to_add_list, &pf->to_add_node); @@ -389,7 +389,7 @@ int gsm_handle_pdu_session_modification_request( ogs_assert_if_reached(); qos_flow_find_or_add( - &update_list, qos_flow, to_update_node); + &update_list, qos_flow, to_modify_node); ogs_list_add( &qos_flow->pf_to_add_list, &pf->to_add_node); @@ -414,7 +414,7 @@ int gsm_handle_pdu_session_modification_request( if (ogs_list_count(&qos_flow->pf_list)) { pfcp_flags |= OGS_PFCP_MODIFY_TFT_DELETE; qos_flow_find_or_add( - &update_list, qos_flow, to_update_node); + &update_list, qos_flow, to_modify_node); } else { pfcp_flags |= OGS_PFCP_MODIFY_REMOVE; qos_flow_find_or_add( @@ -469,7 +469,7 @@ int gsm_handle_pdu_session_modification_request( } pfcp_flags |= OGS_PFCP_MODIFY_QOS_MODIFY; - qos_flow_find_or_add(&update_list, qos_flow, to_update_node); + qos_flow_find_or_add(&update_list, qos_flow, to_modify_node); } } diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index 3af373dfc..14302ae0e 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -303,10 +303,14 @@ void smf_gsm_state_initial_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e) } switch (gtp_xact->gtp_version) { case 1: - ogs_assert(OGS_OK == smf_gtp1_send_create_pdp_context_response(sess, gtp_xact)); + ogs_assert(OGS_OK == + smf_gtp1_send_create_pdp_context_response( + sess, gtp_xact)); break; case 2: - ogs_assert(OGS_OK == smf_gtp_send_create_session_response(sess, gtp_xact)); + ogs_assert(OGS_OK == + smf_gtp2_send_create_session_response( + sess, gtp_xact)); break; } if (sess->gtp_rat_type == OGS_GTP2_RAT_TYPE_WLAN) { @@ -319,17 +323,9 @@ void smf_gsm_state_initial_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e) * PGW-C shall indicate PGW-U to stop counting and stop * forwarding downlink packets for the affected bearer(s). */ - ogs_assert(sess->smf_ue); - smf_sess_t *eutran_sess = smf_sess_find_by_apn( - sess->smf_ue, sess->session.name, OGS_GTP2_RAT_TYPE_EUTRAN); - if (eutran_sess) { - ogs_assert(OGS_OK == - smf_epc_pfcp_send_session_modification_request( - eutran_sess, NULL, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, - OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, - OGS_GTP2_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP)); - } + ogs_assert(OGS_OK == + smf_epc_pfcp_send_deactivation(sess, + OGS_GTP2_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP)); } smf_bearer_binding(sess); } else { @@ -994,7 +990,7 @@ test_can_proceed: ogs_assert(OGS_OK == smf_gtp1_send_delete_pdp_context_response(sess, e->gtp_xact)); break; case 2: - ogs_assert(OGS_OK == smf_gtp_send_delete_session_response(sess, e->gtp_xact)); + ogs_assert(OGS_OK == smf_gtp2_send_delete_session_response(sess, e->gtp_xact)); break; } } else { diff --git a/src/smf/gtp-path.c b/src/smf/gtp-path.c index 509a36d0f..b2d8bcc74 100644 --- a/src/smf/gtp-path.c +++ b/src/smf/gtp-path.c @@ -427,7 +427,7 @@ int smf_gtp1_send_update_pdp_context_response( return rv; } -int smf_gtp_send_create_session_response( +int smf_gtp2_send_create_session_response( smf_sess_t *sess, ogs_gtp_xact_t *xact) { int rv; @@ -453,7 +453,36 @@ int smf_gtp_send_create_session_response( return rv; } -int smf_gtp_send_delete_session_response( +int smf_gtp2_send_modify_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp2_modify_bearer_request_t *req, bool sgw_relocation) +{ + int rv; + ogs_gtp2_header_t h; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(sess); + ogs_assert(xact); + ogs_assert(req); + + memset(&h, 0, sizeof(ogs_gtp2_header_t)); + h.type = OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE; + h.teid = sess->sgw_s5c_teid; + + pkbuf = smf_s5c_build_modify_bearer_response( + h.type, sess, req, sgw_relocation); + ogs_expect_or_return_val(pkbuf, OGS_ERROR); + + rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + rv = ogs_gtp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; +} + +int smf_gtp2_send_delete_session_response( smf_sess_t *sess, ogs_gtp_xact_t *xact) { int rv; @@ -479,7 +508,7 @@ int smf_gtp_send_delete_session_response( return rv; } -int smf_gtp_send_delete_bearer_request( +int smf_gtp2_send_delete_bearer_request( smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value) { int rv; diff --git a/src/smf/gtp-path.h b/src/smf/gtp-path.h index 9673a055a..4b3874fc2 100644 --- a/src/smf/gtp-path.h +++ b/src/smf/gtp-path.h @@ -38,12 +38,14 @@ int smf_gtp1_send_update_pdp_context_request( int smf_gtp1_send_update_pdp_context_response( smf_bearer_t *bearer, ogs_gtp_xact_t *xact); -int smf_gtp_send_create_session_response( +int smf_gtp2_send_create_session_response( smf_sess_t *sess, ogs_gtp_xact_t *xact); -int smf_gtp_send_delete_session_response( +int smf_gtp2_send_modify_bearer_response( + smf_sess_t *sess, ogs_gtp_xact_t *xact, + ogs_gtp2_modify_bearer_request_t *req, bool sgw_relocation); +int smf_gtp2_send_delete_session_response( smf_sess_t *sess, ogs_gtp_xact_t *xact); - -int smf_gtp_send_delete_bearer_request( +int smf_gtp2_send_delete_bearer_request( smf_bearer_t *bearer, uint8_t pti, uint8_t cause_value); #ifdef __cplusplus diff --git a/src/smf/gx-path.c b/src/smf/gx-path.c index 8f260b518..fb3b51927 100644 --- a/src/smf/gx-path.c +++ b/src/smf/gx-path.c @@ -91,7 +91,7 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, char buf[OGS_PLMNIDSTRLEN]; struct sockaddr_in sin; struct sockaddr_in6 sin6; - uint32_t charing_id; + uint32_t charging_id; ogs_assert(sess); @@ -636,9 +636,9 @@ void smf_gx_send_ccr(smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_diam_gx_access_network_charging_identifier_value, 0, &avpch1); ogs_assert(ret == 0); - charing_id = htobe32(sess->charging.id); - val.os.data = (uint8_t *)&charing_id; - val.os.len = sizeof(charing_id); + charging_id = htobe32(sess->charging.id); + val.os.data = (uint8_t *)&charging_id; + val.os.len = sizeof(charging_id); ret = fd_msg_avp_setvalue (avpch1, &val); ogs_assert(ret == 0); ret = fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, avpch1); diff --git a/src/smf/gy-handler.c b/src/smf/gy-handler.c index 4ea88daf3..cfd978f24 100644 --- a/src/smf/gy-handler.c +++ b/src/smf/gy-handler.c @@ -174,10 +174,10 @@ void smf_gy_handle_cca_update_request( /* Send PFCP Session Modification Request if we need to update the params. */ if (modify_flags) { modify_flags |= OGS_PFCP_MODIFY_URR|OGS_PFCP_MODIFY_UL_ONLY; - rv = smf_epc_pfcp_send_session_modification_request(sess, pfcp_xact, - modify_flags, - OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, - OGS_GTP1_CAUSE_REACTIACTION_REQUESTED); + rv = smf_epc_pfcp_send_session_modification_request( + sess, pfcp_xact, NULL, modify_flags, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP1_CAUSE_REACTIACTION_REQUESTED); ogs_assert(rv == OGS_OK); } } diff --git a/src/smf/n4-build.c b/src/smf/n4-build.c index 402d1b5d1..82798ed65 100644 --- a/src/smf/n4-build.c +++ b/src/smf/n4-build.c @@ -110,7 +110,7 @@ ogs_pkbuf_t *smf_n4_build_session_establishment_request( return pkbuf; } -ogs_pkbuf_t *smf_n4_build_session_modification_request( +ogs_pkbuf_t *smf_n4_build_pdr_to_modify_list( uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact) { ogs_pfcp_pdr_t *pdr = NULL; @@ -142,7 +142,7 @@ ogs_pkbuf_t *smf_n4_build_session_modification_request( ogs_pfcp_pdrbuf_init(); } - ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { + ogs_list_for_each_entry(&sess->pdr_to_modify_list, pdr, to_modify_node) { ogs_pfcp_far_t *far = pdr->far; ogs_assert(far); @@ -238,22 +238,29 @@ ogs_pkbuf_t *smf_n4_build_session_modification_request( return pkbuf; } -ogs_pkbuf_t *smf_n4_build_qos_flow_modification_request( - uint8_t type, smf_bearer_t *qos_flow, ogs_pfcp_xact_t *xact) +ogs_pkbuf_t *smf_n4_build_qos_flow_to_modify_list( + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact) { ogs_pfcp_message_t pfcp_message; ogs_pfcp_session_modification_request_t *req = NULL; ogs_pkbuf_t *pkbuf = NULL; - int i; - smf_sess_t *sess = NULL; + smf_bearer_t *qos_flow = NULL; + + int num_of_remove_pdr = 0; + int num_of_remove_far = 0; + int num_of_remove_qer = 0; + int num_of_create_pdr = 0; + int num_of_create_far = 0; + int num_of_create_qer = 0; + int num_of_update_pdr = 0; + int num_of_update_far = 0; + int num_of_update_qer = 0; uint64_t modify_flags = 0; - ogs_debug("QoS Flow Modification Request"); + ogs_debug("Bearer Modification Request"); - ogs_assert(qos_flow); - sess = qos_flow->sess; ogs_assert(sess); ogs_assert(xact); modify_flags = xact->modify_flags; @@ -270,155 +277,163 @@ ogs_pkbuf_t *smf_n4_build_qos_flow_modification_request( ogs_pfcp_pdrbuf_init(); } - if (modify_flags & OGS_PFCP_MODIFY_REMOVE) { - /* Remove PDR */ - i = 0; - if (qos_flow->dl_pdr) { - ogs_pfcp_tlv_remove_pdr_t *message = &req->remove_pdr[i]; + ogs_list_for_each_entry( + &sess->qos_flow_to_modify_list, qos_flow, to_modify_node) { - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = qos_flow->dl_pdr->id; - i++; - } - if (qos_flow->ul_pdr) { - ogs_pfcp_tlv_remove_pdr_t *message = &req->remove_pdr[i]; - - message->presence = 1; - message->pdr_id.presence = 1; - message->pdr_id.u16 = qos_flow->ul_pdr->id; - i++; - } - - /* Remove FAR */ - i = 0; - if (qos_flow->dl_far) { - ogs_pfcp_tlv_remove_far_t *message = &req->remove_far[i]; - - message->presence = 1; - message->far_id.presence = 1; - message->far_id.u32 = qos_flow->dl_far->id; - i++; - } - if (qos_flow->ul_far) { - ogs_pfcp_tlv_remove_far_t *message = &req->remove_far[i]; - - message->presence = 1; - message->far_id.presence = 1; - message->far_id.u32 = qos_flow->ul_far->id; - i++; - } - - /* Remove QER */ - i = 0; - if (qos_flow->qer) { - ogs_pfcp_tlv_remove_qer_t *message = &req->remove_qer[i]; - - message->presence = 1; - message->qer_id.presence = 1; - message->qer_id.u32 = qos_flow->qer->id; - i++; - } - - } else { - if (modify_flags & OGS_PFCP_MODIFY_CREATE) { - - /* Create PDR */ - i = 0; + if (modify_flags & OGS_PFCP_MODIFY_REMOVE) { + /* Remove PDR */ if (qos_flow->dl_pdr) { - ogs_pfcp_build_create_pdr( - &req->create_pdr[i], i, qos_flow->dl_pdr); - i++; + ogs_pfcp_tlv_remove_pdr_t *message = + &req->remove_pdr[num_of_remove_pdr]; - ogs_list_add(&xact->pdr_to_create_list, - &qos_flow->dl_pdr->to_create_node); + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = qos_flow->dl_pdr->id; + num_of_remove_pdr++; } if (qos_flow->ul_pdr) { - ogs_pfcp_build_create_pdr( - &req->create_pdr[i], i, qos_flow->ul_pdr); - i++; + ogs_pfcp_tlv_remove_pdr_t *message = + &req->remove_pdr[num_of_remove_pdr]; - ogs_list_add(&xact->pdr_to_create_list, - &qos_flow->ul_pdr->to_create_node); + message->presence = 1; + message->pdr_id.presence = 1; + message->pdr_id.u16 = qos_flow->ul_pdr->id; + num_of_remove_pdr++; } - /* Create FAR */ - i = 0; + /* Remove FAR */ if (qos_flow->dl_far) { - ogs_pfcp_build_create_far( - &req->create_far[i], i, qos_flow->dl_far); - i++; + ogs_pfcp_tlv_remove_far_t *message = + &req->remove_far[num_of_remove_far]; + + message->presence = 1; + message->far_id.presence = 1; + message->far_id.u32 = qos_flow->dl_far->id; + num_of_remove_far++; } if (qos_flow->ul_far) { - ogs_pfcp_build_create_far( - &req->create_far[i], i, qos_flow->ul_far); - i++; + ogs_pfcp_tlv_remove_far_t *message = + &req->remove_far[num_of_remove_far]; + + message->presence = 1; + message->far_id.presence = 1; + message->far_id.u32 = qos_flow->ul_far->id; + num_of_remove_far++; } - /* Create QER */ - i = 0; + /* Remove QER */ if (qos_flow->qer) { - ogs_pfcp_build_create_qer( - &req->create_qer[i], i, qos_flow->qer); - i++; + ogs_pfcp_tlv_remove_qer_t *message = + &req->remove_qer[num_of_remove_qer]; + + message->presence = 1; + message->qer_id.presence = 1; + message->qer_id.u32 = qos_flow->qer->id; + num_of_remove_qer++; } - } - if (modify_flags & - (OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD| - OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE| - OGS_PFCP_MODIFY_EPC_TFT_UPDATE)) { - /* Update PDR */ - i = 0; - if (qos_flow->dl_pdr) { - ogs_pfcp_build_update_pdr( - &req->update_pdr[i], i, qos_flow->dl_pdr); - i++; - } - if (qos_flow->ul_pdr) { - ogs_pfcp_build_update_pdr( - &req->update_pdr[i], i, qos_flow->ul_pdr); - i++; - } - } - if (modify_flags & OGS_PFCP_MODIFY_ACTIVATE - || modify_flags & OGS_PFCP_MODIFY_UL_ONLY) { - /* Update FAR - Only DL */ - i = 0; - if (qos_flow->dl_far) { - if (qos_flow->dl_far->apply_action & - OGS_PFCP_APPLY_ACTION_FORW) { + } else { + if (modify_flags & OGS_PFCP_MODIFY_CREATE) { - if (modify_flags & OGS_PFCP_MODIFY_END_MARKER) { - qos_flow->dl_far-> - smreq_flags.send_end_marker_packets = 1; - } + /* Create PDR */ + if (qos_flow->dl_pdr) { + ogs_pfcp_build_create_pdr( + &req->create_pdr[num_of_create_pdr], + num_of_create_pdr, qos_flow->dl_pdr); + num_of_create_pdr++; - ogs_pfcp_build_update_far_activate( - &req->update_far[i], i, qos_flow->dl_far); - i++; + ogs_list_add(&xact->pdr_to_create_list, + &qos_flow->dl_pdr->to_create_node); + } + if (qos_flow->ul_pdr) { + ogs_pfcp_build_create_pdr( + &req->create_pdr[num_of_create_pdr], + num_of_create_pdr, qos_flow->ul_pdr); + num_of_create_pdr++; - /* Clear all FAR flags */ - qos_flow->dl_far->smreq_flags.value = 0; + ogs_list_add(&xact->pdr_to_create_list, + &qos_flow->ul_pdr->to_create_node); + } + + /* Create FAR */ + if (qos_flow->dl_far) { + ogs_pfcp_build_create_far( + &req->create_far[num_of_create_far], + num_of_create_far, qos_flow->dl_far); + num_of_create_far++; + } + if (qos_flow->ul_far) { + ogs_pfcp_build_create_far( + &req->create_far[num_of_create_far], + num_of_create_far, qos_flow->ul_far); + num_of_create_far++; + } + + /* Create QER */ + if (qos_flow->qer) { + ogs_pfcp_build_create_qer( + &req->create_qer[num_of_create_qer], + num_of_create_qer, qos_flow->qer); + num_of_create_qer++; } } - } else if (modify_flags & OGS_PFCP_MODIFY_DEACTIVATE) { - i = 0; - if (qos_flow->dl_far) { - ogs_pfcp_build_update_far_deactivate( - &req->update_far[i], i, qos_flow->dl_far); - i++; + if (modify_flags & + (OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD| + OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE| + OGS_PFCP_MODIFY_EPC_TFT_UPDATE)) { + + /* Update PDR */ + if (qos_flow->dl_pdr) { + ogs_pfcp_build_update_pdr( + &req->update_pdr[num_of_update_pdr], + num_of_update_pdr, qos_flow->dl_pdr); + num_of_update_pdr++; + } + if (qos_flow->ul_pdr) { + ogs_pfcp_build_update_pdr( + &req->update_pdr[num_of_update_pdr], + num_of_update_pdr, qos_flow->ul_pdr); + num_of_update_pdr++; + } } - } - if (modify_flags & - (OGS_PFCP_MODIFY_QOS_MODIFY| - OGS_PFCP_MODIFY_EPC_QOS_UPDATE)) { - /* Update QER */ - i = 0; - if (qos_flow->qer) { - ogs_pfcp_build_update_qer( - &req->update_qer[i], i, qos_flow->qer); - i++; + if (modify_flags & OGS_PFCP_MODIFY_ACTIVATE) { + /* Update FAR - Only DL */ + if (qos_flow->dl_far) { + if (qos_flow->dl_far->apply_action & + OGS_PFCP_APPLY_ACTION_FORW) { + + if (modify_flags & OGS_PFCP_MODIFY_END_MARKER) { + qos_flow->dl_far-> + smreq_flags.send_end_marker_packets = 1; + } + + ogs_pfcp_build_update_far_activate( + &req->update_far[num_of_update_far], + num_of_update_far, qos_flow->dl_far); + num_of_update_far++; + + /* Clear all FAR flags */ + qos_flow->dl_far->smreq_flags.value = 0; + } + } + } else if (modify_flags & OGS_PFCP_MODIFY_DEACTIVATE) { + if (qos_flow->dl_far) { + ogs_pfcp_build_update_far_deactivate( + &req->update_far[num_of_update_far], + num_of_update_far, qos_flow->dl_far); + num_of_update_far++; + } + } + if (modify_flags & + (OGS_PFCP_MODIFY_QOS_MODIFY| + OGS_PFCP_MODIFY_EPC_QOS_UPDATE)) { + /* Update QER */ + if (qos_flow->qer) { + ogs_pfcp_build_update_qer( + &req->update_qer[num_of_update_qer], + num_of_update_qer, qos_flow->qer); + num_of_update_qer++; + } } } } diff --git a/src/smf/n4-build.h b/src/smf/n4-build.h index 19a62a283..560a4a0f3 100644 --- a/src/smf/n4-build.h +++ b/src/smf/n4-build.h @@ -28,10 +28,10 @@ extern "C" { ogs_pkbuf_t *smf_n4_build_session_establishment_request( uint8_t type, smf_sess_t *sess); -ogs_pkbuf_t *smf_n4_build_session_modification_request( +ogs_pkbuf_t *smf_n4_build_pdr_to_modify_list( + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact); +ogs_pkbuf_t *smf_n4_build_qos_flow_to_modify_list( uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact); -ogs_pkbuf_t *smf_n4_build_qos_flow_modification_request( - uint8_t type, smf_bearer_t *qos_flow, ogs_pfcp_xact_t *xact); ogs_pkbuf_t *smf_n4_build_session_deletion_request( uint8_t type, smf_sess_t *sess); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index e4a6ace10..67066f18c 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -823,6 +823,7 @@ uint8_t smf_epc_n4_handle_session_establishment_response( void smf_epc_n4_handle_session_modification_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_gtp2_message_t *recv_message, ogs_pfcp_session_modification_response_t *rsp) { int i; @@ -940,7 +941,7 @@ void smf_epc_n4_handle_session_modification_response( } else if (flags & OGS_PFCP_MODIFY_CREATE) { ogs_assert(bearer); - ogs_assert(OGS_OK == smf_gtp_send_create_bearer_request(bearer)); + ogs_assert(OGS_OK == smf_gtp2_send_create_bearer_request(bearer)); } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) { /* @@ -1013,7 +1014,7 @@ void smf_epc_n4_handle_session_modification_response( ogs_assert(linked_bearer); ogs_assert(OGS_OK == - smf_gtp_send_delete_bearer_request( + smf_gtp2_send_delete_bearer_request( linked_bearer, gtp_pti, gtp_cause)); } else { /* @@ -1034,7 +1035,7 @@ void smf_epc_n4_handle_session_modification_response( ogs_assert(bearer); ogs_assert(OGS_OK == - smf_gtp_send_delete_bearer_request( + smf_gtp2_send_delete_bearer_request( bearer, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, gtp_cause)); @@ -1043,12 +1044,36 @@ void smf_epc_n4_handle_session_modification_response( } else if (flags & OGS_PFCP_MODIFY_ACTIVATE) { if (gtp_xact) { + /* SMF send Update PDP Context Response (GTPv1C) to SGSN */ if (gtp_xact->gtp_version == 1) { + bearer = gtp_xact->data; smf_gtp1_send_update_pdp_context_response(bearer, gtp_xact); + } else { - /* TODO: SMF send Modify Bearer Response (GTPv2C) to SGWC */ + + /* SMF send Modify Bearer Response (GTPv2C) to SGW-C */ + ogs_gtp2_indication_t *indication = NULL; + + ogs_assert(recv_message); + ogs_gtp2_modify_bearer_request_t *gtp_req = + &recv_message->modify_bearer_request; + + ogs_assert(OGS_OK == smf_gtp2_send_modify_bearer_response( + sess, gtp_xact, gtp_req, true)); + + /* Check if Handover from Non-3GPP to 3GPP */ + if (gtp_req->indication_flags.presence && + gtp_req->indication_flags.data && + gtp_req->indication_flags.len) { + indication = gtp_req->indication_flags.data; + } + + if (indication && indication->handover_indication) { + ogs_assert(OGS_OK == smf_epc_pfcp_send_deactivation(sess, + OGS_GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP)); + } } } else { /* Nothing */ diff --git a/src/smf/n4-handler.h b/src/smf/n4-handler.h index 0a610e260..00b53009b 100644 --- a/src/smf/n4-handler.h +++ b/src/smf/n4-handler.h @@ -41,6 +41,7 @@ uint8_t smf_epc_n4_handle_session_establishment_response( ogs_pfcp_session_establishment_response_t *rsp); void smf_epc_n4_handle_session_modification_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_gtp2_message_t *gtp2_message, ogs_pfcp_session_modification_response_t *rsp); uint8_t smf_epc_n4_handle_session_deletion_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index a113c25e7..2e9321f00 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -294,6 +294,41 @@ static void bearer_epc_timeout(ogs_pfcp_xact_t *xact, void *data) } } +int smf_pfcp_send_modify_list( + smf_sess_t *sess, + ogs_pkbuf_t *(*modify_list)( + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact), + ogs_pfcp_xact_t *xact, ogs_time_t duration) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(sess); + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + + n4buf = (*modify_list)(h.type, sess, xact); + ogs_expect_or_return_val(n4buf, OGS_ERROR); + + rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + if (duration) { + ogs_pfcp_xact_delayed_commit(xact, duration); + + return OGS_OK; + } else { + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); + + return rv; + } +} + int smf_5gc_pfcp_send_session_establishment_request( smf_sess_t *sess, ogs_sbi_stream_t *stream) { @@ -305,15 +340,15 @@ int smf_5gc_pfcp_send_session_establishment_request( ogs_assert(sess); ogs_assert(stream); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); xact->assoc_stream = stream; + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + n4buf = smf_n4_build_session_establishment_request(h.type, sess); ogs_expect_or_return_val(n4buf, OGS_ERROR); @@ -331,48 +366,34 @@ int smf_5gc_pfcp_send_session_modification_request( uint64_t flags, ogs_time_t duration) { int rv; - ogs_pkbuf_t *n4buf = NULL; - ogs_pfcp_header_t h; ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_pdr_t *pdr = NULL; ogs_assert(sess); if ((flags & OGS_PFCP_MODIFY_ERROR_INDICATION) == 0) ogs_assert(stream); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); xact->assoc_stream = stream; xact->modify_flags = flags | OGS_PFCP_MODIFY_SESSION; - n4buf = smf_n4_build_session_modification_request(h.type, sess, xact); - ogs_expect_or_return_val(n4buf, OGS_ERROR); + ogs_list_init(&sess->pdr_to_modify_list); + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) + ogs_list_add(&sess->pdr_to_modify_list, &pdr->to_modify_node); - rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); - ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + rv = smf_pfcp_send_modify_list( + sess, smf_n4_build_pdr_to_modify_list, xact, duration); + ogs_expect(rv == OGS_OK); - if (duration) { - ogs_pfcp_xact_delayed_commit(xact, duration); - - return OGS_OK; - } else { - rv = ogs_pfcp_xact_commit(xact); - ogs_expect(rv == OGS_OK); - - return rv; - } + return rv; } int smf_5gc_pfcp_send_qos_flow_modification_request(smf_bearer_t *qos_flow, ogs_sbi_stream_t *stream, uint64_t flags) { int rv; - ogs_pkbuf_t *n4buf = NULL; - ogs_pfcp_header_t h; ogs_pfcp_xact_t *xact = NULL; smf_sess_t *sess = NULL; @@ -380,10 +401,6 @@ int smf_5gc_pfcp_send_qos_flow_modification_request(smf_bearer_t *qos_flow, sess = qos_flow->sess; ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create( sess->pfcp_node, qos_flow_5gc_timeout, qos_flow); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -391,13 +408,11 @@ int smf_5gc_pfcp_send_qos_flow_modification_request(smf_bearer_t *qos_flow, xact->assoc_stream = stream; xact->modify_flags = flags; - n4buf = smf_n4_build_qos_flow_modification_request(h.type, qos_flow, xact); - ogs_expect_or_return_val(n4buf, OGS_ERROR); + ogs_list_init(&sess->qos_flow_to_modify_list); + ogs_list_add(&sess->qos_flow_to_modify_list, &qos_flow->to_modify_node); - rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); - ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); - - rv = ogs_pfcp_xact_commit(xact); + rv = smf_pfcp_send_modify_list( + sess, smf_n4_build_qos_flow_to_modify_list, xact, 0); ogs_expect(rv == OGS_OK); return rv; @@ -414,16 +429,16 @@ int smf_5gc_pfcp_send_session_deletion_request( ogs_assert(sess); ogs_assert(trigger); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_5gc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); xact->assoc_stream = stream; xact->delete_trigger = trigger; + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + n4buf = smf_n4_build_session_deletion_request(h.type, sess); ogs_expect_or_return_val(n4buf, OGS_ERROR); @@ -446,16 +461,16 @@ int smf_epc_pfcp_send_session_establishment_request( ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_epc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); xact->epc = true; /* EPC PFCP transaction */ xact->assoc_xact = gtp_xact; + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + n4buf = smf_n4_build_session_establishment_request(h.type, sess); ogs_expect_or_return_val(n4buf, OGS_ERROR); @@ -469,20 +484,15 @@ int smf_epc_pfcp_send_session_establishment_request( } int smf_epc_pfcp_send_session_modification_request( - smf_sess_t *sess, void *gtp_xact, + smf_sess_t *sess, void *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause) { int rv; - ogs_pkbuf_t *n4buf = NULL; - ogs_pfcp_header_t h; ogs_pfcp_xact_t *xact = NULL; + ogs_pfcp_pdr_t *pdr = NULL; ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_epc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -492,14 +502,17 @@ int smf_epc_pfcp_send_session_modification_request( xact->gtp_pti = gtp_pti; xact->gtp_cause = gtp_cause; + if (gtpbuf) { + xact->gtpbuf = ogs_pkbuf_copy(gtpbuf); + ogs_expect_or_return_val(xact->gtpbuf, OGS_ERROR); + } - n4buf = smf_n4_build_session_modification_request(h.type, sess, xact); - ogs_expect_or_return_val(n4buf, OGS_ERROR); + ogs_list_init(&sess->pdr_to_modify_list); + ogs_list_for_each(&sess->pfcp.pdr_list, pdr) + ogs_list_add(&sess->pdr_to_modify_list, &pdr->to_modify_node); - rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); - ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); - - rv = ogs_pfcp_xact_commit(xact); + rv = smf_pfcp_send_modify_list( + sess, smf_n4_build_pdr_to_modify_list, xact, 0); ogs_expect(rv == OGS_OK); return rv; @@ -510,8 +523,6 @@ int smf_epc_pfcp_send_bearer_modification_request( uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause) { int rv; - ogs_pkbuf_t *n4buf = NULL; - ogs_pfcp_header_t h; ogs_pfcp_xact_t *xact = NULL; smf_sess_t *sess = NULL; @@ -519,10 +530,6 @@ int smf_epc_pfcp_send_bearer_modification_request( sess = bearer->sess; ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create( sess->pfcp_node, bearer_epc_timeout, bearer); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -534,13 +541,11 @@ int smf_epc_pfcp_send_bearer_modification_request( xact->gtp_pti = gtp_pti; xact->gtp_cause = gtp_cause; - n4buf = smf_n4_build_qos_flow_modification_request(h.type, bearer, xact); - ogs_expect_or_return_val(n4buf, OGS_ERROR); + ogs_list_init(&sess->qos_flow_to_modify_list); + ogs_list_add(&sess->qos_flow_to_modify_list, &bearer->to_modify_node); - rv = ogs_pfcp_xact_update_tx(xact, &h, n4buf); - ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); - - rv = ogs_pfcp_xact_commit(xact); + rv = smf_pfcp_send_modify_list( + sess, smf_n4_build_qos_flow_to_modify_list, xact, 0); ogs_expect(rv == OGS_OK); return rv; @@ -556,10 +561,6 @@ int smf_epc_pfcp_send_session_deletion_request( ogs_assert(sess); - memset(&h, 0, sizeof(ogs_pfcp_header_t)); - h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; - h.seid = sess->upf_n4_seid; - xact = ogs_pfcp_xact_local_create(sess->pfcp_node, sess_epc_timeout, sess); ogs_expect_or_return_val(xact, OGS_ERROR); @@ -588,6 +589,10 @@ int smf_epc_pfcp_send_session_deletion_request( */ xact->assoc_xact = gtp_xact; + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_DELETION_REQUEST_TYPE; + h.seid = sess->upf_n4_seid; + n4buf = smf_n4_build_session_deletion_request(h.type, sess); ogs_expect_or_return_val(n4buf, OGS_ERROR); @@ -600,6 +605,60 @@ int smf_epc_pfcp_send_session_deletion_request( return rv; } +int smf_epc_pfcp_send_deactivation(smf_sess_t *sess, uint8_t gtp_cause) +{ + int rv; + smf_ue_t *smf_ue = NULL; + smf_sess_t *eutran_sess = NULL, *wlan_sess = NULL; + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + switch (gtp_cause) { + case OGS_GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP: + /* Handover from Non-3GPP to 3GPP */ + wlan_sess = smf_sess_find_by_apn( + smf_ue, sess->session.name, OGS_GTP2_RAT_TYPE_WLAN); + ogs_expect_or_return_val(wlan_sess, OGS_ERROR); + ogs_expect_or_return_val( + ogs_list_first(&wlan_sess->bearer_list), OGS_ERROR); + + /* Deactivate WLAN Session */ + rv = smf_epc_pfcp_send_session_modification_request( + wlan_sess, NULL, NULL, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP); + ogs_expect_or_return_val(rv == OGS_OK, rv); + break; + + case OGS_GTP2_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP: + /* Handover from 3GPP to Non-3GPP */ + eutran_sess = smf_sess_find_by_apn( + smf_ue, sess->session.name, OGS_GTP2_RAT_TYPE_EUTRAN); + if (eutran_sess) { + ogs_expect_or_return_val( + ogs_list_first(&eutran_sess->bearer_list), OGS_ERROR); + + /* Deactivate EUTRAN Session */ + rv = smf_epc_pfcp_send_session_modification_request( + eutran_sess, NULL, NULL, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP2_CAUSE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP); + ogs_expect_or_return_val(rv == OGS_OK, rv); + } + break; + + default: + ogs_fatal("Invalid GTP-Cause[%d]", gtp_cause); + ogs_assert_if_reached(); + } + + return OGS_OK; +} + int smf_pfcp_send_session_report_response( ogs_pfcp_xact_t *xact, smf_sess_t *sess, uint8_t cause) { diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h index ded87f3d3..8f2545b1c 100644 --- a/src/smf/pfcp-path.h +++ b/src/smf/pfcp-path.h @@ -29,20 +29,27 @@ extern "C" { int smf_pfcp_open(void); void smf_pfcp_close(void); +int smf_pfcp_send_modify_list( + smf_sess_t *sess, + ogs_pkbuf_t *(*modify_list)( + uint8_t type, smf_sess_t *sess, ogs_pfcp_xact_t *xact), + ogs_pfcp_xact_t *xact, ogs_time_t duration); + int smf_5gc_pfcp_send_session_establishment_request( smf_sess_t *sess, ogs_sbi_stream_t *stream); int smf_5gc_pfcp_send_session_modification_request( smf_sess_t *sess, ogs_sbi_stream_t *stream, uint64_t flags, ogs_time_t duration); -int smf_5gc_pfcp_send_qos_flow_modification_request(smf_bearer_t *qos_flow, - ogs_sbi_stream_t *stream, uint64_t flags); +int smf_5gc_pfcp_send_qos_flow_modification_request( + smf_bearer_t *qos_flow, ogs_sbi_stream_t *stream, + uint64_t flags); int smf_5gc_pfcp_send_session_deletion_request( smf_sess_t *sess, ogs_sbi_stream_t *stream, int trigger); int smf_epc_pfcp_send_session_establishment_request( smf_sess_t *sess, void *gtp_xact); int smf_epc_pfcp_send_session_modification_request( - smf_sess_t *sess, void *gtp_xact, + smf_sess_t *sess, void *gtp_xact, ogs_pkbuf_t *gtpbuf, uint64_t flags, uint8_t gtp_pti, uint8_t gtp_cause); int smf_epc_pfcp_send_bearer_modification_request( smf_bearer_t *bearer, void *gtp_xact, @@ -50,6 +57,8 @@ int smf_epc_pfcp_send_bearer_modification_request( int smf_epc_pfcp_send_session_deletion_request( smf_sess_t *sess, void *gtp_xact); +int smf_epc_pfcp_send_deactivation(smf_sess_t *sess, uint8_t gtp_cause); + int smf_pfcp_send_session_report_response( ogs_pfcp_xact_t *xact, smf_sess_t *sess, uint8_t cause); diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c index 6425c1a97..de74f4dd9 100644 --- a/src/smf/pfcp-sm.c +++ b/src/smf/pfcp-sm.c @@ -238,7 +238,8 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) if (xact->epc) smf_epc_n4_handle_session_modification_response( - sess, xact, &message->pfcp_session_modification_response); + sess, xact, e->gtp2_message, + &message->pfcp_session_modification_response); else smf_5gc_n4_handle_session_modification_response( sess, xact, &message->pfcp_session_modification_response); diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 25203dbbb..deb035d7f 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -32,11 +32,16 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_gtp2_create_session_response_t *rsp = NULL; ogs_gtp2_cause_t cause; - ogs_gtp2_cause_t bearer_cause; - ogs_gtp2_f_teid_t smf_s5c_teid, pgw_s5u_teid; + + int i; + ogs_gtp2_cause_t bearer_cause[OGS_BEARER_PER_UE]; + ogs_gtp2_f_teid_t pgw_s5u_teid[OGS_BEARER_PER_UE]; + int pgw_s5u_len[OGS_BEARER_PER_UE]; + + ogs_gtp2_f_teid_t smf_s5c_teid; ogs_gtp2_ambr_t ambr; ogs_gtp2_bearer_qos_t bearer_qos; - char bearer_qos_buf[GTP2_BEARER_QOS_LEN]; + char bearer_qos_buf[OGS_BEARER_PER_UE][GTP2_BEARER_QOS_LEN]; int len; uint8_t pco_buf[OGS_MAX_PCO_LEN]; int16_t pco_len; @@ -44,13 +49,9 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_debug("[SMF] Create Session Response"); ogs_assert(sess); - bearer = smf_default_bearer_in_sess(sess); - ogs_assert(bearer); ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); - ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", - bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); rsp = >p_message.create_session_response; memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); @@ -114,7 +115,7 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); ogs_assert_if_reached(); } - + /* APN-AMBR * if PCRF changes APN-AMBR, this should be included. */ if (sess->gtp.create_session_response_apn_ambr == true) { @@ -137,62 +138,78 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( rsp->protocol_configuration_options.len = pco_len; } - /* Bearer EBI */ - rsp->bearer_contexts_created.presence = 1; - rsp->bearer_contexts_created.eps_bearer_id.presence = 1; - rsp->bearer_contexts_created.eps_bearer_id.u8 = bearer->ebi; + i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); - /* Bearer Cause */ - memset(&bearer_cause, 0, sizeof(bearer_cause)); - rsp->bearer_contexts_created.cause.presence = 1; - rsp->bearer_contexts_created.cause.len = sizeof(bearer_cause); - rsp->bearer_contexts_created.cause.data = &bearer_cause; - bearer_cause.value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", + bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); - /* Bearer QoS - * if PCRF changes Bearer QoS, this should be included. */ - if (sess->gtp.create_session_response_bearer_qos == true) { - memset(&bearer_qos, 0, sizeof(bearer_qos)); - bearer_qos.qci = sess->session.qos.index; - bearer_qos.priority_level = sess->session.qos.arp.priority_level; - bearer_qos.pre_emption_capability = - sess->session.qos.arp.pre_emption_capability; - bearer_qos.pre_emption_vulnerability = - sess->session.qos.arp.pre_emption_vulnerability; + /* Bearer EBI */ + rsp->bearer_contexts_created[i].presence = 1; + rsp->bearer_contexts_created[i].eps_bearer_id.presence = 1; + rsp->bearer_contexts_created[i].eps_bearer_id.u8 = bearer->ebi; - rsp->bearer_contexts_created.bearer_level_qos.presence = 1; - ogs_gtp2_build_bearer_qos(&rsp->bearer_contexts_created.bearer_level_qos, - &bearer_qos, bearer_qos_buf, GTP2_BEARER_QOS_LEN); - } + /* Bearer Cause */ + memset(&bearer_cause[i], 0, sizeof(bearer_cause[i])); + rsp->bearer_contexts_created[i].cause.presence = 1; + rsp->bearer_contexts_created[i].cause.len = sizeof(bearer_cause[i]); + rsp->bearer_contexts_created[i].cause.data = &bearer_cause[i]; + bearer_cause[i].value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; - /* Bearer Charging ID */ - rsp->bearer_contexts_created.charging_id.presence = 1; - rsp->bearer_contexts_created.charging_id.u32 = sess->charging.id; + /* Bearer QoS + * if PCRF changes Bearer QoS, this should be included. */ + if (sess->gtp.create_session_response_bearer_qos == true) { + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = sess->session.qos.index; + bearer_qos.priority_level = sess->session.qos.arp.priority_level; + bearer_qos.pre_emption_capability = + sess->session.qos.arp.pre_emption_capability; + bearer_qos.pre_emption_vulnerability = + sess->session.qos.arp.pre_emption_vulnerability; - /* Data Plane(UL) : SMF-S5U */ - memset(&pgw_s5u_teid, 0, sizeof(ogs_gtp2_f_teid_t)); - pgw_s5u_teid.teid = htobe32(bearer->pgw_s5u_teid); - ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); - rv = ogs_gtp2_sockaddr_to_f_teid( - bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, &pgw_s5u_teid, &len); - ogs_expect_or_return_val(rv == OGS_OK, NULL); + rsp->bearer_contexts_created[i].bearer_level_qos.presence = 1; + ogs_gtp2_build_bearer_qos( + &rsp->bearer_contexts_created[i].bearer_level_qos, + &bearer_qos, bearer_qos_buf[i], GTP2_BEARER_QOS_LEN); + } - switch (sess->gtp_rat_type) { - case OGS_GTP2_RAT_TYPE_EUTRAN: - pgw_s5u_teid.interface_type = OGS_GTP2_F_TEID_S5_S8_PGW_GTP_U; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.presence = 1; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.data = &pgw_s5u_teid; - rsp->bearer_contexts_created.s5_s8_u_sgw_f_teid.len = len; - break; - case OGS_GTP2_RAT_TYPE_WLAN: - pgw_s5u_teid.interface_type = OGS_GTP2_F_TEID_S2B_U_PGW_GTP_U; - rsp->bearer_contexts_created.s12_rnc_f_teid.presence = 1; - rsp->bearer_contexts_created.s12_rnc_f_teid.data = &pgw_s5u_teid; - rsp->bearer_contexts_created.s12_rnc_f_teid.len = len; - break; - default: - ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); - ogs_assert_if_reached(); + /* Bearer Charging ID */ + rsp->bearer_contexts_created[i].charging_id.presence = 1; + rsp->bearer_contexts_created[i].charging_id.u32 = sess->charging.id; + + /* Data Plane(UL) : SMF-S5U */ + memset(&pgw_s5u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + pgw_s5u_teid[i].teid = htobe32(bearer->pgw_s5u_teid); + ogs_assert(bearer->pgw_s5u_addr || bearer->pgw_s5u_addr6); + rv = ogs_gtp2_sockaddr_to_f_teid( + bearer->pgw_s5u_addr, bearer->pgw_s5u_addr6, + &pgw_s5u_teid[i], &pgw_s5u_len[i]); + ogs_expect_or_return_val(rv == OGS_OK, NULL); + + switch (sess->gtp_rat_type) { + case OGS_GTP2_RAT_TYPE_EUTRAN: + pgw_s5u_teid[i].interface_type = OGS_GTP2_F_TEID_S5_S8_PGW_GTP_U; + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.presence = 1; + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.data = + &pgw_s5u_teid[i]; + rsp->bearer_contexts_created[i].s5_s8_u_sgw_f_teid.len = + pgw_s5u_len[i]; + break; + case OGS_GTP2_RAT_TYPE_WLAN: + pgw_s5u_teid[i].interface_type = OGS_GTP2_F_TEID_S2B_U_PGW_GTP_U; + rsp->bearer_contexts_created[i].s12_rnc_f_teid.presence = 1; + rsp->bearer_contexts_created[i].s12_rnc_f_teid.data = + &pgw_s5u_teid[i]; + rsp->bearer_contexts_created[i].s12_rnc_f_teid.len = + pgw_s5u_len[i]; + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + + i++; } gtp_message.h.type = type; @@ -208,7 +225,7 @@ ogs_pkbuf_t *smf_s5c_build_delete_session_response( ogs_gtp2_cause_t cause; uint8_t pco_buf[OGS_MAX_PCO_LEN]; int16_t pco_len; - + /* prepare cause */ memset(&cause, 0, sizeof(cause)); cause.value = OGS_GTP2_CAUSE_REQUEST_ACCEPTED; @@ -243,14 +260,21 @@ ogs_pkbuf_t *smf_s5c_build_delete_session_response( ogs_pkbuf_t *smf_s5c_build_modify_bearer_response( uint8_t type, smf_sess_t *sess, - ogs_gtp2_modify_bearer_request_t *req) + ogs_gtp2_modify_bearer_request_t *req, bool sgw_relocation) { + int i; + ogs_gtp2_message_t gtp_message; ogs_gtp2_modify_bearer_response_t *rsp = NULL; ogs_gtp2_cause_t cause; + smf_ue_t *smf_ue = NULL; + smf_bearer_t *bearer = NULL; + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); ogs_assert(req); rsp = >p_message.modify_bearer_response; @@ -263,19 +287,42 @@ ogs_pkbuf_t *smf_s5c_build_modify_bearer_response( rsp->cause.data = &cause; rsp->cause.len = sizeof(cause); - rsp->bearer_contexts_modified[0].presence = 1; - rsp->bearer_contexts_modified[0].eps_bearer_id.presence = 1; - rsp->bearer_contexts_modified[0].eps_bearer_id.u8 = - req->bearer_contexts_to_be_modified[0].eps_bearer_id.u8; - rsp->bearer_contexts_modified[0].s1_u_enodeb_f_teid.presence = 1; - rsp->bearer_contexts_modified[0].s1_u_enodeb_f_teid.data = - req->bearer_contexts_to_be_modified[0].s1_u_enodeb_f_teid.data; - rsp->bearer_contexts_modified[0].s1_u_enodeb_f_teid.len = - req->bearer_contexts_to_be_modified[0].s1_u_enodeb_f_teid.len; + if (sgw_relocation == true) { - rsp->bearer_contexts_modified[0].cause.presence = 1; - rsp->bearer_contexts_modified[0].cause.len = sizeof(cause); - rsp->bearer_contexts_modified[0].cause.data = &cause; + if (smf_ue->msisdn_len) { + rsp->msisdn.presence = 1; + rsp->msisdn.len = smf_ue->msisdn_len; + rsp->msisdn.data = smf_ue->msisdn; + } + + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (req->bearer_contexts_to_be_modified[i].presence == 0) + break; + if (req->bearer_contexts_to_be_modified[i]. + eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + + bearer = smf_bearer_find_by_ebi(sess, + req->bearer_contexts_to_be_modified[i].eps_bearer_id.u8); + if (!bearer) { + ogs_error("Unknown EPS Bearer ID[%d]", + req->bearer_contexts_to_be_modified[i].eps_bearer_id.u8); + break; + } + + rsp->bearer_contexts_modified[i].presence = 1; + rsp->bearer_contexts_modified[i].eps_bearer_id.presence = 1; + rsp->bearer_contexts_modified[i].eps_bearer_id.u8 = + req->bearer_contexts_to_be_modified[i].eps_bearer_id.u8; + + rsp->bearer_contexts_modified[i].charging_id.presence = 1; + rsp->bearer_contexts_modified[i].charging_id.u32 = + sess->charging.id; + } + + } /* build */ gtp_message.h.type = type; @@ -310,7 +357,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request( req = >p_message.create_bearer_request; memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); - + /* Linked EBI */ req->linked_eps_bearer_id.presence = 1; req->linked_eps_bearer_id.u8 = linked_bearer->ebi; @@ -336,7 +383,7 @@ ogs_pkbuf_t *smf_s5c_build_create_bearer_request( memset(&bearer_qos, 0, sizeof(bearer_qos)); bearer_qos.qci = bearer->qos.index; bearer_qos.priority_level = bearer->qos.arp.priority_level; - bearer_qos.pre_emption_capability = + bearer_qos.pre_emption_capability = bearer->qos.arp.pre_emption_capability; bearer_qos.pre_emption_vulnerability = bearer->qos.arp.pre_emption_vulnerability; @@ -383,7 +430,7 @@ ogs_pkbuf_t *smf_s5c_build_update_bearer_request( sess->sgw_s5c_teid, sess->smf_n4_teid); req = >p_message.update_bearer_request; memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); - + /* Bearer EBI */ req->bearer_contexts.presence = 1; req->bearer_contexts.eps_bearer_id.presence = 1; @@ -416,7 +463,7 @@ ogs_pkbuf_t *smf_s5c_build_update_bearer_request( memset(&bearer_qos, 0, sizeof(bearer_qos)); bearer_qos.qci = bearer->qos.index; bearer_qos.priority_level = bearer->qos.arp.priority_level; - bearer_qos.pre_emption_capability = + bearer_qos.pre_emption_capability = bearer->qos.arp.pre_emption_capability; bearer_qos.pre_emption_vulnerability = bearer->qos.arp.pre_emption_vulnerability; @@ -463,7 +510,7 @@ ogs_pkbuf_t *smf_s5c_build_delete_bearer_request( sess->sgw_s5c_teid, sess->smf_n4_teid); req = >p_message.delete_bearer_request; memset(>p_message, 0, sizeof(ogs_gtp2_message_t)); - + if (bearer->ebi == linked_bearer->ebi) { /* * << Linked EPS Bearer ID >> diff --git a/src/smf/s5c-build.h b/src/smf/s5c-build.h index f35bd6c7f..7f4c3e029 100644 --- a/src/smf/s5c-build.h +++ b/src/smf/s5c-build.h @@ -33,7 +33,7 @@ ogs_pkbuf_t *smf_s5c_build_delete_session_response( ogs_pkbuf_t *smf_s5c_build_modify_bearer_response( uint8_t type, smf_sess_t *sess, - ogs_gtp2_modify_bearer_request_t *req); + ogs_gtp2_modify_bearer_request_t *req, bool sgw_relocation); ogs_pkbuf_t *smf_s5c_build_create_bearer_request( uint8_t type, smf_bearer_t *bearer, ogs_gtp2_tft_t *tft); diff --git a/src/smf/s5c-handler.c b/src/smf/s5c-handler.c index f70fe1549..4519d7a5c 100644 --- a/src/smf/s5c-handler.c +++ b/src/smf/s5c-handler.c @@ -52,7 +52,7 @@ uint8_t smf_s5c_handle_create_session_request( char buf1[OGS_ADDRSTRLEN]; char buf2[OGS_ADDRSTRLEN]; - int rv; + int i, rv; uint8_t cause_value = 0; ogs_gtp2_uli_t uli; @@ -82,15 +82,15 @@ uint8_t smf_s5c_handle_create_session_request( ogs_error("No TEID"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.presence == 0) { + if (req->bearer_contexts_to_be_created[0].presence == 0) { ogs_error("No Bearer"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.eps_bearer_id.presence == 0) { + if (req->bearer_contexts_to_be_created[0].eps_bearer_id.presence == 0) { ogs_error("No EPS Bearer ID"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } - if (req->bearer_contexts_to_be_created.bearer_level_qos.presence == 0) { + if (req->bearer_contexts_to_be_created[0].bearer_level_qos.presence == 0) { ogs_error("No EPS Bearer QoS"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; } @@ -118,7 +118,7 @@ uint8_t smf_s5c_handle_create_session_request( } switch (sess->gtp_rat_type) { case OGS_GTP2_RAT_TYPE_EUTRAN: - if (req->bearer_contexts_to_be_created. + if (req->bearer_contexts_to_be_created[0]. s5_s8_u_sgw_f_teid.presence == 0) { ogs_error("No S5/S8 SGW GTP-U TEID"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; @@ -133,7 +133,7 @@ uint8_t smf_s5c_handle_create_session_request( ogs_error("No S6b Diameter Peer"); cause_value = OGS_GTP2_CAUSE_REMOTE_PEER_NOT_RESPONDING; } - if (req->bearer_contexts_to_be_created. + if (req->bearer_contexts_to_be_created[0]. s2b_u_epdg_f_teid_5.presence == 0) { ogs_error("No S2b ePDG GTP-U TEID"); cause_value = OGS_GTP2_CAUSE_MANDATORY_IE_MISSING; @@ -248,51 +248,68 @@ uint8_t smf_s5c_handle_create_session_request( /* Remove all previous bearer */ smf_bearer_remove_all(sess); - /* Setup Default Bearer */ - bearer = smf_bearer_add(sess); - ogs_assert(bearer); + /* Setup Bearer */ + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (req->bearer_contexts_to_be_created[i].presence == 0) + break; + if (req->bearer_contexts_to_be_created[i].eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + if (req->bearer_contexts_to_be_created[i]. + bearer_level_qos.presence == 0) { + ogs_error("No Bearer QoS"); + break; + } - /* Set Bearer EBI */ - bearer->ebi = req->bearer_contexts_to_be_created.eps_bearer_id.u8; + decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, + &req->bearer_contexts_to_be_created[i].bearer_level_qos); + ogs_assert(decoded == + req->bearer_contexts_to_be_created[i].bearer_level_qos.len); - switch (sess->gtp_rat_type) { - case OGS_GTP2_RAT_TYPE_EUTRAN: - sgw_s5u_teid = req->bearer_contexts_to_be_created. - s5_s8_u_sgw_f_teid.data; - ogs_assert(sgw_s5u_teid); - bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); - rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); - ogs_assert(rv == OGS_OK); + bearer = smf_bearer_add(sess); + ogs_assert(bearer); - break; - case OGS_GTP2_RAT_TYPE_WLAN: - sgw_s5u_teid = req->bearer_contexts_to_be_created. - s2b_u_epdg_f_teid_5.data; - ogs_assert(sgw_s5u_teid); - bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); - rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); - ogs_assert(rv == OGS_OK); - break; - default: - ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); - ogs_assert_if_reached(); + /* Set Bearer EBI */ + bearer->ebi = req->bearer_contexts_to_be_created[i].eps_bearer_id.u8; + + switch (sess->gtp_rat_type) { + case OGS_GTP2_RAT_TYPE_EUTRAN: + sgw_s5u_teid = req->bearer_contexts_to_be_created[i]. + s5_s8_u_sgw_f_teid.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); + ogs_assert(rv == OGS_OK); + + break; + case OGS_GTP2_RAT_TYPE_WLAN: + sgw_s5u_teid = req->bearer_contexts_to_be_created[i]. + s2b_u_epdg_f_teid_5.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); + ogs_assert(rv == OGS_OK); + break; + default: + ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); + ogs_assert_if_reached(); + } + + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", + bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); + + /* Set Session QoS from Default Bearer Level QoS */ + if (i == 0) { + sess->session.qos.index = bearer_qos.qci; + sess->session.qos.arp.priority_level = bearer_qos.priority_level; + sess->session.qos.arp.pre_emption_capability = + bearer_qos.pre_emption_capability; + sess->session.qos.arp.pre_emption_vulnerability = + bearer_qos.pre_emption_vulnerability; + } } - ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", - bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); - - /* Set Bearer QoS */ - decoded = ogs_gtp2_parse_bearer_qos(&bearer_qos, - &req->bearer_contexts_to_be_created.bearer_level_qos); - ogs_assert(req->bearer_contexts_to_be_created.bearer_level_qos.len == - decoded); - sess->session.qos.index = bearer_qos.qci; - sess->session.qos.arp.priority_level = bearer_qos.priority_level; - sess->session.qos.arp.pre_emption_capability = - bearer_qos.pre_emption_capability; - sess->session.qos.arp.pre_emption_vulnerability = - bearer_qos.pre_emption_vulnerability; - /* Set AMBR if available */ if (req->aggregate_maximum_bit_rate.presence) { /* @@ -324,6 +341,15 @@ uint8_t smf_s5c_handle_create_session_request( OGS_TLV_STORE_DATA(&sess->gtp.ue_timezone, &req->ue_time_zone); } + /* Set MSISDN */ + if (req->msisdn.presence && req->msisdn.len && req->msisdn.data) { + smf_ue->msisdn_len = req->msisdn.len; + memcpy(smf_ue->msisdn, req->msisdn.data, + ogs_min(smf_ue->msisdn_len, OGS_MAX_MSISDN_LEN)); + ogs_buffer_to_bcd(smf_ue->msisdn, + smf_ue->msisdn_len, smf_ue->msisdn_bcd); + } + return OGS_GTP2_CAUSE_REQUEST_ACCEPTED; } @@ -356,17 +382,14 @@ uint8_t smf_s5c_handle_delete_session_request( void smf_s5c_handle_modify_bearer_request( smf_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_gtp2_modify_bearer_request_t *req) + ogs_pkbuf_t *gtpbuf, ogs_gtp2_modify_bearer_request_t *req) { - int rv; + int rv, i; uint8_t cause_value = 0; - ogs_gtp2_indication_t *indication = NULL; - - ogs_gtp2_header_t h; - ogs_pkbuf_t *pkbuf = NULL; + uint64_t flags = 0; smf_ue_t *smf_ue = NULL; - smf_sess_t *wlan_sess = NULL; + smf_bearer_t *bearer = NULL; ogs_debug("Modify Bearer Request"); @@ -405,69 +428,109 @@ void smf_s5c_handle_modify_bearer_request( rv = ogs_gtp2_f_teid_to_ip(sgw_s5c_teid, &sess->sgw_s5c_ip); ogs_assert(rv == OGS_OK); + OGS_SETUP_GTP_NODE(sess, xact->gnode); + ogs_debug(" SGW_S5C_TEID[0x%x] SMF_N4_TEID[0x%x]", sess->sgw_s5c_teid, sess->smf_n4_teid); } -#if 0 /* TODO */ - switch (sess->gtp_rat_type) { - case OGS_GTP2_RAT_TYPE_EUTRAN: - sgw_s5u_teid = req->bearer_contexts_to_be_created. - s5_s8_u_sgw_f_teid.data; - ogs_assert(sgw_s5u_teid); - bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); - rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); - ogs_assert(rv == OGS_OK); + /* Check Modify Bearer */ + ogs_list_init(&sess->qos_flow_to_modify_list); - break; - case OGS_GTP2_RAT_TYPE_WLAN: - sgw_s5u_teid = req->bearer_contexts_to_be_created. - s2b_u_epdg_f_teid_5.data; - ogs_assert(sgw_s5u_teid); - bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); - rv = ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &bearer->sgw_s5u_ip); - ogs_assert(rv == OGS_OK); - break; - default: - ogs_error("Unknown RAT Type [%d]", sess->gtp_rat_type); - ogs_assert_if_reached(); + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (req->bearer_contexts_to_be_modified[i].presence == 0) + break; + if (req->bearer_contexts_to_be_modified[i]. + eps_bearer_id.presence == 0) { + ogs_error("No EPS Bearer ID"); + break; + } + /* EPS Bearer ID */ + bearer = smf_bearer_find_by_ebi(sess, + req->bearer_contexts_to_be_modified[i].eps_bearer_id.u8); + if (!bearer) { + ogs_error("No Bearer Context"); + break; + } + + if (req->bearer_contexts_to_be_modified[i].s4_u_sgsn_f_teid.presence) { + ogs_pfcp_far_t *far = NULL; + ogs_gtp2_f_teid_t *sgw_s5u_teid = NULL; + + ogs_ip_t remote_ip; + ogs_ip_t zero_ip; + + /* Data Plane(DL) : SGW-S5U */ + sgw_s5u_teid = req->bearer_contexts_to_be_modified[i]. + s4_u_sgsn_f_teid.data; + ogs_assert(sgw_s5u_teid); + bearer->sgw_s5u_teid = be32toh(sgw_s5u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(sgw_s5u_teid, &remote_ip)); + + memset(&zero_ip, 0, sizeof(ogs_ip_t)); + if (memcmp(&bearer->sgw_s5u_ip, &zero_ip, sizeof(ogs_ip_t)) != 0 && + memcmp(&bearer->sgw_s5u_ip, + &remote_ip, sizeof(ogs_ip_t)) != 0) { + + ogs_assert(sess->pfcp_node); + + /* eNB IP is changed during handover */ + if (sess->pfcp_node->up_function_features.empu) { + flags |= OGS_PFCP_MODIFY_END_MARKER; + } else { + ogs_error("UPF does not support End Marker"); + } + } + + memcpy(&bearer->sgw_s5u_ip, &remote_ip, sizeof(ogs_ip_t)); + + far = bearer->dl_far; + ogs_assert(far); + + far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + + ogs_assert(OGS_OK == + ogs_pfcp_ip_to_outer_header_creation( + &bearer->sgw_s5u_ip, + &far->outer_header_creation, + &far->outer_header_creation_len)); + far->outer_header_creation.teid = bearer->sgw_s5u_teid; + + ogs_list_add(&sess->qos_flow_to_modify_list, + &bearer->to_modify_node); + + ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", + bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); + } } - ogs_debug(" SGW_S5U_TEID[0x%x] PGW_S5U_TEID[0x%x]", - bearer->sgw_s5u_teid, bearer->pgw_s5u_teid); -#endif + if (ogs_list_count(&sess->qos_flow_to_modify_list)) { - memset(&h, 0, sizeof(ogs_gtp2_header_t)); - h.type = OGS_GTP2_MODIFY_BEARER_RESPONSE_TYPE; - h.teid = sess->sgw_s5c_teid; + /* Need to modify SGW-S5U */ + rv = smf_epc_pfcp_send_session_modification_request(sess, xact, gtpbuf, + flags|OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE, + OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, + OGS_GTP2_CAUSE_UNDEFINED_VALUE); + ogs_assert(rv == OGS_OK); - pkbuf = smf_s5c_build_modify_bearer_response(h.type, sess, req); - ogs_expect_or_return(pkbuf); + } else { - rv = ogs_gtp_xact_update_tx(xact, &h, pkbuf); - ogs_expect_or_return(rv == OGS_OK); - - rv = ogs_gtp_xact_commit(xact); - ogs_expect(rv == OGS_OK); - - if (req->indication_flags.presence && - req->indication_flags.data && req->indication_flags.len) { - indication = req->indication_flags.data; - } - - if (indication && indication->handover_indication) { - ogs_assert(sess->session.name); - wlan_sess = smf_sess_find_by_apn( - smf_ue, sess->session.name, OGS_GTP2_RAT_TYPE_WLAN); - ogs_expect_or_return(wlan_sess); - ogs_expect_or_return(ogs_list_first(&wlan_sess->bearer_list)); + /* Check if Handover from Non-3GPP to 3GPP */ + ogs_gtp2_indication_t *indication = NULL; ogs_assert(OGS_OK == - smf_epc_pfcp_send_session_modification_request( - wlan_sess, NULL, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, - OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED, - OGS_GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP)); + smf_gtp2_send_modify_bearer_response(sess, xact, req, false)); + + if (req->indication_flags.presence && + req->indication_flags.data && req->indication_flags.len) { + indication = req->indication_flags.data; + } + + if (indication && indication->handover_indication) { + ogs_assert(OGS_OK == smf_epc_pfcp_send_deactivation(sess, + OGS_GTP2_CAUSE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP)); + } } } diff --git a/src/smf/s5c-handler.h b/src/smf/s5c-handler.h index b45e70199..f57e8b2b4 100644 --- a/src/smf/s5c-handler.h +++ b/src/smf/s5c-handler.h @@ -39,7 +39,7 @@ uint8_t smf_s5c_handle_delete_session_request( ogs_gtp2_delete_session_request_t *req); void smf_s5c_handle_modify_bearer_request( smf_sess_t *sess, ogs_gtp_xact_t *xact, - ogs_gtp2_modify_bearer_request_t *req); + ogs_pkbuf_t *gtpbuf, ogs_gtp2_modify_bearer_request_t *req); void smf_s5c_handle_create_bearer_response( smf_sess_t *sess, ogs_gtp_xact_t *xact, ogs_gtp2_create_bearer_response_t *req); diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index f7ced1142..e42ae0fba 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -103,17 +103,8 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) } e->gtp2_message = >p2_message; - if (gtp2_message.h.teid != 0) { - sess = smf_sess_find_by_teid(gtp2_message.h.teid); - } - - if (sess) { - gnode = sess->gnode; - ogs_assert(gnode); - } else { - gnode = e->gnode; - ogs_assert(gnode); - } + gnode = e->gnode; + ogs_assert(gnode); rv = ogs_gtp_xact_receive(gnode, >p2_message.h, >p_xact); if (rv != OGS_OK) { @@ -122,6 +113,10 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) } e->gtp_xact = gtp_xact; + if (gtp2_message.h.teid != 0) { + sess = smf_sess_find_by_teid(gtp2_message.h.teid); + } + switch(gtp2_message.h.type) { case OGS_GTP2_ECHO_REQUEST_TYPE: smf_s5c_handle_echo_request(gtp_xact, >p2_message.echo_request); @@ -157,7 +152,7 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) break; case OGS_GTP2_MODIFY_BEARER_REQUEST_TYPE: smf_s5c_handle_modify_bearer_request( - sess, gtp_xact, >p2_message.modify_bearer_request); + sess, gtp_xact, recvbuf, >p2_message.modify_bearer_request); break; case OGS_GTP2_CREATE_BEARER_RESPONSE_TYPE: smf_s5c_handle_create_bearer_response( @@ -202,13 +197,8 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) sess = smf_sess_find_by_teid(gtp1_message.h.teid); } - if (sess) { - gnode = sess->gnode; - ogs_assert(gnode); - } else { - gnode = e->gnode; - ogs_assert(gnode); - } + gnode = e->gnode; + ogs_assert(gnode); rv = ogs_gtp1_xact_receive(gnode, >p1_message.h, >p_xact); if (rv != OGS_OK) { @@ -380,6 +370,13 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) e->pfcp_message = &pfcp_message; e->pfcp_xact = pfcp_xact; + + e->gtp2_message = NULL; + if (pfcp_xact->gtpbuf) { + rv = ogs_gtp2_parse_msg(>p2_message, pfcp_xact->gtpbuf); + e->gtp2_message = >p2_message; + } + ogs_fsm_dispatch(&pfcp_node->sm, e); if (OGS_FSM_CHECK(&pfcp_node->sm, smf_pfcp_state_exception)) { ogs_error("PFCP state machine exception"); diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index 7292d6175..d1f8c4873 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -179,7 +179,8 @@ static void _gtpv1_tun_recv_common_cb( for (i = 0; i < pdr->num_of_urr; i++) upf_sess_urr_acc_add(sess, pdr->urr[i], recvbuf->len, false); - ogs_assert(true == ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report)); + ogs_assert(true == ogs_pfcp_up_handle_pdr( + pdr, OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); if (report.type.downlink_data_report) { ogs_assert(pdr->sess); @@ -539,7 +540,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ogs_warn("ogs_tun_write() failed"); } else if (far->dst_if == OGS_PFCP_INTERFACE_ACCESS) { - ogs_assert(true == ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report)); + ogs_assert(true == ogs_pfcp_up_handle_pdr( + pdr, gtp_h->type, pkbuf, &report)); if (report.type.downlink_data_report) { ogs_error("Indirect Data Fowarding Buffered"); @@ -565,7 +567,8 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) goto cleanup; } - ogs_assert(true == ogs_pfcp_up_handle_pdr(pdr, pkbuf, &report)); + ogs_assert(true == ogs_pfcp_up_handle_pdr( + pdr, gtp_h->type, pkbuf, &report)); ogs_assert(report.type.downlink_data_report == 0); @@ -755,7 +758,8 @@ static void upf_gtp_handle_multicast(ogs_pkbuf_t *recvbuf) ogs_list_for_each(&sess->pfcp.pdr_list, pdr) { if (pdr->src_if == OGS_PFCP_INTERFACE_CORE) { ogs_assert(true == - ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report)); + ogs_pfcp_up_handle_pdr(pdr, + OGS_GTPU_MSGTYPE_GPDU, recvbuf, &report)); break; } } diff --git a/tests/app/app-init.c b/tests/app/app-init.c index 12cd78712..623c3f732 100644 --- a/tests/app/app-init.c +++ b/tests/app/app-init.c @@ -43,7 +43,7 @@ int app_initialize(const char *const argv[]) for (i = 0; argv[i]; i++) { if (strcmp("-c", argv[i]) == 0) { - user_config = true; + user_config = true; } argv_out[i] = argv[i]; } diff --git a/tests/common/s1ap-handler.c b/tests/common/s1ap-handler.c index 6ddd4048d..5281794eb 100644 --- a/tests/common/s1ap-handler.c +++ b/tests/common/s1ap-handler.c @@ -400,6 +400,78 @@ void tests1ap_handle_handover_request( test_ue->mme_ue_s1ap_id = *MME_UE_S1AP_ID; } +void tests1ap_handle_path_switch_request_ack( + test_ue_t *test_ue, ogs_s1ap_message_t *message) +{ + int rv, i; + char buf[OGS_ADDRSTRLEN]; + + test_sess_t *sess = NULL; + test_bearer_t *bearer = NULL; + + S1AP_S1AP_PDU_t pdu; + S1AP_SuccessfulOutcome_t *successfulOutcome = NULL; + S1AP_PathSwitchRequestAcknowledge_t *PathSwitchRequestAcknowledge = NULL; + + S1AP_PathSwitchRequestAcknowledgeIEs_t *ie = NULL; + S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL; + S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL; + S1AP_E_RABToBeSwitchedULList_t *E_RABToBeSwitchedULList = NULL; + + ogs_assert(test_ue); + ogs_assert(message); + + successfulOutcome = message->choice.successfulOutcome; + ogs_assert(successfulOutcome); + PathSwitchRequestAcknowledge = &successfulOutcome->value.choice.PathSwitchRequestAcknowledge; + ogs_assert(PathSwitchRequestAcknowledge); + + for (i = 0; i < PathSwitchRequestAcknowledge->protocolIEs.list.count; i++) { + ie = PathSwitchRequestAcknowledge->protocolIEs.list.array[i]; + switch (ie->id) { + case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID: + MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID; + break; + case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID: + ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID; + break; + case S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedULList: + E_RABToBeSwitchedULList = + &ie->value.choice.E_RABToBeSwitchedULList; + break; + default: + break; + } + } + + if (MME_UE_S1AP_ID) + test_ue->mme_ue_s1ap_id = *MME_UE_S1AP_ID; + if (ENB_UE_S1AP_ID) + test_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID; + + if (E_RABToBeSwitchedULList) { + for (i = 0; i < E_RABToBeSwitchedULList->list.count; i++) { + S1AP_E_RABToBeSwitchedULItemIEs_t *ie2 = NULL; + S1AP_E_RABToBeSwitchedULItem_t *e_rab = NULL; + + ie2 = (S1AP_E_RABToBeSwitchedULItemIEs_t *) + E_RABToBeSwitchedULList->list.array[i]; + ogs_assert(ie2); + e_rab = &ie2->value.choice.E_RABToBeSwitchedULItem; + + bearer = test_bearer_find_by_ue_ebi(test_ue, e_rab->e_RAB_ID); + ogs_assert(bearer); + + memcpy(&bearer->sgw_s1u_teid, e_rab->gTP_TEID.buf, + sizeof(bearer->sgw_s1u_teid)); + bearer->sgw_s1u_teid = be32toh(bearer->sgw_s1u_teid); + rv = ogs_asn_BIT_STRING_to_ip( + &e_rab->transportLayerAddress, &bearer->sgw_s1u_ip); + ogs_assert(rv == OGS_OK); + } + } +} + void tests1ap_handle_handover_command( test_ue_t *test_ue, ogs_s1ap_message_t *message) { diff --git a/tests/common/s1ap-handler.h b/tests/common/s1ap-handler.h index 73d528e4f..5f0d9c39f 100644 --- a/tests/common/s1ap-handler.h +++ b/tests/common/s1ap-handler.h @@ -38,6 +38,8 @@ void tests1ap_handle_e_rab_modify_request( void tests1ap_handle_e_rab_release_command( test_ue_t *test_ue, ogs_s1ap_message_t *message); +void tests1ap_handle_path_switch_request_ack( + test_ue_t *test_ue, ogs_s1ap_message_t *message); void tests1ap_handle_handover_request( test_ue_t *test_ue, ogs_s1ap_message_t *message); void tests1ap_handle_handover_command( diff --git a/tests/common/s1ap-path.c b/tests/common/s1ap-path.c index 79e788f4d..770efd0e4 100644 --- a/tests/common/s1ap-path.c +++ b/tests/common/s1ap-path.c @@ -97,6 +97,7 @@ void tests1ap_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) tests1ap_handle_s1_setup_response(pdu); break; case S1AP_ProcedureCode_id_PathSwitchRequest: + tests1ap_handle_path_switch_request_ack(test_ue, pdu); break; case S1AP_ProcedureCode_id_HandoverPreparation: tests1ap_handle_handover_command(test_ue, pdu); diff --git a/tests/non3gpp/s2b-build.c b/tests/non3gpp/s2b-build.c index 23a2e3837..20efd661c 100644 --- a/tests/non3gpp/s2b-build.c +++ b/tests/non3gpp/s2b-build.c @@ -27,20 +27,21 @@ ogs_pkbuf_t *test_s2b_build_create_session_request( test_ue_t *test_ue = NULL; test_bearer_t *bearer = NULL; ogs_gtp2_message_t gtp_message; - ogs_gtp2_create_session_request_t *req = >p_message.create_session_request; + ogs_gtp2_create_session_request_t *req = + >p_message.create_session_request; uint8_t msisdn_buf[OGS_MAX_MSISDN_LEN]; int msisdn_len; ogs_gtp2_uli_t uli; char uli_buf[OGS_GTP2_MAX_ULI_LEN]; - ogs_gtp2_f_teid_t test_s2b_c_teid, test_s2b_u_teid; - int len; + ogs_gtp2_f_teid_t test_s2b_c_teid, test_s2b_u_teid[OGS_BEARER_PER_UE]; + int len, test_s2b_u_len; ogs_paa_t paa; ogs_gtp2_ambr_t ambr; ogs_gtp2_bearer_qos_t bearer_qos; - char bearer_qos_buf[GTP2_BEARER_QOS_LEN]; + char bearer_qos_buf[OGS_BEARER_PER_UE][GTP2_BEARER_QOS_LEN]; char apn[OGS_MAX_APN_LEN+1]; ogs_gtp2_indication_t indication; @@ -84,7 +85,7 @@ ogs_pkbuf_t *test_s2b_build_create_session_request( ogs_nas_from_plmn_id(&uli.e_cgi.nas_plmn_id, &test_ue->e_cgi.plmn_id); uli.e_cgi.cell_id = test_ue->e_cgi.cell_id; req->user_location_information.presence = 1; - ogs_gtp2_build_uli(&req->user_location_information, &uli, + ogs_gtp2_build_uli(&req->user_location_information, &uli, uli_buf, OGS_GTP2_MAX_ULI_LEN); req->serving_network.presence = 1; @@ -111,7 +112,7 @@ ogs_pkbuf_t *test_s2b_build_create_session_request( req->access_point_name.data = apn; req->selection_mode.presence = 1; - req->selection_mode.u8 = + req->selection_mode.u8 = OGS_GTP2_SELECTION_MODE_MS_OR_NETWORK_PROVIDED_APN; memset(&paa, 0, sizeof(paa)); @@ -128,31 +129,40 @@ ogs_pkbuf_t *test_s2b_build_create_session_request( req->aggregate_maximum_bit_rate.data = &ambr; req->aggregate_maximum_bit_rate.len = sizeof(ambr); - req->bearer_contexts_to_be_created.presence = 1; - req->bearer_contexts_to_be_created.eps_bearer_id.presence = 1; - req->bearer_contexts_to_be_created.eps_bearer_id.u8 = bearer->ebi; + int i = 0; + ogs_list_for_each(&sess->bearer_list, bearer) { + ogs_assert(i < OGS_BEARER_PER_UE); - memset(&test_s2b_u_teid, 0, sizeof(ogs_gtp2_f_teid_t)); - test_s2b_u_teid.teid = htobe32(bearer->enb_s1u_teid); - test_s2b_u_teid.interface_type = OGS_GTP2_F_TEID_S2B_U_EPDG_GTP_U; - ogs_assert(sess->gnode->sock); - rv = ogs_gtp2_sockaddr_to_f_teid( - &sess->gnode->sock->local_addr, NULL, &test_s2b_u_teid, &len); + req->bearer_contexts_to_be_created[i].presence = 1; + req->bearer_contexts_to_be_created[i].eps_bearer_id.presence = 1; + req->bearer_contexts_to_be_created[i].eps_bearer_id.u8 = bearer->ebi; - req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.presence = 1; - req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.data = - &test_s2b_u_teid; - req->bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.len = len; + memset(&test_s2b_u_teid[i], 0, sizeof(ogs_gtp2_f_teid_t)); + test_s2b_u_teid[i].teid = htobe32(bearer->enb_s1u_teid); + test_s2b_u_teid[i].interface_type = OGS_GTP2_F_TEID_S2B_U_EPDG_GTP_U; + ogs_assert(sess->gnode->sock); + rv = ogs_gtp2_sockaddr_to_f_teid( + &sess->gnode->sock->local_addr, NULL, + &test_s2b_u_teid[i], &test_s2b_u_len); - memset(&bearer_qos, 0, sizeof(bearer_qos)); - bearer_qos.qci = 8; - bearer_qos.priority_level = 1; - bearer_qos.pre_emption_capability = 0; - bearer_qos.pre_emption_vulnerability = 0; - req->bearer_contexts_to_be_created.bearer_level_qos.presence = 1; - ogs_gtp2_build_bearer_qos( - &req->bearer_contexts_to_be_created.bearer_level_qos, - &bearer_qos, bearer_qos_buf, GTP2_BEARER_QOS_LEN); + req->bearer_contexts_to_be_created[i].s2b_u_epdg_f_teid_5.presence = 1; + req->bearer_contexts_to_be_created[i].s2b_u_epdg_f_teid_5.data = + &test_s2b_u_teid[i]; + req->bearer_contexts_to_be_created[i].s2b_u_epdg_f_teid_5.len = + test_s2b_u_len; + + memset(&bearer_qos, 0, sizeof(bearer_qos)); + bearer_qos.qci = 8; + bearer_qos.priority_level = 1; + bearer_qos.pre_emption_capability = 0; + bearer_qos.pre_emption_vulnerability = 0; + req->bearer_contexts_to_be_created[i].bearer_level_qos.presence = 1; + ogs_gtp2_build_bearer_qos( + &req->bearer_contexts_to_be_created[i].bearer_level_qos, + &bearer_qos, bearer_qos_buf[i], GTP2_BEARER_QOS_LEN); + + i++; + } req->recovery.presence = 1; req->recovery.u8 = 66; diff --git a/tests/non3gpp/s2b-handler.c b/tests/non3gpp/s2b-handler.c index 16e2d1a3c..92c00f5b2 100644 --- a/tests/non3gpp/s2b-handler.c +++ b/tests/non3gpp/s2b-handler.c @@ -24,7 +24,7 @@ void test_s2b_handle_create_session_response( ogs_gtp_xact_t *xact, test_sess_t *sess, ogs_gtp2_create_session_response_t *rsp) { - int rv; + int rv, i; uint8_t cause_value; test_bearer_t *bearer = NULL; @@ -58,18 +58,6 @@ void test_s2b_handle_create_session_response( ogs_error("No S5/S8 TEID"); return; } - if (rsp->bearer_contexts_created.presence == 0) { - ogs_error("No Bearer Context"); - return; - } - if (rsp->bearer_contexts_created.eps_bearer_id.presence == 0) { - ogs_error("No EBI"); - return; - } - if (rsp->bearer_contexts_created.s12_rnc_f_teid.presence == 0) { - ogs_error("No S1U TEID"); - return; - } if (rsp->pdn_address_allocation.presence == 0) { ogs_error("No PDN Address Allocation"); return; @@ -78,22 +66,37 @@ void test_s2b_handle_create_session_response( ogs_expect( rsp->pdn_address_allocation.data && rsp->pdn_address_allocation.len); - bearer = test_bearer_find_by_sess_ebi( - sess, rsp->bearer_contexts_created.eps_bearer_id.u8); - ogs_assert(bearer); + for (i = 0; i < OGS_BEARER_PER_UE; i++) { + if (rsp->bearer_contexts_created[i].presence == 0) { + break; + } + if (rsp->bearer_contexts_created[i].eps_bearer_id.presence == 0) { + ogs_error("No EBI"); + break; + } + if (rsp->bearer_contexts_created[i].s12_rnc_f_teid.presence == 0) { + ogs_error("No S1U TEID"); + break; + } + + bearer = test_bearer_find_by_sess_ebi( + sess, rsp->bearer_contexts_created[i].eps_bearer_id.u8); + ogs_assert(bearer); + + smf_s2b_u_teid = rsp->bearer_contexts_created[i].s12_rnc_f_teid.data; + ogs_assert(smf_s2b_u_teid); + + bearer->sgw_s1u_teid = be32toh(smf_s2b_u_teid->teid); + ogs_assert(OGS_OK == + ogs_gtp2_f_teid_to_ip(smf_s2b_u_teid, &bearer->sgw_s1u_ip)); + + } smf_s2b_c_teid = rsp->pgw_s5_s8__s2a_s2b_f_teid_for_pmip_based_interface_or_for_gtp_based_control_plane_interface.data; ogs_assert(smf_s2b_c_teid); sess->smf_s2b_c_teid = be32toh(smf_s2b_c_teid->teid); - smf_s2b_u_teid = rsp->bearer_contexts_created.s12_rnc_f_teid.data; - ogs_assert(smf_s2b_u_teid); - - bearer->sgw_s1u_teid = be32toh(smf_s2b_u_teid->teid); - ogs_assert(OGS_OK == - ogs_gtp2_f_teid_to_ip(smf_s2b_u_teid, &bearer->sgw_s1u_ip)); - memcpy(&paa, rsp->pdn_address_allocation.data, rsp->pdn_address_allocation.len); diff --git a/tests/unit/gtp-message-test.c b/tests/unit/gtp-message-test.c index ce1e558a1..b5866f698 100644 --- a/tests/unit/gtp-message-test.c +++ b/tests/unit/gtp-message-test.c @@ -153,18 +153,18 @@ static void gtp_message_test1(abts_case *tc, void *data) req.protocol_configuration_options.len = ogs_pco_build(pcobuf, OGS_MAX_PCO_LEN, &pco); - req.bearer_contexts_to_be_created.presence = 1; - req.bearer_contexts_to_be_created.eps_bearer_id.presence = 1; - req.bearer_contexts_to_be_created.eps_bearer_id.u8 = 5; + req.bearer_contexts_to_be_created[0].presence = 1; + req.bearer_contexts_to_be_created[0].eps_bearer_id.presence = 1; + req.bearer_contexts_to_be_created[0].eps_bearer_id.u8 = 5; memset(&bearer_qos, 0, sizeof(bearer_qos)); bearer_qos.pre_emption_vulnerability = 1; bearer_qos.priority_level = 1; bearer_qos.pre_emption_capability = 1; bearer_qos.qci = 5; - req.bearer_contexts_to_be_created.bearer_level_qos.presence = 1; + req.bearer_contexts_to_be_created[0].bearer_level_qos.presence = 1; size = ogs_gtp2_build_bearer_qos( - &req.bearer_contexts_to_be_created.bearer_level_qos, + &req.bearer_contexts_to_be_created[0].bearer_level_qos, &bearer_qos, bearer_qos_buf, GTP2_BEARER_QOS_LEN); memset(&ue_timezone, 0, sizeof(ue_timezone)); @@ -259,38 +259,43 @@ static void gtp_message_test1(abts_case *tc, void *data) OGS_PCO_ID_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING, pco.ids[2].id); ABTS_INT_EQUAL(tc, 0, pco.ids[2].len); - ABTS_INT_EQUAL(tc, 1, req.bearer_contexts_to_be_created.presence); + ABTS_INT_EQUAL(tc, 1, req.bearer_contexts_to_be_created[0].presence); + ABTS_INT_EQUAL(tc, 0, req.bearer_contexts_to_be_created[1].presence); ABTS_INT_EQUAL(tc, 1, req. - bearer_contexts_to_be_created.eps_bearer_id.presence); + bearer_contexts_to_be_created[0].eps_bearer_id.presence); + ABTS_INT_EQUAL(tc, 0, req. + bearer_contexts_to_be_created[1].eps_bearer_id.presence); ABTS_INT_EQUAL(tc, 0x05, - req.bearer_contexts_to_be_created.eps_bearer_id.u8); + req.bearer_contexts_to_be_created[0].eps_bearer_id.u8); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.tft.presence); + bearer_contexts_to_be_created[0].tft.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.s1_u_enodeb_f_teid.presence); + bearer_contexts_to_be_created[0].s1_u_enodeb_f_teid.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.s2b_u_epdg_f_teid_5.presence); + bearer_contexts_to_be_created[0].s2b_u_epdg_f_teid_5.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.s2a_u_twan_f_teid_6.presence); + bearer_contexts_to_be_created[0].s2a_u_twan_f_teid_6.presence); ABTS_INT_EQUAL(tc, 1, req. - bearer_contexts_to_be_created.bearer_level_qos.presence); + bearer_contexts_to_be_created[0].bearer_level_qos.presence); + ABTS_INT_EQUAL(tc, 0, req. + bearer_contexts_to_be_created[1].bearer_level_qos.presence); ABTS_INT_EQUAL(tc, 22, - req.bearer_contexts_to_be_created.bearer_level_qos.len); + req.bearer_contexts_to_be_created[0].bearer_level_qos.len); size = ogs_gtp2_parse_bearer_qos(&bearer_qos, - &req.bearer_contexts_to_be_created.bearer_level_qos); + &req.bearer_contexts_to_be_created[0].bearer_level_qos); ABTS_INT_EQUAL(tc, 22, size); ABTS_INT_EQUAL(tc, 1, bearer_qos.pre_emption_vulnerability); ABTS_INT_EQUAL(tc, 1, bearer_qos.priority_level); ABTS_INT_EQUAL(tc, 1, bearer_qos.pre_emption_capability); ABTS_INT_EQUAL(tc, 5, bearer_qos.qci); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.s11_u_mme_f_teid.presence); + bearer_contexts_to_be_created[0].s11_u_mme_f_teid.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.cause.presence); + bearer_contexts_to_be_created[0].cause.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.transaction_identifier.presence); + bearer_contexts_to_be_created[0].transaction_identifier.presence); ABTS_INT_EQUAL(tc, 0, req. - bearer_contexts_to_be_created.packet_flow_id.presence); + bearer_contexts_to_be_created[0].packet_flow_id.presence); ABTS_INT_EQUAL(tc, 0, req.bearer_contexts_to_be_removed.presence); ABTS_INT_EQUAL(tc, 0, req.recovery.presence); ABTS_INT_EQUAL(tc, 0, req.mme_fq_csid.presence);