pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43892?usp=email ) Change subject: smf: Split enc/dec of multipart http2 messages into more generic helpers ...................................................................... smf: Split enc/dec of multipart http2 messages into more generic helpers Add function helpers for: * Tx Create/Update/Release SM Context(SmContextUpdateData, ngap_enc, ngnas_enc). * Rx N1N2MessageTransfer(N1N2MessageTransferReqData, ngap_enc, ngnas_enc). These helpers will be reused in follow-up commits for other procedures, like PDU Session release. Change-Id: I5684cf0a5e955d9415e07e27b2a8d3478202e5fd --- M smf/SMF_Session_CT_5G.ttcn 1 file changed, 141 insertions(+), 99 deletions(-) Approvals: pespin: Looks good to me, approved laforge: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/smf/SMF_Session_CT_5G.ttcn b/smf/SMF_Session_CT_5G.ttcn index 61dfc0a..493b031 100644 --- a/smf/SMF_Session_CT_5G.ttcn +++ b/smf/SMF_Session_CT_5G.ttcn @@ -33,6 +33,7 @@ import from NAS_CommonTypeDefs all; import from NG_NAS_TypeDefs all; import from NG_NAS_MsgContainers all; +import from NG_NAS_Templates all; import from NG_NAS_Osmo_Types all; import from NG_NAS_Osmo_Templates all; import from NG_NAS_Functions all; @@ -125,34 +126,54 @@ amfId := "020040")); } -function f_http2_encode_body_multipart_json_5gnas(octetstring json_encoded, - octetstring nas_ecnoded, - charstring boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==") return octetstring -{ - var template (value) HTTP2_multipart_part_list parts; - parts := { - ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_type("application/json") }, - json_encoded), - ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id("5gnas-sm"), - ts_HTTP2_Hdr_content_type("application/vnd.3gpp.5gnas") }, - nas_ecnoded) - }; - return f_HTTP2_multipart_msg_encode(parts, boundary); -} +/* 3GPP TS 29.502 5.2.2.2 Create SM Context service operation */ +private function f_n11_prepare_create_sm_context(SmContextCreateData sm_ctx_create, + template (omit) octetstring ngap_enc := omit, + template (omit) octetstring ngnas_enc := omit) +runs on SMF_Session_CT return HTTP2_Msg { + var octetstring sm_ctx_create_enc; + var template (value) octetstring body_enc; + var charstring http2_boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==" + var integer http2_idx; + var integer http2_stream_id := 3; + var HTTP2_multipart_part_list parts; + var template (value) HTTP2_Msg http2_tx; + var HTTP2_Msg http2_rx; -function f_http2_encode_body_multipart_json_ngap(octetstring json_encoded, - octetstring ngap_ecnoded, - charstring boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==") return octetstring -{ - var template (value) HTTP2_multipart_part_list parts; - parts := { - ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_type("application/json") }, - json_encoded), - ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id("N2SmInfo"), - ts_HTTP2_Hdr_content_type("application/vnd.3gpp.ngap") }, - ngap_ecnoded) - }; - return f_HTTP2_multipart_msg_encode(parts, boundary); + sm_ctx_create_enc := f_enc_SmContextCreateData(sm_ctx_create); + + parts := { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_type("application/json") }, sm_ctx_create_enc)) }; + if (ispresent(sm_ctx_create.n1SmMsg)) { + parts := parts & { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id(sm_ctx_create.n1SmMsg.contentId), + ts_HTTP2_Hdr_content_type("application/vnd.3gpp.5gnas") }, + valueof(ngnas_enc))) }; + } + if (ispresent(sm_ctx_create.n2SmInfo)) { + parts := parts & { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id(sm_ctx_create.n2SmInfo.contentId), + ts_HTTP2_Hdr_content_type("application/vnd.3gpp.ngap") }, + valueof(ngap_enc))) }; + } + + body_enc := f_HTTP2_multipart_msg_encode(parts, http2_boundary); + http2_idx := f_http2_adapter_find_free_idx(); + http2_tx := ts_HTTP2_Msg(http2_idx, + http2_stream_id, + hb := { + pseudo_headers := ts_HTTP2_pseudo_headers_Req(method := "POST", + scheme := "http", + authority := Nsmf_uri_hostport, + path := Nsmf_PDUSession_path_sm_contexts), + headers := { + ts_HTTP2_Hdr_content_type_multipart(http2_boundary), + ts_HTTP2_Hdr_accept("application/json,application/vnd.3gpp.ngap,application/problem+json"), + ts_HTTP2_Hdr_user_agent("ttcn3-amf"), + ts_HTTP2_Hdr_accept_encoding("gzip") + } + }, + body := ts_HTTP2_Data_frame(http2_stream_id, + end_stream_flag := true, + data := body_enc)); + return valueof(http2_tx); } /* Nsmf_PDUSession_CreateSMContext Request/response @@ -160,15 +181,11 @@ * 3GPP TS 29.502 6.1.3.2 */ function f_n11_create_session() runs on SMF_Session_CT { - var template (value) octetstring body; - var integer http2_idx; - var integer http2_stream_id := 3; - var template (value) HTTP2_Msg http2_tx; + var HTTP2_Msg http2_tx; var HTTP2_Msg http2_rx; var template (present) HTTP2_Msg http2_exp_rx; - var template (value) SmContextCreateData sm_contexts; - var octetstring sm_contexts_enc; + sm_contexts := ts_SmContextCreateData(supi := "imsi-" & g_pars.imsi_str, pei := "imeisv-0790219824011594", pduSessionId := g_pars.namf.pdu_sess_id, @@ -182,33 +199,11 @@ ratType := ts_RatType(NR), ueLocation := f_ts_UserLocation(), smContextStatusUri := ts_Namf_Callback_uri_imsi_sm_context_status_id(g_pars.imsi_str, int2str(g_pars.namf.pdu_sess_id))); - sm_contexts_enc := f_enc_SmContextCreateData(valueof(sm_contexts)); - - var charstring boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==" var octetstring nas_enc := f_ng_nas_gen_session_establishment_request(); + http2_tx := f_n11_prepare_create_sm_context(valueof(sm_contexts), omit, nas_enc); - body := f_http2_encode_body_multipart_json_5gnas(sm_contexts_enc, nas_enc, boundary); - http2_idx := f_http2_adapter_find_free_idx(); - http2_tx := ts_HTTP2_Msg(http2_idx, - http2_stream_id, - hb := { - pseudo_headers := ts_HTTP2_pseudo_headers_Req(method := "POST", - scheme := "http", - authority := Nsmf_uri_hostport, - path := Nsmf_PDUSession_path_sm_contexts), - headers := { - ts_HTTP2_Hdr_content_type_multipart(boundary), - ts_HTTP2_Hdr_accept("application/json,application/vnd.3gpp.ngap,application/problem+json"), - ts_HTTP2_Hdr_user_agent("ttcn3-amf"), - ts_HTTP2_Hdr_accept_encoding("gzip") - } - }, - body := ts_HTTP2_Data_frame(http2_stream_id, - end_stream_flag := true, - data := body)); - - f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_idx); + f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_tx.conn_id); /////////// START MUTUAL EXCLUSION ZONE //////////// /* This code block cannot be executed by more than one component at a time because @@ -235,14 +230,14 @@ as_nudm_sdm_post_sdm_subscriptions(); /* Expect to receive "201 Created body={}" answer to our Nsmf sm-contexts request: */ - http2_exp_rx := tr_HTTP2_Msg(http2_idx, - http2_stream_id, + http2_exp_rx := tr_HTTP2_Msg(http2_tx.conn_id, + http2_tx.stream_id, tr_HTTP2_header_block(pseudo_headers := tr_HTTP2_pseudo_headers_Resp(201), headers := {*, tr_HTTP2_Hdr_location(tr_Nsmf_PDUSession_uri_sm_contexts), *}), - tr_HTTP2_Data_frame(stream_id := http2_stream_id, + tr_HTTP2_Data_frame(stream_id := http2_tx.stream_id, end_stream_flag := true, data := char2oct("{}"))); - as_http2_adapter_receive(http2_rx, http2_exp_rx, idx := http2_idx); + as_http2_adapter_receive(http2_rx, http2_exp_rx, idx := http2_tx.conn_id); /* Store obtained smContextRef:*/ var charstring created_location := valueof(f_HTTP2_header_list_find_header(http2_rx.hb.headers, c_HTTP2_HDR_location)); g_pars.nsmf.smContextRef := regexp(created_location, Nsmf_uri_prefix & Nsmf_PDUSession_path_sm_contexts & "/(?+)", 0); @@ -250,7 +245,7 @@ f_http2_server_emu_register(valueof(ts_Nsmf_PDUSession_path_sm_contexts(g_pars.nsmf.smContextRef)), idx := HTTP2_CONN_SCP); /* Close HTTP2 conn: */ - f_http2_adapter_close(idx := http2_idx); + f_http2_adapter_close(idx := http2_tx.conn_id); /* Expect PCF to receive POST sm-policies: */ as_npcf_smpolicycontrol_post_sm_policies(); @@ -267,9 +262,8 @@ f_Mutex_unlock(__BFILE__, __LINE__); /////////// END MUTUAL EXCLUSION ZONE //////////// - as_namf_comm_post_n1n2_messages(); - - f_n11_update_sm_context(); + as_namf_comm_post_n1n2_messages_pdu_sess_establishment(); + f_n11_update_sm_context_pdu_sess_establishment(); if (g_pars.pdn_type == c_PFCP_PDN_Type_IPv6 or g_pars.pdn_type == c_PFCP_PDN_Type_IPv4v6) { @@ -280,26 +274,34 @@ /* 3GPP TS 29.502 5.2.2.3 Update SM Context service operation */ -function f_n11_update_sm_context() -runs on SMF_Session_CT { - var template (value) SmContextUpdateData sm_ctx_update; +private function f_n11_prepare_update_sm_context(SmContextUpdateData sm_ctx_update, + template (omit) octetstring ngap_enc := omit, + template (omit) octetstring ngnas_enc := omit) +runs on SMF_Session_CT return HTTP2_Msg { var octetstring sm_ctx_update_enc; var template (value) octetstring body_enc; var charstring http2_boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==" var integer http2_idx; var integer http2_stream_id := 3; + var HTTP2_multipart_part_list parts; var template (value) HTTP2_Msg http2_tx; var HTTP2_Msg http2_rx; - sm_ctx_update := ts_SmContextUpdateData(ueLocation := f_ts_UserLocation(), - n2SmInfo := TS29502_Nsmf_PDUSession_Templates.ts_RefToBinaryData("N2SmInfo"), - n2SmInfoType := ts_N2SmInfoType(PDU_RES_SETUP_RSP)); - sm_ctx_update_enc := f_enc_SmContextUpdateData(valueof(sm_ctx_update)); + sm_ctx_update_enc := f_enc_SmContextUpdateData(sm_ctx_update); - /* TODO: generate and encode ngap: */ - var octetstring ngap_enc := f_ngap_pdu_gen_PDUSessionResourceSetupResponseTransfer(); + parts := { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_type("application/json") }, sm_ctx_update_enc)) }; + if (ispresent(sm_ctx_update.n1SmMsg)) { + parts := parts & { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id(sm_ctx_update.n1SmMsg.contentId), + ts_HTTP2_Hdr_content_type("application/vnd.3gpp.5gnas") }, + valueof(ngnas_enc))) }; + } + if (ispresent(sm_ctx_update.n2SmInfo)) { + parts := parts & { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id(sm_ctx_update.n2SmInfo.contentId), + ts_HTTP2_Hdr_content_type("application/vnd.3gpp.ngap") }, + valueof(ngap_enc))) }; + } - body_enc := f_http2_encode_body_multipart_json_ngap(sm_ctx_update_enc, ngap_enc, http2_boundary); + body_enc := f_HTTP2_multipart_msg_encode(parts, http2_boundary); http2_idx := f_http2_adapter_find_free_idx(); http2_tx := ts_HTTP2_Msg(http2_idx, http2_stream_id, @@ -318,8 +320,24 @@ body := ts_HTTP2_Data_frame(http2_stream_id, end_stream_flag := true, data := body_enc)); + return valueof(http2_tx); +} - f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_idx); +function f_n11_update_sm_context_pdu_sess_establishment() +runs on SMF_Session_CT { + var template (value) SmContextUpdateData sm_ctx_update; + var template (value) octetstring body_enc; + var HTTP2_Msg http2_tx; + var HTTP2_Msg http2_rx; + + sm_ctx_update := ts_SmContextUpdateData(ueLocation := f_ts_UserLocation(), + n2SmInfo := TS29502_Nsmf_PDUSession_Templates.ts_RefToBinaryData("ngap-sm"), + n2SmInfoType := ts_N2SmInfoType(PDU_RES_SETUP_RSP)); + var octetstring ngap_enc := f_ngap_pdu_gen_PDUSessionResourceSetupResponseTransfer(); + + http2_tx := f_n11_prepare_update_sm_context(valueof(sm_ctx_update), ngap_enc); + + f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_tx.conn_id); f_http2_adapter_send(http2_tx); /* SMF updates RAN GTPU IP addr+TEID info on UPF: */ @@ -329,32 +347,34 @@ as_nudm_uecm_put_IndividualSmfRegistration(); /* Successful answer with no content: */ - as_http2_adapter_receive(http2_rx, tr_HTTP2_Msg_204_No_Content(), idx := http2_idx); - f_http2_adapter_close(idx := http2_idx); + as_http2_adapter_receive(http2_rx, tr_HTTP2_Msg_204_No_Content(), idx := http2_tx.conn_id); + f_http2_adapter_close(idx := http2_tx.conn_id); setverdict(pass); } -/* 5.2.2.4 Release SM Context service operation */ -function f_n11_delete_session() -runs on SMF_Session_CT { - var template (value) SmContextReleaseData sm_ctx_rel; +/* 3GPP TS 29.502 5.2.2.4 Release SM Context service operation */ +private function f_n11_prepare_release_sm_context(SmContextReleaseData sm_ctx_rel, + template (omit) octetstring ngap_enc := omit) +runs on SMF_Session_CT return HTTP2_Msg { var octetstring sm_ctx_rel_enc; var template (value) octetstring body_enc; var charstring http2_boundary := "=-0EVVjxcWWFYNd1JXh1OQEg==" var integer http2_idx; var integer http2_stream_id := 3; + var HTTP2_multipart_part_list parts; var template (value) HTTP2_Msg http2_tx; var HTTP2_Msg http2_rx; - sm_ctx_rel := ts_SmContextReleaseData(ueLocation := f_ts_UserLocation(), - n2SmInfo := TS29502_Nsmf_PDUSession_Templates.ts_RefToBinaryData("N2SmInfo"), - n2SmInfoType := ts_N2SmInfoType(PDU_RES_SETUP_RSP)); - sm_ctx_rel_enc := f_enc_SmContextReleaseData(valueof(sm_ctx_rel)); + sm_ctx_rel_enc := f_enc_SmContextReleaseData(sm_ctx_rel); - /* TODO: generate and encode ngap: */ - var octetstring ngap_enc := f_ngap_pdu_gen_PDUSessionResourceSetupResponseTransfer(); + parts := { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_type("application/json") }, sm_ctx_rel_enc)) }; + if (ispresent(sm_ctx_rel.n2SmInfo)) { + parts := parts & { valueof(ts_HTTP2_multipart_part({ ts_HTTP2_Hdr_content_id(sm_ctx_rel.n2SmInfo.contentId), + ts_HTTP2_Hdr_content_type("application/vnd.3gpp.ngap") }, + valueof(ngap_enc))) }; + } - body_enc := f_http2_encode_body_multipart_json_ngap(sm_ctx_rel_enc, ngap_enc, http2_boundary); + body_enc := f_HTTP2_multipart_msg_encode(parts, http2_boundary); http2_idx := f_http2_adapter_find_free_idx(); http2_tx := ts_HTTP2_Msg(http2_idx, http2_stream_id, @@ -373,8 +393,23 @@ body := ts_HTTP2_Data_frame(http2_stream_id, end_stream_flag := true, data := body_enc)); + return valueof(http2_tx); +} - f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_idx); +/* 5.2.2.4 Release SM Context service operation */ +function f_n11_delete_session() +runs on SMF_Session_CT { + var template (value) SmContextReleaseData sm_ctx_rel; + var HTTP2_Msg http2_tx; + var HTTP2_Msg http2_rx; + + sm_ctx_rel := ts_SmContextReleaseData(ueLocation := f_ts_UserLocation(), + n2SmInfo := TS29502_Nsmf_PDUSession_Templates.ts_RefToBinaryData("N2SmInfo"), + n2SmInfoType := ts_N2SmInfoType(PDU_RES_SETUP_RSP)); + var octetstring ngap_enc := f_ngap_pdu_gen_PDUSessionResourceSetupResponseTransfer(); + + http2_tx := f_n11_prepare_release_sm_context(valueof(sm_ctx_rel), ngap_enc); + f_http2_adapter_connect(mp_smf_hostname, mp_smf_sbi_port, mp_amf_local_ip, idx := http2_tx.conn_id); f_http2_adapter_send(http2_tx); /* SMF deletes PDU Session on UPF: */ @@ -388,10 +423,10 @@ as_nudm_uecm_delete_IndividualSmfRegistration(); /* Successful answer with no content: */ - as_http2_adapter_receive(http2_rx, tr_HTTP2_Msg_204_No_Content(), idx := http2_idx); + as_http2_adapter_receive(http2_rx, tr_HTTP2_Msg_204_No_Content(), idx := http2_tx.conn_id); f_http2_server_emu_unregister(valueof(ts_Nsmf_PDUSession_path_sm_contexts(g_pars.nsmf.smContextRef)), idx := HTTP2_CONN_SCP); - f_http2_adapter_close(idx := http2_idx); + f_http2_adapter_close(idx := http2_tx.conn_id); setverdict(pass); } @@ -435,10 +470,22 @@ } /* 5.2.2.3.1 N1N2MessageTransfer */ -private altstep as_namf_comm_post_n1n2_messages() +private altstep as_namf_comm_post_n1n2_messages(out HTTP2_Msg http2_rx, out HTTP2_multipart_part_list parts) +runs on SMF_Session_CT { + [] HTTP2_CONN[HTTP2_CONN_SCP].receive(f_tr_Namf_Communication_post_n1n2_messages()) -> value http2_rx { + /* Split http2_rx.body.data into chunks since it is a multipart message: */ + var charstring content_type_val := valueof(f_HTTP2_header_list_find_header(http2_rx.hb.headers, c_HTTP2_HDR_content_type)); + var charstring boundary := f_HTTP2_header_content_type_multipart_val_get_boundary(content_type_val) + parts := f_HTTP2_multipart_msg_parse(http2_rx.body.data, boundary); + } +} + +/* 5.2.2.3.1 N1N2MessageTransfer, PDU Session establishment (see clause 4.3.2 of 3GPP TS 23.502) */ +private altstep as_namf_comm_post_n1n2_messages_pdu_sess_establishment() runs on SMF_Session_CT { var HTTP2_Msg http2_rx; - [] HTTP2_CONN[HTTP2_CONN_SCP].receive(f_tr_Namf_Communication_post_n1n2_messages()) -> value http2_rx { + var HTTP2_multipart_part_list parts; + [] as_namf_comm_post_n1n2_messages(http2_rx, parts) { var N1N2MessageTransferReqData n1n2msg_req; var NGAP_IEs.PDUSessionResourceSetupRequestTransfer setup_req_transf; var template (value) N1N2MessageTransferRspData n1n2msg_rsp; @@ -446,11 +493,6 @@ var template (value) HTTP2_Msg http2_tx; var octetstring body_enc; - /* Split http2_rx.body.data into chunks since it is a multipart message: */ - var charstring content_type_val := valueof(f_HTTP2_header_list_find_header(http2_rx.hb.headers, c_HTTP2_HDR_content_type)); - var charstring boundary := f_HTTP2_header_content_type_multipart_val_get_boundary(content_type_val) - var HTTP2_multipart_part_list parts := f_HTTP2_multipart_msg_parse(http2_rx.body.data, boundary); - /* Decode 1st part: SBI json: */ f_dec_N1N2MessageTransferReqData(parts[0].data, n1n2msg_req); // TODO: check returned integer. -- To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43892?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: merged Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: I5684cf0a5e955d9415e07e27b2a8d3478202e5fd Gerrit-Change-Number: 43892 Gerrit-PatchSet: 2 Gerrit-Owner: pespin <pespin@sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de> Gerrit-Reviewer: laforge <laforge@osmocom.org> Gerrit-Reviewer: osmith <osmith@sysmocom.de> Gerrit-Reviewer: pespin <pespin@sysmocom.de>