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
62816d1c
Commit
62816d1c
authored
Feb 14, 2023
by
Sakthivel Velumani
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pass PDU pointers from PHY to MAC
parent
600a60b5
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
83 additions
and
28 deletions
+83
-28
executables/nr-gnb.c
executables/nr-gnb.c
+29
-3
nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
+1
-1
openair1/PHY/defs_gNB.h
openair1/PHY/defs_gNB.h
+1
-0
openair1/SCHED_NR/fapi_nr_l1.c
openair1/SCHED_NR/fapi_nr_l1.c
+7
-11
openair1/SCHED_NR/fapi_nr_l1.h
openair1/SCHED_NR/fapi_nr_l1.h
+1
-1
openair1/SIMULATION/NR_PHY/dlsim.c
openair1/SIMULATION/NR_PHY/dlsim.c
+1
-1
openair1/SIMULATION/NR_PHY/ulsim.c
openair1/SIMULATION/NR_PHY/ulsim.c
+1
-1
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+10
-2
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
+5
-1
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+5
-1
openair2/NR_PHY_INTERFACE/NR_IF_Module.c
openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+18
-2
openair2/NR_PHY_INTERFACE/NR_IF_Module.h
openair2/NR_PHY_INTERFACE/NR_IF_Module.h
+4
-4
No files found.
executables/nr-gnb.c
View file @
62816d1c
...
...
@@ -232,7 +232,7 @@ void rx_func(void *param) {
}
stop_meas
(
&
softmodem_stats_rxtx_sf
);
LOG_D
(
PHY
,
"%s() Exit proc[rx:%d
%d tx:%d
%d]
\n
"
,
__FUNCTION__
,
frame_rx
,
slot_rx
,
frame_tx
,
slot_tx
);
LOG_D
(
PHY
,
"%s() Exit proc[rx:%d
,%d tx:%d,
%d]
\n
"
,
__FUNCTION__
,
frame_rx
,
slot_rx
,
frame_tx
,
slot_tx
);
clock_gettime
(
CLOCK_MONOTONIC
,
&
info
->
gNB
->
rt_L1_profiling
.
return_L1_RX
[
rt_prof_idx
]);
// Call the scheduler
...
...
@@ -242,11 +242,26 @@ void rx_func(void *param) {
gNB
->
UL_INFO
.
slot
=
slot_rx
;
gNB
->
UL_INFO
.
module_id
=
gNB
->
Mod_id
;
gNB
->
UL_INFO
.
CC_id
=
gNB
->
CC_id
;
gNB
->
if_inst
->
NR_UL_indication
(
&
gNB
->
UL_INFO
);
int
tx_slot_type
=
nr_slot_select
(
cfg
,
frame_rx
,
slot_tx
);
if
((
tx_slot_type
==
NR_DOWNLINK_SLOT
||
tx_slot_type
==
NR_MIXED_SLOT
)
&&
NFAPI_MODE
!=
NFAPI_MODE_PNF
)
{
// Pull PHY msg and send to MAC
notifiedFIFO_elt_t
*
res
;
res
=
pullTpool
(
&
gNB
->
L1_tx_free
,
&
gNB
->
threadPool
);
if
(
res
==
NULL
)
return
;
// Tpool has been stopped, nothing to process
const
time_stats_t
ts
=
exec_time_stats_NotifiedFIFO
(
res
);
merge_meas
(
&
gNB
->
phy_proc_tx
,
&
ts
);
processingData_L1tx_t
*
msgTx
=
(
processingData_L1tx_t
*
)
NotifiedFifoData
(
res
);
gNB
->
if_inst
->
NR_UL_indication
(
&
gNB
->
UL_INFO
,
msgTx
->
fapi_pdu_list
,
(
void
*
)
msgTx
);
// MAC has filled PHY msg (msgTx)
pushNotifiedFIFO
(
&
gNB
->
L1_tx_filled
,
res
);
}
else
if
(
tx_slot_type
==
NR_UPLINK_SLOT
&&
NFAPI_MODE
!=
NFAPI_MODE_PNF
)
{
gNB
->
if_inst
->
NR_UL_indication
(
&
gNB
->
UL_INFO
,
NULL
,
NULL
);
}
pthread_mutex_unlock
(
&
gNB
->
UL_INFO_mutex
);
stop_meas
(
&
gNB
->
ul_indication_stats
);
int
tx_slot_type
=
nr_slot_select
(
cfg
,
frame_rx
,
slot_tx
);
if
((
tx_slot_type
==
NR_DOWNLINK_SLOT
||
tx_slot_type
==
NR_MIXED_SLOT
)
&&
NFAPI_MODE
!=
NFAPI_MODE_PNF
)
{
notifiedFIFO_elt_t
*
res
;
processingData_L1tx_t
*
syncMsg
;
...
...
@@ -433,6 +448,16 @@ void *tx_reorder_thread(void* param) {
return
(
NULL
);
}
static
void
init_phy_fapi_pdus
(
uint32_t
***
pdu_list
)
{
const
int
num_pdus
=
NFAPI_CC_MAX
*
NFAPI_NR_MAX_TX_REQUEST_PDUS
*
NFAPI_NR_MAX_TX_REQUEST_TLV
;
const
int
pdu_len
=
sizeof
(
uint32_t
)
*
38016
+
4
;
/* size of one FAPI PDU + CRC bytes */
*
pdu_list
=
malloc16
(
num_pdus
*
sizeof
(
**
pdu_list
));
for
(
int
i
=
0
;
i
<
num_pdus
;
i
++
)
{
(
*
pdu_list
)[
i
]
=
malloc16
(
pdu_len
);
bzero
((
*
pdu_list
)[
i
],
pdu_len
);
}
}
void
init_gNB_Tpool
(
int
inst
)
{
PHY_VARS_gNB
*
gNB
;
gNB
=
RC
.
gNB
[
inst
];
...
...
@@ -460,6 +485,7 @@ void init_gNB_Tpool(int inst) {
memset
(
msgDataTx
,
0
,
sizeof
(
processingData_L1tx_t
));
init_DLSCH_struct
(
gNB
,
msgDataTx
);
memset
(
msgDataTx
->
ssb
,
0
,
64
*
sizeof
(
NR_gNB_SSB_t
));
init_phy_fapi_pdus
(
&
msgDataTx
->
fapi_pdu_list
);
pushNotifiedFIFO
(
&
gNB
->
L1_tx_free
,
msgL1Tx
);
// to unblock the process in the beginning
}
...
...
nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
View file @
62816d1c
...
...
@@ -195,7 +195,7 @@ int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t* config)
gNB
->
UL_INFO
.
CC_id
=
gNB
->
CC_id
;
NFAPI_TRACE
(
NFAPI_TRACE_DEBUG
,
"Calling NR_UL_indication for gNB->UL_INFO.frame = %d and slot %d
\n
"
,
gNB
->
UL_INFO
.
frame
,
gNB
->
UL_INFO
.
slot
);
gNB
->
if_inst
->
NR_UL_indication
(
&
gNB
->
UL_INFO
);
gNB
->
if_inst
->
NR_UL_indication
(
&
gNB
->
UL_INFO
,
NULL
,
NULL
);
prev_slot
=
gNB
->
UL_INFO
.
slot
;
}
pthread_mutex_unlock
(
&
gNB
->
UL_INFO_mutex
);
...
...
openair1/PHY/defs_gNB.h
View file @
62816d1c
...
...
@@ -818,6 +818,7 @@ typedef struct processingData_L1tx {
uint16_t
num_pdsch_slot
;
int
num_dl_pdcch
;
int
num_ul_pdcch
;
uint32_t
**
fapi_pdu_list
;
}
processingData_L1tx_t
;
#endif
openair1/SCHED_NR/fapi_nr_l1.c
View file @
62816d1c
...
...
@@ -132,7 +132,7 @@ void handle_nr_nfapi_pdsch_pdu(processingData_L1tx_t *msgTx,
}
void
nr_schedule_response
(
NR_Sched_Rsp_t
*
Sched_INFO
){
void
nr_schedule_response
(
NR_Sched_Rsp_t
*
Sched_INFO
,
void
*
phyMsg
){
PHY_VARS_gNB
*
gNB
;
// copy data from L2 interface into L1 structures
...
...
@@ -162,13 +162,7 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
if
(
NFAPI_MODE
==
NFAPI_MONOLITHIC
){
if
(
slot_type
==
NR_DOWNLINK_SLOT
||
slot_type
==
NR_MIXED_SLOT
)
{
notifiedFIFO_elt_t
*
res
;
res
=
pullTpool
(
&
gNB
->
L1_tx_free
,
&
gNB
->
threadPool
);
if
(
res
==
NULL
)
return
;
// Tpool has been stopped, nothing to process
processingData_L1tx_t
*
msgTx
=
(
processingData_L1tx_t
*
)
NotifiedFifoData
(
res
);
const
time_stats_t
ts
=
exec_time_stats_NotifiedFIFO
(
res
);
merge_meas
(
&
gNB
->
phy_proc_tx
,
&
ts
);
processingData_L1tx_t
*
msgTx
=
(
processingData_L1tx_t
*
)
phyMsg
;
msgTx
->
num_pdsch_slot
=
0
;
msgTx
->
num_dl_pdcch
=
0
;
...
...
@@ -202,7 +196,11 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
uint16_t
pduIndex
=
pdsch_pdu_rel15
->
pduIndex
;
AssertFatal
(
TX_req
->
pdu_list
[
pduIndex
].
num_TLV
==
1
,
"TX_req->pdu_list[%d].num_TLV %d != 1
\n
"
,
pduIndex
,
TX_req
->
pdu_list
[
pduIndex
].
num_TLV
);
uint8_t
*
sdu
=
(
uint8_t
*
)
TX_req
->
pdu_list
[
pduIndex
].
TLVs
[
0
].
value
.
direct
;
uint8_t
*
sdu
;
if
(
TX_req
->
pdu_list
[
pduIndex
].
TLVs
[
0
].
tag
)
sdu
=
(
uint8_t
*
)
TX_req
->
pdu_list
[
pduIndex
].
TLVs
[
0
].
value
.
ptr
;
else
sdu
=
(
uint8_t
*
)
TX_req
->
pdu_list
[
pduIndex
].
TLVs
[
0
].
value
.
direct
;
AssertFatal
(
msgTx
->
num_pdsch_slot
<
NUMBER_OF_NR_DLSCH_MAX
,
"Number of PDSCH PDUs %d exceeded the limit %d
\n
"
,
msgTx
->
num_pdsch_slot
,
NUMBER_OF_NR_DLSCH_MAX
);
handle_nr_nfapi_pdsch_pdu
(
msgTx
,
&
dl_tti_pdu
->
pdsch_pdu
,
sdu
);
...
...
@@ -211,8 +209,6 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO){
for
(
int
i
=
0
;
i
<
number_ul_dci_pdu
;
i
++
)
msgTx
->
ul_pdcch_pdu
[
i
]
=
UL_dci_req
->
ul_dci_pdu_list
[
i
];
pushNotifiedFIFO
(
&
gNB
->
L1_tx_filled
,
res
);
}
for
(
int
i
=
0
;
i
<
number_ul_tti_pdu
;
i
++
)
{
...
...
openair1/SCHED_NR/fapi_nr_l1.h
View file @
62816d1c
...
...
@@ -40,7 +40,7 @@ void handle_nr_nfapi_ssb_pdu(processingData_L1tx_t *msgTx,
int
frame
,
int
slot
,
nfapi_nr_dl_tti_request_pdu_t
*
dl_tti_pdu
);
void
nr_schedule_response
(
NR_Sched_Rsp_t
*
Sched_INFO
);
void
nr_schedule_response
(
NR_Sched_Rsp_t
*
Sched_INFO
,
void
*
phyMsg
);
void
handle_nfapi_nr_csirs_pdu
(
processingData_L1tx_t
*
msgTx
,
int
frame
,
int
slot
,
...
...
openair1/SIMULATION/NR_PHY/dlsim.c
View file @
62816d1c
...
...
@@ -997,7 +997,7 @@ int main(int argc, char **argv)
Sched_INFO
.
UL_dci_req
=
NULL
;
Sched_INFO
.
TX_req
=
&
gNB_mac
->
TX_req
[
0
];
pushNotifiedFIFO
(
&
gNB
->
L1_tx_free
,
msgL1Tx
);
nr_schedule_response
(
&
Sched_INFO
);
nr_schedule_response
(
&
Sched_INFO
,
(
void
*
)
msgDataTx
);
/* PTRS values for DLSIM calculations */
nfapi_nr_dl_tti_request_body_t
*
dl_req
=
&
gNB_mac
->
DL_req
[
Sched_INFO
.
CC_id
].
dl_tti_request_body
;
...
...
openair1/SIMULATION/NR_PHY/ulsim.c
View file @
62816d1c
...
...
@@ -1114,7 +1114,7 @@ int main(int argc, char **argv)
// prepare ULSCH/PUSCH reception
pushNotifiedFIFO
(
&
gNB
->
L1_tx_free
,
msgL1Tx
);
// to unblock the process in the beginning
nr_schedule_response
(
Sched_INFO
);
nr_schedule_response
(
Sched_INFO
,
(
void
*
)
msgDataTx
);
// --------- setting parameters for UE --------
...
...
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
View file @
62816d1c
...
...
@@ -1367,7 +1367,11 @@ void nr_generate_Msg2(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
// Program UL processing for Msg3
nr_get_Msg3alloc
(
module_idP
,
CC_id
,
scc
,
slotP
,
frameP
,
ra
,
nr_mac
->
tdd_beam_association
);
nr_add_msg3
(
module_idP
,
CC_id
,
frameP
,
slotP
,
ra
,
(
uint8_t
*
)
&
tx_req
->
TLVs
[
0
].
value
.
direct
[
0
]);
if
(
tx_req
->
TLVs
[
0
].
tag
)
{
nr_add_msg3
(
module_idP
,
CC_id
,
frameP
,
slotP
,
ra
,
(
uint8_t
*
)
tx_req
->
TLVs
[
0
].
value
.
ptr
);
}
else
{
nr_add_msg3
(
module_idP
,
CC_id
,
frameP
,
slotP
,
ra
,
(
uint8_t
*
)
&
tx_req
->
TLVs
[
0
].
value
.
direct
[
0
]);
}
if
(
ra
->
cfra
)
{
LOG_D
(
NR_MAC
,
"Frame %d, Subframe %d: Setting RA-Msg3 reception (CFRA) for SFN.Slot %d.%d
\n
"
,
frameP
,
slotP
,
ra
->
Msg3_frame
,
ra
->
Msg3_slot
);
...
...
@@ -1779,7 +1783,11 @@ void nr_generate_Msg4(module_id_t module_idP, int CC_id, frame_t frameP, sub_fra
// DL TX request
nfapi_nr_pdu_t
*
tx_req
=
&
nr_mac
->
TX_req
[
CC_id
].
pdu_list
[
nr_mac
->
TX_req
[
CC_id
].
Number_of_PDUs
];
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
harq
->
transportBlock
,
sizeof
(
uint8_t
)
*
harq
->
tb_size
);
if
(
tx_req
->
TLVs
[
0
].
tag
)
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
ptr
,
harq
->
transportBlock
,
sizeof
(
uint8_t
)
*
harq
->
tb_size
);
}
else
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
harq
->
transportBlock
,
sizeof
(
uint8_t
)
*
harq
->
tb_size
);
}
tx_req
->
PDU_length
=
harq
->
tb_size
;
tx_req
->
PDU_index
=
pduindex
;
tx_req
->
num_TLV
=
1
;
...
...
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c
View file @
62816d1c
...
...
@@ -597,7 +597,11 @@ void schedule_nr_sib1(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
nfapi_nr_pdu_t
*
tx_req
=
&
gNB_mac
->
TX_req
[
CC_id
].
pdu_list
[
ntx_req
];
// Data to be transmitted
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
sib1_payload
,
TBS
);
if
(
tx_req
->
TLVs
[
0
].
tag
)
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
ptr
,
sib1_payload
,
TBS
);
}
else
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
sib1_payload
,
TBS
);
}
tx_req
->
PDU_length
=
TBS
;
tx_req
->
PDU_index
=
pdu_index
;
...
...
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
View file @
62816d1c
...
...
@@ -1332,7 +1332,11 @@ void nr_schedule_ue_spec(module_id_t module_id,
tx_req
->
PDU_index
=
pduindex
;
tx_req
->
num_TLV
=
1
;
tx_req
->
TLVs
[
0
].
length
=
TBS
+
2
;
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
harq
->
transportBlock
,
TBS
);
if
(
tx_req
->
TLVs
[
0
].
tag
)
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
ptr
,
harq
->
transportBlock
,
TBS
);
}
else
{
memcpy
(
tx_req
->
TLVs
[
0
].
value
.
direct
,
harq
->
transportBlock
,
TBS
);
}
gNB_mac
->
TX_req
[
CC_id
].
Number_of_PDUs
++
;
gNB_mac
->
TX_req
[
CC_id
].
SFN
=
frame
;
gNB_mac
->
TX_req
[
CC_id
].
Slot
=
slot
;
...
...
openair2/NR_PHY_INTERFACE/NR_IF_Module.c
View file @
62816d1c
...
...
@@ -385,7 +385,22 @@ static void match_crc_rx_pdu(nfapi_nr_rx_data_indication_t *rx_ind, nfapi_nr_crc
}
}
void
NR_UL_indication
(
NR_UL_IND_t
*
UL_info
)
{
static
void
assign_fapi_pdu_pointers
(
uint32_t
**
fapi_pdu_list
,
gNB_MAC_INST
*
mac
)
{
if
(
fapi_pdu_list
==
NULL
)
return
;
int
count
=
0
;
for
(
int
cc
=
0
;
cc
<
NFAPI_CC_MAX
;
cc
++
)
{
for
(
int
pdu
=
0
;
pdu
<
NFAPI_NR_MAX_TX_REQUEST_PDUS
;
pdu
++
)
{
for
(
int
tlv
=
0
;
tlv
<
NFAPI_NR_MAX_TX_REQUEST_TLV
;
tlv
++
)
{
mac
->
TX_req
[
cc
].
pdu_list
[
pdu
].
TLVs
[
tlv
].
value
.
ptr
=
fapi_pdu_list
[
count
];
mac
->
TX_req
[
cc
].
pdu_list
[
pdu
].
TLVs
[
tlv
].
tag
=
1
;
count
++
;
}
}
}
}
void
NR_UL_indication
(
NR_UL_IND_t
*
UL_info
,
uint32_t
**
fapi_pdu_list
,
void
*
phyMsg
)
{
AssertFatal
(
UL_info
!=
NULL
,
"UL_info is null
\n
"
);
module_id_t
module_id
=
UL_info
->
module_id
;
int
CC_id
=
UL_info
->
CC_id
;
...
...
@@ -451,6 +466,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
}
if
(
NFAPI_MODE
!=
NFAPI_MODE_PNF
)
{
gNB_MAC_INST
*
mac
=
RC
.
nrmac
[
module_id
];
assign_fapi_pdu_pointers
(
fapi_pdu_list
,
mac
);
// clear UL DCI prior to handling ULSCH
mac
->
UL_dci_req
[
CC_id
].
numPdus
=
0
;
if
(
ifi
->
CC_mask
==
0
)
{
...
...
@@ -494,7 +510,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
"nr_schedule_response is null (mod %d, cc %d)
\n
"
,
module_id
,
CC_id
);
ifi
->
NR_Schedule_response
(
sched_info
);
ifi
->
NR_Schedule_response
(
sched_info
,
phyMsg
);
LOG_D
(
NR_PHY
,
"NR_Schedule_response: SFN SLOT:%d %d dl_pdus:%d
\n
"
,
sched_info
->
frame
,
...
...
openair2/NR_PHY_INTERFACE/NR_IF_Module.h
View file @
62816d1c
...
...
@@ -109,8 +109,8 @@ typedef struct {
typedef
struct
NR_IF_Module_s
{
//define the function pointer
void
(
*
NR_UL_indication
)(
NR_UL_IND_t
*
UL_INFO
);
void
(
*
NR_Schedule_response
)(
NR_Sched_Rsp_t
*
Sched_INFO
);
void
(
*
NR_UL_indication
)(
NR_UL_IND_t
*
UL_INFO
,
uint32_t
**
fapi_pdu_list
,
void
*
phyMsg
);
void
(
*
NR_Schedule_response
)(
NR_Sched_Rsp_t
*
Sched_INFO
,
void
*
phyMsg
);
void
(
*
NR_PHY_config_req
)(
NR_PHY_Config_t
*
config_INFO
);
uint32_t
CC_mask
;
uint16_t
current_frame
;
...
...
@@ -124,11 +124,11 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id);
void
NR_IF_Module_kill
(
int
Mod_id
);
void
NR_UL_indication
(
NR_UL_IND_t
*
UL_INFO
);
void
NR_UL_indication
(
NR_UL_IND_t
*
UL_INFO
,
uint32_t
**
fapi_pdu_list
,
void
*
phyMsg
);
void
RCconfig_nr_ue_macrlc
(
void
);
/*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/
void
NR_Schedule_Response
(
NR_Sched_Rsp_t
*
Sched_INFO
);
void
NR_Schedule_Response
(
NR_Sched_Rsp_t
*
Sched_INFO
,
void
*
phyMsg
);
#endif
/*_NFAPI_INTERFACE_NR_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