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
b5e13204
Commit
b5e13204
authored
Aug 26, 2022
by
Sakthivel Velumani
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Send UL UP address via F1 UE cxt mod msg
parent
ecfd0fe2
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
259 additions
and
32 deletions
+259
-32
openair2/COMMON/e1ap_messages_types.h
openair2/COMMON/e1ap_messages_types.h
+17
-5
openair2/E1AP/e1ap.c
openair2/E1AP/e1ap.c
+198
-9
openair2/E1AP/e1ap.h
openair2/E1AP/e1ap.h
+3
-0
openair2/E1AP/e1ap_common.c
openair2/E1AP/e1ap_common.c
+5
-1
openair2/E1AP/e1ap_common.h
openair2/E1AP/e1ap_common.h
+4
-0
openair2/RRC/NR/rrc_gNB.c
openair2/RRC/NR/rrc_gNB.c
+32
-17
No files found.
openair2/COMMON/e1ap_messages_types.h
View file @
b5e13204
...
@@ -35,6 +35,8 @@
...
@@ -35,6 +35,8 @@
#define E1AP_MAX_NUM_DRBS 4
#define E1AP_MAX_NUM_DRBS 4
#define E1AP_MAX_NUM_DRBS 4
#define E1AP_MAX_NUM_DRBS 4
#define E1AP_MAX_NUM_UP_PARAM 4
#define E1AP_MAX_NUM_UP_PARAM 4
#define E1AP_GTP_INST_N3 10
#define E1AP_GTP_INST_F1U 11
#define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req
#define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req
#define E1AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_resp
#define E1AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_resp
...
@@ -75,6 +77,12 @@ typedef struct cell_group_s {
...
@@ -75,6 +77,12 @@ typedef struct cell_group_s {
long
id
;
long
id
;
}
cell_group_t
;
}
cell_group_t
;
typedef
struct
up_params_s
{
in_addr_t
tlAddress
;
long
teId
;
int
cell_group_id
;
}
up_params_t
;
typedef
struct
drb_to_setup_s
{
typedef
struct
drb_to_setup_s
{
long
drbId
;
long
drbId
;
long
pDCP_SN_Size_UL
;
long
pDCP_SN_Size_UL
;
...
@@ -115,6 +123,8 @@ typedef struct DRB_nGRAN_to_setup_s {
...
@@ -115,6 +123,8 @@ typedef struct DRB_nGRAN_to_setup_s {
long
rLC_Mode
;
long
rLC_Mode
;
in_addr_t
tlAddress
;
in_addr_t
tlAddress
;
int
teId
;
int
teId
;
int
numDlUpParam
;
up_params_t
DlUpParamList
[
E1AP_MAX_NUM_UP_PARAM
];
int
numCellGroups
;
int
numCellGroups
;
cell_group_t
cellGroupList
[
E1AP_MAX_NUM_CELL_GROUPS
];
cell_group_t
cellGroupList
[
E1AP_MAX_NUM_CELL_GROUPS
];
int
numQosFlow2Setup
;
int
numQosFlow2Setup
;
...
@@ -135,10 +145,13 @@ typedef struct pdu_session_to_setup_s {
...
@@ -135,10 +145,13 @@ typedef struct pdu_session_to_setup_s {
int
tl_port_dl
;
int
tl_port_dl
;
long
numDRB2Setup
;
long
numDRB2Setup
;
DRB_nGRAN_to_setup_t
DRBnGRanList
[
E1AP_MAX_NUM_NGRAN_DRB
];
DRB_nGRAN_to_setup_t
DRBnGRanList
[
E1AP_MAX_NUM_NGRAN_DRB
];
long
numDRB2Modify
;
DRB_nGRAN_to_setup_t
DRBnGRanModList
[
E1AP_MAX_NUM_NGRAN_DRB
];
}
pdu_session_to_setup_t
;
}
pdu_session_to_setup_t
;
typedef
struct
e1ap_bearer_setup_req_s
{
typedef
struct
e1ap_bearer_setup_req_s
{
uint64_t
gNB_cu_cp_ue_id
;
uint64_t
gNB_cu_cp_ue_id
;
uint64_t
gNB_cu_up_ue_id
;
rnti_t
rnti
;
rnti_t
rnti
;
uint64_t
cipheringAlgorithm
;
uint64_t
cipheringAlgorithm
;
uint64_t
integrityProtectionAlgorithm
;
uint64_t
integrityProtectionAlgorithm
;
...
@@ -151,13 +164,10 @@ typedef struct e1ap_bearer_setup_req_s {
...
@@ -151,13 +164,10 @@ typedef struct e1ap_bearer_setup_req_s {
drb_to_setup_t
DRBList
[
E1AP_MAX_NUM_DRBS
];
drb_to_setup_t
DRBList
[
E1AP_MAX_NUM_DRBS
];
int
numPDUSessions
;
int
numPDUSessions
;
pdu_session_to_setup_t
pduSession
[
E1AP_MAX_NUM_PDU_SESSIONS
];
pdu_session_to_setup_t
pduSession
[
E1AP_MAX_NUM_PDU_SESSIONS
];
int
numPDUSessionsMod
;
pdu_session_to_setup_t
pduSessionMod
[
E1AP_MAX_NUM_PDU_SESSIONS
];
}
e1ap_bearer_setup_req_t
;
}
e1ap_bearer_setup_req_t
;
typedef
struct
up_params_s
{
in_addr_t
tlAddress
;
long
teId
;
}
up_params_t
;
typedef
struct
drb_setup_s
{
typedef
struct
drb_setup_s
{
int
drbId
;
int
drbId
;
in_addr_t
tlAddress
;
in_addr_t
tlAddress
;
...
@@ -205,6 +215,8 @@ typedef struct e1ap_bearer_setup_resp_s {
...
@@ -205,6 +215,8 @@ typedef struct e1ap_bearer_setup_resp_s {
typedef
struct
e1ap_upcp_inst_s
{
typedef
struct
e1ap_upcp_inst_s
{
uint32_t
assoc_id
;
uint32_t
assoc_id
;
instance_t
gtpInstN3
;
instance_t
gtpInstF1U
;
e1ap_setup_req_t
setupReq
;
e1ap_setup_req_t
setupReq
;
e1ap_bearer_setup_req_t
bearerSetupReq
;
e1ap_bearer_setup_req_t
bearerSetupReq
;
e1ap_bearer_setup_resp_t
bearerSetupResp
;
e1ap_bearer_setup_resp_t
bearerSetupResp
;
...
...
openair2/E1AP/e1ap.c
View file @
b5e13204
...
@@ -40,7 +40,7 @@ e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3] = {
...
@@ -40,7 +40,7 @@ e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3] = {
{
0
,
0
,
0
},
/* gNBCUCPConfigurationUpdate */
{
0
,
0
,
0
},
/* gNBCUCPConfigurationUpdate */
{
0
,
0
,
0
},
/* E1Release */
{
0
,
0
,
0
},
/* E1Release */
{
e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST
,
e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE
,
e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE
},
/* bearerContextSetup */
{
e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST
,
e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE
,
e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE
},
/* bearerContextSetup */
{
0
,
0
,
0
},
/* bearerContextModification */
{
e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST
,
0
,
0
},
/* bearerContextModification */
{
0
,
0
,
0
},
/* bearerContextModificationRequired */
{
0
,
0
,
0
},
/* bearerContextModificationRequired */
{
0
,
0
,
0
},
/* bearerContextRelease */
{
0
,
0
,
0
},
/* bearerContextRelease */
{
0
,
0
,
0
},
/* bearerContextReleaseRequired */
{
0
,
0
,
0
},
/* bearerContextReleaseRequired */
...
@@ -1059,6 +1059,24 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(instance_t instance,
...
@@ -1059,6 +1059,24 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(instance_t instance,
E1AP_DRB_Setup_Item_NG_RAN_t
*
drb
=
pdu
->
dRB_Setup_List_NG_RAN
.
list
.
array
[
j
];
E1AP_DRB_Setup_Item_NG_RAN_t
*
drb
=
pdu
->
dRB_Setup_List_NG_RAN
.
list
.
array
[
j
];
drbSetup
->
id
=
drb
->
dRB_ID
;
drbSetup
->
id
=
drb
->
dRB_ID
;
drbSetup
->
numUpParam
=
drb
->
uL_UP_Transport_Parameters
.
list
.
count
;
for
(
int
k
=
0
;
k
<
drb
->
uL_UP_Transport_Parameters
.
list
.
count
;
k
++
)
{
up_params_t
*
UL_UP_param
=
drbSetup
->
UpParamList
+
k
;
E1AP_UP_Parameters_Item_t
*
in_UL_UP_param
=
drb
->
uL_UP_Transport_Parameters
.
list
.
array
[
k
];
AssertFatal
(
in_UL_UP_param
->
uP_TNL_Information
.
present
==
E1AP_UP_TNL_Information_PR_gTPTunnel
,
"in_UL_UP_param->uP_TNL_Information.present != E1AP_UP_TNL_Information_PR_gTPTunnel
\n
"
);
E1AP_GTPTunnel_t
*
gTPTunnel
=
in_UL_UP_param
->
uP_TNL_Information
.
choice
.
gTPTunnel
;
if
(
gTPTunnel
)
{
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4
(
&
gTPTunnel
->
transportLayerAddress
,
UL_UP_param
->
tlAddress
);
OCTET_STRING_TO_INT32
(
&
gTPTunnel
->
gTP_TEID
,
UL_UP_param
->
teId
);
}
else
{
AssertFatal
(
false
,
"gTPTunnel information in required
\n
"
);
}
}
}
}
}
}
break
;
break
;
...
@@ -1087,9 +1105,76 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance,
...
@@ -1087,9 +1105,76 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance,
*/
*/
int
e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST
(
instance_t
instance
,
int
e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST
(
instance_t
instance
,
e1ap_bearer_setup_req_t
*
req
)
{
e1ap_bearer_setup_req_t
*
bearerCxt
)
{
AssertFatal
(
false
,
"Not implemented yet
\n
"
);
E1AP_E1AP_PDU_t
pdu
=
{
0
};
/* Create */
/* 0. pdu Type */
e1ap_setup_req_t
*
setup
=
&
getCxtE1
(
CPtype
,
instance
)
->
setupReq
;
if
(
!
setup
)
{
LOG_E
(
E1AP
,
"got send_BEARER_CONTEXT_MODIFICATION_REQUEST on not established instance (%ld)
\n
"
,
instance
);
return
-
1
;
return
-
1
;
}
pdu
.
present
=
E1AP_E1AP_PDU_PR_initiatingMessage
;
asn1cCalloc
(
pdu
.
choice
.
initiatingMessage
,
msg
);
msg
->
procedureCode
=
E1AP_ProcedureCode_id_bearerContextModification
;
msg
->
criticality
=
E1AP_Criticality_reject
;
msg
->
value
.
present
=
E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest
;
E1AP_BearerContextModificationRequest_t
*
out
=
&
pdu
.
choice
.
initiatingMessage
->
value
.
choice
.
BearerContextModificationRequest
;
/* mandatory */
/* c1. gNB-CU-CP UE E1AP ID */
asn1cSequenceAdd
(
out
->
protocolIEs
.
list
,
E1AP_BearerContextModificationRequestIEs_t
,
ieC1
);
ieC1
->
id
=
E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID
;
ieC1
->
criticality
=
E1AP_Criticality_reject
;
ieC1
->
value
.
present
=
E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID
;
ieC1
->
value
.
choice
.
GNB_CU_CP_UE_E1AP_ID
=
bearerCxt
->
gNB_cu_cp_ue_id
;
/* mandatory */
/* c2. gNB-CU-UP UE E1AP ID */
asn1cSequenceAdd
(
out
->
protocolIEs
.
list
,
E1AP_BearerContextModificationRequestIEs_t
,
ieC2
);
ieC2
->
id
=
E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID
;
ieC2
->
criticality
=
E1AP_Criticality_reject
;
ieC2
->
value
.
present
=
E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID
;
ieC2
->
value
.
choice
.
GNB_CU_UP_UE_E1AP_ID
=
bearerCxt
->
gNB_cu_cp_ue_id
;
/* optional */
/* */
asn1cSequenceAdd
(
out
->
protocolIEs
.
list
,
E1AP_BearerContextModificationRequestIEs_t
,
ieC3
);
ieC3
->
id
=
E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest
;
ieC3
->
criticality
=
E1AP_Criticality_reject
;
ieC3
->
value
.
present
=
E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest
;
ieC3
->
value
.
choice
.
System_BearerContextModificationRequest
.
present
=
E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest
;
E1AP_ProtocolIE_Container_4932P26_t
*
msgNGRAN_list
=
calloc
(
1
,
sizeof
(
E1AP_ProtocolIE_Container_4932P26_t
));
ieC3
->
value
.
choice
.
System_BearerContextModificationRequest
.
choice
.
nG_RAN_BearerContextModificationRequest
=
(
struct
E1AP_ProtocolIE_Container
*
)
msgNGRAN_list
;
asn1cSequenceAdd
(
msgNGRAN_list
->
list
,
E1AP_NG_RAN_BearerContextModificationRequest_t
,
msgNGRAN
);
msgNGRAN
->
id
=
E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List
;
msgNGRAN
->
criticality
=
E1AP_Criticality_reject
;
msgNGRAN
->
value
.
present
=
E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List
;
E1AP_PDU_Session_Resource_To_Modify_List_t
*
pdu2Setup
=
&
msgNGRAN
->
value
.
choice
.
PDU_Session_Resource_To_Modify_List
;
for
(
pdu_session_to_setup_t
*
i
=
bearerCxt
->
pduSessionMod
;
i
<
bearerCxt
->
pduSessionMod
+
bearerCxt
->
numPDUSessionsMod
;
i
++
)
{
asn1cSequenceAdd
(
pdu2Setup
->
list
,
E1AP_PDU_Session_Resource_To_Modify_Item_t
,
ieC3_1
);
ieC3_1
->
pDU_Session_ID
=
i
->
sessionId
;
for
(
DRB_nGRAN_to_setup_t
*
j
=
i
->
DRBnGRanModList
;
j
<
i
->
DRBnGRanModList
+
i
->
numDRB2Modify
;
j
++
)
{
asn1cCalloc
(
ieC3_1
->
dRB_To_Modify_List_NG_RAN
,
drb2Mod_List
);
asn1cSequenceAdd
(
drb2Mod_List
->
list
,
E1AP_DRB_To_Modify_Item_NG_RAN_t
,
drb2Mod
);
drb2Mod
->
dRB_ID
=
j
->
id
;
if
(
j
->
numDlUpParam
>
0
)
{
asn1cCalloc
(
drb2Mod
->
dL_UP_Parameters
,
DL_UP_Param_List
);
for
(
up_params_t
*
k
=
j
->
DlUpParamList
;
k
<
j
->
DlUpParamList
+
j
->
numDlUpParam
;
k
++
)
{
asn1cSequenceAdd
(
DL_UP_Param_List
->
list
,
E1AP_UP_Parameters_Item_t
,
DL_UP_Param
);
DL_UP_Param
->
uP_TNL_Information
.
present
=
E1AP_UP_TNL_Information_PR_gTPTunnel
;
asn1cCalloc
(
DL_UP_Param
->
uP_TNL_Information
.
choice
.
gTPTunnel
,
gTPTunnel
);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING
(
k
->
tlAddress
,
&
gTPTunnel
->
transportLayerAddress
);
INT32_TO_OCTET_STRING
(
k
->
teId
,
&
gTPTunnel
->
gTP_TEID
);
DL_UP_Param
->
cell_Group_ID
=
k
->
cell_group_id
;
}
}
}
}
e1ap_encode_send
(
CPtype
,
instance
,
&
pdu
,
0
,
__func__
);
return
0
;
}
}
int
e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE
(
instance_t
instance
)
{
int
e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE
(
instance_t
instance
)
{
...
@@ -1103,11 +1188,115 @@ int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance) {
...
@@ -1103,11 +1188,115 @@ int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance) {
}
}
int
e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST
(
instance_t
instance
,
int
e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST
(
instance_t
instance
,
uint32_t
assoc_id
,
uint32_t
stream
,
E1AP_E1AP_PDU_t
*
pdu
)
{
E1AP_E1AP_PDU_t
*
pdu
)
{
AssertFatal
(
false
,
"Not implemented yet
\n
"
);
e1ap_upcp_inst_t
*
e1_inst
=
getCxtE1
(
UPtype
,
instance
);
if
(
!
e1_inst
)
{
LOG_E
(
E1AP
,
"got BEARER_CONTEXT_MODIFICATION_REQUEST on not established instance (%ld)
\n
"
,
instance
);
return
-
1
;
return
-
1
;
}
DevAssert
(
pdu
!=
NULL
);
AssertFatal
(
pdu
->
present
==
E1AP_E1AP_PDU_PR_initiatingMessage
,
"pdu->present != E1AP_E1AP_PDU_PR_initiatingMessage
\n
"
);
AssertFatal
(
pdu
->
choice
.
initiatingMessage
->
procedureCode
==
E1AP_ProcedureCode_id_bearerContextModification
,
"procedureCode != E1AP_ProcedureCode_id_bearerContextModification
\n
"
);
AssertFatal
(
pdu
->
choice
.
initiatingMessage
->
criticality
==
E1AP_Criticality_reject
,
"criticality != E1AP_Criticality_reject
\n
"
);
AssertFatal
(
pdu
->
choice
.
initiatingMessage
->
value
.
present
==
E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest
,
"initiatingMessage->value.present != E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest
\n
"
);
E1AP_BearerContextModificationRequest_t
*
in
=
&
pdu
->
choice
.
initiatingMessage
->
value
.
choice
.
BearerContextModificationRequest
;
E1AP_BearerContextModificationRequestIEs_t
*
ie
;
MessageDef
*
msg
=
itti_alloc_new_message
(
TASK_CUUP_E1
,
0
,
E1AP_BEARER_CONTEXT_MODIFICATION_REQ
);
e1ap_bearer_setup_req_t
*
bearerCxt
=
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg
);
LOG_I
(
E1AP
,
"Bearer context setup number of IEs %d
\n
"
,
in
->
protocolIEs
.
list
.
count
);
for
(
int
i
=
0
;
i
<
in
->
protocolIEs
.
list
.
count
;
i
++
)
{
ie
=
in
->
protocolIEs
.
list
.
array
[
i
];
switch
(
ie
->
id
)
{
case
E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID
:
AssertFatal
(
ie
->
criticality
==
E1AP_Criticality_reject
,
"ie->criticality != E1AP_Criticality_reject
\n
"
);
AssertFatal
(
ie
->
value
.
present
==
E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID
,
"ie->value.present != E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID
\n
"
);
bearerCxt
->
gNB_cu_cp_ue_id
=
ie
->
value
.
choice
.
GNB_CU_CP_UE_E1AP_ID
;
break
;
case
E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID
:
AssertFatal
(
ie
->
criticality
==
E1AP_Criticality_reject
,
"ie->criticality != E1AP_Criticality_reject
\n
"
);
AssertFatal
(
ie
->
value
.
present
==
E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID
,
"ie->value.present != E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID
\n
"
);
bearerCxt
->
gNB_cu_up_ue_id
=
ie
->
value
.
choice
.
GNB_CU_UP_UE_E1AP_ID
;
break
;
case
E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest
:
AssertFatal
(
ie
->
criticality
==
E1AP_Criticality_reject
,
"ie->criticality != E1AP_Criticality_reject
\n
"
);
AssertFatal
(
ie
->
value
.
present
==
E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest
,
"ie->value.present != E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest
\n
"
);
AssertFatal
(
ie
->
value
.
choice
.
System_BearerContextModificationRequest
.
present
==
E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest
,
"ie->value.choice.System_BearerContextSetupRequest.present !="
"E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest
\n
"
);
AssertFatal
(
ie
->
value
.
choice
.
System_BearerContextModificationRequest
.
choice
.
nG_RAN_BearerContextModificationRequest
,
"nG_RAN_BearerContextModificationRequest is NULL
\n
"
);
E1AP_ProtocolIE_Container_4932P26_t
*
msgNGRAN_list
=
(
E1AP_ProtocolIE_Container_4932P26_t
*
)
ie
->
value
.
choice
.
System_BearerContextModificationRequest
.
choice
.
nG_RAN_BearerContextModificationRequest
;
E1AP_NG_RAN_BearerContextModificationRequest_t
*
msgNGRAN
=
msgNGRAN_list
->
list
.
array
[
0
];
AssertFatal
(
msgNGRAN_list
->
list
.
count
==
1
,
"nG_RAN_BearerContextModificationRequest supports only 1 count for now
\n
"
);
AssertFatal
(
msgNGRAN
->
id
==
E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List
,
"msgNGRAN->id (%ld) != E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List
\n
"
,
msgNGRAN
->
id
);
AssertFatal
(
msgNGRAN
->
value
.
present
=
E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List
,
"msgNGRAN->value.present != E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List
\n
"
);
E1AP_PDU_Session_Resource_To_Modify_List_t
*
pdu2ModList
=
&
msgNGRAN
->
value
.
choice
.
PDU_Session_Resource_To_Modify_List
;
bearerCxt
->
numPDUSessionsMod
=
pdu2ModList
->
list
.
count
;
for
(
int
i
=
0
;
i
<
pdu2ModList
->
list
.
count
;
i
++
)
{
pdu_session_to_setup_t
*
pdu
=
bearerCxt
->
pduSessionMod
+
i
;
E1AP_PDU_Session_Resource_To_Modify_Item_t
*
pdu2Mod
=
pdu2ModList
->
list
.
array
[
i
];
pdu
->
sessionId
=
pdu2Mod
->
pDU_Session_ID
;
E1AP_DRB_To_Modify_List_NG_RAN_t
*
drb2ModList
=
pdu2Mod
->
dRB_To_Modify_List_NG_RAN
;
pdu
->
numDRB2Modify
=
drb2ModList
->
list
.
count
;
for
(
int
j
=
0
;
j
<
drb2ModList
->
list
.
count
;
j
++
)
{
DRB_nGRAN_to_setup_t
*
drb
=
pdu
->
DRBnGRanModList
+
j
;
E1AP_DRB_To_Modify_Item_NG_RAN_t
*
drb2Mod
=
drb2ModList
->
list
.
array
[
j
];
drb
->
id
=
drb2Mod
->
dRB_ID
;
E1AP_UP_Parameters_t
*
dl_up_paramList
=
drb2Mod
->
dL_UP_Parameters
;
drb
->
numDlUpParam
=
dl_up_paramList
->
list
.
count
;
for
(
int
k
=
0
;
k
<
dl_up_paramList
->
list
.
count
;
k
++
)
{
up_params_t
*
dl_up_param
=
drb
->
DlUpParamList
+
k
;
E1AP_UP_Parameters_Item_t
*
dl_up_param_in
=
dl_up_paramList
->
list
.
array
[
k
];
if
(
dl_up_param_in
->
uP_TNL_Information
.
choice
.
gTPTunnel
)
{
// Optional IE
AssertFatal
(
dl_up_param_in
->
uP_TNL_Information
.
present
=
E1AP_UP_TNL_Information_PR_gTPTunnel
,
"dl_up_param_in->uP_TNL_Information.present != E1AP_UP_TNL_Information_PR_gTPTunnel
\n
"
);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4
(
&
dl_up_param_in
->
uP_TNL_Information
.
choice
.
gTPTunnel
->
transportLayerAddress
,
dl_up_param
->
tlAddress
);
OCTET_STRING_TO_INT32
(
&
dl_up_param_in
->
uP_TNL_Information
.
choice
.
gTPTunnel
->
gTP_TEID
,
dl_up_param
->
teId
);
}
else
{
AssertFatal
(
false
,
"gTPTunnel IE is missing. It is mandatory at this point
\n
"
);
}
dl_up_param
->
cell_group_id
=
dl_up_param_in
->
cell_Group_ID
;
}
}
}
break
;
default:
LOG_E
(
E1AP
,
"Handle for this IE is not implemented (or) invalid IE detected
\n
"
);
break
;
}
}
itti_send_msg_to_task
(
TASK_RRC_GNB
,
instance
,
msg
);
return
0
;
}
}
int
e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE
(
instance_t
instance
,
int
e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE
(
instance_t
instance
,
...
...
openair2/E1AP/e1ap.h
View file @
b5e13204
...
@@ -53,6 +53,9 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(instance_t instance,
...
@@ -53,6 +53,9 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(instance_t instance,
int
e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE
(
instance_t
instance
,
int
e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE
(
instance_t
instance
,
E1AP_E1AP_PDU_t
*
pdu
);
E1AP_E1AP_PDU_t
*
pdu
);
int
e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST
(
instance_t
instance
,
E1AP_E1AP_PDU_t
*
pdu
);
void
*
E1AP_CUUP_task
(
void
*
arg
);
void
*
E1AP_CUUP_task
(
void
*
arg
);
void
*
E1AP_CUCP_task
(
void
*
arg
);
void
*
E1AP_CUCP_task
(
void
*
arg
);
openair2/E1AP/e1ap_common.c
View file @
b5e13204
...
@@ -51,11 +51,12 @@ void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req) {
...
@@ -51,11 +51,12 @@ void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req) {
if
(
type
==
CPtype
)
{
if
(
type
==
CPtype
)
{
AssertFatal
(
e1ap_cp_inst
[
instance
]
==
NULL
,
"Double call to E1 CP instance %d
\n
"
,
(
int
)
instance
);
AssertFatal
(
e1ap_cp_inst
[
instance
]
==
NULL
,
"Double call to E1 CP instance %d
\n
"
,
(
int
)
instance
);
e1ap_cp_inst
[
instance
]
=
(
e1ap_upcp_inst_t
*
)
calloc
(
1
,
sizeof
(
e1ap_upcp_inst_t
));
e1ap_cp_inst
[
instance
]
=
(
e1ap_upcp_inst_t
*
)
calloc
(
1
,
sizeof
(
e1ap_upcp_inst_t
));
memcpy
(
&
e1ap_cp_inst
[
instance
]
->
setupReq
,
req
,
sizeof
(
e1ap_setup_req_t
));
}
else
if
(
type
==
UPtype
)
{
}
else
if
(
type
==
UPtype
)
{
AssertFatal
(
e1ap_up_inst
[
instance
]
==
NULL
,
"Double call to E1 UP instance %d
\n
"
,
(
int
)
instance
);
AssertFatal
(
e1ap_up_inst
[
instance
]
==
NULL
,
"Double call to E1 UP instance %d
\n
"
,
(
int
)
instance
);
e1ap_up_inst
[
instance
]
=
(
e1ap_upcp_inst_t
*
)
calloc
(
1
,
sizeof
(
e1ap_upcp_inst_t
));
e1ap_up_inst
[
instance
]
=
(
e1ap_upcp_inst_t
*
)
calloc
(
1
,
sizeof
(
e1ap_upcp_inst_t
));
memcpy
(
&
e1ap_up_inst
[
instance
]
->
setupReq
,
req
,
sizeof
(
e1ap_setup_req_t
));
memcpy
(
&
e1ap_up_inst
[
instance
]
->
setupReq
,
req
,
sizeof
(
e1ap_setup_req_t
));
e1ap_up_inst
[
instance
]
->
gtpInstN3
=
E1AP_GTP_INST_N3
;
e1ap_up_inst
[
instance
]
->
gtpInstF1U
=
E1AP_GTP_INST_F1U
;
}
else
{
}
else
{
AssertFatal
(
false
,
"Unknown CU type
\n
"
);
AssertFatal
(
false
,
"Unknown CU type
\n
"
);
}
}
...
@@ -121,6 +122,9 @@ int e1ap_decode_initiating_message(E1AP_E1AP_PDU_t *pdu) {
...
@@ -121,6 +122,9 @@ int e1ap_decode_initiating_message(E1AP_E1AP_PDU_t *pdu) {
case
E1AP_ProcedureCode_id_bearerContextSetup
:
case
E1AP_ProcedureCode_id_bearerContextSetup
:
break
;
break
;
case
E1AP_ProcedureCode_id_bearerContextModification
:
break
;
default:
default:
LOG_E
(
E1AP
,
"Unsupported procedure code (%d) for initiating message
\n
"
,
LOG_E
(
E1AP
,
"Unsupported procedure code (%d) for initiating message
\n
"
,
(
int
)
pdu
->
choice
.
initiatingMessage
->
procedureCode
);
(
int
)
pdu
->
choice
.
initiatingMessage
->
procedureCode
);
...
...
openair2/E1AP/e1ap_common.h
View file @
b5e13204
...
@@ -53,6 +53,10 @@
...
@@ -53,6 +53,10 @@
#include <E1AP_DRB-To-Setup-Item-NG-RAN.h>
#include <E1AP_DRB-To-Setup-Item-NG-RAN.h>
#include <E1AP_Cell-Group-Information-Item.h>
#include <E1AP_Cell-Group-Information-Item.h>
#include <E1AP_PDU-Session-Resource-To-Setup-Item.h>
#include <E1AP_PDU-Session-Resource-To-Setup-Item.h>
#include <E1AP_PDU-Session-Resource-To-Modify-List.h>
#include <E1AP_PDU-Session-Resource-To-Modify-Item.h>
#include <E1AP_DRB-To-Modify-List-NG-RAN.h>
#include <E1AP_DRB-To-Modify-Item-NG-RAN.h>
#include <E1AP_GTPTunnel.h>
#include <E1AP_GTPTunnel.h>
#include <E1AP_Non-Dynamic5QIDescriptor.h>
#include <E1AP_Non-Dynamic5QIDescriptor.h>
#include <E1AP_Dynamic5QIDescriptor.h>
#include <E1AP_Dynamic5QIDescriptor.h>
...
...
openair2/RRC/NR/rrc_gNB.c
View file @
b5e13204
...
@@ -3597,27 +3597,28 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch
...
@@ -3597,27 +3597,28 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, const ch
}
}
static
void
update_UL_UP_tunnel_info
(
e1ap_bearer_setup_req_t
*
req
,
instance_t
instance
,
ue_id_t
ue_id
)
{
static
void
update_UL_UP_tunnel_info
(
e1ap_bearer_setup_req_t
*
req
,
instance_t
instance
,
ue_id_t
ue_id
)
{
for
(
int
i
=
0
;
i
<
req
->
numPDUSessions
;
i
++
)
{
for
(
int
i
=
0
;
i
<
req
->
numPDUSessions
Mod
;
i
++
)
{
for
(
int
j
=
0
;
j
<
req
->
pduSession
[
i
].
numDRB2Setup
;
j
++
)
{
for
(
int
j
=
0
;
j
<
req
->
pduSession
Mod
[
i
].
numDRB2Modify
;
j
++
)
{
DRB_nGRAN_to_setup_t
*
drb_p
=
req
->
pduSession
[
i
].
DRBnGRan
List
+
j
;
DRB_nGRAN_to_setup_t
*
drb_p
=
req
->
pduSession
Mod
[
i
].
DRBnGRanMod
List
+
j
;
transport_layer_addr_t
newRemoteAddr
;
transport_layer_addr_t
newRemoteAddr
;
newRemoteAddr
.
length
=
32
;
// IPv4
newRemoteAddr
.
length
=
32
;
// IPv4
memcpy
(
newRemoteAddr
.
buffer
,
memcpy
(
newRemoteAddr
.
buffer
,
&
drb_p
->
tlAddress
,
&
drb_p
->
DlUpParamList
[
0
].
tlAddress
,
sizeof
(
in_addr_t
));
sizeof
(
in_addr_t
));
GtpuUpdateTunnelOutgoingPair
(
instance
,
GtpuUpdateTunnelOutgoingPair
(
instance
,
ue_id
,
ue_id
,
(
ebi_t
)
drb_p
->
id
,
(
ebi_t
)
drb_p
->
id
,
drb_p
->
teId
,
drb_p
->
DlUpParamList
[
0
].
teId
,
newRemoteAddr
);
newRemoteAddr
);
}
}
}
}
}
}
void
rrc_CUUP_process_bearer_context_mod_req
(
e1ap_bearer_setup_req_t
*
req
,
instance_t
instance
)
{
void
rrc_CUUP_process_bearer_context_mod_req
(
e1ap_bearer_setup_req_t
*
req
,
instance_t
instance
)
{
update_UL_UP_tunnel_info
(
req
,
instance
,
req
->
gNB_cu_cp_ue_id
);
instance_t
gtpInst
=
getCxtE1
(
UPtype
,
instance
)
->
gtpInstF1U
;
update_UL_UP_tunnel_info
(
req
,
gtpInst
,
req
->
gNB_cu_cp_ue_id
);
// TODO: send bearer cxt mod response
// TODO: send bearer cxt mod response
}
}
...
@@ -3652,18 +3653,19 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c
...
@@ -3652,18 +3653,19 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, c
MessageDef
*
msg_e1
=
itti_alloc_new_message
(
TASK_CUCP_E1
,
instance
,
E1AP_BEARER_CONTEXT_MODIFICATION_REQ
);
MessageDef
*
msg_e1
=
itti_alloc_new_message
(
TASK_CUCP_E1
,
instance
,
E1AP_BEARER_CONTEXT_MODIFICATION_REQ
);
e1ap_bearer_setup_req_t
*
req
=
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg_e1
);
e1ap_bearer_setup_req_t
*
req
=
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg_e1
);
req
->
numPDUSessions
=
ue_context_p
->
ue_context
.
nb_of_pdusessions
;
req
->
numPDUSessions
Mod
=
ue_context_p
->
ue_context
.
nb_of_pdusessions
;
req
->
gNB_cu_cp_ue_id
=
ue_context_p
->
ue_context
.
gNB_ue_ngap_id
;
req
->
gNB_cu_cp_ue_id
=
ue_context_p
->
ue_context
.
gNB_ue_ngap_id
;
req
->
rnti
=
ue_context_p
->
ue_context
.
rnti
;
req
->
rnti
=
ue_context_p
->
ue_context
.
rnti
;
for
(
int
i
=
0
;
i
<
req
->
numPDUSessions
;
i
++
)
{
for
(
int
i
=
0
;
i
<
req
->
numPDUSessions
Mod
;
i
++
)
{
req
->
pduSession
[
i
].
numDRB2Setup
=
resp
->
drbs_to_be_setup_length
;
req
->
pduSession
Mod
[
i
].
numDRB2Modify
=
resp
->
drbs_to_be_setup_length
;
for
(
int
j
=
0
;
j
<
resp
->
drbs_to_be_setup_length
;
j
++
)
{
for
(
int
j
=
0
;
j
<
resp
->
drbs_to_be_setup_length
;
j
++
)
{
f1ap_drb_to_be_setup_t
*
drb_f1
=
resp
->
drbs_to_be_setup
+
j
;
f1ap_drb_to_be_setup_t
*
drb_f1
=
resp
->
drbs_to_be_setup
+
j
;
DRB_nGRAN_to_setup_t
*
drb_e1
=
req
->
pduSession
[
i
].
DRBnGRan
List
+
j
;
DRB_nGRAN_to_setup_t
*
drb_e1
=
req
->
pduSession
Mod
[
i
].
DRBnGRanMod
List
+
j
;
drb_e1
->
id
=
drb_f1
->
drb_id
;
drb_e1
->
id
=
drb_f1
->
drb_id
;
drb_e1
->
tlAddress
=
drb_f1
->
up_dl_tnl
[
0
].
tl_address
;
drb_e1
->
numDlUpParam
=
drb_f1
->
up_dl_tnl_length
;
drb_e1
->
teId
=
drb_f1
->
up_dl_tnl
[
0
].
teid
;
drb_e1
->
DlUpParamList
[
0
].
tlAddress
=
drb_f1
->
up_dl_tnl
[
0
].
tl_address
;
drb_e1
->
DlUpParamList
[
0
].
teId
=
drb_f1
->
up_dl_tnl
[
0
].
teid
;
}
}
}
}
...
@@ -4167,7 +4169,8 @@ void rrc_gNB_process_e1_bearer_context_setup_req(e1ap_bearer_setup_req_t *req, i
...
@@ -4167,7 +4169,8 @@ void rrc_gNB_process_e1_bearer_context_setup_req(e1ap_bearer_setup_req_t *req, i
gtpv1u_gnb_create_tunnel_resp_t
create_tunnel_resp_N3
=
{
0
};
gtpv1u_gnb_create_tunnel_resp_t
create_tunnel_resp_N3
=
{
0
};
// GTP tunnel for UL
// GTP tunnel for UL
drb_config_N3gtpu_create_e1
(
req
,
&
create_tunnel_resp_N3
,
instance
);
instance_t
gtpInst
=
getCxtE1
(
UPtype
,
instance
)
->
gtpInstN3
;
drb_config_N3gtpu_create_e1
(
req
,
&
create_tunnel_resp_N3
,
gtpInst
);
MessageDef
*
message_p
;
MessageDef
*
message_p
;
message_p
=
itti_alloc_new_message
(
TASK_RRC_GNB
,
instance
,
E1AP_BEARER_CONTEXT_SETUP_RESP
);
message_p
=
itti_alloc_new_message
(
TASK_RRC_GNB
,
instance
,
E1AP_BEARER_CONTEXT_SETUP_RESP
);
...
@@ -4175,10 +4178,12 @@ void rrc_gNB_process_e1_bearer_context_setup_req(e1ap_bearer_setup_req_t *req, i
...
@@ -4175,10 +4178,12 @@ void rrc_gNB_process_e1_bearer_context_setup_req(e1ap_bearer_setup_req_t *req, i
int
remote_port
=
RC
.
nrrrc
[
ctxt
.
module_id
]
->
eth_params_s
.
remote_portd
;
int
remote_port
=
RC
.
nrrrc
[
ctxt
.
module_id
]
->
eth_params_s
.
remote_portd
;
in_addr_t
my_addr
;
in_addr_t
my_addr
;
memcpy
(
&
my_addr
,
inet_pton
(
AF_INET
,
&
getCxtE1
(
UPtype
,
instance
)
->
setupReq
.
CUUP_e1_ip_address
.
ipv4_address
,
getCxtE1
(
UPtype
,
instance
)
->
setupReq
.
CUUP_e1_ip_address
.
ipv4_address
,
sizeof
(
my_addr
));
&
my_addr
);
gNB_CU_create_up_ul_tunnel
(
resp
,
req
,
instance
,
req
->
gNB_cu_cp_ue_id
,
remote_port
,
my_addr
);
gtpInst
=
getCxtE1
(
UPtype
,
instance
)
->
gtpInstF1U
;
gNB_CU_create_up_ul_tunnel
(
resp
,
req
,
gtpInst
,
req
->
gNB_cu_cp_ue_id
,
remote_port
,
my_addr
);
resp
->
gNB_cu_cp_ue_id
=
req
->
gNB_cu_cp_ue_id
;
resp
->
gNB_cu_cp_ue_id
=
req
->
gNB_cu_cp_ue_id
;
resp
->
numPDUSessions
=
req
->
numPDUSessions
;
resp
->
numPDUSessions
=
req
->
numPDUSessions
;
...
@@ -4278,6 +4283,11 @@ void bearer_context_setup_e1ap(e1ap_bearer_setup_req_t *req, instance_t instance
...
@@ -4278,6 +4283,11 @@ void bearer_context_setup_e1ap(e1ap_bearer_setup_req_t *req, instance_t instance
// create ITTI msg and send to CUCP E1 task to send via SCTP
// create ITTI msg and send to CUCP E1 task to send via SCTP
// then in CUUP the function rrc_gNB_process_e1_bearer_context_setup_req
// then in CUUP the function rrc_gNB_process_e1_bearer_context_setup_req
rrc_gNB_ue_context_t
*
ue_context_p
=
rrc_gNB_get_ue_context
(
RC
.
nrrrc
[
GNB_INSTANCE_TO_MODULE_ID
(
instance
)],
req
->
rnti
);
protocol_ctxt_t
ctxt
=
{
0
};
PROTOCOL_CTXT_SET_BY_MODULE_ID
(
&
ctxt
,
0
,
GNB_FLAG_YES
,
ue_context_p
->
ue_context
.
rnti
,
0
,
0
,
0
);
fill_DRB_configList
(
&
ctxt
,
ue_context_p
);
MessageDef
*
msg_p
=
itti_alloc_new_message
(
TASK_CUCP_E1
,
instance
,
E1AP_BEARER_CONTEXT_SETUP_REQ
);
MessageDef
*
msg_p
=
itti_alloc_new_message
(
TASK_CUCP_E1
,
instance
,
E1AP_BEARER_CONTEXT_SETUP_REQ
);
e1ap_bearer_setup_req_t
*
bearer_req
=
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg_p
);
e1ap_bearer_setup_req_t
*
bearer_req
=
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg_p
);
memcpy
(
bearer_req
,
req
,
sizeof
(
e1ap_bearer_setup_req_t
));
memcpy
(
bearer_req
,
req
,
sizeof
(
e1ap_bearer_setup_req_t
));
...
@@ -4487,6 +4497,11 @@ void *rrc_gnb_task(void *args_p) {
...
@@ -4487,6 +4497,11 @@ void *rrc_gnb_task(void *args_p) {
rrc_gNB_process_e1_bearer_context_setup_resp
(
&
E1AP_BEARER_CONTEXT_SETUP_RESP
(
msg_p
),
instance
);
rrc_gNB_process_e1_bearer_context_setup_resp
(
&
E1AP_BEARER_CONTEXT_SETUP_RESP
(
msg_p
),
instance
);
break
;
break
;
case
E1AP_BEARER_CONTEXT_MODIFICATION_REQ
:
LOG_I
(
NR_RRC
,
"Received E1AP_BEARER_CONTEXT_MODIFICATION_REQ for instance %d
\n
"
,
(
int
)
instance
);
rrc_CUUP_process_bearer_context_mod_req
(
&
E1AP_BEARER_CONTEXT_SETUP_REQ
(
msg_p
),
instance
);
break
;
default:
default:
LOG_E
(
NR_RRC
,
"[gNB %ld] Received unexpected message %s
\n
"
,
instance
,
msg_name_p
);
LOG_E
(
NR_RRC
,
"[gNB %ld] Received unexpected message %s
\n
"
,
instance
,
msg_name_p
);
break
;
break
;
...
...
FANG WANG
@wf
mentioned in commit
553f1d1a
·
Feb 11, 2023
mentioned in commit
553f1d1a
mentioned in commit 553f1d1a52845911be4ba61ec2bcc5c60ad42ae7
Toggle commit list
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