Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ITS - Intelligent Transport Systems
ITS
Commits
a20dc87d
Commit
a20dc87d
authored
Jun 28, 2017
by
garciay
Browse files
Layers ongoing
parent
26db76eb
Changes
10
Hide whitespace changes
Inline
Side-by-side
ccsrc/Framework/Layer.hh
View file @
a20dc87d
...
...
@@ -9,7 +9,9 @@
#include
"loggers.hh"
class
OCTETSTRING
;
class
BITSTRING
;
class
CHARSTRING
;
class
INTEGER
;
class
Layer
{
std
::
vector
<
Layer
*>
upperLayers
;
...
...
ccsrc/Framework/Params.hh
View file @
a20dc87d
#pragma once
#include
<vector>
#include
<map>
class
Params
:
public
std
::
map
<
std
::
string
,
std
::
string
>
{
public:
static
const
std
::
string
&
mac_src
;
static
const
std
::
string
&
mac_dst
;
static
const
std
::
string
&
ssp
;
static
const
std
::
string
&
its_aid
;
static
const
std
::
vector
<
unsigned
char
>&
mac_address
;
Params
()
:
std
::
map
<
std
::
string
,
std
::
string
>
()
{};
Params
(
const
Params
&
p_params
)
:
std
::
map
<
std
::
string
,
std
::
string
>
(
p_params
.
begin
(),
p_params
.
end
())
{};
...
...
ccsrc/Framework/src/Params.cc
View file @
a20dc87d
...
...
@@ -4,6 +4,12 @@
#include
"Params.hh"
#include
"loggers.hh"
const
std
::
string
&
Params
::
mac_src
=
std
::
string
(
"mac_src"
);
const
std
::
string
&
Params
::
mac_dst
=
std
::
string
(
"mac_dst"
);
const
std
::
string
&
Params
::
its_aid
=
std
::
string
(
"its_aid"
);
const
std
::
string
&
Params
::
ssp
=
std
::
string
(
"ssp"
);
const
std
::
vector
<
unsigned
char
>&
Params
::
mac_address
({
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
});
void
Params
::
convert
(
Params
&
p_param
,
const
std
::
string
p_parameters
)
{
//loggers::get_instance().log(">>> Params::convert: '%s'", p_parameters.c_str());
// Sanity checks
...
...
ccsrc/Ports/LibIts_ports/BTP_ports/BtpPort.cc
View file @
a20dc87d
...
...
@@ -8,63 +8,86 @@
// add your member functions here.
#include
"BtpPort.hh"
#include
"BTPLayer.hh"
#include
"loggers.hh"
namespace
LibItsBtp__TestSystem
{
BtpPort
::
BtpPort
(
const
char
*
par_port_name
)
:
BtpPort_BASE
(
par_port_name
)
{
BtpPort
::
BtpPort
(
const
char
*
par_port_name
)
:
BtpPort_BASE
(
par_port_name
)
,
_cfg_params
(),
_layer_params
(),
_layer
(
NULL
),
_time_key
(
"BtpPort::outgoing_send"
)
{
}
}
BtpPort
::~
BtpPort
()
{
BtpPort
::~
BtpPort
()
{
if
(
_layer
!=
NULL
)
{
delete
_layer
;
}
}
}
void
BtpPort
::
set_parameter
(
const
char
*
/*parameter_name*/
,
const
char
*
/*parameter_value*/
)
{
void
BtpPort
::
set_parameter
(
const
char
*
parameter_name
,
const
char
*
parameter_value
)
{
loggers
::
get_instance
().
log
(
"BtpPort::set_parameter: %s=%s"
,
parameter_name
,
parameter_value
);
_cfg_params
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
std
::
string
(
parameter_name
),
std
::
string
(
parameter_value
)));
}
}
/*void BtpPort::Handle_Fd_Event(int fd, boolean is_readable,
boolean is_writable, boolean is_error) {}*/
/*void BtpPort::Handle_Fd_Event(int fd, boolean is_readable,
boolean is_writable, boolean is_error) {}*/
void
BtpPort
::
Handle_Fd_Event_Error
(
int
/*fd*/
)
{
void
BtpPort
::
Handle_Fd_Event_Error
(
int
/*fd*/
)
{
}
}
void
BtpPort
::
Handle_Fd_Event_Writable
(
int
/*fd*/
)
{
void
BtpPort
::
Handle_Fd_Event_Writable
(
int
/*fd*/
)
{
}
}
void
BtpPort
::
Handle_Fd_Event_Readable
(
int
/*fd*/
)
{
void
BtpPort
::
Handle_Fd_Event_Readable
(
int
/*fd*/
)
{
}
}
/*void BtpPort::Handle_Timeout(double time_since_last_call) {}*/
/*void BtpPort::Handle_Timeout(double time_since_last_call) {}*/
void
BtpPort
::
user_map
(
const
char
*
system_port
)
{
loggers
::
get_instance
().
log
(
">>> BtpPort::user_map: %s"
,
system_port
);
// Build layer stack
std
::
map
<
std
::
string
,
std
::
string
>::
iterator
it
=
_cfg_params
.
find
(
std
::
string
(
"params"
));
if
(
it
!=
_cfg_params
.
end
())
{
//loggers::get_instance().log("BtpPort::user_map: %s", it->second.c_str());
_layer
=
LayerStackBuilder
::
GetInstance
()
->
createLayerStack
(
it
->
second
.
c_str
());
dynamic_cast
<
BTPLayer
*>
(
_layer
)
->
addUpperPort
(
this
);
}
}
void
BtpPort
::
user_map
(
const
char
*
/*system_port*/
)
{
void
BtpPort
::
user_unmap
(
const
char
*
system_port
)
{
loggers
::
get_instance
().
log
(
">>> BtpPort::user_unmap: %s"
,
system_port
);
if
(
_layer
!=
NULL
)
{
delete
_layer
;
_layer
=
NULL
;
}
}
}
void
BtpPort
::
user_start
()
{
void
BtpPort
::
user_unmap
(
const
char
*
/*system_port*/
)
{
}
}
void
BtpPort
::
user_stop
()
{
void
BtpPort
::
user_start
()
{
}
}
void
BtpPort
::
outgoing_send
(
const
BtpReq
&
send_par
)
{
loggers
::
get_instance
().
log_msg
(
">>> BtpPort::outgoing_send: payload="
,
send_par
);
float
duration
;
loggers
::
get_instance
().
set_start_time
(
_time_key
);
dynamic_cast
<
BTPLayer
*>
(
_layer
)
->
sendMsg
(
send_par
,
_layer_params
);
loggers
::
get_instance
().
set_stop_time
(
_time_key
,
duration
);
}
void
BtpPort
::
user_stop
()
{
void
BtpPort
::
receiveMsg
(
const
LibItsBtp__TestSystem
::
BtpInd
&
p_ind
,
const
Params
&
p_params
)
{
loggers
::
get_instance
().
log_msg
(
">>> BtpPort::receive_msg: "
,
p_ind
);
}
void
BtpPort
::
outgoing_send
(
const
BtpReq
&
/*send_par*/
)
{
}
void
BtpPort
::
receiveMsg
(
const
LibItsBtp__TypesAndValues
::
BtpPacket
&
,
const
Params
&
)
{
}
incoming_message
(
p_ind
);
}
}
/* end of namespace */
ccsrc/Ports/LibIts_ports/BTP_ports/BtpPort.hh
View file @
a20dc87d
...
...
@@ -12,37 +12,41 @@
#include
"LibItsBtp_TestSystem.hh"
#include
"BTPLayer.hh"
#include
"Layer.hh"
#include
"Params.hh"
namespace
LibItsBtp__TestSystem
{
class
BtpPort
:
public
BtpPort_BASE
{
BTPLayer
*
layer
;
public:
BtpPort
(
const
char
*
par_port_name
=
NULL
);
~
BtpPort
();
void
set_parameter
(
const
char
*
parameter_name
,
const
char
*
parameter_value
);
void
receiveMsg
(
const
LibItsBtp__TypesAndValues
::
BtpPacket
&
,
const
Params
&
);
private:
/* void Handle_Fd_Event(int fd, boolean is_readable,
boolean is_writable, boolean is_error); */
void
Handle_Fd_Event_Error
(
int
fd
);
void
Handle_Fd_Event_Writable
(
int
fd
);
void
Handle_Fd_Event_Readable
(
int
fd
);
/* void Handle_Timeout(double time_since_last_call); */
protected:
void
user_map
(
const
char
*
system_port
);
void
user_unmap
(
const
char
*
system_port
);
void
user_start
();
void
user_stop
();
void
outgoing_send
(
const
BtpReq
&
send_par
);
};
class
BtpPort
:
public
BtpPort_BASE
{
Params
_cfg_params
;
Params
_layer_params
;
Layer
*
_layer
;
std
::
string
_time_key
;
public:
BtpPort
(
const
char
*
par_port_name
=
NULL
);
~
BtpPort
();
void
set_parameter
(
const
char
*
parameter_name
,
const
char
*
parameter_value
);
void
receiveMsg
(
const
LibItsBtp__TestSystem
::
BtpInd
&
,
const
Params
&
);
private:
/* void Handle_Fd_Event(int fd, boolean is_readable,
boolean is_writable, boolean is_error); */
void
Handle_Fd_Event_Error
(
int
fd
);
void
Handle_Fd_Event_Writable
(
int
fd
);
void
Handle_Fd_Event_Readable
(
int
fd
);
/* void Handle_Timeout(double time_since_last_call); */
protected:
void
user_map
(
const
char
*
system_port
);
void
user_unmap
(
const
char
*
system_port
);
void
user_start
();
void
user_stop
();
void
outgoing_send
(
const
BtpReq
&
send_par
);
};
}
/* end of namespace */
...
...
ccsrc/Ports/LibIts_ports/GN_ports/GeoNetworkingPort.cc
View file @
a20dc87d
...
...
@@ -55,7 +55,7 @@ namespace LibItsGeoNetworking__TestSystem {
void
GeoNetworkingPort
::
user_map
(
const
char
*
system_port
)
{
loggers
::
get_instance
().
log
(
">>> GeoNetworkingPort::user_map: %s"
,
system_port
);
// Build layer stack
std
::
map
<
std
::
string
,
std
::
string
>::
iterator
it
=
_cfg_params
.
find
(
std
::
string
(
"params"
));
if
(
it
!=
_cfg_params
.
end
())
{
//loggers::get_instance().log("GeoNetworkingPort::user_map: %s", it->second.c_str());
...
...
@@ -71,7 +71,6 @@ namespace LibItsGeoNetworking__TestSystem {
delete
_layer
;
_layer
=
NULL
;
}
}
void
GeoNetworkingPort
::
user_start
()
...
...
ccsrc/Protocols/BTP/BTPLayer.cc
View file @
a20dc87d
#include
"BTPLayer.hh"
#include
"BTPTypes.hh"
void
BTPLayer
::
sendMsg
(
LibItsBtp__TypesAndValues
::
BtpPacket
&
p
,
Params
&
params
){
#include
"loggers.hh"
BTPLayer
::
BTPLayer
(
const
std
::
string
&
p_type
,
const
std
::
string
&
param
)
:
TLayer
<
LibItsBtp__TestSystem
::
BtpPort
>
(
p_type
),
_params
(),
_codec
()
{
loggers
::
get_instance
().
log
(
">>> BTPLayer::BTPLayer: %s, %s"
,
to_string
().
c_str
(),
param
.
c_str
());
// Setup parameters
Params
::
convert
(
_params
,
param
);
}
void
BTPLayer
::
sendMsg
(
const
LibItsBtp__TestSystem
::
BtpReq
&
p
,
const
Params
&
params
){
loggers
::
get_instance
().
log
(
">>> BTPLayer::sendMsg"
);
// Encode BTP PDU
OCTETSTRING
data
;
_codec
.
encode
(
p
,
data
);
sendData
(
data
,
params
);
_codec
.
encode
(
p
.
msgOut
(),
data
);
// Update parameters
Params
par
(
params
);
// FIXME Review all const Param& in method declarations
sendData
(
data
,
par
);
}
void
BTPLayer
::
sendData
(
OCTETSTRING
&
data
,
Params
&
params
){
void
BTPLayer
::
sendData
(
OCTETSTRING
&
data
,
Params
&
params
)
{
loggers
::
get_instance
().
log_msg
(
">>> BTPLayer::sendData: "
,
data
);
params
.
log
();
sendToAllLayers
(
data
,
params
);
}
void
BTPLayer
::
receiveData
(
OCTETSTRING
&
data
,
Params
&
info
)
void
BTPLayer
::
receiveData
(
OCTETSTRING
&
data
,
Params
&
params
)
{
LibItsBtp__TypesAndValues
::
BtpPacket
p
;
_codec
.
decode
(
data
,
p
);
toAllUpperPorts
(
p
,
info
);
/*if(p.payload().is_present()) {
toAllUpperLayers(p.payload().rawPayload(), info);
}*/
loggers
::
get_instance
().
log_msg
(
">>> BTPLayer::receiveData: "
,
data
);
// Decode the payload
LibItsBtp__TestSystem
::
BtpInd
p
;
_codec
.
decode
(
data
,
p
.
msgIn
());
// Send it to the ports
toAllUpperPorts
(
p
,
params
);
}
class
BTPFactory
:
public
LayerFactory
{
...
...
@@ -31,12 +45,13 @@ public:
};
BTPFactory
::
BTPFactory
(){
// register factory
LayerStackBuilder
::
RegisterLayerFactory
(
"BTP"
,
this
);
// Register factory
loggers
::
get_instance
().
log
(
">>> BTPFactory::BTPFactory"
);
LayerStackBuilder
::
RegisterLayerFactory
(
"BTP"
,
this
);
}
Layer
*
BTPFactory
::
createLayer
(
const
std
::
string
&
p_type
,
const
std
::
string
&
param
){
return
new
BTPLayer
(
p_type
);
return
new
BTPLayer
(
p_type
,
param
);
}
BTPFactory
BTPFactory
::
_f
;
ccsrc/Protocols/BTP/BTPLayer.hh
View file @
a20dc87d
#ifndef BTP_LAYER_H
#define BTP_LAYER_H
#include
"Layer.hh"
#include
"BTPCodec.hh"
namespace
LibItsBtp__TypesAndValues
{
class
BtpPacket
;
}
namespace
LibItsBtp__TestSystem
{
class
BtpPort
;
class
BtpPort
;
class
BtpReq
;
class
BtpInd
;
}
class
BTPLayer
:
public
TLayer
<
LibItsBtp__TestSystem
::
BtpPort
>
{
BTPCodec
_codec
;
public:
BTPLayer
(
const
std
::
string
&
p_type
)
:
TLayer
<
LibItsBtp__TestSystem
::
BtpPort
>
(
p_type
)
{};
Params
_params
;
BTPCodec
_codec
;
public:
BTPLayer
()
:
_params
(),
_codec
()
{};
BTPLayer
(
const
std
::
string
&
p_type
,
const
std
::
string
&
param
);
virtual
~
BTPLayer
()
{};
void
sendMsg
(
LibItsBtp__T
ypesAndValues
::
BtpPacket
&
,
Params
&
param
);
void
sendMsg
(
const
LibItsBtp__T
estSystem
::
BtpReq
&
,
const
Params
&
param
);
virtual
void
sendData
(
OCTETSTRING
&
data
,
Params
&
params
);
virtual
void
receiveData
(
OCTETSTRING
&
data
,
Params
&
info
);
virtual
void
sendData
(
OCTETSTRING
&
data
,
Params
&
params
);
virtual
void
receiveData
(
OCTETSTRING
&
data
,
Params
&
info
);
};
#endif
ccsrc/Protocols/ETH/EthernetLayer.cc
View file @
a20dc87d
...
...
@@ -12,19 +12,17 @@ void EthernetLayer::sendData(OCTETSTRING& data, Params& params) {
loggers
::
get_instance
().
log_msg
(
">>> EthernetLayer::sendData: "
,
data
);
OCTETSTRING
eth
;
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
params
.
find
(
"
mac_dst
"
);
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
params
.
find
(
Params
::
mac_dst
);
if
(
it
!=
params
.
cend
())
{
eth
=
str2oct
(
CHARSTRING
(
it
->
second
.
c_str
()));
}
else
{
const
unsigned
char
mac_address
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
};
eth
=
OCTETSTRING
(
sizeof
(
mac_address
),
static_cast
<
const
unsigned
char
*>
(
mac_address
));
eth
=
OCTETSTRING
(
Params
::
mac_address
.
size
(),
Params
::
mac_address
.
data
());
}
it
=
params
.
find
(
"
mac_src
"
);
it
=
params
.
find
(
Params
::
mac_src
);
if
(
it
!=
params
.
cend
())
{
eth
+=
str2oct
(
CHARSTRING
(
it
->
second
.
c_str
()));
}
else
{
const
unsigned
char
mac_address
[]
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0xFF
};
eth
+=
OCTETSTRING
(
sizeof
(
mac_address
),
static_cast
<
const
unsigned
char
*>
(
mac_address
));
eth
+=
OCTETSTRING
(
Params
::
mac_address
.
size
(),
Params
::
mac_address
.
data
());
}
it
=
params
.
find
(
"eth_type"
);
if
(
it
!=
params
.
cend
())
{
...
...
@@ -53,9 +51,9 @@ void EthernetLayer::receiveData(OCTETSTRING& data, Params& params) {
data
=
OCTETSTRING
(
data
.
lengthof
()
-
14
,
14
+
static_cast
<
const
unsigned
char
*>
(
data
));
// Update params
CHARSTRING
s
=
oct2str
(
dst
);
params
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
std
::
string
(
"
mac_dst
"
)
,
std
::
string
(
static_cast
<
const
char
*>
(
s
))));
params
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
Params
::
mac_dst
,
std
::
string
(
static_cast
<
const
char
*>
(
s
))));
s
=
oct2str
(
src
);
params
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
std
::
string
(
"
mac_src
"
)
,
std
::
string
(
static_cast
<
const
char
*>
(
s
))));
params
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
Params
::
mac_src
,
std
::
string
(
static_cast
<
const
char
*>
(
s
))));
//loggers::get_instance().log_msg("EthernetLayer::receiveData: payload for upper layer:", data);
receiveToAllLayers
(
data
,
params
);
...
...
ccsrc/Protocols/GeoNetworking/GeoNetworkingLayer.cc
View file @
a20dc87d
...
...
@@ -5,23 +5,26 @@
GeoNetworkingLayer
::
GeoNetworkingLayer
(
const
std
::
string
&
p_type
,
const
std
::
string
&
param
)
:
TLayer
<
LibItsGeoNetworking__TestSystem
::
GeoNetworkingPort
>
(
p_type
),
_params
(),
_codec
()
{
loggers
::
get_instance
().
log
(
">>> GeoNetworkingLayer::GeoNetworkingLayer: %s, %s"
,
to_string
().
c_str
(),
param
.
c_str
());
// Setup parameters
Params
::
convert
(
_params
,
param
);
//_params.log();
// Setup parameters
Params
::
convert
(
_params
,
param
);
}
void
GeoNetworkingLayer
::
sendMsg
(
const
LibItsGeoNetworking__TestSystem
::
GeoNetworkingReq
&
p
,
const
Params
&
params
)
{
loggers
::
get_instance
().
log
(
">>> GeoNetworkingLayer::sendMsg"
);
// Encode GeoNetworking PDU
OCTETSTRING
data
;
_codec
.
encode
(
p
.
msgOut
(),
data
);
Params
par
(
params
);
// Update parameters
Params
par
(
params
);
// FIXME Review all const Param& in method declarations
par
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
Params
::
mac_dst
,
std
::
string
(
static_cast
<
const
char
*>
(
oct2str
(
p
.
macDestinationAddress
())))));
par
.
insert
(
std
::
pair
<
std
::
string
,
std
::
string
>
(
Params
::
its_aid
,
std
::
string
(
static_cast
<
const
char
*>
(
int2str
(
p
.
its__aid
())))));
sendData
(
data
,
par
);
}
void
GeoNetworkingLayer
::
sendData
(
OCTETSTRING
&
data
,
Params
&
params
)
{
loggers
::
get_instance
().
log_msg
(
">>> GeoNetworkingLayer::sendData: "
,
data
);
params
.
log
();
sendToAllLayers
(
data
,
params
);
}
...
...
@@ -32,33 +35,46 @@ void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) {
_codec
.
decode
(
data
,
p
.
msgIn
());
// Add lower layers parameters
// 1. Destination MAC address
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
params
.
find
(
"
dst
"
);
std
::
map
<
std
::
string
,
std
::
string
>::
const_iterator
it
=
params
.
find
(
Params
::
mac_
dst
);
if
(
it
!=
params
.
cend
())
{
loggers
::
get_instance
().
log
(
"GeoNetworkingLayer::receiveData: dst="
,
it
->
second
.
c_str
());
p
.
macDestinationAddress
()
=
str2oct
(
CHARSTRING
(
it
->
second
.
c_str
()));
}
else
{
const
unsigned
char
mac_address
[]
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
};
// TODO Declare it as a C++ constant
p
.
macDestinationAddress
()
=
OCTETSTRING
(
sizeof
(
mac_address
),
static_cast
<
const
unsigned
char
*>
(
mac_address
));
p
.
macDestinationAddress
()
=
OCTETSTRING
(
Params
::
mac_address
.
size
(),
Params
::
mac_address
.
data
());
}
// 2. ssp
it
=
params
.
find
(
Params
::
ssp
);
if
(
it
!=
params
.
cend
())
{
loggers
::
get_instance
().
log
(
"GeoNetworkingLayer::receiveData: ssp="
,
it
->
second
.
c_str
());
p
.
ssp
()
=
str2bit
(
CHARSTRING
(
it
->
second
.
c_str
()));
}
else
{
p
.
ssp
().
set_to_omit
();
}
p
.
ssp
().
set_to_omit
();
// Its_Aid
p
.
its__aid
().
set_to_omit
();
// 3. its_aid
it
=
params
.
find
(
Params
::
its_aid
);
if
(
it
!=
params
.
cend
())
{
loggers
::
get_instance
().
log
(
"GeoNetworkingLayer::receiveData: its_aid="
,
it
->
second
.
c_str
());
p
.
its__aid
()
=
std
::
stoi
(
it
->
second
.
c_str
());
}
else
{
p
.
its__aid
().
set_to_omit
();
}
// Send it to the ports
toAllUpperPorts
(
p
,
params
);
}
class
GeoNetworkingFactory
:
public
LayerFactory
{
static
GeoNetworkingFactory
_f
;
static
GeoNetworkingFactory
_f
;
public:
GeoNetworkingFactory
();
virtual
Layer
*
createLayer
(
const
std
::
string
&
type
,
const
std
::
string
&
param
);
GeoNetworkingFactory
();
virtual
Layer
*
createLayer
(
const
std
::
string
&
type
,
const
std
::
string
&
param
);
};
GeoNetworkingFactory
::
GeoNetworkingFactory
()
{
//
r
egister factory
loggers
::
get_instance
().
log
(
">>> GeoNetworkingFactory::GeoNetworkingFactory"
);
LayerStackBuilder
::
RegisterLayerFactory
(
"GN"
,
this
);
//
R
egister factory
loggers
::
get_instance
().
log
(
">>> GeoNetworkingFactory::GeoNetworkingFactory"
);
LayerStackBuilder
::
RegisterLayerFactory
(
"GN"
,
this
);
}
Layer
*
GeoNetworkingFactory
::
createLayer
(
const
std
::
string
&
type
,
const
std
::
string
&
param
)
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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