Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-AMF
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
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-AMF
Commits
2cb6671b
Commit
2cb6671b
authored
Jul 21, 2021
by
Tien-Thinh Nguyen
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'fix_n2_handover' into 'develop'
Fix n2 handover See merge request oai/cn5g/oai-cn5g-amf!36
parents
8f5c3c14
2025ea76
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
208 additions
and
77 deletions
+208
-77
docs/FEATURE_SET.md
docs/FEATURE_SET.md
+1
-1
src/amf-app/amf_n11.cpp
src/amf-app/amf_n11.cpp
+38
-28
src/amf-app/amf_n2.cpp
src/amf-app/amf_n2.cpp
+88
-5
src/contexts/pdu_session_context.hpp
src/contexts/pdu_session_context.hpp
+2
-0
src/ngap/ngapMsgs/DownlinkRANStatusTransfer.cpp
src/ngap/ngapMsgs/DownlinkRANStatusTransfer.cpp
+11
-5
src/ngap/ngapMsgs/HandoverCommandMsg.cpp
src/ngap/ngapMsgs/HandoverCommandMsg.cpp
+18
-12
src/ngap/ngapMsgs/HandoverPreparationFailure.cpp
src/ngap/ngapMsgs/HandoverPreparationFailure.cpp
+13
-7
src/ngap/ngapMsgs/HandoverRequest.cpp
src/ngap/ngapMsgs/HandoverRequest.cpp
+17
-14
src/ngap/ngapMsgs/HandoverRequiredMsg.cpp
src/ngap/ngapMsgs/HandoverRequiredMsg.cpp
+4
-0
src/ngap/ngapMsgs/UplinkRANStatusTransfer.cpp
src/ngap/ngapMsgs/UplinkRANStatusTransfer.cpp
+16
-5
No files found.
docs/FEATURE_SET.md
View file @
2cb6671b
...
...
@@ -45,7 +45,7 @@ Based on document **3GPP TS 23.501 V16.0.0 §6.2.1**.
| 4 | Registration management | :heavy_check_mark: | |
| 5 | Connection management | :heavy_check_mark: | |
| 6 | Reachability management | :x: | |
| 7 | Mobility Management | :
x: |
|
| 7 | Mobility Management | :
heavy_check_mark: | (Experimental) Support N2 Handover
|
| 8 | Lawful intercept (for AMF events and interface to LI System) | :x: | |
| 9 | Provide transport for SM messages between UE and SMF | :heavy_check_mark: | |
| 10 | Transparent proxy for routing SM messages | :x: | |
...
...
src/amf-app/amf_n11.cpp
View file @
2cb6671b
...
...
@@ -224,6 +224,8 @@ void amf_n11::handle_itti_message(
pdu_session_update_request
[
"hoState"
]
=
"PREPARING"
;
}
else
if
(
itti_msg
.
n2sm_info_type
.
compare
(
"HANDOVER_REQ_ACK"
)
==
0
)
{
pdu_session_update_request
[
"hoState"
]
=
"PREPARED"
;
}
else
if
(
itti_msg
.
n2sm_info_type
.
compare
(
"SECONDARY_RAT_USAGE"
)
==
0
)
{
pdu_session_update_request
[
"hoState"
]
=
"COMPLETED"
;
}
curl_http_client
(
...
...
@@ -666,13 +668,10 @@ void amf_n11::curl_http_client(
}
}
// Transfer N1/N2 to gNB/UE if available
if
(
number_parts
>
1
)
{
try
{
response_data
=
nlohmann
::
json
::
parse
(
json_data_response
);
}
catch
(
nlohmann
::
json
::
exception
&
e
)
{
Logger
::
amf_n11
().
warn
(
"Could not get Json content from the response"
);
Logger
::
amf_n11
().
warn
(
"Could not get Json content from the response"
);
curl_slist_free_all
(
headers
);
curl_easy_cleanup
(
curl
);
curl_global_cleanup
();
...
...
@@ -683,13 +682,22 @@ void amf_n11::curl_http_client(
// For N2 HO
bool
is_ho_procedure
=
false
;
std
::
string
promise_result
=
{};
if
(
response_data
.
find
(
"hoState"
)
!=
response_data
.
end
())
{
is_ho_procedure
=
true
;
std
::
string
ho_state
=
{};
response_data
.
at
(
"hoState"
).
get_to
(
ho_state
);
if
(
ho_state
.
compare
(
"COMPLETED"
)
==
0
)
{
if
(
response_data
.
find
(
"pduSessionId"
)
!=
response_data
.
end
())
response_data
.
at
(
"pduSessionId"
).
get_to
(
promise_result
);
}
else
if
(
number_parts
>
1
)
{
promise_result
=
n1sm
;
// actually, N2 SM Info
}
}
// Notify to the result
if
((
promise_id
>
0
)
and
(
is_ho_procedure
))
{
amf_app_inst
->
trigger_process_response
(
promise_id
,
n1sm
);
// actually, N2 SM Info
amf_app_inst
->
trigger_process_response
(
promise_id
,
promise_result
);
curl_slist_free_all
(
headers
);
curl_easy_cleanup
(
curl
);
curl_global_cleanup
();
...
...
@@ -697,6 +705,8 @@ void amf_n11::curl_http_client(
return
;
}
// Transfer N1/N2 to gNB/UE if available
if
(
number_parts
>
1
)
{
itti_n1n2_message_transfer_request
*
itti_msg
=
new
itti_n1n2_message_transfer_request
(
TASK_AMF_N11
,
TASK_AMF_APP
);
...
...
src/amf-app/amf_n2.cpp
View file @
2cb6671b
...
...
@@ -1402,6 +1402,10 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
(
long
)
QosFlowWithDataForwardinglist
[
0
].
qosFlowIdentifier
;
Logger
::
ngap
().
debug
(
"QFI %lu"
,
qosflowidentifiervalue
);
std
::
shared_ptr
<
nas_context
>
nc
=
amf_n1_inst
->
amf_ue_id_2_nas_context
(
amf_ue_ngap_id
);
string
supi
=
"imsi-"
+
nc
.
get
()
->
imsi
;
// Send PDUSessionUpdateSMContextRequest to SMF for each active PDU sessions
std
::
map
<
uint8_t
,
boost
::
shared_future
<
std
::
string
>>
curl_responses
;
...
...
@@ -1449,8 +1453,6 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
handovercommand
->
setAmfUeNgapId
(
amf_ue_ngap_id
);
handovercommand
->
setRanUeNgapId
(
unc
.
get
()
->
ran_ue_ngap_id
);
handovercommand
->
setHandoverType
(
Ngap_HandoverType_intra5gs
);
std
::
shared_ptr
<
nas_context
>
nc
=
amf_n1_inst
->
amf_ue_id_2_nas_context
(
amf_ue_ngap_id
);
std
::
vector
<
PDUSessionResourceHandoverItem_t
>
handover_list
;
PDUSessionResourceHandoverItem_t
item
=
{};
...
...
@@ -1483,7 +1485,11 @@ void amf_n2::handle_itti_message(itti_handover_request_Ack& itti_msg) {
handover_list
.
push_back
(
item
);
// free memory
free_wrapper
((
void
**
)
&
data
);
std
::
shared_ptr
<
pdu_session_context
>
psc
=
{};
if
(
amf_app_inst
->
find_pdu_session_context
(
supi
,
item
.
pduSessionId
,
psc
))
{
psc
.
get
()
->
is_ho_accepted
=
true
;
}
}
else
{
result
=
false
;
}
...
...
@@ -1562,6 +1568,84 @@ void amf_n2::handle_itti_message(itti_handover_notify& itti_msg) {
return
;
}
std
::
shared_ptr
<
nas_context
>
nc
=
amf_n1_inst
->
amf_ue_id_2_nas_context
(
amf_ue_ngap_id
);
string
supi
=
"imsi-"
+
nc
.
get
()
->
imsi
;
std
::
vector
<
std
::
shared_ptr
<
pdu_session_context
>>
sessions_ctx
;
if
(
!
amf_app_inst
->
get_pdu_sessions_context
(
supi
,
sessions_ctx
))
{
}
// Send PDUSessionUpdateSMContextRequest to SMF for accepted PDU sessions
std
::
map
<
uint8_t
,
boost
::
shared_future
<
std
::
string
>>
curl_responses
;
for
(
auto
pdu_session
:
sessions_ctx
)
{
if
(
pdu_session
.
get
()
->
is_ho_accepted
)
{
// Generate a promise and associate this promise to the curl handle
uint32_t
promise_id
=
amf_app_inst
->
generate_promise_id
();
Logger
::
amf_n2
().
debug
(
"Promise ID generated %d"
,
promise_id
);
boost
::
shared_ptr
<
boost
::
promise
<
std
::
string
>>
p
=
boost
::
make_shared
<
boost
::
promise
<
std
::
string
>>
();
boost
::
shared_future
<
std
::
string
>
f
=
p
->
get_future
();
amf_app_inst
->
add_promise
(
promise_id
,
p
);
curl_responses
.
emplace
(
pdu_session
.
get
()
->
pdu_session_id
,
f
);
Logger
::
amf_n2
().
debug
(
"Sending ITTI to trigger PDUSessionUpdateSMContextRequest to SMF to "
"task TASK_AMF_N11"
);
itti_nsmf_pdusession_update_sm_context
*
itti_msg
=
new
itti_nsmf_pdusession_update_sm_context
(
TASK_NGAP
,
TASK_AMF_N11
);
itti_msg
->
pdu_session_id
=
pdu_session
.
get
()
->
pdu_session_id
;
// TODO: Secondary RAT Usage
itti_msg
->
n2sm
=
blk2bstr
(
""
,
0
);
itti_msg
->
is_n2sm_set
=
true
;
itti_msg
->
n2sm_info_type
=
"SECONDARY_RAT_USAGE"
;
itti_msg
->
amf_ue_ngap_id
=
amf_ue_ngap_id
;
itti_msg
->
ran_ue_ngap_id
=
ran_ue_ngap_id
;
itti_msg
->
promise_id
=
promise_id
;
std
::
shared_ptr
<
itti_nsmf_pdusession_update_sm_context
>
i
=
std
::
shared_ptr
<
itti_nsmf_pdusession_update_sm_context
>
(
itti_msg
);
int
ret
=
itti_inst
->
send_msg
(
i
);
if
(
0
!=
ret
)
{
Logger
::
ngap
().
error
(
"Could not send ITTI message %s to task TASK_AMF_N11"
,
i
->
get_msg_name
());
}
}
}
bool
result
=
true
;
while
(
!
curl_responses
.
empty
())
{
boost
::
future_status
status
;
// wait for timeout or ready
status
=
curl_responses
.
begin
()
->
second
.
wait_for
(
boost
::
chrono
::
milliseconds
(
FUTURE_STATUS_TIMEOUT_MS
));
if
(
status
==
boost
::
future_status
::
ready
)
{
assert
(
curl_responses
.
begin
()
->
second
.
is_ready
());
assert
(
curl_responses
.
begin
()
->
second
.
has_value
());
assert
(
!
curl_responses
.
begin
()
->
second
.
has_exception
());
// Wait for the result from APP and send reply to AMF
std
::
string
pdu_session_id_str
=
curl_responses
.
begin
()
->
second
.
get
();
Logger
::
ngap
().
debug
(
"Got result for PDU Session ID %d"
,
curl_responses
.
begin
()
->
first
);
if
(
pdu_session_id_str
.
size
()
>
0
)
{
result
=
result
&&
true
;
}
else
{
result
=
false
;
}
}
else
{
result
=
true
;
}
curl_responses
.
erase
(
curl_responses
.
begin
());
}
// Send UE Release Command to Source gNB
std
::
unique_ptr
<
UEContextReleaseCommandMsg
>
ueContextReleaseCommand
=
std
::
make_unique
<
UEContextReleaseCommandMsg
>
();
ueContextReleaseCommand
->
setMessageType
();
...
...
@@ -1574,8 +1658,7 @@ void amf_n2::handle_itti_message(itti_handover_notify& itti_msg) {
int
encoded_size
=
ueContextReleaseCommand
->
encode2buffer
(
buffer
,
BUFFER_SIZE_1024
);
bstring
b
=
blk2bstr
(
buffer
,
encoded_size
);
std
::
shared_ptr
<
nas_context
>
nc
=
amf_n1_inst
->
amf_ue_id_2_nas_context
(
amf_ue_ngap_id
);
sctp_s_38412
.
sctp_send_msg
(
unc
.
get
()
->
gnb_assoc_id
,
0
,
&
b
);
/*std::shared_ptr<nas_context> nc =
...
...
src/contexts/pdu_session_context.hpp
View file @
2cb6671b
...
...
@@ -55,5 +55,7 @@ class pdu_session_context {
snssai_t
snssai
;
plmn_t
plmn
;
std
::
string
smf_context_location
;
bool
is_ho_accepted
;
};
#endif
src/ngap/ngapMsgs/DownlinkRANStatusTransfer.cpp
View file @
2cb6671b
...
...
@@ -30,14 +30,17 @@ extern "C" {
using
namespace
std
;
namespace
ngap
{
DownlinkRANStatusTransfer
::
DownlinkRANStatusTransfer
()
{
amfUeNgapId
=
NULL
;
ranUeNgapId
=
NULL
;
ranStatusTransfer_TransparentContainer
=
NULL
;
DownlinkranstatustransferIEs
=
NULL
;
DownlinkranstatustransferPDU
=
NULL
;
amfUeNgapId
=
nullptr
;
ranUeNgapId
=
nullptr
;
ranStatusTransfer_TransparentContainer
=
nullptr
;
DownlinkranstatustransferIEs
=
nullptr
;
DownlinkranstatustransferPDU
=
nullptr
;
}
DownlinkRANStatusTransfer
::~
DownlinkRANStatusTransfer
()
{}
void
DownlinkRANStatusTransfer
::
setAmfUeNgapId
(
unsigned
long
id
)
{
if
(
!
amfUeNgapId
)
amfUeNgapId
=
new
AMF_UE_NGAP_ID
();
amfUeNgapId
->
setAMF_UE_NGAP_ID
(
id
);
...
...
@@ -61,6 +64,7 @@ void DownlinkRANStatusTransfer::setAmfUeNgapId(unsigned long id) {
if
(
ret
!=
0
)
cout
<<
"encode AMF_UE_NGAP_ID IE error"
<<
endl
;
// free_wrapper((void**) &ie);
}
void
DownlinkRANStatusTransfer
::
setRanUeNgapId
(
uint32_t
id
)
{
if
(
!
ranUeNgapId
)
ranUeNgapId
=
new
RAN_UE_NGAP_ID
();
ranUeNgapId
->
setRanUeNgapId
(
id
);
...
...
@@ -152,6 +156,7 @@ void DownlinkRANStatusTransfer::setRANStatusTransfer_TransparentContainer(
free_wrapper((void**) &ie);
*/
}
void
DownlinkRANStatusTransfer
::
setmessagetype
()
{
if
(
!
DownlinkranstatustransferPDU
)
{
DownlinkranstatustransferPDU
=
...
...
@@ -180,6 +185,7 @@ void DownlinkRANStatusTransfer::setmessagetype() {
<<
endl
;
}
}
int
DownlinkRANStatusTransfer
::
encodetobuffer
(
uint8_t
*
buf
,
int
buf_size
)
{
asn_fprint
(
stderr
,
&
asn_DEF_Ngap_NGAP_PDU
,
DownlinkranstatustransferPDU
);
asn_enc_rval_t
er
=
aper_encode_to_buffer
(
...
...
src/ngap/ngapMsgs/HandoverCommandMsg.cpp
View file @
2cb6671b
...
...
@@ -41,25 +41,31 @@ using namespace std;
namespace
ngap
{
HandoverCommandMsg
::
HandoverCommandMsg
()
{
amfUeNgapId
=
NULL
;
ranUeNgapId
=
NULL
;
ngap_handovertype
=
NULL
;
NASSecurityParametersFromNGRAN
=
NULL
;
PDUSessionResourceHandoverList
=
NULL
;
PDUSessionResourceToReleaseListHOCmd
=
NULL
;
TargetToSource_TransparentContainer
=
NULL
;
CriticalityDiagnostics
=
NULL
;
handoverCommandPdu
=
NULL
;
handoverCommandIEs
=
NULL
;
amfUeNgapId
=
nullptr
;
ranUeNgapId
=
nullptr
;
ngap_handovertype
=
nullptr
;
NASSecurityParametersFromNGRAN
=
nullptr
;
PDUSessionResourceHandoverList
=
nullptr
;
PDUSessionResourceToReleaseListHOCmd
=
nullptr
;
TargetToSource_TransparentContainer
=
nullptr
;
CriticalityDiagnostics
=
nullptr
;
handoverCommandPdu
=
nullptr
;
handoverCommandIEs
=
nullptr
;
}
HandoverCommandMsg
::~
HandoverCommandMsg
()
{}
unsigned
long
HandoverCommandMsg
::
getAmfUeNgapId
()
{
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
else
return
0
;
}
uint32_t
HandoverCommandMsg
::
getRanUeNgapId
()
{
if
(
ranUeNgapId
)
return
ranUeNgapId
->
getRanUeNgapId
();
if
(
ranUeNgapId
)
return
ranUeNgapId
->
getRanUeNgapId
();
else
return
0
;
}
bool
HandoverCommandMsg
::
decodefrompdu
(
Ngap_NGAP_PDU_t
*
ngap_msg_pdu
)
{
...
...
src/ngap/ngapMsgs/HandoverPreparationFailure.cpp
View file @
2cb6671b
...
...
@@ -40,21 +40,27 @@ using namespace std;
namespace
ngap
{
HandoverPreparationFailure
::
HandoverPreparationFailure
()
{
amfUeNgapId
=
NULL
;
ranUeNgapId
=
NULL
;
cause
=
NULL
;
hoPreparationFailureIEs
=
NULL
;
CriticalityDiagnostics
=
NULL
;
amfUeNgapId
=
nullptr
;
ranUeNgapId
=
nullptr
;
cause
=
nullptr
;
hoPreparationFailureIEs
=
nullptr
;
CriticalityDiagnostics
=
nullptr
;
}
HandoverPreparationFailure
::~
HandoverPreparationFailure
()
{}
unsigned
long
HandoverPreparationFailure
::
getAmfUeNgapId
()
const
{
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
else
return
0
;
}
uint32_t
HandoverPreparationFailure
::
getRanUeNgapId
()
const
{
if
(
ranUeNgapId
)
return
ranUeNgapId
->
getRanUeNgapId
();
if
(
ranUeNgapId
)
return
ranUeNgapId
->
getRanUeNgapId
();
else
return
0
;
}
bool
HandoverPreparationFailure
::
decodefrompdu
(
Ngap_NGAP_PDU_t
*
ngap_msg_pdu
)
{
...
...
src/ngap/ngapMsgs/HandoverRequest.cpp
View file @
2cb6671b
...
...
@@ -40,24 +40,27 @@ using namespace std;
namespace
ngap
{
HandoverRequest
::
HandoverRequest
()
{
amfUeNgapId
=
NULL
;
handovertype
=
NULL
;
cause
=
NULL
;
ueAggregateMaximumBitRate
=
NULL
;
ueSecurityCapabilities
=
NULL
;
SecurityContext
=
NULL
;
PDUSessionResourceSetupList
=
NULL
;
allowedNSSAI
=
NULL
;
SourceToTarget_TransparentContainer
=
NULL
;
mobilityrestrictionlist
=
NULL
;
guami
=
NULL
;
handoverRequestPdu
=
NULL
;
handoverRequestIEs
=
NULL
;
amfUeNgapId
=
nullptr
;
handovertype
=
nullptr
;
cause
=
nullptr
;
ueAggregateMaximumBitRate
=
nullptr
;
ueSecurityCapabilities
=
nullptr
;
SecurityContext
=
nullptr
;
PDUSessionResourceSetupList
=
nullptr
;
allowedNSSAI
=
nullptr
;
SourceToTarget_TransparentContainer
=
nullptr
;
mobilityrestrictionlist
=
nullptr
;
guami
=
nullptr
;
handoverRequestPdu
=
nullptr
;
handoverRequestIEs
=
nullptr
;
}
HandoverRequest
::~
HandoverRequest
()
{}
unsigned
long
HandoverRequest
::
getAmfUeNgapId
()
{
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
else
return
0
;
}
/*bool HandoverRequest::decodefrompdu(Ngap_NGAP_PDU_t *ngap_msg_pdu)
...
...
src/ngap/ngapMsgs/HandoverRequiredMsg.cpp
View file @
2cb6671b
...
...
@@ -100,6 +100,8 @@ void HandoverRequiredMsg::getTAI(TAI*& ptr) {
OCTET_STRING_t
HandoverRequiredMsg
::
getSourceToTarget_TransparentContainer
()
{
if
(
SourceToTarget_TransparentContainer
)
return
*
SourceToTarget_TransparentContainer
;
else
return
OCTET_STRING_t
();
}
bool
HandoverRequiredMsg
::
getPDUSessionResourceList
(
...
...
@@ -128,6 +130,8 @@ bool HandoverRequiredMsg::getPDUSessionResourceList(
long
HandoverRequiredMsg
::
getDirectForwardingPathAvailability
()
{
if
(
directforwardingPathAvailability
)
return
*
directforwardingPathAvailability
;
else
return
0
;
}
bool
HandoverRequiredMsg
::
decodefrompdu
(
Ngap_NGAP_PDU_t
*
ngap_msg_pdu
)
{
...
...
src/ngap/ngapMsgs/UplinkRANStatusTransfer.cpp
View file @
2cb6671b
...
...
@@ -32,27 +32,38 @@
using
namespace
std
;
namespace
ngap
{
UplinkRANStatusTransfer
::
UplinkRANStatusTransfer
()
{
amfUeNgapId
=
NULL
;
ranUeNgapId
=
NULL
;
ranStatusTransfer_TransparentContainer
=
NULL
;
amfUeNgapId
=
nullptr
;
ranUeNgapId
=
nullptr
;
ranStatusTransfer_TransparentContainer
=
nullptr
;
UplinkRANStatusTransferPDU
=
nullptr
;
UplinkRANStatusTransferIEs
=
nullptr
;
}
UplinkRANStatusTransfer
::~
UplinkRANStatusTransfer
()
{}
unsigned
long
UplinkRANStatusTransfer
::
getAmfUeNgapId
()
{
if
(
amfUeNgapId
)
return
amfUeNgapId
->
getAMF_UE_NGAP_ID
();
else
return
0
;
}
uint32_t
UplinkRANStatusTransfer
::
getRanUeNgapId
()
{
if
(
ranUeNgapId
)
return
ranUeNgapId
->
getRanUeNgapId
();
else
return
0
;
}
void
UplinkRANStatusTransfer
::
getRANStatusTransfer_TransparentContainer
(
RANStatusTransferTransparentContainer
*&
ranstatustransfer_transparentcontainer
)
{
ranstatustransfer_transparentcontainer
=
ranStatusTransfer_TransparentContainer
;
}
bool
UplinkRANStatusTransfer
::
defromPDU
(
Ngap_NGAP_PDU_t
*
ngap_msg_pdu
)
{
UplinkRANStatusTransferPDU
=
ngap_msg_pdu
;
if
(
UplinkRANStatusTransferPDU
->
present
==
...
...
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