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
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
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
Michael Black
OpenXG-RAN
Commits
ca3c98ba
Commit
ca3c98ba
authored
Nov 23, 2022
by
Marius Tillner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added uplink latseq points for latency measurement
parent
64084e7f
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
46 additions
and
16 deletions
+46
-16
executables/nr-ru.c
executables/nr-ru.c
+3
-1
openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
+1
-0
openair1/SCHED_NR/phy_procedures_nr_gNB.c
openair1/SCHED_NR/phy_procedures_nr_gNB.c
+6
-0
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+5
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
+8
-4
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
+2
-2
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+5
-4
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
+3
-0
openair2/SDAP/nr_sdap/nr_sdap.c
openair2/SDAP/nr_sdap/nr_sdap.c
+5
-2
openair2/SDAP/nr_sdap/nr_sdap.h
openair2/SDAP/nr_sdap/nr_sdap.h
+2
-1
openair2/SDAP/nr_sdap/nr_sdap_entity.c
openair2/SDAP/nr_sdap/nr_sdap_entity.c
+4
-1
openair2/SDAP/nr_sdap/nr_sdap_entity.h
openair2/SDAP/nr_sdap/nr_sdap_entity.h
+2
-1
No files found.
executables/nr-ru.c
View file @
ca3c98ba
...
...
@@ -58,6 +58,7 @@
#include "PHY/TOOLS/smbv.h"
unsigned
short
config_frames
[
4
]
=
{
2
,
9
,
11
,
13
};
#endif
#include "common/utils/LATSEQ/latseq.h"
/* these variables have to be defined before including ENB_APP/enb_paramdef.h and GNB_APP/gnb_paramdef.h */
...
...
@@ -621,6 +622,7 @@ void *emulatedRF_thread(void *param) {
void
rx_rf
(
RU_t
*
ru
,
int
*
frame
,
int
*
slot
)
{
RU_proc_t
*
proc
=
&
ru
->
proc
;
LATSEQ_P
(
"U phy.start--phy.ant"
,
"::frame%d.slot%d"
,
*
frame
,
*
slot
);
NR_DL_FRAME_PARMS
*
fp
=
ru
->
nr_frame_parms
;
openair0_config_t
*
cfg
=
&
ru
->
openair0_cfg
;
void
*
rxp
[
ru
->
nb_rx
];
...
...
@@ -717,7 +719,7 @@ void rx_rf(RU_t *ru,int *frame,int *slot) {
//exit_fun( "problem receiving samples" );
LOG_E
(
PHY
,
"problem receiving samples
\n
"
);
}
LATSEQ_P
(
"U phy.ant--phy.demodulatestart"
,
"len%d::frame%d.slot%d"
,
rxs
,
proc
->
frame_rx
,
proc
->
tti_rx
);
stop_meas
(
&
ru
->
rx_fhaul
);
}
...
...
openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c
View file @
ca3c98ba
...
...
@@ -47,6 +47,7 @@
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "common/utils/LOG/log.h"
#include <syscall.h>
#include "common/utils/LATSEQ/latseq.h"
//#define DEBUG_ULSCH_DECODING
//#define gNB_DEBUG_TRACE
...
...
openair1/SCHED_NR/phy_procedures_nr_gNB.c
View file @
ca3c98ba
...
...
@@ -44,6 +44,7 @@
#include <time.h>
#include "intertask_interface.h"
#include "common/utils/LATSEQ/latseq.h"
//#define DEBUG_RXDATA
//#define SRS_IND_DEBUG
...
...
@@ -221,6 +222,7 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) {
gNB
->
nbDecode
--
;
LOG_D
(
PHY
,
"remain to decoded in subframe: %d
\n
"
,
gNB
->
nbDecode
);
if
(
decodeSuccess
)
{
LATSEQ_P
(
"U mac.decoded--mac.demuxed"
,
"::frame%d.slot%d.ulschid%d.harqpid%d.harqround%d"
,
ulsch_harq
->
frame
,
ulsch_harq
->
slot
,
rdata
->
ulsch_id
,
rdata
->
harq_pid
,
ulsch_harq
->
round
);
memcpy
(
ulsch_harq
->
b
+
rdata
->
offset
,
ulsch_harq
->
c
[
r
],
rdata
->
Kr_bytes
-
(
ulsch_harq
->
F
>>
3
)
-
((
ulsch_harq
->
C
>
1
)
?
3
:
0
));
...
...
@@ -265,6 +267,8 @@ void nr_postDecode(PHY_VARS_gNB *gNB, notifiedFIFO_elt_t *req) {
LOG_D
(
PHY
,
"ULSCH %d in error
\n
"
,
rdata
->
ulsch_id
);
nr_fill_indication
(
gNB
,
ulsch_harq
->
frame
,
ulsch_harq
->
slot
,
rdata
->
ulsch_id
,
rdata
->
harq_pid
,
1
,
0
);
LATSEQ_P
(
"U mac.decoded--mac.retx"
,
"::frame%d.slot%d.ulschid%d.harqpid%d"
,
ulsch_harq
->
frame
,
ulsch_harq
->
slot
,
rdata
->
ulsch_id
,
rdata
->
harq_pid
);
LATSEQ_P
(
"U mac.retx--phy.demodulatestart"
,
"::harqpid%d.harqround%d"
,
rdata
->
harq_pid
,
ulsch_harq
->
round
+
1
);
// dumpsig=1;
}
/*
...
...
@@ -824,7 +828,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME
(
VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RX_PUSCH
,
1
);
start_meas
(
&
gNB
->
rx_pusch_stats
);
LATSEQ_P
(
"U phy.demodulatestart--phy.demodulateend"
,
"::frame%d.slot%d.ulschid%d.harqpid%d.harqround%d"
,
frame_rx
,
slot_rx
,
ULSCH_id
,
harq_pid
,
ulsch_harq
->
round
);
nr_rx_pusch
(
gNB
,
ULSCH_id
,
frame_rx
,
slot_rx
,
harq_pid
);
LATSEQ_P
(
"U phy.demodulateend--mac.decoded"
,
"::frame%d.slot%d.ulschid%d.harqpid%d.harqround%d"
,
frame_rx
,
slot_rx
,
ULSCH_id
,
harq_pid
,
ulsch_harq
->
round
);
gNB
->
pusch_vars
[
ULSCH_id
]
->
ulsch_power_tot
=
0
;
gNB
->
pusch_vars
[
ULSCH_id
]
->
ulsch_noise_power_tot
=
0
;
for
(
int
aarx
=
0
;
aarx
<
gNB
->
frame_parms
.
nb_antennas_rx
;
aarx
++
)
{
...
...
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
View file @
ca3c98ba
...
...
@@ -36,6 +36,7 @@
#include <openair2/UTIL/OPT/opt.h>
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "common/utils/LATSEQ/latseq.h"
//#define SRS_IND_DEBUG
...
...
@@ -138,6 +139,7 @@ int nr_process_mac_pdu(instance_t module_idP,
uint8_t
rx_lcid
=
((
NR_MAC_SUBHEADER_FIXED
*
)
pduP
)
->
LCID
;
LOG_D
(
NR_MAC
,
"In %s: received UL-SCH sub-PDU with LCID 0x%x in %d.%d (remaining PDU length %d)
\n
"
,
__func__
,
rx_lcid
,
frameP
,
slot
,
pdu_len
);
LATSEQ_P
(
"U mac.toDemux--"
,
"len%d::frame%d.slot%d.carriercompid%d.lcid%d.bufaddress%u.pdubytes%d.harqpid%d"
,
mac_len
,
frameP
,
slot
,
CC_id
,
rx_lcid
,
pduP
+
mac_subheader_len
,
pdu_len
,
harq_pid
);
unsigned
char
*
ce_ptr
;
int
n_Lcg
=
0
;
...
...
@@ -404,6 +406,9 @@ int nr_process_mac_pdu(instance_t module_idP,
mac_len
);
UE
->
mac_stats
.
ul
.
lc_bytes
[
rx_lcid
]
+=
mac_len
;
if
(
mac_len
>
3
)
LATSEQ_P
(
"U mac.demuxed--rlc.decoded"
,
"len%d::frame%d.slot%d.carriercompid%d.lcid%d.harqpid%d.bufaddress%u"
,
mac_len
,
frameP
,
slot
,
CC_id
,
rx_lcid
,
harq_pid
,
pduP
+
mac_subheader_len
);
mac_rlc_data_ind
(
module_idP
,
UE
->
rnti
,
module_idP
,
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
View file @
ca3c98ba
...
...
@@ -31,6 +31,7 @@
#include "nr_pdcp_sdu.h"
#include "LOG/log.h"
#include "common/utils/LATSEQ/latseq.h"
static
void
nr_pdcp_entity_recv_pdu
(
nr_pdcp_entity_t
*
entity
,
char
*
_buffer
,
int
size
)
...
...
@@ -151,8 +152,9 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity,
uint32_t
count
=
entity
->
rx_deliv
;
while
(
entity
->
rx_list
!=
NULL
&&
count
==
entity
->
rx_list
->
count
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
LATSEQ_P
(
"U pdcp.decoded--sdap.sdu"
,
"len%d::sn%d.count%d.rcvdcount%d.rcvdhfn%d"
,
cur
->
size
,
rcvd_sn
,
count
,
rcvd_count
,
rcvd_hfn
);
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
cur
->
buffer
,
cur
->
size
,
rcvd_sn
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
entity
->
stats
.
txsdu_pkts
++
;
...
...
@@ -332,8 +334,9 @@ static void check_t_reordering(nr_pdcp_entity_t *entity)
/* deliver all SDUs with count < rx_reord */
while
(
entity
->
rx_list
!=
NULL
&&
entity
->
rx_list
->
count
<
entity
->
rx_reord
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
LATSEQ_P
(
"U pdcp.reorderdeliv1--sdap.sdu"
,
"len%d::sn%d.count%d"
,
cur
->
size
,
cur
->
count
,
cur
->
count
);
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
cur
->
buffer
,
cur
->
size
,
cur
->
count
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
nr_pdcp_free_sdu
(
cur
);
...
...
@@ -343,8 +346,9 @@ static void check_t_reordering(nr_pdcp_entity_t *entity)
count
=
entity
->
rx_reord
;
while
(
entity
->
rx_list
!=
NULL
&&
count
==
entity
->
rx_list
->
count
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
LATSEQ_P
(
"U pdcp.reorderdeliv2--sdap.sdu"
,
"len%d::sn%d.count%d"
,
cur
->
size
,
cur
->
count
,
cur
->
count
);
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
cur
->
buffer
,
cur
->
size
,
cur
->
count
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
nr_pdcp_free_sdu
(
cur
);
...
...
@@ -393,7 +397,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
int
is_gnb
,
int
rb_id
,
int
pdusession_id
,
int
has_sdap
,
int
has_sdapULheader
,
int
has_sdapDLheader
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
),
char
*
buf
,
int
size
,
int
sn_latseq
),
void
*
deliver_sdu_data
,
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
),
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
View file @
ca3c98ba
...
...
@@ -93,7 +93,7 @@ typedef struct nr_pdcp_entity_t {
/* callbacks provided to the PDCP module */
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
);
char
*
buf
,
int
size
,
int
sn_latseq
);
void
*
deliver_sdu_data
;
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
);
...
...
@@ -172,7 +172,7 @@ nr_pdcp_entity_t *new_nr_pdcp_entity(
int
is_gnb
,
int
rb_id
,
int
pdusession_id
,
int
has_sdap
,
int
has_sdapULheader
,
int
has_sdapDLheader
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
),
char
*
buf
,
int
size
,
int
sn_latseq
),
void
*
deliver_sdu_data
,
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
),
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
View file @
ca3c98ba
...
...
@@ -39,6 +39,7 @@
#include <openair3/ocp-gtpu/gtp_itf.h>
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "executables/softmodem-common.h"
#include "common/utils/LATSEQ/latseq.h"
#define TODO do { \
printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \
...
...
@@ -609,7 +610,7 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id)
}
static
void
deliver_sdu_drb
(
void
*
_ue
,
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
)
char
*
buf
,
int
size
,
int
sn_latseq
)
{
nr_pdcp_ue_t
*
ue
=
_ue
;
int
rb_id
;
...
...
@@ -617,7 +618,7 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
if
(
IS_SOFTMODEM_NOS1
||
UE_NAS_USE_TUN
)
{
LOG_D
(
PDCP
,
"IP packet received with size %d, to be sent to SDAP interface, UE ID/RNTI: %ld
\n
"
,
size
,
ue
->
rntiMaybeUEid
);
sdap_data_ind
(
entity
->
rb_id
,
entity
->
is_gnb
,
entity
->
has_sdap
,
entity
->
has_sdapULheader
,
entity
->
pdusession_id
,
ue
->
rntiMaybeUEid
,
buf
,
size
);
sdap_data_ind
(
entity
->
rb_id
,
entity
->
is_gnb
,
entity
->
has_sdap
,
entity
->
has_sdapULheader
,
entity
->
pdusession_id
,
ue
->
rntiMaybeUEid
,
buf
,
size
,
sn_latseq
);
}
else
{
for
(
i
=
0
;
i
<
MAX_DRBS_PER_UE
;
i
++
)
{
...
...
@@ -633,7 +634,7 @@ static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity,
rb_found:
{
LOG_D
(
PDCP
,
"%s() (drb %d) sending message to SDAP size %d
\n
"
,
__func__
,
rb_id
,
size
);
sdap_data_ind
(
rb_id
,
ue
->
drb
[
rb_id
-
1
]
->
is_gnb
,
ue
->
drb
[
rb_id
-
1
]
->
has_sdap
,
ue
->
drb
[
rb_id
-
1
]
->
has_sdapULheader
,
ue
->
drb
[
rb_id
-
1
]
->
pdusession_id
,
ue
->
rntiMaybeUEid
,
buf
,
size
);
sdap_data_ind
(
rb_id
,
ue
->
drb
[
rb_id
-
1
]
->
is_gnb
,
ue
->
drb
[
rb_id
-
1
]
->
has_sdap
,
ue
->
drb
[
rb_id
-
1
]
->
has_sdapULheader
,
ue
->
drb
[
rb_id
-
1
]
->
pdusession_id
,
ue
->
rntiMaybeUEid
,
buf
,
size
,
sn_latseq
);
}
}
}
...
...
@@ -699,7 +700,7 @@ rb_found:
}
static
void
deliver_sdu_srb
(
void
*
_ue
,
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
)
char
*
buf
,
int
size
,
int
sn_latseq
)
{
nr_pdcp_ue_t
*
ue
=
_ue
;
int
srb_id
;
...
...
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
View file @
ca3c98ba
...
...
@@ -28,6 +28,7 @@
#include "LOG/log.h"
#include "common/utils/time_stat.h"
#include "common/utils/LATSEQ/latseq.h"
/* for a given SDU/SDU segment, computes the corresponding PDU header size */
static
int
compute_pdu_header_size
(
nr_rlc_entity_am_t
*
entity
,
...
...
@@ -219,6 +220,7 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn)
return
;
/* deliver */
LATSEQ_P
(
"U rlc.reassembled--pdcp.decoded"
,
"len%d::sn%d"
,
so
,
sn
);
entity
->
common
.
deliver_sdu
(
entity
->
common
.
deliver_sdu_data
,
(
nr_rlc_entity_t
*
)
entity
,
sdu
,
so
);
...
...
@@ -719,6 +721,7 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity,
}
data_size
=
size
-
decoder
.
byte
;
LATSEQ_P
(
"U rlc.decoded--rlc.reassembled"
,
"len%d::bufaddress%u.dc%d.p%d.si%d.sn%d.so%d"
,
data_size
,
buffer
,
dc
,
p
,
si
,
sn
,
so
);
/* dicard PDU if no data */
if
(
data_size
<=
0
)
{
...
...
openair2/SDAP/nr_sdap/nr_sdap.c
View file @
ca3c98ba
...
...
@@ -20,6 +20,7 @@
*/
#include "nr_sdap.h"
#include "common/utils/LATSEQ/latseq.h"
uint8_t
nas_qfi
;
uint8_t
nas_pduid
;
...
...
@@ -69,7 +70,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
int
pdusession_id
,
ue_id_t
ue_id
,
char
*
buf
,
int
size
)
{
int
size
,
int
sn_latseq
)
{
nr_sdap_entity_t
*
sdap_entity
;
sdap_entity
=
nr_sdap_get_entity
(
ue_id
,
pdusession_id
);
...
...
@@ -86,7 +88,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
pdusession_id
,
ue_id
,
buf
,
size
);
size
,
sn_latseq
);
}
void
set_qfi_pduid
(
uint8_t
qfi
,
uint8_t
pduid
){
...
...
openair2/SDAP/nr_sdap/nr_sdap.h
View file @
ca3c98ba
...
...
@@ -60,7 +60,8 @@ void sdap_data_ind(rb_id_t pdcp_entity,
int
pdusession_id
,
ue_id_t
ue_id
,
char
*
buf
,
int
size
int
size
,
int
sn_latseq
);
void
set_qfi_pduid
(
uint8_t
qfi
,
uint8_t
pduid
);
...
...
openair2/SDAP/nr_sdap/nr_sdap_entity.c
View file @
ca3c98ba
...
...
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common/utils/LATSEQ/latseq.h"
typedef
struct
{
nr_sdap_entity_t
*
sdap_entity_llist
;
...
...
@@ -178,7 +179,8 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
int
pdusession_id
,
ue_id_t
ue_id
,
char
*
buf
,
int
size
)
{
int
size
,
int
sn_latseq
)
{
/* The offset of the SDAP header, it might be 0 if the has_sdap is not true in the pdcp entity. */
int
offset
=
0
;
...
...
@@ -218,6 +220,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
req
->
bearer_id
=
pdusession_id
;
LOG_D
(
SDAP
,
"%s() sending message to gtp size %d
\n
"
,
__func__
,
size
-
offset
);
itti_send_msg_to_task
(
TASK_GTPV1_U
,
INSTANCE_DEFAULT
,
message_p
);
LATSEQ_P
(
"U sdap.sdu--gtp.out"
,
"len%d::sn%d"
,
size
-
offset
,
sn_latseq
);
}
else
{
//nrUE
/*
* TS 37.324 5.2 Data transfer
...
...
openair2/SDAP/nr_sdap/nr_sdap_entity.h
View file @
ca3c98ba
...
...
@@ -106,7 +106,8 @@ typedef struct nr_sdap_entity_s {
int
pdusession_id
,
ue_id_t
ue_id
,
char
*
buf
,
int
size
);
int
size
,
int
sn_latseq
);
/* List of entities */
struct
nr_sdap_entity_s
*
next_entity
;
...
...
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