Newer
Older
#include <thread>
#include <chrono>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "GeoNetworkingTypes.hh"
#include "GeoNetworkingLayerFactory.hh"
#include "registration.hh"
#include "loggers.hh"
using namespace LibItsGeoNetworking__TypesAndValues;
GeoNetworkingLayer::GeoNetworkingLayer(const std::string & p_type, const std::string & param) : TLayer<LibItsGeoNetworking__TestSystem::GeoNetworkingPort>(p_type), _params(), _codec(), _beacon(nullptr), _gbc_packet(nullptr), _shb_packet(nullptr), _ls_reply(nullptr), _location_table(), _pass_beacon_table(), _device_mode{false}, _secured_mode{false}, _enable_security_checks{false}, _sendData(), _timerid{0}, _sev{0}, _its{0}, _freq_nanosecs(0), _mask{0}, _sa{0}, _sequence_number{0} {
loggers::get_instance().log(">>> GeoNetworkingLayer::GeoNetworkingLayer: %s, %s", to_string().c_str(), param.c_str());
// Setup parameters
Params::convert(_params, param);
// Sanity checks
INTEGER latitude;
Params::const_iterator it = _params.find(Params::latitude);
if (it != _params.cend()) {
latitude = converter::get_instance().string_to_int(it->second);
}
INTEGER longitude;
it = _params.find(Params::longitude);
if (it != _params.cend()) {
longitude = converter::get_instance().string_to_int(it->second);
}
OCTETSTRING ll_address;
it = _params.find(Params::ll_address);
if (it != _params.cend()) {
ll_address = str2oct(CHARSTRING(it->second.c_str()));
}
INTEGER distanceA = 1000; // 1km
it = _params.find(Params::distanceA);
if (it != _params.cend()) {
distanceA = converter::get_instance().string_to_int(it->second);
}
INTEGER distanceB = 1000; // 1Km
it = _params.find(Params::distanceB);
if (it != _params.cend()) {
distanceB = converter::get_instance().string_to_int(it->second);
}
INTEGER angle = 0;
it = _params.find(Params::angle);
if (it != _params.cend()) {
angle = converter::get_instance().string_to_int(it->second);
}
it = _params.find(Params::device_mode);
if (it != _params.cend()) {
_device_mode = (1 == converter::get_instance().string_to_int(it->second));
it = _params.find(Params::secured_mode);
if (it != _params.cend()) {
_secured_mode = (1 == converter::get_instance().string_to_int(it->second));
}
it = _params.find(Params::enable_security_checks);
if (it != _params.cend()) {
_enable_security_checks = (1 == converter::get_instance().string_to_int(it->second));
}
// Add broadcast address if needed
it = _params.find("mac_bc");
if (it == _params.cend()) {
_params.insert(std::pair<std::string, std::string>(std::string("mac_bc"), "FFFFFFFFFFFF"));
}
// Register this object for AdapterControlPort
loggers::get_instance().log("GeoNetworkingLayer::GeoNetworkingLayer: register %s/%p", p_type.c_str(), this);
registration<GeoNetworkingLayer>::get_instance().add_item(p_type, this);
// Set up default security parameters value
it = _params.find(Params::certificate);
if (it == _params.cend()) {
_params.insert(std::pair<std::string, std::string>(std::string("certificate"), "cert_ta"));
}
it = _params.find(Params::sec_db_path);
if (it == _params.cend()) {
_params.insert(std::pair<std::string, std::string>(std::string("sec_db_path"), ""));
}
it = _params.find(Params::hash);
if (it == _params.cend()) {
_params.insert(std::pair<std::string, std::string>(std::string("sec_sign"), "SHA-256"));
}
it = _params.find(Params::signature);
if (it == _params.cend()) {
_params.insert(std::pair<std::string, std::string>(std::string("signature"), "NISTP-256"));
}
// Set up security services
security_services::get_instance().setup(_params);
Params::const_iterator i = _params.find(Params::beaconing);
if ((i != _params.cend()) && (i->second.compare("1") == 0)) { // Immediate beaconing was requested
// Prepare beaconing operation
fill_beacon(latitude, longitude, ll_address);
start_beaconing();
}
// Fill packet templates
fill_gbc_packet(latitude, longitude, ll_address, latitude, longitude, distanceA, distanceB, angle);// TODO Check if GeoBroadcastArea lat/lon are identical to lat/lon of the Test System
fill_shb_packet(latitude, longitude, ll_address);
fill_ls_reply(latitude, longitude, ll_address);
GeoNetworkingLayer::~GeoNetworkingLayer() {
loggers::get_instance().log(">>> GeoNetworkingLayer::~GeoNetworkingLayer");
if (_timerid != 0) {
timer_delete(_timerid);
}
if (_beacon != nullptr) {
delete _beacon;
}
if (_gbc_packet != nullptr) {
delete _gbc_packet;
}
if (_shb_packet != nullptr) {
delete _shb_packet;
if (_ls_reply != nullptr) {
delete _ls_reply;
}
} // End of destructor
void GeoNetworkingLayer::sendMsg(const LibItsGeoNetworking__TestSystem::GeoNetworkingReq& p, Params& params) {
loggers::get_instance().log(">>> GeoNetworkingLayer::sendMsg");
// Encode GeoNetworking PDU
OCTETSTRING data;
_codec.encode(p.msgOut(), data);
sendData(data, params);
}
void GeoNetworkingLayer::sendData(OCTETSTRING& data, Params& params) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::sendData: ", data);
if (_device_mode) { // Need to build a GN packet
if (build_geonetworking_pdu(data, params) != 0) {
if (_secured_mode) {
if (build_secured_geonetworking_pdu(data, _params) != 0) {
return;
}
}
// TODO To be removed
while (_sendData.try_lock() == FALSE) {
// not ready yet
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} // End of 'while' statement
sendToAllLayers(data, params);
_sendData.unlock();
loggers::get_instance().log("<<< GeoNetworkingLayer::sendData");
}
void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::receiveData: ", data);
// Check security mode
LibItsGeoNetworking__TypesAndValues::BasicHeader basic_header;
decode_basic_header(data, basic_header);
if ((int)basic_header.nextHeader() == 2) { // Verify and extract the GeoNetworking Secured Packet as specified in ETSI EN 302 636-4-1 V1.3.1 (2017-08) Clause 9.6.1 Composition of the Basic Header
// Verify and extract the GeoNetworking Secured Packet as specified in ETSI EN 302 636-4-1 V1.3.1 (2017-08) Clause 9.4 GeoNetworking Secured Packet
OCTETSTRING unsecured_gn_payload;
if (security_services::get_instance().verify_and_extract_gn_payload(data, _enable_security_checks, unsecured_gn_payload, params) != 0) {
loggers::get_instance().warning("GeoNetworkingLayer::receiveData: security error");
if (_enable_security_checks) {
return;
}
}
// Update data
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Unsecured payload: ", unsecured_gn_payload);
data = OCTETSTRING(4, static_cast<const unsigned char*>(data)) + unsecured_gn_payload;
}
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Geonetworking payload to decode: ", data);
LibItsGeoNetworking__TestSystem::GeoNetworkingInd ind;
_codec.decode(data, ind.msgIn(), ¶ms);
const LibItsGeoNetworking__TypesAndValues::LongPosVector* sopv = nullptr;
const LibItsGeoNetworking__TypesAndValues::GnNonSecuredPacket& p = ind.msgIn().gnPacket().packet();
const LibItsGeoNetworking__TypesAndValues::HeaderTST& htst = p.commonHeader().headerTST();
if (p.extendedHeader().ispresent()) { // Update location table
const LibItsGeoNetworking__TypesAndValues::ExtendedHeader& ex = p.extendedHeader();
if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_beaconHdr)) { // Receive a beacon
sopv = &ex.beaconHeader().srcPosVector();
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_tsbHdr)) { // Receive a topologicallyScopeBroadcast
if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_tsbHeader)) {
sopv = &ex.tsbHeader().srcPosVector();
} else {
sopv = &ex.shbHeader().srcPosVector();
}
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoBroadcastHdr)) {
sopv = &ex.geoBroadcastHeader().srcPosVector();
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_lsHdr)) { // Receive a location service
if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_lsRequestHeader)) { // Receive a LocationService/LsRequest
sopv = &ex.lsRequestHeader().srcPosVector();
// TODO Send LsReply if we are not in context of GN ATS in case of non GN test suite
if (_device_mode) {
// Update _ls_reply
ExtendedHeader* eh = static_cast<ExtendedHeader *>(_ls_reply->gnPacket().packet().extendedHeader().get_opt_value());
if (eh != nullptr) {
// Update sequence number
eh->lsReplyHeader().seqNumber() = _sequence_number++;
// Update destination
eh->lsReplyHeader().dstPosVector().gnAddr() = sopv->gnAddr();
eh->lsReplyHeader().dstPosVector().latitude() = sopv->latitude();
eh->lsReplyHeader().dstPosVector().longitude() = sopv->longitude();
// Update timestamp
unsigned long long ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - 1072911600000L; // TODO Add method such as its_tme() & its_time_mod() beacuse it is used also in LibItsCommon_externals
eh->lsReplyHeader().srcPosVector().timestamp__().set_long_long_val(ms);
eh->lsReplyHeader().dstPosVector().timestamp__() = eh->lsReplyHeader().srcPosVector().timestamp__();
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: ", *_ls_reply);
// send it
// Encode GeoNetworking PDU
OCTETSTRING os;
_codec.encode(*_ls_reply, os);
// Apply security
if (_secured_mode) {
if (build_secured_geonetworking_pdu(data, _params) != 0) {
return;
}
}
// Send it
// TODO To be removed
while (_sendData.try_lock() == FALSE) {
// not ready yet
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} // End of 'while' statement
sendToAllLayers(os, params);
_sendData.unlock();
} else {
loggers::get_instance().error("GeoNetworkingLayer::sendData: Wrong cast");
return;
}
}
} else {
sopv = &ex.lsReplyHeader().srcPosVector();
}
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoAnycastHdr)) { // Receive a GeoAnycast
sopv = &ex.geoAnycastHeader().srcPosVector();
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoUnicastHdr)) {
sopv = &ex.geoUnicastHeader().srcPosVector();
} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_saHdr)) { // Receive Service Advertisement
if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_tsbHeader)) { // TODO Check that Service Advertisment (ETSI TS 102 890-1) uses TSB
sopv = &ex.tsbHeader().srcPosVector();
} else {
sopv = &ex.tsbHeader().srcPosVector();
}
} // else, nothing to do
loggers::get_instance().log("GeoNetworkingLayer::receiveData: sopv is boud: %d", sopv->is_bound());
if(sopv->is_bound()) {
const LibItsGeoNetworking__TypesAndValues::LongPosVector& lpv = *sopv;
_location_table.add_entry(lpv);
}
}
// By default incoming beacons are filtered by the test adapter
if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_beaconHdr)) {
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Pass beaconing filtering", sopv->gnAddr().mid());
if (_pass_beacon_table.empty()) { // Discard beacon
loggers::get_instance().log("GeoNetworkingLayer::receiveData: Pass beaconing table empty, discard it");
return;
} else { // Check beacon filter for StartPassBeaconing/Stop
if (!_pass_beacon_table.has_entry(sopv->gnAddr().mid())) { // Discard beacon
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Not in pass beaconing table, discard it", *sopv);
return;
} // else, continue
}
} // else, continue
} else {
// Inavlid GeoNetworking payload, discard it
loggers::get_instance().warning("GeoNetworkingLayer::receiveData: Failed to decode payload, discard it");
return;
}
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
// Add lower layers parameters
// 1. Destination MAC address
Params::const_iterator it = params.find(Params::mac_dst);
if (it != params.cend()) {
loggers::get_instance().log("GeoNetworkingLayer::receiveData: dst=%s", it->second.c_str());
ind.macDestinationAddress() = str2oct(CHARSTRING(it->second.c_str()));
} else {
ind.macDestinationAddress() = str2oct(CHARSTRING(_params["mac_bc"].c_str()));
}
// 2. ssp
it = params.find(Params::ssp);
if (it != params.cend()) {
loggers::get_instance().log("GeoNetworkingLayer::receiveData: ssp=%s", it->second.c_str());
ind.ssp() = str2bit(CHARSTRING(it->second.c_str()));
} else {
ind.ssp().set_to_omit();
}
// 3. its_aid
it = params.find(Params::its_aid);
if (it != params.cend()) {
loggers::get_instance().log("GeoNetworkingLayer::receiveData: its_aid=%s", it->second.c_str());
ind.its__aid() = std::stoi(it->second.c_str());
} else {
ind.its__aid().set_to_omit();
}
// Pass the GeoNetworking raw payload to the upper layers if any
it = params.find(Params::gn_payload);
if (it != params.cend()) {
loggers::get_instance().log("GeoNetworkingLayer::receiveData: gn_payload=%s", it->second.c_str());
OCTETSTRING os(str2oct(CHARSTRING(it->second.c_str())));
receiveToAllLayers(os, params);
} else {
loggers::get_instance().warning("GeoNetworkingLayer::receiveData: No payload to pass to upper layers");
}
// Pass it to the ports
toAllUpperPorts(ind, params);
}
OCTETSTRING GeoNetworkingLayer::trigger_ac_event(OCTETSTRING& data, Params& params)
{
loggers::get_instance().log_to_hexa(">>> GeoNetworkingLayer::trigger_ac_event: ", data);
return int2oct(0, 2);
} // End of trigger_ac_event method
void GeoNetworkingLayer::start_beaconing() {
loggers::get_instance().log(">>> GeoNetworkingLayer::start_beaconing");
//loggers::get_instance().log_msg("GeoNetworkingLayer::start_beaconing: _beacon=", *_beacon);
// Establish handler for timer signal
loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Establishing handler for signal %d\n", _signal_id);
_sa.sa_flags = SA_SIGINFO;
_sa.sa_sigaction = timer_irq_sigalrm_handler;
sigemptyset(&_sa.sa_mask);
if (sigaction(_signal_id, &_sa, nullptr) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigaction failure: %d", errno);
}
// Block timer signal temporarily
loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Blocking signal %d\n", _signal_id);
sigemptyset(&_mask);
sigaddset(&_mask, _signal_id);
if (sigprocmask(SIG_SETMASK, &_mask, nullptr) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno);
}
// Create the timer
_sev.sigev_notify = SIGEV_SIGNAL;
_sev.sigev_signo = _signal_id; // Use signal alarm
_sev.sigev_value.sival_ptr = this; // The GeoNetworkingLayer object address
if (timer_create(CLOCK_REALTIME, &_sev, &_timerid) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Timer failure: %d", errno);
}
loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: timer ID is 0x%x\n", (long)_timerid);
// Start the timer
unsigned int expiry = 1000; // Default expiry time 1000ms
Params::const_iterator i = _params.find("expiry");
if (i != _params.cend()) {
expiry = static_cast<unsigned int>(std::strtoul(i->second.c_str(), nullptr, 10));
}
_freq_nanosecs = expiry * 1000000;
_its.it_value.tv_sec = _freq_nanosecs / 1000000000;
_its.it_value.tv_nsec = _freq_nanosecs % 1000000000;
_its.it_interval.tv_sec = _its.it_value.tv_sec;
_its.it_interval.tv_nsec = _its.it_value.tv_nsec;
if (timer_settime(_timerid, 0, &_its, nullptr) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno);
}
// Unlock the timer signal, so that timer notification can be delivered
loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Unblocking signal %d\n", _signal_id);
if (sigprocmask(SIG_UNBLOCK, &_mask, nullptr) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno);
}
} // End of start_beaconing method
void GeoNetworkingLayer::start_beaconing(const LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu& p_beacon) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::start_beaconing", p_beacon);
// Initialize the beacon
if (_beacon != nullptr) {
delete _beacon;
}
_beacon = new LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu(p_beacon);
start_beaconing(); // TODO Refined adding a boolean return code
} // End of start_beaconing method
void GeoNetworkingLayer::stop_beaconing() {
loggers::get_instance().log(">>> GeoNetworkingLayer::stop_beaconing");
// Block timer signal temporarily
loggers::get_instance().log("GeoNetworkingLayer::stop_beaconing: Blocking signal %d\n", _signal_id);
sigemptyset(&_mask);
sigaddset(&_mask, _signal_id);
if (sigprocmask(SIG_SETMASK, &_mask, nullptr) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::stop_beaconing: Sigprocmask failure: %d", errno);
}
timer_delete(_timerid);
_timerid = 0;
} // End of stop_beaconing method
void GeoNetworkingLayer::send_beacon() {
loggers::get_instance().log(">>> GeoNetworkingLayer::send_beacon");
ExtendedHeader* eh = static_cast<ExtendedHeader *>(_beacon->gnPacket().packet().extendedHeader().get_opt_value());
loggers::get_instance().error("GeoNetworkingLayer::send_beacon: Wrong cast");
}
// Update timestamp
unsigned long long ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - 1072911600000L; // TODO Add method such as its_time() & its_time_mod()
eh->beaconHeader().srcPosVector().timestamp__().set_long_long_val(static_cast<unsigned int>(ms));
//loggers::get_instance().log_msg("GeoNetworkingLayer::send_beacon: ", *_beacon);
// Encode message using TITAN because of payload in omited
TTCN_Buffer encoding_buffer;
_beacon->encode(*(_beacon->get_descriptor()), encoding_buffer, TTCN_EncDec::CT_RAW);
OCTETSTRING data(encoding_buffer.get_len(), encoding_buffer.get_data());
// Apply security
Params params(_params);
if (_secured_mode) {
if (build_secured_geonetworking_pdu(data, _params) != 0) {
return;
}
}
// TODO To be removed
while (_sendData.try_lock() == FALSE) {
// not ready yet
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} // End of 'while' statement
sendToAllLayers(data, params);
_sendData.unlock();
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
//loggers::get_instance().log("<<< GeoNetworkingLayer::send_beacon");
} // End of send_beacon method
void GeoNetworkingLayer::start_pass_beaconing(const LibItsGeoNetworking__TypesAndValues::BeaconHeader& p_beacon) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::start_pass_beaconing", p_beacon);
const LibItsGeoNetworking__TypesAndValues::LongPosVector& lpv = p_beacon.srcPosVector();
if (!_pass_beacon_table.has_entry(lpv.gnAddr().mid())) {
_pass_beacon_table.add_entry(lpv);
} // TODO Refined adding a boolean return code
} // End of start_pass_beaconing method
void GeoNetworkingLayer::stop_pass_beaconing() {
loggers::get_instance().log(">>> GeoNetworkingLayer::stop_pass_beaconing");
_pass_beacon_table.reset();
} // End of stop_pass_beaconing method
const LongPosVector* GeoNetworkingLayer::get_lpv(const GN__Address& p_gn_address)
{
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::get_lpv", p_gn_address);
const LongPosVector* lpv = nullptr;
if (_location_table.has_entry(p_gn_address.mid())) {
lpv = _location_table.get_entry(p_gn_address.mid());
}
return lpv;
} // End of get_lpv
void GeoNetworkingLayer::fill_beacon(INTEGER& p_latitude, INTEGER& p_longitude, OCTETSTRING& p_ll_address)
{
_beacon = new GeoNetworkingPdu();
HeaderTST h;
h.beaconHdr() = BeaconHeaderType(
HeaderType(HeaderType::e__beacon),
0
);
ExtendedHeader eh;
eh.beaconHeader() = BeaconHeader(
LongPosVector(
GN__Address(
TypeOfAddress(TypeOfAddress::e__manual), // TODO Use Params
StationType(StationType::e__roadSideUnit), // TODO Use Params
33,
p_ll_address
),
0,
p_latitude,
p_longitude,
int2bit(0, 1),
0,
0
)
);
_beacon->basicHeader() = BasicHeader(
0,
BasicNextHeader(
BasicNextHeader::e__commonHeader
),
0,
Lifetime(
4,
LtBase(LtBase::e__50ms)
),
5
);
_beacon->gnPacket().packet() = GnNonSecuredPacket(
CommonHeader(
NextHeader(
NextHeader::e__any
),
0,
h,
TrafficClass(
SCF(SCF::e__scfDisabled),
ChannelOffload(ChannelOffload::e__choffDisabled),
0
),
int2bit(0, 8),
0,
1,
0
),
OPTIONAL<ExtendedHeader>(eh),
OPTIONAL<GnRawPayload>()
);
_beacon->gnPacket().packet().payload().set_to_omit();
_beacon->gnPacket().securedMsg().set_to_omit();
//loggers::get_instance().log_msg("GeoNetworkingLayer::fill_beacon: beacon value: ", *_beacon);
} // End of fill_beacon method
void GeoNetworkingLayer::fill_gbc_packet(const INTEGER& p_latitude, const INTEGER& p_longitude, const OCTETSTRING& p_ll_address, const INTEGER& p_geoAreaPosLatitude, const INTEGER& p_geoAreaPosLongitude, const INTEGER& p_distanceA, const INTEGER& p_distanceB, const INTEGER& p_angle)
_gbc_packet = new GeoNetworkingPdu();
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
HeaderTST h;
h.geoBroadcastHdr() = GeoBroadcastHeaderType(
HeaderType(HeaderType::e__geoBroadcast),
HeaderSubTypeGeoBroadcast(HeaderSubTypeGeoBroadcast::e__geoBroadcastElip)
);
ExtendedHeader eh;
eh.geoBroadcastHeader() = GeoAnycastHeader( // GeoBradcastHeader is identical as GeoAnycastHeader
0,
0,
LongPosVector(
GN__Address(
TypeOfAddress(TypeOfAddress::e__manual), // TODO Use Params
StationType(StationType::e__passengerCar), // TODO Use Params
33,
p_ll_address
),
0,
p_latitude,
p_longitude,
int2bit(1, 1), // PAI
0,
0
),
p_geoAreaPosLatitude,
p_geoAreaPosLongitude,
p_distanceA,
p_distanceB,
p_angle,
0
);
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
_gbc_packet->basicHeader() = BasicHeader(
0,
BasicNextHeader(
BasicNextHeader::e__commonHeader
),
0,
Lifetime(
4,
LtBase(LtBase::e__50ms)
),
5
);
_gbc_packet->gnPacket().packet() = GnNonSecuredPacket(
CommonHeader(
NextHeader(
NextHeader::e__btpA
),
0,
h,
TrafficClass(
SCF(SCF::e__scfDisabled),
ChannelOffload(ChannelOffload::e__choffDisabled),
0
),
int2bit(128, 8), // Mobile stationnary flag set
0,
5,
0
),
OPTIONAL<ExtendedHeader>(eh),
OPTIONAL<GnRawPayload>()
);
_gbc_packet->gnPacket().packet().payload().set_to_omit();
_gbc_packet->gnPacket().securedMsg().set_to_omit();
//loggers::get_instance().log_msg("GeoNetworkingLayer::fill_gbc_packet: packet value: ", *_gbc_packet);
} // End of fill_gbc_packet method
void GeoNetworkingLayer::fill_shb_packet(const INTEGER& p_latitude, const INTEGER& p_longitude, const OCTETSTRING& p_ll_address)
{
_shb_packet = new GeoNetworkingPdu();
HeaderTST h;
h.tsbHdr() = TsbHeaderType(
HeaderType(HeaderType::e__topologicallyScopedBroadcast),
HeaderSubTypeTSB(HeaderSubTypeTSB::e__singleHop)
);
ExtendedHeader eh;
eh.shbHeader() = SHBHeader(
LongPosVector(
GN__Address(
TypeOfAddress(TypeOfAddress::e__manual), // TODO Use Params
StationType(StationType::e__passengerCar), // TODO Use Params
33,
p_ll_address
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
0,
p_latitude,
p_longitude,
int2bit(1, 1), // PAI
0,
0
),
0
);
_shb_packet->basicHeader() = BasicHeader(
0,
BasicNextHeader(
BasicNextHeader::e__commonHeader
),
0,
Lifetime(
4,
LtBase(LtBase::e__50ms)
),
1
);
_shb_packet->gnPacket().packet() = GnNonSecuredPacket(
CommonHeader(
NextHeader(
NextHeader::e__btpA
),
0,
h,
TrafficClass(
SCF(SCF::e__scfDisabled),
ChannelOffload(ChannelOffload::e__choffDisabled),
0
),
int2bit(128, 8), // Mobile stationnary flag set
0,
1,
0
),
OPTIONAL<ExtendedHeader>(eh),
OPTIONAL<GnRawPayload>()
);
_shb_packet->gnPacket().packet().payload().set_to_omit();
_shb_packet->gnPacket().securedMsg().set_to_omit();
//loggers::get_instance().log_msg("GeoNetworkingLayer::fill_shb_packet: packet value: ", *_shb_packet);
} // End of fill_shb_packet method
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
void GeoNetworkingLayer::fill_ls_reply(const INTEGER& p_latitude, const INTEGER& p_longitude, const OCTETSTRING& p_ll_address)
{
_ls_reply = new GeoNetworkingPdu();
HeaderTST h;
h.lsHdr() = LsHeaderType(
HeaderType(HeaderType::e__locationService),
HeaderSubTypeLs(HeaderSubTypeLs::e__lsReply)
);
ExtendedHeader eh;
eh.lsReplyHeader() = LSReplyHeader(
0,
0,
LongPosVector(
GN__Address(
TypeOfAddress(TypeOfAddress::e__manual), // TODO Use Params
StationType(StationType::e__passengerCar), // TODO Use Params
33,
p_ll_address
),
0,
p_latitude,
p_longitude,
int2bit(1, 1), // PAI
0,
0
),
ShortPosVector(
GN__Address(
TypeOfAddress(TypeOfAddress::e__manual), // TODO Use Params
StationType(StationType::e__passengerCar), // TODO Use Params
33,
p_ll_address
),
0,
p_latitude,
p_longitude
)
);
_ls_reply->basicHeader() = BasicHeader(
0,
BasicNextHeader(
BasicNextHeader::e__commonHeader
),
0,
Lifetime(
4,
LtBase(LtBase::e__50ms)
),
5
);
_ls_reply->gnPacket().packet() = GnNonSecuredPacket(
CommonHeader(
NextHeader(
NextHeader::e__any
),
0,
h,
TrafficClass(
SCF(SCF::e__scfDisabled),
ChannelOffload(ChannelOffload::e__choffDisabled),
0
),
int2bit(128, 8), // Mobile stationnary flag set
0,
5,
0
),
OPTIONAL<ExtendedHeader>(eh),
OPTIONAL<GnRawPayload>()
);
_ls_reply->gnPacket().packet().payload().set_to_omit();
_ls_reply->gnPacket().securedMsg().set_to_omit();
//loggers::get_instance().log_msg("GeoNetworkingLayer::fill_ls_reply: packet value: ", *_ls_reply);
} // End of fill_ls_reply method
void GeoNetworkingLayer::timer_irq_sigalrm_handler(int p_signal, siginfo_t *p_signal_info, void *p_uc) {
//loggers::get_instance().log(">>> GeoNetworkingLayer::timer_irq_sigalrm_handler: Caught signal %d", p_signal);
static_cast<GeoNetworkingLayer *>(p_signal_info->si_value.sival_ptr)->send_beacon();
} // End of method timer_irq_sigalrm_handler
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
int GeoNetworkingLayer::build_geonetworking_pdu(OCTETSTRING& data, Params& params) {
loggers::get_instance().log(">>> GeoNetworkingLayer::build_geonetworking_pdu");
params.log();
std::string next_header;
Params::const_iterator it = params.find(Params::next_header);
if (it != params.cend()) {
next_header = it->second.c_str();
}
std::string header_type;
it = params.find(Params::header_type);
if (it != params.cend()) {
header_type = it->second.c_str();
}
std::string header_sub_type;
it = params.find(Params::header_sub_type);
if (it != params.cend()) {
header_sub_type = it->second.c_str();
}
loggers::get_instance().log("GeoNetworkingLayer::build_geonetworking_pdu: %s, %s, %s", next_header.c_str(), header_type.c_str(), header_sub_type.c_str());
if (header_type.compare("tsb") == 0) {
if (header_sub_type.compare("sh") == 0) { // Use SHB
ExtendedHeader* eh = static_cast<ExtendedHeader *>(_shb_packet->gnPacket().packet().extendedHeader().get_opt_value());
if (eh == nullptr) {
loggers::get_instance().error("GeoNetworkingLayer::build_geonetworking_pdu: Wrong cast");
return -1;
}
// Update NextHeader
it = params.find(Params::next_header);
if (next_header.compare("btpB") == 0) {
_shb_packet->gnPacket().packet().commonHeader().nextHeader() = NextHeader::e__btpB;
} else { // Default btp is btpA
_shb_packet->gnPacket().packet().commonHeader().nextHeader() = NextHeader::e__btpA;
}
// Update payload
_shb_packet->gnPacket().packet().commonHeader().plLength() = data.lengthof();
_shb_packet->gnPacket().packet().payload() = OPTIONAL<OCTETSTRING>(data);
// Update timestamp
unsigned long long ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - 1072911600000L; // TODO Add method such as its_tme() & its_time_mod()
eh->shbHeader().srcPosVector().timestamp__().set_long_long_val(static_cast<unsigned int>(ms));
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
loggers::get_instance().log_msg("GeoNetworkingLayer::build_geonetworking_pdu: ", *_shb_packet);
// Encode GeoNetworking PDU
OCTETSTRING os;
_codec.encode(*_shb_packet, os);
data = os;
} else { // TODO Use TSB
loggers::get_instance().error("GeoNetworkingLayer::build_geonetworking_pdu: Not implemented");
return -2;
}
} else { // TODO To be continued
// Default: Use GBC
ExtendedHeader* eh = static_cast<ExtendedHeader *>(_shb_packet->gnPacket().packet().extendedHeader().get_opt_value());
if (eh == nullptr) {
loggers::get_instance().error("GeoNetworkingLayer::build_geonetworking_pdu: Wrong cast");
return -1;
}
// Update NextHeader
it = params.find(Params::next_header);
if (next_header.compare("btpB") == 0) {
_gbc_packet->gnPacket().packet().commonHeader().nextHeader() = NextHeader::e__btpB;
} else { // Default btp is btpA
_gbc_packet->gnPacket().packet().commonHeader().nextHeader() = NextHeader::e__btpA;
}
// Update sequence number
eh->geoBroadcastHeader().seqNumber() = _sequence_number++;
// Update payload
_gbc_packet->gnPacket().packet().commonHeader().plLength() = data.lengthof();
_gbc_packet->gnPacket().packet().payload() = OPTIONAL<OCTETSTRING>(data);
// Update timestamp
unsigned long long ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - 1072911600000L; // TODO Add method such as its_tme() & its_time_mod()
eh->geoBroadcastHeader().srcPosVector().timestamp__().set_long_long_val(static_cast<unsigned int>(ms));
loggers::get_instance().log_msg("GeoNetworkingLayer::build_geonetworking_pdu: ", *_gbc_packet);
// Encode GeoNetworking PDU
OCTETSTRING os;
_codec.encode(*_gbc_packet, os);
data = os;
}
return 0;
}
int GeoNetworkingLayer::build_secured_geonetworking_pdu(OCTETSTRING& data, Params& params) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::build_secured_geonetworking_pdu: ", data);
LibItsGeoNetworking__TypesAndValues::BasicHeader basic_header;
decode_basic_header(data, basic_header);
// Update security mode
basic_header.nextHeader() = BasicNextHeader::e__securedPacket;
OCTETSTRING unsecured_gn_payload = OCTETSTRING(data.lengthof() - 4, static_cast<const unsigned char*>(data) + 4);
OCTETSTRING secured_gn_payload;
return security_services::get_instance().secure_gn_payload(unsecured_gn_payload, false, secured_gn_payload, params); // TODO Add timer to check if certificate shall be sent
}
int GeoNetworkingLayer::decode_basic_header(const OCTETSTRING& p_data, LibItsGeoNetworking__TypesAndValues::BasicHeader& p_basic_header) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::decode_basic_header: ", p_data);
// Update security mode
OCTETSTRING bh = OCTETSTRING(4, static_cast<const unsigned char*>(p_data)); // Extract the basic header as specified in ETSI EN 302 636-4-1 V1.3.1 (2017-08) Clause 9.6
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: bh: ", bh);
TTCN_Buffer decoding_buffer(bh);
p_basic_header.RAW_decode(*p_basic_header.get_descriptor(), decoding_buffer, decoding_buffer.get_len() * 8, raw_order_t::ORDER_MSB);
loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: decode_basic_header: ", p_basic_header);
return 0;
}
GeoNetworkingLayerFactory GeoNetworkingLayerFactory::_f;