Coverage Report

Created: 2026-10-28 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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