Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenXG
OpenXG-RAN
Commits
6de1b780
Commit
6de1b780
authored
May 31, 2024
by
Robert Schmidt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TODO HO trigger through UE context setup
handover prep CU
parent
01d69687
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
193 additions
and
0 deletions
+193
-0
openair2/RRC/NR/MESSAGES/asn1_msg.c
openair2/RRC/NR/MESSAGES/asn1_msg.c
+41
-0
openair2/RRC/NR/MESSAGES/asn1_msg.h
openair2/RRC/NR/MESSAGES/asn1_msg.h
+2
-0
openair2/RRC/NR/rrc_gNB.c
openair2/RRC/NR/rrc_gNB.c
+120
-0
openair2/RRC/NR/rrc_gNB_du.c
openair2/RRC/NR/rrc_gNB_du.c
+28
-0
openair2/RRC/NR/rrc_gNB_du.h
openair2/RRC/NR/rrc_gNB_du.h
+2
-0
No files found.
openair2/RRC/NR/MESSAGES/asn1_msg.c
View file @
6de1b780
...
...
@@ -80,6 +80,8 @@
#include "NR_PCCH-Message.h"
#include "NR_PagingRecord.h"
#include "NR_UE-CapabilityRequestFilterNR.h"
#include "NR_HandoverPreparationInformation.h"
#include "NR_HandoverPreparationInformation-IEs.h"
#include "common/utils/nr/nr_common.h"
#if defined(NR_Rel16)
#include "NR_SCS-SpecificCarrier.h"
...
...
@@ -1372,3 +1374,42 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi)
return
((
enc_rval
.
encoded
+
7
)
/
8
);
}
/* \brief generate HandoverPreparationInformation to be sent to the DU for
* handover. Takes uecap_buf in encoded form as (1) this is the form present at
* the CU already (2) we have to clone this information anyway, so can take it
* in encoded form which we decode + add to the handoverPreparationInformation */
int
do_NR_HandoverPreparationInformation
(
const
uint8_t
*
uecap_buf
,
int
uecap_buf_size
,
uint8_t
*
buf
,
int
buf_size
)
{
NR_HandoverPreparationInformation_t
*
hpi
=
calloc
(
1
,
sizeof
(
*
hpi
));
AssertFatal
(
hpi
!=
NULL
,
"out of memory
\n
"
);
hpi
->
criticalExtensions
.
present
=
NR_HandoverPreparationInformation__criticalExtensions_PR_c1
;
hpi
->
criticalExtensions
.
choice
.
c1
=
calloc
(
1
,
sizeof
(
*
hpi
->
criticalExtensions
.
choice
.
c1
));
AssertFatal
(
hpi
->
criticalExtensions
.
choice
.
c1
!=
NULL
,
"out of memory
\n
"
);
hpi
->
criticalExtensions
.
choice
.
c1
->
present
=
NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation
;
NR_HandoverPreparationInformation_IEs_t
*
hpi_ie
=
calloc
(
1
,
sizeof
(
*
hpi_ie
));
AssertFatal
(
hpi_ie
!=
NULL
,
"out of memory
\n
"
);
hpi
->
criticalExtensions
.
choice
.
c1
->
choice
.
handoverPreparationInformation
=
hpi_ie
;
NR_UE_CapabilityRAT_ContainerList_t
*
list
=
NULL
;
asn_dec_rval_t
dec_rval
=
uper_decode_complete
(
NULL
,
&
asn_DEF_NR_UE_CapabilityRAT_ContainerList
,
(
void
**
)
&
list
,
uecap_buf
,
uecap_buf_size
);
if
(
dec_rval
.
code
==
RC_OK
)
{
hpi_ie
->
ue_CapabilityRAT_List
=
*
list
;
free
(
list
);
/* list itself is not needed, members below will be freed in ASN_STRUCT_FREE */
}
else
{
/* problem with decoding, don't put a capability */
ASN_STRUCT_FREE
(
asn_DEF_NR_UE_CapabilityRAT_ContainerList
,
list
);
list
=
NULL
;
}
if
(
true
)
xer_fprint
(
stdout
,
&
asn_DEF_NR_HandoverPreparationInformation
,
hpi
);
asn_enc_rval_t
enc_rval
=
uper_encode_to_buffer
(
&
asn_DEF_NR_HandoverPreparationInformation
,
NULL
,
hpi
,
buf
,
buf_size
);
AssertFatal
(
enc_rval
.
encoded
>
0
,
"ASN1 message encoding failed (%s, %lu)!
\n
"
,
enc_rval
.
failed_type
->
name
,
enc_rval
.
encoded
);
ASN_STRUCT_FREE
(
asn_DEF_NR_HandoverPreparationInformation
,
hpi
);
return
(
enc_rval
.
encoded
+
7
)
/
8
;
}
openair2/RRC/NR/MESSAGES/asn1_msg.h
View file @
6de1b780
...
...
@@ -113,6 +113,8 @@ int do_RRCSetupComplete(uint8_t *buffer,
const
int
dedicatedInfoNASLength
,
const
char
*
dedicatedInfoNAS
);
int
do_NR_HandoverPreparationInformation
(
const
uint8_t
*
uecap_buf
,
int
uecap_buf_size
,
uint8_t
*
buf
,
int
buf_size
);
int
do_RRCSetupRequest
(
uint8_t
*
buffer
,
size_t
buffer_size
,
uint8_t
*
rv
);
int
do_NR_RRCReconfigurationComplete_for_nsa
(
uint8_t
*
buffer
,
size_t
buffer_size
,
NR_RRC_TransactionIdentifier_t
Transaction_id
);
...
...
openair2/RRC/NR/rrc_gNB.c
View file @
6de1b780
...
...
@@ -265,6 +265,126 @@ static void rrc_gNB_CU_DU_init(gNB_RRC_INST *rrc)
cu_init_f1_ue_data
();
}
static
pdusession_level_qos_parameter_t
*
get_qos_characteristics
(
const
int
qfi
,
rrc_pdu_session_param_t
*
pduSession
);
static
f1ap_qos_characteristics_t
get_qos_char_from_qos_flow_param
(
const
pdusession_level_qos_parameter_t
*
qos_param
);
/* \brief Initiate a handover of UE to a specific target cell handled by this
* CU.
* \param ue a UE context for which the handover should be triggered. The UE
* context must be non-null (if the HO request comes from "outside" (N2, Xn),
* the UE contex must be created first.
* \param target_du the DU towards which to handover. Note: currently, the CU
* is limited to one cell per DU, so DU and cell are equivalent here.
* \param ho_ctxt contextual data for the type of handover (F1, N2, Xn) */
void
nr_initiate_handover
(
const
gNB_RRC_INST
*
rrc
,
gNB_RRC_UE_t
*
ue
,
const
nr_rrc_du_container_t
*
target_du
,
const
nr_handover_context_t
*
ho_ctxt
)
{
if
(
ue
->
ho_context
!=
NULL
)
{
LOG_E
(
NR_RRC
,
"handover for UE %u ongoing, cannot trigger new
\n
"
,
ue
->
rrc_ue_id
);
return
;
}
ue
->
ho_context
=
malloc
(
sizeof
(
*
ue
->
ho_context
));
AssertFatal
(
ue
->
ho_context
!=
NULL
,
"out of memory
\n
"
);
*
ue
->
ho_context
=
*
ho_ctxt
;
LOG_I
(
NR_RRC
,
"Handover triggered for UE %u towards DU %ld
\n
"
,
ue
->
rrc_ue_id
,
target_du
->
setup_req
->
gNB_DU_id
);
// The gNB-CU sends a UE CONTEXT SETUP REQUEST message to the target gNB-DU to create a UE context and setup
uint8_t
buf
[
RRC_BUF_SIZE
];
int
size
=
do_NR_HandoverPreparationInformation
(
ue
->
ue_cap_buffer
.
buf
,
ue
->
ue_cap_buffer
.
len
,
buf
,
RRC_BUF_SIZE
);
cu_to_du_rrc_information_t
cu2du
=
{
.
handoverPreparationInfo
=
buf
,
.
handoverPreparationInfo_length
=
size
,
};
f1ap_drb_to_be_setup_t
drbs
[
32
];
// maximum DRB can be 32
int
nb_drb
=
0
;
for
(
int
i
=
0
;
i
<
32
;
++
i
)
{
/* for each DRB */
drb_t
*
rrc_drb
=
&
ue
->
established_drbs
[
i
];
if
(
rrc_drb
->
status
==
DRB_INACTIVE
)
continue
;
f1ap_drb_to_be_setup_t
*
drb
=
&
drbs
[
nb_drb
];
nb_drb
++
;
drb
->
drb_id
=
rrc_drb
->
drb_id
;
memcpy
(
&
drb
->
up_ul_tnl
[
0
].
tl_address
,
&
rrc_drb
->
cuup_tunnel_config
.
addr
.
buffer
,
sizeof
(
uint8_t
)
*
4
);
drb
->
up_ul_tnl
[
0
].
port
=
rrc
->
eth_params_s
.
my_portd
;
drb
->
up_ul_tnl
[
0
].
teid
=
rrc_drb
->
cuup_tunnel_config
.
teid
;
drb
->
up_ul_tnl_length
=
1
;
/* fetch an existing PDU session for this DRB */
rrc_pdu_session_param_t
*
pdu
=
find_pduSession_from_drbId
(
ue
,
drb
->
drb_id
);
AssertFatal
(
pdu
!=
NULL
,
"no PDU session for DRB ID %ld
\n
"
,
drb
->
drb_id
);
drb
->
nssai
=
pdu
->
param
.
nssai
;
// for the moment, we only support one QoS flow. Put a reminder in case
// this changes
AssertFatal
(
pdu
->
param
.
nb_qos
==
1
,
"only 1 Qos flow supported
\n
"
);
drb
->
drb_info
.
flows_to_be_setup_length
=
1
;
drb
->
drb_info
.
flows_mapped_to_drb
=
calloc
(
1
,
sizeof
(
f1ap_flows_mapped_to_drb_t
));
AssertFatal
(
drb
->
drb_info
.
flows_mapped_to_drb
,
"could not allocate memory
\n
"
);
int
qfi
=
rrc_drb
->
cnAssociation
.
sdap_config
.
mappedQoS_FlowsToAdd
[
0
];
DevAssert
(
qfi
>
0
);
drb
->
drb_info
.
flows_mapped_to_drb
[
0
].
qfi
=
qfi
;
pdusession_level_qos_parameter_t
*
in_qos_char
=
get_qos_characteristics
(
qfi
,
pdu
);
drb
->
drb_info
.
flows_mapped_to_drb
[
0
].
qos_params
.
qos_characteristics
=
get_qos_char_from_qos_flow_param
(
in_qos_char
);
/* the DRB QoS parameters: we just reuse the ones from the first flow */
drb
->
drb_info
.
drb_qos
=
drb
->
drb_info
.
flows_mapped_to_drb
[
0
].
qos_params
;
}
f1ap_srb_to_be_setup_t
srbs
[
2
]
=
{{.
srb_id
=
1
,
.
lcid
=
1
},
{.
srb_id
=
2
,
.
lcid
=
2
}};
f1_ue_data_t
ue_data
=
cu_get_f1_ue_data
(
ue
->
rrc_ue_id
);
f1ap_served_cell_info_t
*
cell_info
=
&
target_du
->
setup_req
->
cell
[
0
].
info
;
RETURN_IF_INVALID_ASSOC_ID
(
ue_data
);
f1ap_ue_context_setup_t
ue_context_setup_req
=
{
.
gNB_CU_ue_id
=
ue
->
rrc_ue_id
,
.
gNB_DU_ue_id
=
0
,
/* TODO: this should be optional! */
.
plmn
.
mcc
=
cell_info
->
plmn
.
mcc
,
.
plmn
.
mnc
=
cell_info
->
plmn
.
mnc
,
.
plmn
.
mnc_digit_length
=
cell_info
->
plmn
.
mnc_digit_length
,
.
nr_cellid
=
cell_info
->
nr_cellid
,
.
servCellId
=
0
,
// TODO: correct value?
.
srbs_to_be_setup_length
=
2
,
.
srbs_to_be_setup
=
srbs
,
.
drbs_to_be_setup_length
=
nb_drb
,
.
drbs_to_be_setup
=
drbs
,
.
cu_to_du_rrc_information
=
&
cu2du
,
};
rrc
->
mac_rrc
.
ue_context_setup_request
(
target_du
->
assoc_id
,
&
ue_context_setup_req
);
}
void
nr_HO_F1_trigger
(
gNB_RRC_INST
*
rrc
,
uint32_t
rrc_ue_id
)
{
rrc_gNB_ue_context_t
*
ue_context_p
=
rrc_gNB_get_ue_context
(
rrc
,
rrc_ue_id
);
if
(
ue_context_p
==
NULL
)
{
LOG_E
(
NR_RRC
,
"cannot find UE context for UE ID %d
\n
"
,
rrc_ue_id
);
return
;
}
gNB_RRC_UE_t
*
ue
=
&
ue_context_p
->
ue_context
;
nr_rrc_du_container_t
*
source_du
=
get_du_for_ue
(
rrc
,
ue
->
rrc_ue_id
);
if
(
source_du
==
NULL
)
{
LOG_E
(
NR_RRC
,
"cannot get source gNB-DU u for UE %u
\n
"
,
ue
->
rrc_ue_id
);
return
;
}
nr_rrc_du_container_t
*
target_du
=
find_target_du
(
rrc
,
source_du
->
assoc_id
);
// get_du_by_cell_id(rrc, target_cell);
if
(
target_du
==
NULL
)
{
LOG_E
(
NR_RRC
,
"No target gNB-DU found. Handover for UE %u aborted.
\n
"
,
ue
->
rrc_ue_id
);
// target_cell?
return
;
}
f1_ue_data_t
ue_data
=
cu_get_f1_ue_data
(
ue
->
rrc_ue_id
);
nr_handover_context_t
ho_ctxt
=
{
.
type
=
HANDOVER_TYPE_INTRA_CU
,
.
data
.
intra_cu
.
source_du
=
source_du
->
assoc_id
,
.
data
.
intra_cu
.
target_du
=
target_du
->
assoc_id
,
.
data
.
intra_cu
.
source_secondary_ue
=
ue_data
.
secondary_ue
,
};
nr_initiate_handover
(
rrc
,
ue
,
target_du
,
&
ho_ctxt
);
}
void
openair_rrc_gNB_configuration
(
gNB_RRC_INST
*
rrc
,
gNB_RrcConfigurationReq
*
configuration
)
{
AssertFatal
(
rrc
!=
NULL
,
"RC.nrrrc not initialized!"
);
...
...
openair2/RRC/NR/rrc_gNB_du.c
View file @
6de1b780
...
...
@@ -529,3 +529,31 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f)
}
}
}
nr_rrc_du_container_t
*
find_target_du
(
gNB_RRC_INST
*
rrc
,
sctp_assoc_t
source_assoc_id
)
{
nr_rrc_du_container_t
*
target_du
=
NULL
;
nr_rrc_du_container_t
*
it
=
NULL
;
bool
next_du
=
false
;
RB_FOREACH
(
it
,
rrc_du_tree
,
&
rrc
->
dus
)
{
if
(
next_du
==
false
&&
source_assoc_id
!=
it
->
assoc_id
)
{
continue
;
}
else
if
(
source_assoc_id
==
it
->
assoc_id
)
{
next_du
=
true
;
}
else
{
target_du
=
it
;
break
;
}
}
if
(
target_du
==
NULL
)
{
RB_FOREACH
(
it
,
rrc_du_tree
,
&
rrc
->
dus
)
{
if
(
source_assoc_id
==
it
->
assoc_id
)
{
continue
;
}
else
{
target_du
=
it
;
break
;
}
}
}
return
target_du
;
}
openair2/RRC/NR/rrc_gNB_du.h
View file @
6de1b780
...
...
@@ -49,4 +49,6 @@ int get_dl_band(const struct f1ap_served_cell_info_t *cell_info);
int
get_ssb_scs
(
const
struct
f1ap_served_cell_info_t
*
cell_info
);
int
get_ssb_arfcn
(
const
struct
nr_rrc_du_container_t
*
du
);
struct
nr_rrc_du_container_t
*
find_target_du
(
struct
gNB_RRC_INST_s
*
rrc
,
sctp_assoc_t
source_assoc_id
);
#endif
/* RRC_GNB_DU_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment