/src/ocudu/lib/ngap/ngap_asn1_helpers.h
Line | Count | Source |
1 | | // SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited |
2 | | // SPDX-FileCopyrightText: Copyright (C) 2026 OCUDU contributors |
3 | | // SPDX-License-Identifier: BSD-3-Clause-Open-MPI |
4 | | // Portions of this file may implement 3GPP specifications, which may be subject to additional licensing requirements. |
5 | | |
6 | | #pragma once |
7 | | |
8 | | #include "ngap_asn1_converters.h" |
9 | | #include "ocudu/adt/byte_buffer.h" |
10 | | #include "ocudu/asn1/asn1_utils.h" |
11 | | #include "ocudu/asn1/ngap/ngap_ies.h" |
12 | | #include "ocudu/asn1/ngap/ngap_pdu_contents.h" |
13 | | #include "ocudu/ngap/ngap_context.h" |
14 | | #include "ocudu/ngap/ngap_handover.h" |
15 | | #include "ocudu/ngap/ngap_init_context_setup.h" |
16 | | #include "ocudu/ngap/ngap_nas.h" |
17 | | #include "ocudu/ngap/ngap_rrc_inactive_transition.h" |
18 | | #include "ocudu/ngap/ngap_ue_context_mod.h" |
19 | | #include "ocudu/ngap/ngap_warning.h" |
20 | | #include "ocudu/ran/cu_cp_location_reporting_types.h" |
21 | | #include "ocudu/ran/cu_cp_pdu_session.h" |
22 | | #include "ocudu/ran/cu_cp_ue_context_release.h" |
23 | | #include "ocudu/ran/cu_types.h" |
24 | | #include "ocudu/ran/five_g_s_tmsi.h" |
25 | | #include "ocudu/ran/inter_cu_handover_messages.h" |
26 | | #include "ocudu/ran/tac.h" |
27 | | #include <string> |
28 | | #include <variant> |
29 | | #include <vector> |
30 | | |
31 | | namespace ocudu::ocucp { |
32 | | |
33 | | /// \brief Converts a satellite RAT type into the RAT Information of a supported TA, as per TS 38.413, |
34 | | /// Section 9.3.1.125. |
35 | | inline asn1::ngap::rat_info_e satellite_rat_type_to_asn1(satellite_rat_type rat) |
36 | 0 | { |
37 | 0 | switch (rat) { |
38 | 0 | case satellite_rat_type::nr_leo: |
39 | 0 | return asn1::ngap::rat_info_opts::nr_leo; |
40 | 0 | case satellite_rat_type::nr_meo: |
41 | 0 | return asn1::ngap::rat_info_opts::nr_meo; |
42 | 0 | case satellite_rat_type::nr_geo: |
43 | 0 | return asn1::ngap::rat_info_opts::nr_geo; |
44 | 0 | case satellite_rat_type::nr_othersat: |
45 | 0 | return asn1::ngap::rat_info_opts::nr_othersat; |
46 | 0 | } |
47 | 0 | return asn1::ngap::rat_info_opts::nulltype; |
48 | 0 | } |
49 | | |
50 | | /// \brief Fills ASN.1 NGSetupRequest struct. |
51 | | /// \param[out] asn1_request The NGSetupRequest ASN.1 struct to fill. |
52 | | /// \param[in] ngap_ctxt The NGAP context. |
53 | | inline void fill_asn1_ng_setup_request(asn1::ngap::ng_setup_request_s& asn1_request, const ngap_context_t& ngap_ctxt) |
54 | 2 | { |
55 | | // Fill global RAN node id. |
56 | 2 | auto& global_gnb = asn1_request->global_ran_node_id.set_global_gnb_id(); |
57 | 2 | global_gnb.gnb_id.set_gnb_id(); |
58 | 2 | global_gnb.gnb_id.gnb_id().from_number(ngap_ctxt.gnb_id.id, ngap_ctxt.gnb_id.bit_length); |
59 | | // TODO: Which PLMN do we need to use here? |
60 | 2 | global_gnb.plmn_id = ngap_ctxt.supported_tas.front().plmn_list.front().plmn_id.to_bytes(); |
61 | | |
62 | | // Fill RAN node name. |
63 | 2 | asn1_request->ran_node_name_present = true; |
64 | 2 | asn1_request->ran_node_name.from_string(ngap_ctxt.ran_node_name); |
65 | | |
66 | | // Fill supported TA list. |
67 | 2 | for (const auto& supported_ta_item : ngap_ctxt.supported_tas) { |
68 | 2 | asn1::ngap::supported_ta_item_s asn1_supported_ta_item = {}; |
69 | | |
70 | | // Fill TAC. |
71 | 2 | asn1_supported_ta_item.tac.from_number(supported_ta_item.tac); |
72 | | |
73 | | // Fill broadcast PLMN list. |
74 | 2 | for (const auto& plmn_item : supported_ta_item.plmn_list) { |
75 | 2 | asn1::ngap::broadcast_plmn_item_s asn1_broadcast_plmn_item = {}; |
76 | | |
77 | | // Fill PLMN id. |
78 | 2 | asn1_broadcast_plmn_item.plmn_id = plmn_item.plmn_id.to_bytes(); |
79 | | |
80 | | // Fill TAI slice support list. |
81 | 2 | for (const auto& slice_support_item : plmn_item.slice_support_list) { |
82 | | // Fill s_nssai. |
83 | 2 | asn1::ngap::slice_support_item_s asn1_slice_support_item = {}; |
84 | 2 | asn1_slice_support_item.s_nssai = s_nssai_to_asn1(slice_support_item); |
85 | | |
86 | 2 | asn1_broadcast_plmn_item.tai_slice_support_list.push_back(asn1_slice_support_item); |
87 | 2 | } |
88 | 2 | asn1_supported_ta_item.broadcast_plmn_list.push_back(asn1_broadcast_plmn_item); |
89 | 2 | } |
90 | | |
91 | | // Fill the RAT Information of an NTN tracking area, from which the AMF derives the satellite RAT type of the UEs |
92 | | // it serves (TS 23.501, Section 5.4.10). |
93 | 2 | if (supported_ta_item.satellite_rat.has_value()) { |
94 | 0 | asn1_supported_ta_item.ie_exts_present = true; |
95 | 0 | asn1_supported_ta_item.ie_exts.rat_info_present = true; |
96 | 0 | asn1_supported_ta_item.ie_exts.rat_info = satellite_rat_type_to_asn1(*supported_ta_item.satellite_rat); |
97 | 0 | } |
98 | | |
99 | 2 | asn1_request->supported_ta_list.push_back(asn1_supported_ta_item); |
100 | 2 | } |
101 | | |
102 | | // Fill paging DRX. |
103 | 2 | asn1::number_to_enum(asn1_request->default_paging_drx, ngap_ctxt.default_paging_drx); |
104 | 2 | } |
105 | | |
106 | | /// \brief Fills the common type \c ngap_dl_nas_transport_message struct. |
107 | | /// \param[out] msg The common type \c ngap_dl_nas_transport_message struct to fill. |
108 | | /// \param[in] ue_index The index of the UE. |
109 | | /// \param[in] asn1_msg The ASN.1 type DLNASTransport. |
110 | | inline void fill_ngap_dl_nas_transport_message(ngap_dl_nas_transport_message& msg, |
111 | | cu_cp_ue_index_t ue_index, |
112 | | const asn1::ngap::dl_nas_transport_s& asn1_msg) |
113 | 0 | { |
114 | 0 | msg.ue_index = ue_index; |
115 | 0 | msg.nas_pdu = asn1_msg->nas_pdu.copy(); |
116 | 0 | if (asn1_msg->ue_cap_info_request_present && |
117 | 0 | asn1_msg->ue_cap_info_request == asn1::ngap::ue_cap_info_request_opts::options::requested) { |
118 | 0 | msg.ue_cap_info_request = true; |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | /// \brief Convert common type Initial UE Message to NGAP Initial UE Message. |
123 | | /// \param[out] asn1_msg The ASN1 NGAP Initial UE Message. |
124 | | /// \param[in] msg The CU-CP Initial UE Message. |
125 | | inline void fill_asn1_initial_ue_message(asn1::ngap::init_ue_msg_s& asn1_msg, |
126 | | const cu_cp_initial_ue_message& msg, |
127 | | const ngap_context_t& context) |
128 | 8.56k | { |
129 | 8.56k | asn1_msg->nas_pdu = msg.nas_pdu.copy(); |
130 | | |
131 | 8.56k | asn1_msg->rrc_establishment_cause = establishment_cause_to_asn1(msg.establishment_cause); |
132 | | |
133 | 8.56k | auto& user_loc_info_nr = asn1_msg->user_location_info.set_user_location_info_nr(); |
134 | 8.56k | user_loc_info_nr = cu_cp_user_location_info_to_asn1(msg.user_location_info); |
135 | | |
136 | 8.56k | asn1_msg->ue_context_request_present = true; |
137 | 8.56k | asn1_msg->ue_context_request.value = asn1::ngap::ue_context_request_opts::options::requested; |
138 | | |
139 | 8.56k | if (msg.five_g_s_tmsi.has_value()) { |
140 | | // TS 23.003 - 5G-S-TMSI contains AMF Set ID, AMF Pointer and 5G TMSI. |
141 | 0 | asn1_msg->five_g_s_tmsi_present = true; |
142 | 0 | asn1_msg->five_g_s_tmsi.amf_set_id.from_number(msg.five_g_s_tmsi.value().get_amf_set_id()); |
143 | 0 | asn1_msg->five_g_s_tmsi.amf_pointer.from_number(msg.five_g_s_tmsi.value().get_amf_pointer()); |
144 | 0 | asn1_msg->five_g_s_tmsi.five_g_tmsi.from_number(msg.five_g_s_tmsi.value().get_five_g_tmsi()); |
145 | 0 | } |
146 | | |
147 | | // TODO: Add missing optional values. |
148 | 8.56k | } |
149 | | |
150 | | /// \brief Convert common type UL NAS Transport message to NGAP UL NAS Transport message. |
151 | | /// \param[out] asn1_msg The ASN1 NGAP UL NAS Transport message. |
152 | | /// \param[in] msg The CU-CP UL NAS Transport message. |
153 | | inline void fill_asn1_ul_nas_transport(asn1::ngap::ul_nas_transport_s& asn1_msg, const cu_cp_ul_nas_transport& msg) |
154 | 0 | { |
155 | 0 | asn1_msg->nas_pdu = msg.nas_pdu.copy(); |
156 | |
|
157 | 0 | auto& user_loc_info_nr = asn1_msg->user_location_info.set_user_location_info_nr(); |
158 | 0 | user_loc_info_nr = cu_cp_user_location_info_to_asn1(msg.user_location_info); |
159 | 0 | } |
160 | | |
161 | | /// Converts the NGAP ASN.1 QoS Flow Level QoS Parameters IE to common type. |
162 | | inline qos_flow_level_qos_parameters |
163 | | ngap_asn1_to_qos_flow_level_qos_parameters(const asn1::ngap::qos_flow_level_qos_params_s& asn1_qos_params) |
164 | 0 | { |
165 | 0 | qos_flow_level_qos_parameters qos_params; |
166 | |
|
167 | 0 | if (asn1_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::dyn5qi) { |
168 | 0 | const auto& asn1_dyn_5qi = asn1_qos_params.qos_characteristics.dyn5qi(); |
169 | |
|
170 | 0 | dyn_5qi_descriptor dyn_5qi = {}; |
171 | 0 | dyn_5qi.qos_prio_level = qos_prio_level_t{asn1_dyn_5qi.prio_level_qos}; |
172 | 0 | dyn_5qi.packet_delay_budget = asn1_dyn_5qi.packet_delay_budget; |
173 | 0 | dyn_5qi.per.exponent = asn1_dyn_5qi.packet_error_rate.per_exponent; |
174 | 0 | dyn_5qi.per.scalar = asn1_dyn_5qi.packet_error_rate.per_scalar; |
175 | |
|
176 | 0 | if (asn1_dyn_5qi.five_qi_present) { |
177 | 0 | dyn_5qi.five_qi = uint_to_five_qi(asn1_dyn_5qi.five_qi); |
178 | 0 | } |
179 | | // The Delay Critical and Averaging Window IEs are only present for GBR QoS flows. |
180 | 0 | if (asn1_dyn_5qi.delay_crit_present) { |
181 | 0 | dyn_5qi.is_delay_critical = asn1_dyn_5qi.delay_crit.value == asn1::ngap::delay_crit_opts::delay_crit; |
182 | 0 | } |
183 | 0 | if (asn1_dyn_5qi.averaging_win_present) { |
184 | 0 | dyn_5qi.averaging_win = asn1_dyn_5qi.averaging_win; |
185 | 0 | } |
186 | 0 | if (asn1_dyn_5qi.max_data_burst_volume_present) { |
187 | 0 | dyn_5qi.max_data_burst_volume = asn1_dyn_5qi.max_data_burst_volume; |
188 | 0 | } |
189 | |
|
190 | 0 | qos_params.qos_desc = dyn_5qi; |
191 | 0 | } else if (asn1_qos_params.qos_characteristics.type() == asn1::ngap::qos_characteristics_c::types::non_dyn5qi) { |
192 | 0 | non_dyn_5qi_descriptor non_dyn_5qi = {}; |
193 | 0 | non_dyn_5qi.five_qi = uint_to_five_qi(asn1_qos_params.qos_characteristics.non_dyn5qi().five_qi); |
194 | 0 | qos_params.qos_desc = non_dyn_5qi; |
195 | | |
196 | | // TODO: Add optional values. |
197 | 0 | } |
198 | | |
199 | | // Fill allocation and retention priority. |
200 | 0 | qos_params.alloc_retention_prio.prio_level_arp = asn1_qos_params.alloc_and_retention_prio.prio_level_arp; |
201 | 0 | qos_params.alloc_retention_prio.may_trigger_preemption = asn1_qos_params.alloc_and_retention_prio.pre_emption_cap == |
202 | 0 | asn1::ngap::pre_emption_cap_opts::may_trigger_pre_emption; |
203 | 0 | qos_params.alloc_retention_prio.is_preemptable = asn1_qos_params.alloc_and_retention_prio.pre_emption_vulnerability == |
204 | 0 | asn1::ngap::pre_emption_vulnerability_opts::pre_emptable; |
205 | | |
206 | | // Fill optional parameters. |
207 | 0 | if (asn1_qos_params.add_qos_flow_info_present) { |
208 | 0 | qos_params.add_qos_flow_info = asn1_qos_params.add_qos_flow_info.to_string(); |
209 | 0 | } |
210 | 0 | if (asn1_qos_params.gbr_qos_info_present) { |
211 | 0 | qos_params.gbr_qos_info = ngap_asn1_to_gbr_qos_flow_information(asn1_qos_params.gbr_qos_info); |
212 | 0 | } |
213 | 0 | if (asn1_qos_params.reflective_qos_attribute_present) { |
214 | 0 | qos_params.reflective_qos_attribute_subject_to = true; |
215 | 0 | } |
216 | |
|
217 | 0 | return qos_params; |
218 | 0 | } |
219 | | |
220 | | /// Helper function to fill the CU-CP PDU Session Resource Setup Item for both, PDUSessionResourceSetupItemSUReq and |
221 | | /// PDUSessionResourceSetupItemCxtReq. Note that the NAS-PDU is added in separate functions |
222 | | /// \param[out] setup_item The cu_cp_pdu_session_res_setup_item struct to fill. |
223 | | /// \param[in] asn1_session_item The pdu_session_res_setup_item_su_req_s or pdu_session_res_setup_item_cxt_req_s ASN1 |
224 | | /// struct. |
225 | | /// \returns True if the conversion was successful, false otherwise. |
226 | | template <typename template_asn1_item> |
227 | | inline bool fill_cu_cp_pdu_session_resource_setup_item_base(cu_cp_pdu_session_res_setup_item& setup_item, |
228 | | const template_asn1_item& asn1_session_item, |
229 | | byte_buffer asn1_request_transfer) |
230 | 0 | { |
231 | | // Fill PDU session id. |
232 | 0 | setup_item.pdu_session_id = uint_to_pdu_session_id(asn1_session_item.pdu_session_id); |
233 | | |
234 | | // pDUSessionNAS-PDU / NAS-PDU will be added in a separate function. |
235 | | |
236 | | // Fill s-NSSAI. |
237 | 0 | setup_item.s_nssai = ngap_asn1_to_s_nssai(asn1_session_item.s_nssai); |
238 | | |
239 | | // Fill PDU session resource setup request transfer. |
240 | 0 | asn1::ngap::pdu_session_res_setup_request_transfer_s asn1_setup_req_transfer; |
241 | 0 | asn1::cbit_ref bref({asn1_request_transfer.begin(), asn1_request_transfer.end()}); |
242 | |
|
243 | 0 | if (asn1_setup_req_transfer.unpack(bref) != asn1::OCUDUASN_SUCCESS) { |
244 | 0 | ocudulog::fetch_basic_logger("NGAP").error("Couldn't unpack PDU Session Resource Setup Request Transfer PDU"); |
245 | 0 | return false; |
246 | 0 | } |
247 | | |
248 | 0 | if (asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate_present) { |
249 | | // Fill PDU session aggregate maximum bit rate. |
250 | 0 | setup_item.pdu_session_aggregate_maximum_bit_rate_dl = |
251 | 0 | asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate.pdu_session_aggr_max_bit_rate_dl; |
252 | 0 | setup_item.pdu_session_aggregate_maximum_bit_rate_ul = |
253 | 0 | asn1_setup_req_transfer->pdu_session_aggr_max_bit_rate.pdu_session_aggr_max_bit_rate_ul; |
254 | 0 | } |
255 | | |
256 | | // id-UL-NGU-UP-TNLInformation. |
257 | 0 | if (asn1_setup_req_transfer->ul_ngu_up_tnl_info.type() == |
258 | 0 | asn1::ngap::up_transport_layer_info_c::types_opts::gtp_tunnel && |
259 | 0 | asn1_setup_req_transfer->ul_ngu_up_tnl_info.gtp_tunnel().transport_layer_address.length() == 160) { |
260 | 0 | ocudulog::fetch_basic_logger("NGAP").error( |
261 | 0 | "Invalid PDU Session Resource Setup Request Transfer PDU. Cause: Combined " |
262 | 0 | "IPv4 and IPv6 addresses are currently not supported"); |
263 | 0 | return false; |
264 | 0 | } |
265 | | |
266 | 0 | setup_item.ul_ngu_up_tnl_info = asn1_to_up_transport_layer_info(asn1_setup_req_transfer->ul_ngu_up_tnl_info); |
267 | | |
268 | | // Fill data forwarding not possible. |
269 | 0 | if (asn1_setup_req_transfer->direct_forwarding_path_availability_present) { |
270 | 0 | setup_item.direct_forwarding_path_available = true; |
271 | 0 | } |
272 | |
|
273 | 0 | if (asn1_setup_req_transfer->data_forwarding_not_possible_present) { |
274 | 0 | setup_item.data_forwarding_not_possible = true; |
275 | 0 | } |
276 | | |
277 | | // Fill PDU session type. |
278 | 0 | if (!asn1_to_pdu_session_type(setup_item.pdu_session_type, asn1_setup_req_transfer->pdu_session_type)) { |
279 | 0 | ocudulog::fetch_basic_logger("NGAP").error( |
280 | 0 | "Invalid PDU Session Type in PDU Session Resource Setup Request Transfer PDU"); |
281 | 0 | return false; |
282 | 0 | } |
283 | | |
284 | | // Fill security indication. |
285 | 0 | if (asn1_setup_req_transfer->security_ind_present) { |
286 | 0 | security_indication_t ind = {}; |
287 | 0 | asn1_to_security_indication(ind, asn1_setup_req_transfer->security_ind); |
288 | 0 | setup_item.security_ind = ind; |
289 | 0 | } |
290 | | |
291 | | // Fill Qos flow setup request list. |
292 | 0 | for (const auto& asn1_flow_item : asn1_setup_req_transfer->qos_flow_setup_request_list) { |
293 | 0 | qos_flow_setup_request_item qos_flow_setup_req_item; |
294 | | |
295 | | // Fill QoS flow identifier. |
296 | 0 | qos_flow_setup_req_item.qos_flow_id = uint_to_qos_flow_id(asn1_flow_item.qos_flow_id); |
297 | | |
298 | | // Fill QoS flow level QoS parameters. |
299 | 0 | qos_flow_setup_req_item.qos_flow_level_qos_params = |
300 | 0 | ngap_asn1_to_qos_flow_level_qos_parameters(asn1_flow_item.qos_flow_level_qos_params); |
301 | |
|
302 | 0 | if (asn1_flow_item.erab_id_present) { |
303 | 0 | qos_flow_setup_req_item.erab_id = asn1_flow_item.erab_id; |
304 | 0 | } |
305 | |
|
306 | 0 | setup_item.qos_flow_setup_request_items.emplace(qos_flow_setup_req_item.qos_flow_id, qos_flow_setup_req_item); |
307 | 0 | } |
308 | 0 | return true; |
309 | 0 | } Unexecuted instantiation: bool ocudu::ocucp::fill_cu_cp_pdu_session_resource_setup_item_base<asn1::ngap::pdu_session_res_setup_item_cxt_req_s>(ocudu::ocucp::cu_cp_pdu_session_res_setup_item&, asn1::ngap::pdu_session_res_setup_item_cxt_req_s const&, ocudu::byte_buffer) Unexecuted instantiation: bool ocudu::ocucp::fill_cu_cp_pdu_session_resource_setup_item_base<asn1::ngap::pdu_session_res_setup_item_su_req_s>(ocudu::ocucp::cu_cp_pdu_session_res_setup_item&, asn1::ngap::pdu_session_res_setup_item_su_req_s const&, ocudu::byte_buffer) Unexecuted instantiation: bool ocudu::ocucp::fill_cu_cp_pdu_session_resource_setup_item_base<asn1::ngap::pdu_session_res_setup_item_ho_req_s>(ocudu::ocucp::cu_cp_pdu_session_res_setup_item&, asn1::ngap::pdu_session_res_setup_item_ho_req_s const&, ocudu::byte_buffer) |
310 | | |
311 | | /// \brief Convert NGAP ASN1 PDU Session Resource Setup List SU REQ ASN1 struct to common type. |
312 | | /// \param[out] cu_cp_pdu_session_res_setup_msg The cu_cp_pdu_session_res_setup_msg struct to fill. |
313 | | /// \param[in] asn1_pdu_session_res_setup_list The pdu_session_res_setup_list_su_req ASN1 struct. |
314 | | /// \returns True if the conversion was successful, false otherwise. |
315 | | inline bool fill_ngap_pdu_session_resource_setup_request( |
316 | | ngap_pdu_session_resource_setup_request& cu_cp_pdu_session_resource_setup_msg, |
317 | | const asn1::dyn_seq_of<asn1::ngap::pdu_session_res_setup_item_su_req_s, 1U, 256U, true>& |
318 | | asn1_pdu_session_res_setup_list) |
319 | 0 | { |
320 | 0 | if (asn1_pdu_session_res_setup_list.size() == 0) { |
321 | 0 | return false; |
322 | 0 | } |
323 | | |
324 | 0 | for (const auto& asn1_session_item : asn1_pdu_session_res_setup_list) { |
325 | 0 | cu_cp_pdu_session_res_setup_item setup_item; |
326 | |
|
327 | 0 | if (!fill_cu_cp_pdu_session_resource_setup_item_base( |
328 | 0 | setup_item, asn1_session_item, asn1_session_item.pdu_session_res_setup_request_transfer.copy())) { |
329 | 0 | return false; |
330 | 0 | } |
331 | | |
332 | | // Fill PDU session NAS-PDU. |
333 | 0 | if (!asn1_session_item.pdu_session_nas_pdu.empty()) { |
334 | 0 | if (!setup_item.pdu_session_nas_pdu.resize(asn1_session_item.pdu_session_nas_pdu.size())) { |
335 | 0 | return false; |
336 | 0 | } |
337 | 0 | std::copy(asn1_session_item.pdu_session_nas_pdu.begin(), |
338 | 0 | asn1_session_item.pdu_session_nas_pdu.end(), |
339 | 0 | setup_item.pdu_session_nas_pdu.begin()); |
340 | 0 | } |
341 | | |
342 | 0 | cu_cp_pdu_session_resource_setup_msg.pdu_session_res_setup_items.emplace(setup_item.pdu_session_id, |
343 | 0 | std::move(setup_item)); |
344 | 0 | } |
345 | 0 | return true; |
346 | 0 | } |
347 | | |
348 | | /// \brief Convert NGAP ASN1 PDU Session Resource Setup List CTX REQ |
349 | | /// ASN1 struct to common type. |
350 | | /// \param[out] cu_cp_pdu_session_res_setup_msg The cu_cp_pdu_session_res_setup_msg struct to fill. |
351 | | /// \param[in] asn1_pdu_session_res_setup_list The pdu_session_res_setup_item_cxt_req_s ASN1 struct. |
352 | | /// \returns True if the conversion was successful, false otherwise. |
353 | | inline bool fill_ngap_pdu_session_resource_setup_request( |
354 | | ngap_pdu_session_resource_setup_request& cu_cp_pdu_session_resource_setup_msg, |
355 | | const asn1::dyn_seq_of<asn1::ngap::pdu_session_res_setup_item_cxt_req_s, 1U, 256U, true>& |
356 | | asn1_pdu_session_res_setup_list) |
357 | 0 | { |
358 | 0 | for (const auto& asn1_session_item : asn1_pdu_session_res_setup_list) { |
359 | 0 | cu_cp_pdu_session_res_setup_item setup_item; |
360 | |
|
361 | 0 | if (!fill_cu_cp_pdu_session_resource_setup_item_base( |
362 | 0 | setup_item, asn1_session_item, asn1_session_item.pdu_session_res_setup_request_transfer.copy())) { |
363 | 0 | return false; |
364 | 0 | } |
365 | | |
366 | | // Fill NAS-PDU. |
367 | 0 | if (!asn1_session_item.nas_pdu.empty()) { |
368 | 0 | if (!setup_item.pdu_session_nas_pdu.resize(asn1_session_item.nas_pdu.size())) { |
369 | 0 | return false; |
370 | 0 | } |
371 | 0 | std::copy( |
372 | 0 | asn1_session_item.nas_pdu.begin(), asn1_session_item.nas_pdu.end(), setup_item.pdu_session_nas_pdu.begin()); |
373 | 0 | } |
374 | | |
375 | 0 | cu_cp_pdu_session_resource_setup_msg.pdu_session_res_setup_items.emplace(setup_item.pdu_session_id, |
376 | 0 | std::move(setup_item)); |
377 | 0 | } |
378 | 0 | return true; |
379 | 0 | } |
380 | | |
381 | | /// \brief Convert NGAP ASN1 Init Context Setup Request ASN1 struct to common type. |
382 | | /// \param[out] request The ngap_init_context_setup_request struct to fill. |
383 | | /// \param[in] asn1_request The Init Context Setup Request ASN1 struct. |
384 | | inline bool fill_ngap_initial_context_setup_request(ngap_init_context_setup_request& request, |
385 | | const asn1::ngap::init_context_setup_request_s& asn1_request) |
386 | 6.02k | { |
387 | | // Fill old_amf. |
388 | 6.02k | if (asn1_request->old_amf_present) { |
389 | 0 | request.old_amf = asn1_request->old_amf.to_string(); |
390 | 0 | } |
391 | | |
392 | | // Fill UE aggregated max bit rate. |
393 | 6.02k | if (asn1_request->ue_aggr_max_bit_rate_present) { |
394 | 0 | request.ue_aggr_max_bit_rate.emplace(); |
395 | 0 | request.ue_aggr_max_bit_rate.value().dl = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_dl; |
396 | 0 | request.ue_aggr_max_bit_rate.value().ul = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_ul; |
397 | 0 | } |
398 | | |
399 | | // Fill core network assist info for inactive. |
400 | 6.02k | if (asn1_request->core_network_assist_info_for_inactive_present) { |
401 | 0 | request.core_network_assist_info_for_inactive = |
402 | 0 | asn1_to_core_network_assist_info_for_inactive(asn1_request->core_network_assist_info_for_inactive); |
403 | 0 | } |
404 | | |
405 | | // Fill GUAMI. |
406 | 6.02k | expected<guami_t, std::string> guami = asn1_to_guami(asn1_request->guami); |
407 | 6.02k | if (!guami.has_value()) { |
408 | 0 | return false; |
409 | 0 | } |
410 | 6.02k | request.guami = guami.value(); |
411 | | |
412 | | // Fill PDU session resource setup list context request. |
413 | 6.02k | if (asn1_request->pdu_session_res_setup_list_cxt_req_present) { |
414 | 0 | request.pdu_session_res_setup_list_cxt_req.emplace(); |
415 | 0 | if (!fill_ngap_pdu_session_resource_setup_request(request.pdu_session_res_setup_list_cxt_req.value(), |
416 | 0 | asn1_request->pdu_session_res_setup_list_cxt_req)) { |
417 | 0 | return false; |
418 | 0 | } |
419 | 0 | } |
420 | | |
421 | | // Fill allowed S-NSSAI. |
422 | 6.02k | for (const auto& asn1_s_nssai : asn1_request->allowed_nssai) { |
423 | 6.02k | request.allowed_nssai.push_back(ngap_asn1_to_s_nssai(asn1_s_nssai.s_nssai)); |
424 | 6.02k | } |
425 | | |
426 | | // Fill security context. |
427 | 6.02k | security::asn1_to_key(request.security_context.k, asn1_request->security_key); |
428 | 6.02k | security::asn1_to_supported_algorithms(request.security_context.supported_int_algos, |
429 | 6.02k | asn1_request->ue_security_cap.nr_integrity_protection_algorithms); |
430 | 6.02k | security::asn1_to_supported_algorithms(request.security_context.supported_enc_algos, |
431 | 6.02k | asn1_request->ue_security_cap.nr_encryption_algorithms); |
432 | | |
433 | | // Fill UE radio capabilities. |
434 | 6.02k | if (asn1_request->ue_radio_cap_present) { |
435 | 0 | request.ue_radio_cap = asn1_request->ue_radio_cap.copy(); |
436 | 0 | } |
437 | | |
438 | | // Fill idx to RFSP. |
439 | 6.02k | if (asn1_request->idx_to_rfsp_present) { |
440 | 0 | request.idx_to_rfsp = asn1_request->idx_to_rfsp; |
441 | 0 | } |
442 | | |
443 | | // Fill masked IMEISV. |
444 | 6.02k | if (asn1_request->masked_imeisv_present) { |
445 | 6.02k | request.masked_imeisv = asn1_request->masked_imeisv.to_number(); |
446 | 6.02k | } |
447 | | |
448 | | // Fill NAS-PDU. |
449 | 6.02k | if (asn1_request->nas_pdu_present) { |
450 | 6.02k | request.nas_pdu = asn1_request->nas_pdu.copy(); |
451 | 6.02k | } |
452 | | |
453 | | // Fill RRC Inactive Transition Report Request. |
454 | 6.02k | if (asn1_request->rrc_inactive_transition_report_request_present) { |
455 | 0 | request.rrc_inactive_transition_report_request = |
456 | 0 | asn1_to_rrc_inactive_transition_report_request(asn1_request->rrc_inactive_transition_report_request); |
457 | 0 | } |
458 | | |
459 | | // Fill UE radio capabilities for paging. |
460 | 6.02k | if (asn1_request->ue_radio_cap_for_paging_present) { |
461 | 0 | cu_cp_ue_radio_cap_for_paging ue_radio_cap_for_paging; |
462 | 0 | ue_radio_cap_for_paging.ue_radio_cap_for_paging_of_nr = |
463 | 0 | asn1_request->ue_radio_cap_for_paging.ue_radio_cap_for_paging_of_nr.copy(); |
464 | |
|
465 | 0 | request.ue_radio_cap_for_paging = ue_radio_cap_for_paging; |
466 | 0 | } |
467 | | |
468 | | // Fill Location Report Request Type. |
469 | 6.02k | if (asn1_request->location_report_request_type_present) { |
470 | 0 | request.location_report_request_type = asn1_to_location_report_request(asn1_request->location_report_request_type); |
471 | 0 | } |
472 | | |
473 | | // TODO: Add missing optional values. |
474 | | |
475 | 6.02k | return true; |
476 | 6.02k | } |
477 | | |
478 | | /// \brief Convert common type Initial Context Setup Response message to NGAP Initial Context Setup Response message. |
479 | | /// \param[out] asn1_resp The ASN1 NGAP Initial Context Setup Response message. |
480 | | /// \param[in] resp The CU-CP Initial Context Setup Response message. |
481 | | /// \return True on success, otherwise false. |
482 | | inline bool fill_asn1_initial_context_setup_response(asn1::ngap::init_context_setup_resp_s& asn1_resp, |
483 | | const ngap_init_context_setup_response& resp) |
484 | 6.02k | { |
485 | | // Fill PDU Session Resource Setup Response List |
486 | 6.02k | if (!resp.pdu_session_res_setup_response_items.empty()) { |
487 | 0 | asn1_resp->pdu_session_res_setup_list_cxt_res_present = true; |
488 | |
|
489 | 0 | for (const auto& resp_item : resp.pdu_session_res_setup_response_items) { |
490 | 0 | asn1::ngap::pdu_session_res_setup_item_cxt_res_s asn1_resp_item; |
491 | |
|
492 | 0 | if (!pdu_session_res_setup_response_item_to_asn1(asn1_resp_item, resp_item)) { |
493 | 0 | return false; |
494 | 0 | } |
495 | | |
496 | 0 | asn1_resp->pdu_session_res_setup_list_cxt_res.push_back(asn1_resp_item); |
497 | 0 | } |
498 | 0 | } |
499 | | |
500 | | // Fill PDU session resource failed to setup list. |
501 | 6.02k | if (!resp.pdu_session_res_failed_to_setup_items.empty()) { |
502 | 0 | asn1_resp->pdu_session_res_failed_to_setup_list_cxt_res_present = true; |
503 | 0 | for (const auto& setup_failed_item : resp.pdu_session_res_failed_to_setup_items) { |
504 | 0 | asn1::ngap::pdu_session_res_failed_to_setup_item_cxt_res_s asn1_setup_failed_item; |
505 | |
|
506 | 0 | if (!pdu_session_res_setup_failed_item_to_asn1(asn1_setup_failed_item, setup_failed_item)) { |
507 | 0 | return false; |
508 | 0 | } |
509 | | |
510 | 0 | asn1_resp->pdu_session_res_failed_to_setup_list_cxt_res.push_back(asn1_setup_failed_item); |
511 | 0 | } |
512 | 0 | } |
513 | | |
514 | | // Fill criticality diagnostics. |
515 | 6.02k | if (resp.crit_diagnostics.has_value()) { |
516 | | // TODO: Add crit diagnostics. |
517 | 0 | } |
518 | | |
519 | 6.02k | return true; |
520 | 6.02k | } |
521 | | |
522 | | /// \brief Convert common type Initial Context Setup Failure message to NGAP Initial Context Setup Failure |
523 | | /// message. |
524 | | /// \param[out] asn1_fail The ASN1 NGAP Initial Context Setup Failure message. |
525 | | /// \param[in] fail The CU-CP Initial Context Setup Failure message. |
526 | | inline void fill_asn1_initial_context_setup_failure(asn1::ngap::init_context_setup_fail_s& asn1_fail, |
527 | | const ngap_init_context_setup_failure& fail) |
528 | 0 | { |
529 | | // Fill cause. |
530 | 0 | asn1_fail->cause = cause_to_asn1(fail.cause); |
531 | | |
532 | | // Fill PDU session resource failed to setup list. |
533 | 0 | if (!fail.pdu_session_res_failed_to_setup_items.empty()) { |
534 | 0 | asn1_fail->pdu_session_res_failed_to_setup_list_cxt_fail_present = true; |
535 | 0 | for (const auto& setup_failed_item : fail.pdu_session_res_failed_to_setup_items) { |
536 | 0 | asn1::ngap::pdu_session_res_failed_to_setup_item_cxt_fail_s asn1_setup_failed_item; |
537 | |
|
538 | 0 | pdu_session_res_setup_failed_item_to_asn1(asn1_setup_failed_item, setup_failed_item); |
539 | |
|
540 | 0 | asn1_fail->pdu_session_res_failed_to_setup_list_cxt_fail.push_back(asn1_setup_failed_item); |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | // Fill criticality diagnostics. |
545 | 0 | if (fail.crit_diagnostics.has_value()) { |
546 | | // TODO: Add crit diagnostics. |
547 | 0 | } |
548 | 0 | } |
549 | | |
550 | | /// \brief Convert a NGAP ASN1 modify item to common type. |
551 | | /// \param[out] modify_item The flat/common version |
552 | | /// \param[in] asn1_session_item The ASN1 struct to be converted. |
553 | | /// \return True on success, otherwise false. |
554 | | inline bool fill_ngap_pdu_session_resource_modify_item_base( |
555 | | ngap_pdu_session_res_modify_item_mod_req& modify_item, |
556 | | const asn1::ngap::pdu_session_res_modify_item_mod_req_s& asn1_session_item) |
557 | 0 | { |
558 | 0 | modify_item.pdu_session_id = uint_to_pdu_session_id(asn1_session_item.pdu_session_id); |
559 | |
|
560 | 0 | asn1::ngap::pdu_session_res_modify_request_transfer_s asn1_modify_req_transfer; |
561 | 0 | asn1::cbit_ref bref(asn1_session_item.pdu_session_res_modify_request_transfer); |
562 | 0 | if (asn1_modify_req_transfer.unpack(bref) != asn1::OCUDUASN_SUCCESS) { |
563 | 0 | ocudulog::fetch_basic_logger("NGAP").error("Couldn't unpack PDU Session Resource Modify Request Transfer PDU."); |
564 | 0 | return false; |
565 | 0 | } |
566 | | |
567 | 0 | if (asn1_modify_req_transfer->qos_flow_add_or_modify_request_list_present) { |
568 | 0 | for (const auto& asn1_flow_item : asn1_modify_req_transfer->qos_flow_add_or_modify_request_list) { |
569 | 0 | ngap_qos_flow_add_or_mod_item qos_flow_add_item; |
570 | | |
571 | | // Fill QoS flow identifier. |
572 | 0 | qos_flow_add_item.qos_flow_id = uint_to_qos_flow_id(asn1_flow_item.qos_flow_id); |
573 | | |
574 | | // Fill QoS flow level QoS parameters. |
575 | 0 | if (asn1_flow_item.qos_flow_level_qos_params_present) { |
576 | 0 | qos_flow_add_item.qos_flow_level_qos_params = |
577 | 0 | ngap_asn1_to_qos_flow_level_qos_parameters(asn1_flow_item.qos_flow_level_qos_params); |
578 | 0 | } |
579 | |
|
580 | 0 | modify_item.transfer.qos_flow_add_or_modify_request_list.emplace(qos_flow_add_item.qos_flow_id, |
581 | 0 | qos_flow_add_item); |
582 | 0 | } |
583 | 0 | } |
584 | |
|
585 | 0 | if (asn1_modify_req_transfer->qos_flow_to_release_list_present) { |
586 | 0 | for (const auto& asn1_flow_item : asn1_modify_req_transfer->qos_flow_to_release_list) { |
587 | 0 | ngap_qos_flow_failed_to_setup_item qos_flow_release_item; |
588 | 0 | qos_flow_release_item.qos_flow_id = uint_to_qos_flow_id(asn1_flow_item.qos_flow_id); |
589 | 0 | qos_flow_release_item.cause = asn1_to_cause(asn1_flow_item.cause); |
590 | 0 | modify_item.transfer.qos_flow_to_release_list.emplace(qos_flow_release_item.qos_flow_id, qos_flow_release_item); |
591 | 0 | } |
592 | 0 | } |
593 | |
|
594 | 0 | if (!asn1_session_item.nas_pdu.empty()) { |
595 | 0 | if (!modify_item.nas_pdu.resize(asn1_session_item.nas_pdu.size())) { |
596 | 0 | return false; |
597 | 0 | } |
598 | 0 | std::copy(asn1_session_item.nas_pdu.begin(), asn1_session_item.nas_pdu.end(), modify_item.nas_pdu.begin()); |
599 | 0 | } |
600 | | |
601 | 0 | return true; |
602 | 0 | } |
603 | | |
604 | | /// \brief Convert NGAP ASN1 PDU Session Resource Modify List ASN1 struct to common type. |
605 | | /// \param[out] ngap_pdu_session_resource_modify_msg The ngap_pdu_session_res_modify_msg struct to fill. |
606 | | /// \param[in] asn1_pdu_session_res_modify_list The pdu_session_res_modify_list ASN1 struct. |
607 | | /// \return True on success, otherwise false. |
608 | | inline bool fill_ngap_pdu_session_resource_modify_request( |
609 | | ngap_pdu_session_resource_modify_request& ngap_pdu_session_resource_modify_msg, |
610 | | const asn1::dyn_seq_of<asn1::ngap::pdu_session_res_modify_item_mod_req_s, 1, 256, true>& |
611 | | asn1_pdu_session_res_modify_list) |
612 | 0 | { |
613 | 0 | for (const auto& asn1_session_item : asn1_pdu_session_res_modify_list) { |
614 | 0 | ngap_pdu_session_res_modify_item_mod_req modify_item; |
615 | 0 | if (!fill_ngap_pdu_session_resource_modify_item_base(modify_item, asn1_session_item)) { |
616 | 0 | return false; |
617 | 0 | } |
618 | 0 | ngap_pdu_session_resource_modify_msg.pdu_session_res_modify_items.emplace(modify_item.pdu_session_id, |
619 | 0 | std::move(modify_item)); |
620 | 0 | } |
621 | | |
622 | 0 | return true; |
623 | 0 | } |
624 | | |
625 | | /// \brief Convert common type PDU Session Resource Setup Response message to NGAP PDU Session Resource Setup Response |
626 | | /// message. |
627 | | /// \param[out] resp The ASN1 NGAP PDU Session Resource Setup Response message. |
628 | | /// \param[in] cu_cp_resp The CU-CP PDU Session Resource Setup Response message. |
629 | | inline void fill_asn1_pdu_session_res_setup_response(asn1::ngap::pdu_session_res_setup_resp_s& resp, |
630 | | const ngap_pdu_session_resource_setup_response& cu_cp_resp) |
631 | 0 | { |
632 | | // Fill PDU session resource setup response list. |
633 | 0 | if (!cu_cp_resp.pdu_session_res_setup_response_items.empty()) { |
634 | 0 | resp->pdu_session_res_setup_list_su_res_present = true; |
635 | |
|
636 | 0 | for (const auto& cu_cp_resp_item : cu_cp_resp.pdu_session_res_setup_response_items) { |
637 | 0 | asn1::ngap::pdu_session_res_setup_item_su_res_s resp_item; |
638 | |
|
639 | 0 | pdu_session_res_setup_response_item_to_asn1(resp_item, cu_cp_resp_item); |
640 | |
|
641 | 0 | resp->pdu_session_res_setup_list_su_res.push_back(resp_item); |
642 | 0 | } |
643 | 0 | } |
644 | | |
645 | | // Fill PDU session resource failed to setup list. |
646 | 0 | if (!cu_cp_resp.pdu_session_res_failed_to_setup_items.empty()) { |
647 | 0 | resp->pdu_session_res_failed_to_setup_list_su_res_present = true; |
648 | 0 | for (const auto& cu_cp_setup_failed_item : cu_cp_resp.pdu_session_res_failed_to_setup_items) { |
649 | 0 | ocudu_assert(!cu_cp_setup_failed_item.unsuccessful_transfer.cause.valueless_by_exception(), |
650 | 0 | "Failed cause must not be null."); |
651 | 0 | asn1::ngap::pdu_session_res_failed_to_setup_item_su_res_s setup_failed_item; |
652 | |
|
653 | 0 | pdu_session_res_setup_failed_item_to_asn1(setup_failed_item, cu_cp_setup_failed_item); |
654 | |
|
655 | 0 | resp->pdu_session_res_failed_to_setup_list_su_res.push_back(setup_failed_item); |
656 | 0 | } |
657 | 0 | } |
658 | 0 | } |
659 | | |
660 | | /// \brief Convert common type UE Context Release Request to NGAP UE Context Release Request. |
661 | | /// \param[out] asn1_msg The ASN1 NGAP UE Context Release Request. |
662 | | /// \param[in] msg The CU-CP UE Context Release Request. |
663 | | inline void fill_asn1_ue_context_release_request(asn1::ngap::ue_context_release_request_s& asn1_msg, |
664 | | const cu_cp_ue_context_release_request& msg) |
665 | 6.02k | { |
666 | | // Fill PDU session ids. |
667 | 6.02k | if (!msg.pdu_session_res_list_cxt_rel_req.empty()) { |
668 | 0 | asn1_msg->pdu_session_res_list_cxt_rel_req_present = true; |
669 | 0 | for (const auto& session_id : msg.pdu_session_res_list_cxt_rel_req) { |
670 | 0 | asn1::ngap::pdu_session_res_item_cxt_rel_req_s pdu_session_item; |
671 | 0 | pdu_session_item.pdu_session_id = to_underlying(session_id); |
672 | 0 | asn1_msg->pdu_session_res_list_cxt_rel_req.push_back(pdu_session_item); |
673 | 0 | } |
674 | 0 | } |
675 | | |
676 | 6.02k | asn1_msg->cause = cause_to_asn1(msg.cause); |
677 | 6.02k | } |
678 | | |
679 | | /// \brief Convert NGAP ASN1 PDU Session Resource Release Command ASN1 struct to common type. |
680 | | /// \param[out] pdu_session_resource_release_cmd The ngap_pdu_session_resource_release_command struct to fill. |
681 | | /// \param[in] asn1_pdu_session_resource_release_cmd The pdu_session_res_release_cmd ASN1 struct. |
682 | | inline void fill_ngap_pdu_session_resource_release_command( |
683 | | ngap_pdu_session_resource_release_command& pdu_session_resource_release_cmd, |
684 | | const asn1::ngap::pdu_session_res_release_cmd_s& asn1_pdu_session_resource_release_cmd) |
685 | 0 | { |
686 | 0 | if (asn1_pdu_session_resource_release_cmd->ran_paging_prio_present) { |
687 | 0 | pdu_session_resource_release_cmd.ran_paging_prio = asn1_pdu_session_resource_release_cmd->ran_paging_prio; |
688 | 0 | } |
689 | |
|
690 | 0 | if (asn1_pdu_session_resource_release_cmd->nas_pdu_present) { |
691 | 0 | pdu_session_resource_release_cmd.nas_pdu = asn1_pdu_session_resource_release_cmd->nas_pdu.copy(); |
692 | 0 | } |
693 | |
|
694 | 0 | for (const auto& pdu_session_res_to_release_item : |
695 | 0 | asn1_pdu_session_resource_release_cmd->pdu_session_res_to_release_list_rel_cmd) { |
696 | 0 | ngap_pdu_session_res_to_release_item_rel_cmd pdu_session_res_to_release_item_rel_cmd; |
697 | 0 | pdu_session_res_to_release_item_rel_cmd.pdu_session_id = |
698 | 0 | uint_to_pdu_session_id(pdu_session_res_to_release_item.pdu_session_id); |
699 | |
|
700 | 0 | asn1::ngap::pdu_session_res_release_cmd_transfer_s asn1_pdu_session_res_release_cmd_transfer; |
701 | 0 | asn1::cbit_ref bref(pdu_session_res_to_release_item.pdu_session_res_release_cmd_transfer); |
702 | |
|
703 | 0 | if (asn1_pdu_session_res_release_cmd_transfer.unpack(bref) != asn1::OCUDUASN_SUCCESS) { |
704 | 0 | ocudulog::fetch_basic_logger("NGAP").error("Couldn't unpack PDU Session Resource Release Command Transfer PDU."); |
705 | 0 | return; |
706 | 0 | } |
707 | | |
708 | 0 | pdu_session_res_to_release_item_rel_cmd.pdu_session_res_release_cmd_transfer.cause = |
709 | 0 | asn1_to_cause(asn1_pdu_session_res_release_cmd_transfer.cause); |
710 | |
|
711 | 0 | pdu_session_resource_release_cmd.pdu_session_res_to_release_list_rel_cmd.emplace( |
712 | 0 | pdu_session_res_to_release_item_rel_cmd.pdu_session_id, pdu_session_res_to_release_item_rel_cmd); |
713 | 0 | } |
714 | 0 | } |
715 | | |
716 | | /// \brief Convert NGAP ASN1 UE Context Release Command ASN1 struct to common type. |
717 | | /// \param[out] cu_cp_ngap_ue_context_release_cmd The cu_cp_ngap_ue_context_release_cmd struct to fill. |
718 | | /// \param[in] asn1_ue_context_release_cmd The UE Context Release Command ASN1 struct. |
719 | | inline void |
720 | | fill_cu_cp_ue_context_release_command(cu_cp_ue_context_release_command& cu_cp_ue_context_release_cmd, |
721 | | const asn1::ngap::ue_context_release_cmd_s& asn1_ue_context_release_cmd) |
722 | 6.02k | { |
723 | 6.02k | cu_cp_ue_context_release_cmd.cause = asn1_to_cause(asn1_ue_context_release_cmd->cause); |
724 | 6.02k | } |
725 | | |
726 | | /// \brief Convert common type UE Context Release Complete message to NGAP ASN1 UE Context Release Complete |
727 | | /// message. |
728 | | /// \param[out] asn1_resp The ASN1 NGAP UE Context Release Complete message. |
729 | | /// \param[in] cu_cp_resp The CU-CP UE Context Release Complete message. |
730 | | inline void fill_asn1_ue_context_release_complete(asn1::ngap::ue_context_release_complete_s& asn1_resp, |
731 | | const cu_cp_ue_context_release_complete& cu_cp_resp) |
732 | 6.02k | { |
733 | | // Fill user location info. |
734 | 6.02k | if (cu_cp_resp.user_location_info.has_value()) { |
735 | 6.02k | asn1_resp->user_location_info_present = true; |
736 | 6.02k | asn1_resp->user_location_info.set_user_location_info_nr() = |
737 | 6.02k | cu_cp_user_location_info_to_asn1(cu_cp_resp.user_location_info.value()); |
738 | 6.02k | } |
739 | | |
740 | | // Fill info on recommended cells and RAN nodes for paging. |
741 | 6.02k | if (cu_cp_resp.info_on_recommended_cells_and_ran_nodes_for_paging.has_value()) { |
742 | 0 | asn1_resp->info_on_recommended_cells_and_ran_nodes_for_paging_present = true; |
743 | |
|
744 | 0 | for (auto cu_cp_recommended_cell_item : cu_cp_resp.info_on_recommended_cells_and_ran_nodes_for_paging.value() |
745 | 0 | .recommended_cells_for_paging.recommended_cell_list) { |
746 | 0 | asn1::ngap::recommended_cell_item_s asn1_recommended_cell_item; |
747 | | |
748 | | // Fill NG RAN CGI. |
749 | 0 | auto& asn1_nr_cgi = asn1_recommended_cell_item.ngran_cgi.set_nr_cgi(); |
750 | 0 | asn1_nr_cgi.nr_cell_id.from_number(cu_cp_recommended_cell_item.ngran_cgi.nci.value()); |
751 | 0 | asn1_nr_cgi.plmn_id = cu_cp_recommended_cell_item.ngran_cgi.plmn_id.to_bytes(); |
752 | | |
753 | | // Fill time stayed in cell. |
754 | 0 | if (cu_cp_recommended_cell_item.time_stayed_in_cell.has_value()) { |
755 | 0 | asn1_recommended_cell_item.time_stayed_in_cell_present = true; |
756 | 0 | asn1_recommended_cell_item.time_stayed_in_cell = cu_cp_recommended_cell_item.time_stayed_in_cell.value(); |
757 | 0 | } |
758 | |
|
759 | 0 | asn1_resp->info_on_recommended_cells_and_ran_nodes_for_paging.recommended_cells_for_paging.recommended_cell_list |
760 | 0 | .push_back(asn1_recommended_cell_item); |
761 | 0 | } |
762 | |
|
763 | 0 | for (auto cu_cp_recommended_ran_node_item : cu_cp_resp.info_on_recommended_cells_and_ran_nodes_for_paging.value() |
764 | 0 | .recommended_ran_nodes_for_paging.recommended_ran_node_list) { |
765 | 0 | asn1::ngap::recommended_ran_node_item_s asn1_recommended_ran_node_item; |
766 | | |
767 | | // Fill AMF paging target. |
768 | 0 | if (cu_cp_recommended_ran_node_item.amf_paging_target.is_global_ran_node_id) { |
769 | | // Fill global GNB id. |
770 | 0 | auto& asn1_global_ran_node_id = asn1_recommended_ran_node_item.amf_paging_target.set_global_ran_node_id(); |
771 | 0 | auto& global_gnb = asn1_global_ran_node_id.set_global_gnb_id(); |
772 | 0 | global_gnb.plmn_id = |
773 | 0 | cu_cp_recommended_ran_node_item.amf_paging_target.global_ran_node_id.value().plmn_id.to_bytes(); |
774 | 0 | global_gnb.gnb_id.set_gnb_id().from_number( |
775 | 0 | cu_cp_recommended_ran_node_item.amf_paging_target.global_ran_node_id.value().gnb_id.id, |
776 | 0 | cu_cp_recommended_ran_node_item.amf_paging_target.global_ran_node_id.value().gnb_id.bit_length); |
777 | 0 | } else if (cu_cp_recommended_ran_node_item.amf_paging_target.is_tai) { |
778 | | // Fill TAI. |
779 | 0 | auto& asn1_tai = asn1_recommended_ran_node_item.amf_paging_target.set_tai(); |
780 | 0 | asn1_tai.plmn_id = cu_cp_recommended_ran_node_item.amf_paging_target.tai.value().plmn_id.to_bytes(); |
781 | 0 | asn1_tai.tac.from_number(cu_cp_recommended_ran_node_item.amf_paging_target.tai.value().tac); |
782 | 0 | } else { |
783 | 0 | asn1_recommended_ran_node_item.amf_paging_target.set(asn1::ngap::amf_paging_target_c::types_opts::nulltype); |
784 | 0 | } |
785 | |
|
786 | 0 | asn1_resp->info_on_recommended_cells_and_ran_nodes_for_paging.recommend_ran_nodes_for_paging |
787 | 0 | .recommended_ran_node_list.push_back(asn1_recommended_ran_node_item); |
788 | 0 | } |
789 | 0 | } |
790 | | |
791 | | // Fill PDU session res list context release complete. |
792 | 6.02k | if (!cu_cp_resp.pdu_session_res_list_cxt_rel_cpl.empty()) { |
793 | 0 | asn1_resp->pdu_session_res_list_cxt_rel_cpl_present = true; |
794 | |
|
795 | 0 | for (auto pdu_session_id : cu_cp_resp.pdu_session_res_list_cxt_rel_cpl) { |
796 | 0 | asn1::ngap::pdu_session_res_item_cxt_rel_cpl_s asn1_rel_item; |
797 | 0 | asn1_rel_item.pdu_session_id = to_underlying(pdu_session_id); |
798 | 0 | asn1_resp->pdu_session_res_list_cxt_rel_cpl.push_back(asn1_rel_item); |
799 | 0 | } |
800 | 0 | } |
801 | | |
802 | | // Fill crit diagnostics. |
803 | 6.02k | if (cu_cp_resp.crit_diagnostics.has_value()) { |
804 | | // TODO: Add crit diagnostics. |
805 | 0 | } |
806 | 6.02k | } |
807 | | |
808 | | /// \brief Convert NGAP ASN1 Paging ASN1 struct to common type. |
809 | | /// \param[out] paging The cu_cp_paging_message struct to fill. |
810 | | /// \param[in] asn1_paging The Paging ASN1 struct. |
811 | | inline void fill_cu_cp_paging_message(cu_cp_paging_message& paging, const asn1::ngap::paging_s& asn1_paging) |
812 | 0 | { |
813 | | // Fill UE paging id. |
814 | 0 | paging.ue_paging_id = ngap_asn1_to_ue_paging_id(asn1_paging->ue_paging_id); |
815 | | |
816 | | // UE Identity Index value is defined as: UE_ID 5G-S-TMSI mod 1024 (see TS 38.304 section 7.1). |
817 | 0 | paging.ue_id_idx_value = std::get<five_g_s_tmsi_t>(paging.ue_paging_id).to_number() % 1024; |
818 | | |
819 | | // Fill paging DRX. |
820 | 0 | if (asn1_paging->paging_drx_present) { |
821 | 0 | paging.paging_drx = asn1_paging->paging_drx.to_number(); |
822 | 0 | } |
823 | | |
824 | | // Fill TAI list for paging. |
825 | 0 | for (const auto& asn1_tai_item : asn1_paging->tai_list_for_paging) { |
826 | 0 | cu_cp_tai_list_for_paging_item tai_item; |
827 | 0 | tai_item.tai.plmn_id = plmn_identity::from_bytes(asn1_tai_item.tai.plmn_id.to_bytes()).value(); |
828 | 0 | tai_item.tai.tac = asn1_tai_item.tai.tac.to_number(); |
829 | |
|
830 | 0 | paging.tai_list_for_paging.push_back(tai_item); |
831 | 0 | } |
832 | | |
833 | | // Fill paging prio. |
834 | 0 | if (asn1_paging->paging_prio_present) { |
835 | 0 | paging.paging_prio = asn1_paging->paging_prio.to_number(); |
836 | 0 | } |
837 | | |
838 | | // Fill UE radio capabilities for paging. |
839 | 0 | if (asn1_paging->ue_radio_cap_for_paging_present) { |
840 | 0 | cu_cp_ue_radio_cap_for_paging ue_radio_cap_for_paging; |
841 | 0 | ue_radio_cap_for_paging.ue_radio_cap_for_paging_of_nr = |
842 | 0 | asn1_paging->ue_radio_cap_for_paging.ue_radio_cap_for_paging_of_nr.copy(); |
843 | |
|
844 | 0 | paging.ue_radio_cap_for_paging = ue_radio_cap_for_paging; |
845 | 0 | } |
846 | | |
847 | | // Fill paging origin. |
848 | 0 | if (asn1_paging->paging_origin_present) { |
849 | 0 | paging.paging_origin = asn1_paging->paging_origin.to_string(); |
850 | 0 | } |
851 | | |
852 | | // Fill assist data for paging. |
853 | 0 | if (asn1_paging->assist_data_for_paging_present) { |
854 | 0 | cu_cp_assist_data_for_paging assist_data_for_paging; |
855 | | |
856 | | // Fill assist data for recommended cells. |
857 | 0 | if (asn1_paging->assist_data_for_paging.assist_data_for_recommended_cells_present) { |
858 | 0 | cu_cp_assist_data_for_recommended_cells assist_data_for_recommended_cells; |
859 | |
|
860 | 0 | for (const auto& asn1_recommended_cell : asn1_paging->assist_data_for_paging.assist_data_for_recommended_cells |
861 | 0 | .recommended_cells_for_paging.recommended_cell_list) { |
862 | 0 | cu_cp_recommended_cell_item recommended_cell_item; |
863 | | |
864 | | // Fill NG RAN CGI. |
865 | 0 | recommended_cell_item.ngran_cgi.nci = |
866 | 0 | nr_cell_identity::create(asn1_recommended_cell.ngran_cgi.nr_cgi().nr_cell_id.to_number()).value(); |
867 | 0 | recommended_cell_item.ngran_cgi.plmn_id = |
868 | 0 | plmn_identity::from_bytes(asn1_recommended_cell.ngran_cgi.nr_cgi().plmn_id.to_bytes()).value(); |
869 | | |
870 | | // Fill time stayed in cell. |
871 | 0 | if (asn1_recommended_cell.time_stayed_in_cell_present) { |
872 | 0 | recommended_cell_item.time_stayed_in_cell = asn1_recommended_cell.time_stayed_in_cell; |
873 | 0 | } |
874 | |
|
875 | 0 | assist_data_for_recommended_cells.recommended_cells_for_paging.recommended_cell_list.push_back( |
876 | 0 | recommended_cell_item); |
877 | 0 | } |
878 | |
|
879 | 0 | assist_data_for_paging.assist_data_for_recommended_cells = assist_data_for_recommended_cells; |
880 | 0 | } |
881 | | |
882 | | // Fill paging attempt info. |
883 | 0 | if (asn1_paging->assist_data_for_paging.paging_attempt_info_present) { |
884 | 0 | cu_cp_paging_attempt_info paging_attempt_info; |
885 | |
|
886 | 0 | paging_attempt_info.paging_attempt_count = |
887 | 0 | asn1_paging->assist_data_for_paging.paging_attempt_info.paging_attempt_count; |
888 | 0 | paging_attempt_info.intended_nof_paging_attempts = |
889 | 0 | asn1_paging->assist_data_for_paging.paging_attempt_info.intended_nof_paging_attempts; |
890 | |
|
891 | 0 | if (asn1_paging->assist_data_for_paging.paging_attempt_info.next_paging_area_scope_present) { |
892 | 0 | paging_attempt_info.next_paging_area_scope = |
893 | 0 | asn1_paging->assist_data_for_paging.paging_attempt_info.next_paging_area_scope.to_string(); |
894 | 0 | } |
895 | |
|
896 | 0 | assist_data_for_paging.paging_attempt_info = paging_attempt_info; |
897 | 0 | } |
898 | |
|
899 | 0 | paging.assist_data_for_paging = assist_data_for_paging; |
900 | 0 | } |
901 | | |
902 | | // Add Paging eDRX Information. |
903 | 0 | if (asn1_paging->nr_paginge_drx_info_present) { |
904 | 0 | cu_cp_paging_edrx_info paging_edrx_info{}; |
905 | 0 | paging_edrx_info.nr_paging_edrx_cycle = asn1_paging->nr_paginge_drx_info.nr_paging_e_drx_cycle.to_number(); |
906 | |
|
907 | 0 | if (asn1_paging->nr_paginge_drx_info.nr_paging_time_win_present) { |
908 | 0 | paging_edrx_info.nr_paging_time_window = asn1_paging->nr_paginge_drx_info.nr_paging_time_win.to_number(); |
909 | 0 | } |
910 | 0 | paging.paging_edrx_info = paging_edrx_info; |
911 | 0 | } |
912 | 0 | } |
913 | | |
914 | | /// \brief Convert Handover Request ASN1 struct to common type. |
915 | | /// \param[out] request The ngap_handover_request struct to fill. |
916 | | /// \param[in] asn1_request The Handover Request ASN1 struct. |
917 | | /// \returns True if the conversion was successful, false otherwise. |
918 | | inline bool fill_ngap_handover_request(ngap_handover_request& request, const asn1::ngap::ho_request_s& asn1_request) |
919 | 0 | { |
920 | | // Fill handover type. |
921 | 0 | asn1_to_handov_type(request.handov_type, asn1_request->handov_type); |
922 | | |
923 | | // Fill cause. |
924 | 0 | request.cause = asn1_to_cause(asn1_request->cause); |
925 | | |
926 | | // Fill UE aggregated max bit rate. |
927 | 0 | request.ue_aggr_max_bit_rate.dl = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_dl; |
928 | 0 | request.ue_aggr_max_bit_rate.ul = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_ul; |
929 | | |
930 | | // Fill core network assist info for inactive. |
931 | 0 | if (asn1_request->core_network_assist_info_for_inactive_present) { |
932 | 0 | request.core_network_assist_info_for_inactive = |
933 | 0 | asn1_to_core_network_assist_info_for_inactive(asn1_request->core_network_assist_info_for_inactive); |
934 | 0 | } |
935 | | |
936 | | // Fill UE security cap & security context. |
937 | 0 | asn1_to_security_context(request.security_context, asn1_request->ue_security_cap, asn1_request->security_context); |
938 | | |
939 | | // Fill new security context indication. |
940 | 0 | if (asn1_request->new_security_context_ind_present) { |
941 | 0 | request.new_security_context_ind = asn1::enum_to_bool(asn1_request->new_security_context_ind); |
942 | 0 | } |
943 | | |
944 | | // Fill NASC. |
945 | 0 | if (asn1_request->nasc_present) { |
946 | 0 | request.nasc = asn1_request->nasc.copy(); |
947 | 0 | } |
948 | | |
949 | | // Fill PDU session resource setup list HO request. |
950 | 0 | for (const auto& asn1_pdu_session_res_setup_item : asn1_request->pdu_session_res_setup_list_ho_req) { |
951 | 0 | cu_cp_pdu_session_res_setup_item pdu_session_res_setup_item; |
952 | 0 | if (!fill_cu_cp_pdu_session_resource_setup_item_base(pdu_session_res_setup_item, |
953 | 0 | asn1_pdu_session_res_setup_item, |
954 | 0 | asn1_pdu_session_res_setup_item.ho_request_transfer.copy())) { |
955 | 0 | ocudulog::fetch_basic_logger("NGAP").error("Couldn't convert PDU Session Resource Setup List HO Request."); |
956 | 0 | return false; |
957 | 0 | } |
958 | | |
959 | 0 | request.pdu_session_res_setup_list_ho_req.emplace(pdu_session_res_setup_item.pdu_session_id, |
960 | 0 | pdu_session_res_setup_item); |
961 | 0 | } |
962 | | |
963 | | // Fill allowed S-NSSAI. |
964 | 0 | for (const auto& asn1_s_nssai : asn1_request->allowed_nssai) { |
965 | 0 | request.allowed_nssai.push_back(ngap_asn1_to_s_nssai(asn1_s_nssai.s_nssai)); |
966 | 0 | } |
967 | | |
968 | | // TODO: Add trace activation. |
969 | | |
970 | | // Fill masked IMEISV. |
971 | 0 | if (asn1_request->masked_imeisv_present) { |
972 | 0 | request.masked_imeisv = asn1_request->masked_imeisv.to_number(); |
973 | 0 | } |
974 | | |
975 | | // Fill source to target transparent container. |
976 | 0 | asn1::cbit_ref bref(asn1_request->source_to_target_transparent_container); |
977 | 0 | asn1::ngap::source_ngran_node_to_target_ngran_node_transparent_container_s asn1_transparent_container; |
978 | 0 | if (asn1_transparent_container.unpack(bref) != asn1::OCUDUASN_SUCCESS) { |
979 | 0 | ocudulog::fetch_basic_logger("NGAP").error("Couldn't unpack Source to Target Transparent Container."); |
980 | 0 | return false; |
981 | 0 | } |
982 | 0 | asn1_to_source_to_target_transport_container(request.source_to_target_transparent_container, |
983 | 0 | asn1_transparent_container); |
984 | | |
985 | | // TODO: Add Mob restrict list. |
986 | | |
987 | | // Fill Location Report Request Type. |
988 | 0 | if (asn1_request->location_report_request_type_present) { |
989 | 0 | request.location_report_request_type = asn1_to_location_report_request(asn1_request->location_report_request_type); |
990 | 0 | } |
991 | | |
992 | | // Fill RRC Inactive Transition Report Request. |
993 | 0 | if (asn1_request->rrc_inactive_transition_report_request_present) { |
994 | 0 | request.rrc_inactive_transition_report_request = |
995 | 0 | asn1_to_rrc_inactive_transition_report_request(asn1_request->rrc_inactive_transition_report_request); |
996 | 0 | } |
997 | | |
998 | | // Fill GUAMI. |
999 | 0 | expected<guami_t, std::string> guami = asn1_to_guami(asn1_request->guami); |
1000 | 0 | if (!guami.has_value()) { |
1001 | 0 | return false; |
1002 | 0 | } |
1003 | 0 | request.guami = guami.value(); |
1004 | | |
1005 | | // TODO: Add redirection voice fallback. |
1006 | | |
1007 | | // TODO: Add CN assisted RAN tuning. |
1008 | |
|
1009 | 0 | return true; |
1010 | 0 | } |
1011 | | |
1012 | | /// \brief Convert \c cu_cp_handover_request_ack common type struct to ASN.1. |
1013 | | /// \param[out] asn1_ho_request_ack The Handover Request Ack ASN1 struct to fill. |
1014 | | /// \param[in] ho_response The cu_cp_handover_request_ack common type struct. |
1015 | | /// \returns True if the conversion was successful, false otherwise. |
1016 | | inline bool fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_request_ack_s& asn1_ho_request_ack, |
1017 | | const cu_cp_handover_request_ack& ho_response) |
1018 | 0 | { |
1019 | | // Fill PDU session resource admitted list. |
1020 | 0 | for (const auto& admitted_item : ho_response.pdu_session_res_admitted_list) { |
1021 | 0 | if (!std::holds_alternative<cu_cp_ng_pdu_session_res_admitted_item>(admitted_item)) { |
1022 | 0 | return false; |
1023 | 0 | } |
1024 | | |
1025 | 0 | asn1::ngap::pdu_session_res_admitted_item_s asn1_admitted_item; |
1026 | 0 | if (!pdu_session_res_admitted_item_to_asn1(asn1_admitted_item, |
1027 | 0 | std::get<cu_cp_ng_pdu_session_res_admitted_item>(admitted_item))) { |
1028 | 0 | return false; |
1029 | 0 | } |
1030 | 0 | asn1_ho_request_ack->pdu_session_res_admitted_list.push_back(asn1_admitted_item); |
1031 | 0 | } |
1032 | | |
1033 | | // Fill PDU session resource failed to setup list HO ACK. |
1034 | 0 | if (!ho_response.pdu_session_failed_to_setup_list.empty()) { |
1035 | 0 | asn1_ho_request_ack->pdu_session_res_failed_to_setup_list_ho_ack_present = true; |
1036 | 0 | for (const auto& failed_item : ho_response.pdu_session_failed_to_setup_list) { |
1037 | 0 | asn1::ngap::pdu_session_res_failed_to_setup_item_ho_ack_s asn1_failed_item; |
1038 | 0 | if (!pdu_session_res_failed_to_setup_item_ho_ack_to_asn1(asn1_failed_item, failed_item)) { |
1039 | 0 | return false; |
1040 | 0 | } |
1041 | 0 | asn1_ho_request_ack->pdu_session_res_failed_to_setup_list_ho_ack.push_back(asn1_failed_item); |
1042 | 0 | } |
1043 | 0 | } |
1044 | | |
1045 | | // Fill target to source transparent container. |
1046 | 0 | if (!target_to_source_transport_container_to_asn1(asn1_ho_request_ack->target_to_source_transparent_container, |
1047 | 0 | ho_response.rrc_handover_command)) { |
1048 | 0 | return false; |
1049 | 0 | } |
1050 | | |
1051 | 0 | return true; |
1052 | 0 | } |
1053 | | |
1054 | | /// \brief Convert \c cu_cp_handover_request_failure common type struct to ASN.1. |
1055 | | /// \param[out] asn1_ho_failure The Handover Request Failure ASN1 struct to fill. |
1056 | | /// \param[in] ho_failure The cu_cp_handover_request_failure common type struct. |
1057 | | /// \returns True if the conversion was successful, false otherwise. |
1058 | | inline bool fill_asn1_handover_resource_allocation_response(asn1::ngap::ho_fail_s& asn1_ho_failure, |
1059 | | const cu_cp_handover_request_failure& ho_failure) |
1060 | 0 | { |
1061 | | // Fill cause. |
1062 | 0 | if (!std::holds_alternative<ngap_cause_t>(ho_failure.cause)) { |
1063 | 0 | return false; |
1064 | 0 | } |
1065 | 0 | asn1_ho_failure->cause = cause_to_asn1(std::get<ngap_cause_t>(ho_failure.cause)); |
1066 | |
|
1067 | 0 | return true; |
1068 | 0 | } |
1069 | | |
1070 | | /// \brief Fill the Handover Notify to ASN.1 struct. |
1071 | | /// \param[out] asn1_msg The Handover Notify ASN1 struct to fill. |
1072 | | /// \param[in] user_location_info The User Location Information of the UE in the target cell. |
1073 | | inline void fill_asn1_handover_notify(asn1::ngap::ho_notify_s& asn1_msg, |
1074 | | const cu_cp_user_location_info_nr& user_location_info) |
1075 | 0 | { |
1076 | 0 | asn1_msg->user_location_info.set_user_location_info_nr() = cu_cp_user_location_info_to_asn1(user_location_info); |
1077 | 0 | } |
1078 | | |
1079 | | /// \brief Convert the UL RAN Status Transfer struct to ASN.1. |
1080 | | /// \param[out] asn1_msg The UL RAN Status Transfer ASN1 struct to fill. |
1081 | | /// \param[in] drb_list The list of DRB status transfer information. |
1082 | | inline void fill_asn1_ul_ran_status_transfer( |
1083 | | asn1::ngap::ul_ran_status_transfer_s& asn1_msg, |
1084 | | const slotted_id_vector<drb_id_t, cu_cp_drbs_subject_to_status_transfer_item>& drb_list) |
1085 | 0 | { |
1086 | 0 | asn1::ngap::drbs_subject_to_status_transfer_list_l& asn1_drb_list = |
1087 | 0 | asn1_msg->ran_status_transfer_transparent_container.drbs_subject_to_status_transfer_list; |
1088 | 0 | for (const cu_cp_drbs_subject_to_status_transfer_item& drb : drb_list) { |
1089 | 0 | asn1::ngap::drbs_subject_to_status_transfer_item_s asn1_drb_item = {}; |
1090 | 0 | asn1_drb_item.drb_id = to_underlying(drb.drb_id); |
1091 | 0 | if (drb.drb_status_ul.sn_size == pdcp_sn_size::size12bits) { |
1092 | 0 | asn1_drb_item.drb_status_ul.set_drb_status_ul12(); |
1093 | 0 | asn1_drb_item.drb_status_ul.drb_status_ul12().ul_count_value.hfn_pdcp_sn12 = drb.drb_status_ul.ul_count.hfn; |
1094 | 0 | asn1_drb_item.drb_status_ul.drb_status_ul12().ul_count_value.pdcp_sn12 = drb.drb_status_ul.ul_count.sn; |
1095 | 0 | } else { |
1096 | 0 | asn1_drb_item.drb_status_ul.set_drb_status_ul18(); |
1097 | 0 | asn1_drb_item.drb_status_ul.drb_status_ul18().ul_count_value.hfn_pdcp_sn18 = drb.drb_status_ul.ul_count.hfn; |
1098 | 0 | asn1_drb_item.drb_status_ul.drb_status_ul18().ul_count_value.pdcp_sn18 = drb.drb_status_ul.ul_count.sn; |
1099 | 0 | } |
1100 | 0 | if (drb.drb_status_dl.sn_size == pdcp_sn_size::size12bits) { |
1101 | 0 | asn1_drb_item.drb_status_dl.set_drb_status_dl12(); |
1102 | 0 | asn1_drb_item.drb_status_dl.drb_status_dl12().dl_count_value.hfn_pdcp_sn12 = drb.drb_status_dl.dl_count.hfn; |
1103 | 0 | asn1_drb_item.drb_status_dl.drb_status_dl12().dl_count_value.pdcp_sn12 = drb.drb_status_dl.dl_count.sn; |
1104 | 0 | } else { |
1105 | 0 | asn1_drb_item.drb_status_dl.set_drb_status_dl18(); |
1106 | 0 | asn1_drb_item.drb_status_dl.drb_status_dl18().dl_count_value.hfn_pdcp_sn18 = drb.drb_status_dl.dl_count.hfn; |
1107 | 0 | asn1_drb_item.drb_status_dl.drb_status_dl18().dl_count_value.pdcp_sn18 = drb.drb_status_dl.dl_count.sn; |
1108 | 0 | } |
1109 | 0 | asn1_drb_list.push_back(asn1_drb_item); |
1110 | 0 | } |
1111 | 0 | } |
1112 | | |
1113 | | /// \brief Convert common type RRC Inactive Transition Report to NGAP ASN1 RRC Inactive Transition Report. |
1114 | | /// \param[out] asn1_report The ASN1 NGAP RRC Inactive Transition Report. |
1115 | | /// \param[in] report The CU-CP RRC Inactive Transition Report. |
1116 | | inline void fill_asn1_rrc_inactive_transition_report(asn1::ngap::rrc_inactive_transition_report_s& asn1_report, |
1117 | | const ngap_rrc_inactive_transition_report& report) |
1118 | 0 | { |
1119 | | // Fill RRC state. |
1120 | 0 | if (report.rrc_state == ngap_rrc_inactive_transition_report::ngap_rrc_state::inactive) { |
1121 | 0 | asn1_report->rrc_state = asn1::ngap::rrc_state_opts::inactive; |
1122 | 0 | } else { |
1123 | 0 | asn1_report->rrc_state = asn1::ngap::rrc_state_opts::connected; |
1124 | 0 | } |
1125 | | |
1126 | | // Fill user location info. |
1127 | 0 | auto& user_loc_info_nr = asn1_report->user_location_info.set_user_location_info_nr(); |
1128 | 0 | user_loc_info_nr = cu_cp_user_location_info_to_asn1(report.user_location_info); |
1129 | 0 | } |
1130 | | |
1131 | | /// \brief Convert NGAP ASN1 Location Reporting Control message to common type. |
1132 | | inline void fill_ngap_location_report_request(location_report_request& location_report_ctrl, |
1133 | | const asn1::ngap::location_report_ctrl_s& asn1_location_report_ctrl) |
1134 | 0 | { |
1135 | 0 | location_report_ctrl = asn1_to_location_report_request(asn1_location_report_ctrl->location_report_request_type); |
1136 | 0 | } |
1137 | | |
1138 | | /// \brief Fill ASN1 Location Report IEs from common type. |
1139 | | inline void fill_asn1_location_report(asn1::ngap::location_report_ies_container& asn1_msg, |
1140 | | const location_report& report) |
1141 | 0 | { |
1142 | | // Fill user location info. |
1143 | 0 | asn1_msg.user_location_info.set_user_location_info_nr() = cu_cp_user_location_info_to_asn1(report.user_location_info); |
1144 | | |
1145 | | // Fill location report request type (echo back the triggering config). |
1146 | 0 | asn1_msg.location_report_request_type = location_report_request_to_asn1(report.request); |
1147 | | |
1148 | | // Fill UE presence in area of interest list (optional). |
1149 | 0 | if (report.ue_presence_in_area_of_interest_list.has_value()) { |
1150 | 0 | asn1_msg.ue_presence_in_area_of_interest_list_present = true; |
1151 | 0 | for (const auto& item : report.ue_presence_in_area_of_interest_list.value()) { |
1152 | 0 | asn1::ngap::ue_presence_in_area_of_interest_item_s asn1_item; |
1153 | 0 | asn1_item.location_report_ref_id = item.location_report_ref_id; |
1154 | 0 | asn1_item.ue_presence = ue_presence_to_asn1(item.ue_presence_in_aio); |
1155 | 0 | asn1_msg.ue_presence_in_area_of_interest_list.push_back(asn1_item); |
1156 | 0 | } |
1157 | 0 | } |
1158 | 0 | } |
1159 | | |
1160 | | inline bool ue_context_modification_request_from_asn1(ngap_ue_context_modification_request& request, |
1161 | | const asn1::ngap::ue_context_mod_request_s& asn1_request) |
1162 | 0 | { |
1163 | | // Fill UE aggregated max bit rate. |
1164 | 0 | if (asn1_request->ue_aggr_max_bit_rate_present) { |
1165 | 0 | request.ue_aggr_max_bit_rate.emplace(); |
1166 | 0 | request.ue_aggr_max_bit_rate->dl = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_dl; |
1167 | 0 | request.ue_aggr_max_bit_rate->ul = asn1_request->ue_aggr_max_bit_rate.ue_aggr_max_bit_rate_ul; |
1168 | 0 | } |
1169 | | |
1170 | | // Fill core network assist info for inactive. |
1171 | 0 | if (asn1_request->core_network_assist_info_for_inactive_present) { |
1172 | 0 | request.core_network_assist_info_for_inactive = |
1173 | 0 | asn1_to_core_network_assist_info_for_inactive(asn1_request->core_network_assist_info_for_inactive); |
1174 | 0 | } |
1175 | | |
1176 | | // Fill new GUAMI. |
1177 | 0 | if (asn1_request->new_guami_present) { |
1178 | 0 | expected<guami_t, std::string> guami = asn1_to_guami(asn1_request->new_guami); |
1179 | 0 | if (!guami.has_value()) { |
1180 | 0 | return false; |
1181 | 0 | } |
1182 | 0 | request.new_guami = guami.value(); |
1183 | 0 | } |
1184 | | |
1185 | | /// TODO: Fill missing optional values. |
1186 | | |
1187 | 0 | return true; |
1188 | 0 | } |
1189 | | |
1190 | | /// \brief Convert NGAP ASN.1 Write-Replace Warning Request to common type. |
1191 | | /// \param[out] req The common-type struct to fill. |
1192 | | /// \param[in] msg The ASN.1 Write-Replace Warning Request. |
1193 | | inline void fill_ngap_write_replace_warning_request(ngap_write_replace_warning_request& req, |
1194 | | const asn1::ngap::write_replace_warning_request_s& msg) |
1195 | 0 | { |
1196 | | // Mandatory IEs. |
1197 | 0 | req.msg_id = static_cast<uint16_t>(msg->msg_id.to_number()); |
1198 | 0 | req.serial_num = static_cast<uint16_t>(msg->serial_num.to_number()); |
1199 | 0 | req.repeat_period = msg->repeat_period; |
1200 | 0 | req.nof_broadcasts_requested = msg->nof_broadcasts_requested; |
1201 | | |
1202 | | // Warning Area List (optional). |
1203 | 0 | if (msg->warning_area_list_present) { |
1204 | 0 | const auto& wal = msg->warning_area_list; |
1205 | 0 | switch (wal.type()) { |
1206 | 0 | case asn1::ngap::warning_area_list_c::types_opts::nr_cgi_list_for_warning: { |
1207 | 0 | ngap_nr_cgi_list_for_warning cgi_list; |
1208 | 0 | for (const auto& asn1_cgi : wal.nr_cgi_list_for_warning()) { |
1209 | 0 | nr_cell_global_id_t cgi; |
1210 | 0 | cgi.plmn_id = plmn_identity::from_bytes(asn1_cgi.plmn_id.to_bytes()).value(); |
1211 | 0 | cgi.nci = nr_cell_identity::create(asn1_cgi.nr_cell_id.to_number()).value(); |
1212 | 0 | cgi_list.push_back(cgi); |
1213 | 0 | } |
1214 | 0 | req.warning_area_list = std::move(cgi_list); |
1215 | 0 | break; |
1216 | 0 | } |
1217 | 0 | case asn1::ngap::warning_area_list_c::types_opts::tai_list_for_warning: { |
1218 | 0 | ngap_tai_list_for_warning tai_list; |
1219 | 0 | for (const auto& asn1_tai : wal.tai_list_for_warning()) { |
1220 | 0 | tai_t tai; |
1221 | 0 | tai.plmn_id = plmn_identity::from_bytes(asn1_tai.plmn_id.to_bytes()).value(); |
1222 | 0 | tai.tac = asn1_tai.tac.to_number(); |
1223 | 0 | tai_list.push_back(tai); |
1224 | 0 | } |
1225 | 0 | req.warning_area_list = std::move(tai_list); |
1226 | 0 | break; |
1227 | 0 | } |
1228 | 0 | case asn1::ngap::warning_area_list_c::types_opts::emergency_area_id_list: { |
1229 | 0 | ngap_emergency_area_id_list eaid_list; |
1230 | 0 | for (const auto& asn1_eaid : wal.emergency_area_id_list()) { |
1231 | 0 | eaid_list.push_back(asn1_eaid.to_bytes()); |
1232 | 0 | } |
1233 | 0 | req.warning_area_list = std::move(eaid_list); |
1234 | 0 | break; |
1235 | 0 | } |
1236 | 0 | default: |
1237 | | // EUTRA CGI list and choice extensions not supported; treat as absent. |
1238 | 0 | break; |
1239 | 0 | } |
1240 | 0 | } |
1241 | | |
1242 | | // Warning Type (optional, fixed_octstring<2>). |
1243 | 0 | if (msg->warning_type_present) { |
1244 | 0 | req.warning_type = static_cast<uint16_t>(msg->warning_type.to_number()); |
1245 | 0 | } |
1246 | | |
1247 | | // Data Coding Scheme (optional, 8-bit bitstring). |
1248 | 0 | if (msg->data_coding_scheme_present) { |
1249 | 0 | req.data_coding_scheme = static_cast<uint8_t>(msg->data_coding_scheme.to_number()); |
1250 | 0 | } |
1251 | | |
1252 | | // Warning Message Contents (optional, bounded_octstring<1,9600>). |
1253 | 0 | if (msg->warning_msg_contents_present) { |
1254 | 0 | const auto& wmc = msg->warning_msg_contents; |
1255 | 0 | req.warning_msg_contents = byte_buffer::create(wmc.data(), wmc.data() + wmc.size()).value(); |
1256 | 0 | } |
1257 | | |
1258 | | // Concurrent Warning Message Indication (optional). |
1259 | 0 | if (msg->concurrent_warning_msg_ind_present) { |
1260 | 0 | req.concurrent_warning_msg_ind = true; |
1261 | 0 | } |
1262 | 0 | } |
1263 | | |
1264 | | /// \brief Fill ASN.1 Write-Replace Warning Response from common type. |
1265 | | /// \param[out] asn1_resp The ASN.1 struct to fill. |
1266 | | /// \param[in] resp The common-type response. |
1267 | | inline void fill_asn1_write_replace_warning_response(asn1::ngap::write_replace_warning_resp_s& asn1_resp, |
1268 | | const ngap_write_replace_warning_response& resp) |
1269 | 0 | { |
1270 | 0 | asn1_resp->msg_id.from_number(resp.msg_id, 16); |
1271 | 0 | asn1_resp->serial_num.from_number(resp.serial_num, 16); |
1272 | 0 | } |
1273 | | |
1274 | | } // namespace ocudu::ocucp |