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
63a4dc20
Commit
63a4dc20
authored
Feb 02, 2021
by
Tien-Thinh Nguyen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code cleanup
parent
033c09f6
Changes
4
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
120 additions
and
94 deletions
+120
-94
src/amf-app/amf_app.cpp
src/amf-app/amf_app.cpp
+17
-14
src/amf-app/amf_n1.cpp
src/amf-app/amf_n1.cpp
+69
-55
src/amf-app/amf_n11.cpp
src/amf-app/amf_n11.cpp
+13
-13
src/amf-app/amf_n2.cpp
src/amf-app/amf_n2.cpp
+21
-12
No files found.
src/amf-app/amf_app.cpp
View file @
63a4dc20
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
/*! \file amf_app.cpp
/*! \file amf_app.cpp
\brief
\brief
\author Keliang DU, BUPT
\author Keliang DU, BUPT
, Tien-Thinh NGUYEN, EURECOM
\date 2020
\date 2020
\email: contact@openairinterface.org
\email: contact@openairinterface.org
*/
*/
...
@@ -162,7 +162,7 @@ std::shared_ptr<ue_context> amf_app::amf_ue_id_2_ue_context(
...
@@ -162,7 +162,7 @@ std::shared_ptr<ue_context> amf_app::amf_ue_id_2_ue_context(
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
amf_app
::
set_amf_ue_ngap_id_2_ue_context
(
void
amf_app
::
set_amf_ue_ngap_id_2_ue_context
(
const
long
&
amf_ue_ngap_id
,
std
::
shared_ptr
<
ue_context
>
uc
)
{
const
long
&
amf_ue_ngap_id
,
std
::
shared_ptr
<
ue_context
>
uc
)
{
std
::
shared
_lock
lock
(
m_amf_ue_ngap_id2ue_ctx
);
std
::
unique
_lock
lock
(
m_amf_ue_ngap_id2ue_ctx
);
amf_ue_ngap_id2ue_ctx
[
amf_ue_ngap_id
]
=
uc
;
amf_ue_ngap_id2ue_ctx
[
amf_ue_ngap_id
]
=
uc
;
}
}
...
@@ -182,7 +182,7 @@ std::shared_ptr<ue_context> amf_app::ran_amf_id_2_ue_context(
...
@@ -182,7 +182,7 @@ std::shared_ptr<ue_context> amf_app::ran_amf_id_2_ue_context(
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
amf_app
::
set_ran_amf_id_2_ue_context
(
void
amf_app
::
set_ran_amf_id_2_ue_context
(
const
string
&
ue_context_key
,
std
::
shared_ptr
<
ue_context
>
uc
)
{
const
string
&
ue_context_key
,
std
::
shared_ptr
<
ue_context
>
uc
)
{
std
::
shared
_lock
lock
(
m_ue_ctx_key
);
std
::
unique
_lock
lock
(
m_ue_ctx_key
);
ue_ctx_key
[
ue_context_key
]
=
uc
;
ue_ctx_key
[
ue_context_key
]
=
uc
;
}
}
...
@@ -206,7 +206,9 @@ void amf_app::set_supi_2_ue_context(
...
@@ -206,7 +206,9 @@ void amf_app::set_supi_2_ue_context(
supi2ue_ctx
[
supi
]
=
uc
;
supi2ue_ctx
[
supi
]
=
uc
;
}
}
bool
amf_app
::
find_pdu_session_context
(
const
string
&
supi
,
const
std
::
uint8_t
pdu_session_id
,
std
::
shared_ptr
<
pdu_session_context
>&
psc
){
bool
amf_app
::
find_pdu_session_context
(
const
string
&
supi
,
const
std
::
uint8_t
pdu_session_id
,
std
::
shared_ptr
<
pdu_session_context
>&
psc
)
{
if
(
!
is_supi_2_ue_context
(
supi
))
return
false
;
if
(
!
is_supi_2_ue_context
(
supi
))
return
false
;
std
::
shared_ptr
<
ue_context
>
uc
=
{};
std
::
shared_ptr
<
ue_context
>
uc
=
{};
uc
=
supi_2_ue_context
(
supi
);
uc
=
supi_2_ue_context
(
supi
);
...
@@ -218,13 +220,14 @@ bool amf_app::find_pdu_session_context(const string& supi, const std::uint8_t pd
...
@@ -218,13 +220,14 @@ bool amf_app::find_pdu_session_context(const string& supi, const std::uint8_t pd
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
amf_app
::
handle_itti_message
(
void
amf_app
::
handle_itti_message
(
itti_n1n2_message_transfer_request
&
itti_msg
)
{
itti_n1n2_message_transfer_request
&
itti_msg
)
{
//
1. e
ncode DL NAS TRANSPORT message(NAS message)
//
E
ncode DL NAS TRANSPORT message(NAS message)
DLNASTransport
*
dl
=
new
DLNASTransport
();
DLNASTransport
*
dl
=
new
DLNASTransport
();
dl
->
setHeader
(
PLAIN_5GS_MSG
);
dl
->
setHeader
(
PLAIN_5GS_MSG
);
dl
->
setPayload_Container_Type
(
N1_SM_INFORMATION
);
dl
->
setPayload_Container_Type
(
N1_SM_INFORMATION
);
dl
->
setPayload_Container
(
dl
->
setPayload_Container
(
(
uint8_t
*
)
bdata
(
itti_msg
.
n1sm
),
blength
(
itti_msg
.
n1sm
));
(
uint8_t
*
)
bdata
(
itti_msg
.
n1sm
),
blength
(
itti_msg
.
n1sm
));
dl
->
setPDUSessionId
(
itti_msg
.
pdu_session_id
);
dl
->
setPDUSessionId
(
itti_msg
.
pdu_session_id
);
uint8_t
nas
[
1024
];
uint8_t
nas
[
1024
];
int
encoded_size
=
dl
->
encode2buffer
(
nas
,
1024
);
int
encoded_size
=
dl
->
encode2buffer
(
nas
,
1024
);
print_buffer
(
"amf_app"
,
"n1n2 transfer"
,
nas
,
encoded_size
);
print_buffer
(
"amf_app"
,
"n1n2 transfer"
,
nas
,
encoded_size
);
...
@@ -256,28 +259,28 @@ void amf_app::handle_itti_message(
...
@@ -256,28 +259,28 @@ void amf_app::handle_itti_message(
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
amf_app
::
handle_itti_message
(
void
amf_app
::
handle_itti_message
(
itti_nas_signalling_establishment_request
&
itti_msg
)
{
itti_nas_signalling_establishment_request
&
itti_msg
)
{
// 1.
g
enerate amf_ue_ngap_id
// 1.
G
enerate amf_ue_ngap_id
// 2.
establish ue_context associated with amf_ue_ngap_id
// 2.
Create UE Context and store related information information
// 3.
store ue-reated core information
// 3.
Send nas-pdu to task_amf_n1
// 4. send nas-pdu to task_amf_n1
long
amf_ue_ngap_id
=
0
;
long
amf_ue_ngap_id
=
0
;
std
::
shared_ptr
<
ue_context
>
uc
;
std
::
shared_ptr
<
ue_context
>
uc
;
// check ue context with 5g-s-tmsi
// check UE Context with 5g-s-tmsi
if
((
amf_ue_ngap_id
=
itti_msg
.
amf_ue_ngap_id
)
==
-
1
)
{
if
((
amf_ue_ngap_id
=
itti_msg
.
amf_ue_ngap_id
)
==
-
1
)
{
amf_ue_ngap_id
=
generate_amf_ue_ngap_id
();
amf_ue_ngap_id
=
generate_amf_ue_ngap_id
();
}
}
string
ue_context_key
=
"app_ue_ranid_"
+
to_string
(
itti_msg
.
ran_ue_ngap_id
)
+
string
ue_context_key
=
"app_ue_ranid_"
+
to_string
(
itti_msg
.
ran_ue_ngap_id
)
+
":amfid_"
+
to_string
(
amf_ue_ngap_id
);
":amfid_"
+
to_string
(
amf_ue_ngap_id
);
// if(!is_amf_ue_id_2_ue_context(amf_ue_ngap_id)){
if
(
!
is_ran_amf_id_2_ue_context
(
ue_context_key
))
{
if
(
!
is_ran_amf_id_2_ue_context
(
ue_context_key
))
{
Logger
::
amf_app
().
debug
(
Logger
::
amf_app
().
debug
(
"No existing UE Context, Create a new one with ran_amf_id %s"
,
"No existing UE Context, Create a new one with ran_amf_id %s"
,
ue_context_key
.
c_str
());
ue_context_key
.
c_str
());
uc
=
std
::
shared_ptr
<
ue_context
>
(
new
ue_context
());
uc
=
std
::
shared_ptr
<
ue_context
>
(
new
ue_context
());
// set_amf_ue_ngap_id_2_ue_context(amf_ue_ngap_id, uc);
set_ran_amf_id_2_ue_context
(
ue_context_key
,
uc
);
set_ran_amf_id_2_ue_context
(
ue_context_key
,
uc
);
}
}
if
(
uc
.
get
()
==
nullptr
)
{
if
(
uc
.
get
()
==
nullptr
)
{
Logger
::
amf_app
().
error
(
Logger
::
amf_app
().
error
(
"Failed to create ue_context with ran_amf_id %s"
,
"Failed to create ue_context with ran_amf_id %s"
,
...
...
src/amf-app/amf_n1.cpp
View file @
63a4dc20
This diff is collapsed.
Click to expand it.
src/amf-app/amf_n11.cpp
View file @
63a4dc20
...
@@ -427,8 +427,8 @@ void amf_n11::handle_pdu_session_initial_request(
...
@@ -427,8 +427,8 @@ void amf_n11::handle_pdu_session_initial_request(
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
amf_n11
::
handle_itti_message
(
void
amf_n11
::
handle_itti_message
(
itti_nsmf_pdusession_release_sm_context
&
itti_msg
)
{
itti_nsmf_pdusession_release_sm_context
&
itti_msg
)
{
//
TTN: Should be replace by new mechanism to support multiple PDU sessions
//
TTN: Should be replace by new mechanism to support multiple PDU sessions
//
Need PDU session ID
//
Need PDU session ID
std
::
shared_ptr
<
pdu_session_context
>
psc
=
supi_to_pdu_ctx
(
itti_msg
.
supi
);
std
::
shared_ptr
<
pdu_session_context
>
psc
=
supi_to_pdu_ctx
(
itti_msg
.
supi
);
string
smf_addr
;
string
smf_addr
;
std
::
string
smf_api_version
;
std
::
string
smf_api_version
;
...
@@ -530,13 +530,13 @@ void amf_n11::curl_http_client(
...
@@ -530,13 +530,13 @@ void amf_n11::curl_http_client(
std
::
string
body
;
std
::
string
body
;
std
::
shared_ptr
<
pdu_session_context
>
psc
;
std
::
shared_ptr
<
pdu_session_context
>
psc
;
//TTN: Should be replace by new mechanism to support multiple PDU sessions
//
TTN: Should be replace by new mechanism to support multiple PDU sessions
if
(
!
amf_app_inst
->
find_pdu_session_context
(
supi
,
pdu_session_id
,
psc
))
{
if
(
!
amf_app_inst
->
find_pdu_session_context
(
supi
,
pdu_session_id
,
psc
))
{
Logger
::
amf_n11
().
warn
(
Logger
::
amf_n11
().
warn
(
"PDU Session context for SUPI %s doesn't exit!"
,
supi
.
c_str
());
"PDU Session context for SUPI %s doesn't exit!"
,
supi
.
c_str
());
//
TODO:
//
TODO:
}
}
/*
/*
if (is_supi_to_pdu_ctx(supi)) {
if (is_supi_to_pdu_ctx(supi)) {
psc = supi_to_pdu_ctx(supi);
psc = supi_to_pdu_ctx(supi);
} else {
} else {
...
@@ -544,7 +544,7 @@ void amf_n11::curl_http_client(
...
@@ -544,7 +544,7 @@ void amf_n11::curl_http_client(
"PDU Session context for SUPI %s doesn't exit!", supi.c_str());
"PDU Session context for SUPI %s doesn't exit!", supi.c_str());
// TODO:
// TODO:
}
}
*/
*/
if
((
n1SmMsg
.
size
()
>
0
)
and
(
n2SmMsg
.
size
()
>
0
))
{
if
((
n1SmMsg
.
size
()
>
0
)
and
(
n2SmMsg
.
size
()
>
0
))
{
// prepare the body content for Curl
// prepare the body content for Curl
...
...
src/amf-app/amf_n2.cpp
View file @
63a4dc20
...
@@ -349,7 +349,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -349,7 +349,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
// gNB, for example, here RAN UE NGAP ID and location information and RRC
// gNB, for example, here RAN UE NGAP ID and location information and RRC
// Establishment Cause send NAS-PDU to NAS layer Get INITIAL_UE_MESSAGE IEs
// Establishment Cause send NAS-PDU to NAS layer Get INITIAL_UE_MESSAGE IEs
//
c
heck the gNB context on which this UE is attached with assoc_id
//
C
heck the gNB context on which this UE is attached with assoc_id
itti_nas_signalling_establishment_request
*
itti_msg
=
itti_nas_signalling_establishment_request
*
itti_msg
=
new
itti_nas_signalling_establishment_request
(
TASK_AMF_N2
,
TASK_AMF_APP
);
new
itti_nas_signalling_establishment_request
(
TASK_AMF_N2
,
TASK_AMF_APP
);
...
@@ -358,6 +358,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -358,6 +358,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
"No existing gNG context with assoc_id (%d)"
,
init_ue_msg
.
assoc_id
);
"No existing gNG context with assoc_id (%d)"
,
init_ue_msg
.
assoc_id
);
return
;
return
;
}
}
std
::
shared_ptr
<
gnb_context
>
gc
;
std
::
shared_ptr
<
gnb_context
>
gc
;
gc
=
assoc_id_2_gnb_context
(
init_ue_msg
.
assoc_id
);
gc
=
assoc_id_2_gnb_context
(
init_ue_msg
.
assoc_id
);
if
(
gc
.
get
()
->
ng_state
==
NGAP_RESETING
||
if
(
gc
.
get
()
->
ng_state
==
NGAP_RESETING
||
...
@@ -378,6 +379,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -378,6 +379,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
Logger
::
amf_n2
().
error
(
"Missing Mandatory IE (RanUeNgapId)"
);
Logger
::
amf_n2
().
error
(
"Missing Mandatory IE (RanUeNgapId)"
);
return
;
return
;
}
}
std
::
shared_ptr
<
ue_ngap_context
>
unc
;
std
::
shared_ptr
<
ue_ngap_context
>
unc
;
if
(
!
is_ran_ue_id_2_ue_ngap_context
(
ran_ue_ngap_id
))
{
if
(
!
is_ran_ue_id_2_ue_ngap_context
(
ran_ue_ngap_id
))
{
Logger
::
amf_n2
().
debug
(
Logger
::
amf_n2
().
debug
(
...
@@ -388,11 +390,12 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -388,11 +390,12 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
}
else
{
}
else
{
unc
=
ran_ue_id_2_ue_ngap_context
(
ran_ue_ngap_id
);
unc
=
ran_ue_id_2_ue_ngap_context
(
ran_ue_ngap_id
);
}
}
if
(
unc
.
get
()
==
nullptr
)
{
if
(
unc
.
get
()
==
nullptr
)
{
Logger
::
amf_n2
().
error
(
Logger
::
amf_n2
().
error
(
"Failed to get UE NGAP context for ran_ue_ngap_id 0x%x"
,
21
);
"Failed to get UE NGAP context for ran_ue_ngap_id 0x%x"
,
21
);
}
else
{
}
else
{
//
store
information into UE NGAP context
//
Store related
information into UE NGAP context
unc
.
get
()
->
ran_ue_ngap_id
=
ran_ue_ngap_id
;
unc
.
get
()
->
ran_ue_ngap_id
=
ran_ue_ngap_id
;
unc
.
get
()
->
sctp_stream_recv
=
init_ue_msg
.
stream
;
unc
.
get
()
->
sctp_stream_recv
=
init_ue_msg
.
stream
;
unc
.
get
()
->
sctp_stream_send
==
gc
.
get
()
->
next_sctp_stream
;
unc
.
get
()
->
sctp_stream_send
==
gc
.
get
()
->
next_sctp_stream
;
...
@@ -402,6 +405,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -402,6 +405,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
unc
.
get
()
->
gnb_assoc_id
=
init_ue_msg
.
assoc_id
;
unc
.
get
()
->
gnb_assoc_id
=
init_ue_msg
.
assoc_id
;
NrCgi_t
cgi
;
NrCgi_t
cgi
;
Tai_t
tai
;
Tai_t
tai
;
if
(
init_ue_msg
.
initUeMsg
->
getUserLocationInfoNR
(
cgi
,
tai
))
{
if
(
init_ue_msg
.
initUeMsg
->
getUserLocationInfoNR
(
cgi
,
tai
))
{
itti_msg
->
cgi
=
cgi
;
itti_msg
->
cgi
=
cgi
;
itti_msg
->
tai
=
tai
;
itti_msg
->
tai
=
tai
;
...
@@ -409,12 +413,14 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -409,12 +413,14 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
Logger
::
amf_n2
().
error
(
"Missing Mandatory IE UserLocationInfoNR"
);
Logger
::
amf_n2
().
error
(
"Missing Mandatory IE UserLocationInfoNR"
);
return
;
return
;
}
}
if
(
init_ue_msg
.
initUeMsg
->
getRRCEstablishmentCause
()
==
-
1
)
{
if
(
init_ue_msg
.
initUeMsg
->
getRRCEstablishmentCause
()
==
-
1
)
{
Logger
::
amf_n2
().
warn
(
"IE RRCEstablishmentCause not present"
);
Logger
::
amf_n2
().
warn
(
"IE RRCEstablishmentCause not present"
);
itti_msg
->
rrc_cause
=
-
1
;
// not present
itti_msg
->
rrc_cause
=
-
1
;
// not present
}
else
{
}
else
{
itti_msg
->
rrc_cause
=
init_ue_msg
.
initUeMsg
->
getRRCEstablishmentCause
();
itti_msg
->
rrc_cause
=
init_ue_msg
.
initUeMsg
->
getRRCEstablishmentCause
();
}
}
#if 0
#if 0
if(init_ue_msg.initUeMsg->getUeContextRequest() == -1){
if(init_ue_msg.initUeMsg->getUeContextRequest() == -1){
Logger::amf_n2().warn("IE UeContextRequest not present");
Logger::amf_n2().warn("IE UeContextRequest not present");
...
@@ -423,6 +429,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
...
@@ -423,6 +429,7 @@ void amf_n2::handle_itti_message(itti_initial_ue_message& init_ue_msg) {
itti_msg->ueCtxReq = init_ue_msg.initUeMsg->getUeContextRequest();
itti_msg->ueCtxReq = init_ue_msg.initUeMsg->getUeContextRequest();
}
}
#endif
#endif
std
::
string
_5g_s_tmsi
;
std
::
string
_5g_s_tmsi
;
if
(
!
init_ue_msg
.
initUeMsg
->
get5GS_TMSI
(
_5g_s_tmsi
))
{
if
(
!
init_ue_msg
.
initUeMsg
->
get5GS_TMSI
(
_5g_s_tmsi
))
{
itti_msg
->
is_5g_s_tmsi_present
=
false
;
itti_msg
->
is_5g_s_tmsi_present
=
false
;
...
@@ -688,11 +695,13 @@ void amf_n2::handle_itti_message(
...
@@ -688,11 +695,13 @@ void amf_n2::handle_itti_message(
Logger
::
amf_n2
().
debug
(
"SUPI (%s)"
,
supi
.
c_str
());
Logger
::
amf_n2
().
debug
(
"SUPI (%s)"
,
supi
.
c_str
());
std
::
shared_ptr
<
pdu_session_context
>
psc
;
std
::
shared_ptr
<
pdu_session_context
>
psc
;
//TODO: REMOVE supi_to_pdu_ctx
// TODO: REMOVE supi_to_pdu_ctx
if
(
!
amf_app_inst
->
find_pdu_session_context
(
supi
,
itti_msg
.
pdu_session_id
,
psc
)){
if
(
!
amf_app_inst
->
find_pdu_session_context
(
Logger
::
amf_n2
().
warn
(
"Cannot get pdu_session_context with SUPI (%s)"
,
supi
.
c_str
());
supi
,
itti_msg
.
pdu_session_id
,
psc
))
{
Logger
::
amf_n2
().
warn
(
"Cannot get pdu_session_context with SUPI (%s)"
,
supi
.
c_str
());
}
}
/*
/*
if (amf_n11_inst->is_supi_to_pdu_ctx(supi)) {
if (amf_n11_inst->is_supi_to_pdu_ctx(supi)) {
psc = amf_n11_inst->supi_to_pdu_ctx(supi);
psc = amf_n11_inst->supi_to_pdu_ctx(supi);
} else {
} else {
...
@@ -1023,7 +1032,7 @@ void amf_n2::handle_itti_message(itti_handover_required& itti_msg) {
...
@@ -1023,7 +1032,7 @@ void amf_n2::handle_itti_message(itti_handover_required& itti_msg) {
// handoverrequest->setSourceToTarget_TransparentContainer(sourceTotarget);
// handoverrequest->setSourceToTarget_TransparentContainer(sourceTotarget);
string
supi
=
"imsi-"
+
nc
.
get
()
->
imsi
;
string
supi
=
"imsi-"
+
nc
.
get
()
->
imsi
;
//TODO: REMOVE supi_to_pdu_ctx (need PDU Session ID)/ list of PDU Session ID
//
TODO: REMOVE supi_to_pdu_ctx (need PDU Session ID)/ list of PDU Session ID
std
::
shared_ptr
<
pdu_session_context
>
psc
=
std
::
shared_ptr
<
pdu_session_context
>
psc
=
amf_n11_inst
->
supi_to_pdu_ctx
(
supi
);
amf_n11_inst
->
supi_to_pdu_ctx
(
supi
);
...
...
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