Vanetza
Loading...
Searching...
No Matches
router.cpp
1#include <vanetza/btp/data_indication.hpp>
2#include <vanetza/btp/data_request.hpp>
3#include <vanetza/common/annotation.hpp>
4#include <vanetza/common/its_aid.hpp>
5#include <vanetza/common/position_fix.hpp>
6#include <vanetza/common/runtime.hpp>
7#include <vanetza/dcc/data_request.hpp>
8#include <vanetza/dcc/interface.hpp>
9#include <vanetza/dcc/profile.hpp>
10#include <vanetza/net/mac_address.hpp>
11#include <vanetza/net/osi_layer.hpp>
12#include <vanetza/units/frequency.hpp>
13#include <vanetza/units/length.hpp>
14#include <vanetza/units/time.hpp>
15#include <vanetza/geonet/router.hpp>
16#include <vanetza/geonet/cbf_counter.hpp>
17#include <vanetza/geonet/data_confirm.hpp>
18#include <vanetza/geonet/dcc_field_generator.hpp>
19#include <vanetza/geonet/duplicate_packet_list.hpp>
20#include <vanetza/geonet/indication_context.hpp>
21#include <vanetza/geonet/loctex_g5.hpp>
22#include <vanetza/geonet/next_hop.hpp>
23#include <vanetza/geonet/pdu_conversion.hpp>
24#include <vanetza/geonet/repetition_dispatcher.hpp>
25#include <vanetza/geonet/transport_interface.hpp>
26#include <vanetza/geonet/extended_pdu.hpp>
27#include <vanetza/geonet/secured_pdu.hpp>
28#include <boost/units/cmath.hpp>
29#include <functional>
30#include <stdexcept>
31#include <tuple>
32#include <type_traits>
33
34namespace vanetza
35{
36namespace geonet
37{
38namespace
39{
40
41struct ControlInfo
42{
43 ControlInfo(const DataRequest& request) :
44 communication_profile(request.communication_profile),
45 its_aid(request.its_aid),
46 permissions(request.permissions)
47 {}
48
49 const CommunicationProfile communication_profile;
50 const ItsAid its_aid;
51 const ByteBuffer permissions;
52};
53
54template<typename PDU>
55class PendingPacketBufferData : public packet_buffer::Data
56{
57public:
58 PendingPacketBufferData(PendingPacket<PDU>&& packet) : m_packet(std::move(packet)) {}
59
60 std::size_t length() const override
61 {
62 return m_packet.length();
63 }
64
65 Clock::duration reduce_lifetime(Clock::duration d) override
66 {
67 return m_packet.reduce_lifetime(d);
68 }
69
70 void flush() override
71 {
72 m_packet.process();
73 }
74
75protected:
76 PendingPacket<PDU> m_packet;
77};
78
79dcc::RequestInterface* get_default_request_interface()
80{
81 static dcc::NullRequestInterface null;
82 return &null;
83}
84
85DccFieldGenerator* get_default_dcc_field_generator()
86{
87 static NullDccFieldGenerator null;
88 return &null;
89}
90
91template<typename PDU>
92auto create_forwarding_duplicate(const PDU& pdu, const UpPacket& packet) ->
93std::tuple<std::unique_ptr<ExtendedPdu<typename PDU::ExtendedHeader>>, std::unique_ptr<DownPacket>>
94{
95 using pdu_type = ExtendedPdu<typename PDU::ExtendedHeader>;
96 std::unique_ptr<pdu_type> pdu_dup { new pdu_type { pdu }};
97 std::unique_ptr<DownPacket> packet_dup;
98 if (pdu.secured()) {
99 packet_dup.reset(new DownPacket());
100 } else {
101 packet_dup = duplicate(packet);
102 }
103 return std::make_tuple(std::move(pdu_dup), std::move(packet_dup));
104}
105
106template<typename PDU>
107PDU& get_pdu(const std::tuple<std::unique_ptr<PDU>, std::unique_ptr<DownPacket>>& packet)
108{
109 PDU* pdu = std::get<0>(packet).get();
110 assert(pdu);
111 return *pdu;
112}
113
114std::unique_ptr<CbfCounter> create_cbf_counter(Runtime& rt, const MIB& mib)
115{
116 std::unique_ptr<CbfCounter> counter;
117 if (mib.vanetzaFadingCbfCounter) {
118 counter.reset(new CbfCounterFading(rt, units::clock_cast(mib.vanetzaFadingCbfCounterLifetime)));
119 } else {
120 counter.reset(new CbfCounterContending());
121 }
122 assert(counter);
123 return counter;
124}
125
126} // namespace
127
128using units::clock_cast;
129using PendingPacketGbc = PendingPacket<GbcPdu>;
130
131const access::EtherType ether_type = access::ethertype::GeoNetworking;
132
133Router::Router(Runtime& rt, const MIB& mib) :
134 m_mib(mib),
135 m_runtime(rt),
136 m_request_interface(get_default_request_interface()),
137 m_dcc_field_generator(get_default_dcc_field_generator()),
138 m_security_entity(nullptr),
139 m_location_table(mib, m_runtime),
140 m_bc_forward_buffer(mib.itsGnBcForwardingPacketBufferSize * 1024),
141 m_uc_forward_buffer(mib.itsGnUcForwardingPacketBufferSize * 1024),
142 m_cbf_buffer(m_runtime,
143 [](PendingPacketGbc&& packet) { packet.process(); },
144 create_cbf_counter(rt, mib),
145 mib.itsGnCbfPacketBufferSize * 1024),
146 m_local_sequence_number(0),
147 m_repeater(m_runtime,
148 std::bind(&Router::dispatch_repetition, this, std::placeholders::_1, std::placeholders::_2)),
149 m_random_gen(mib.vanetzaDefaultSeed)
150{
151 if (!m_mib.vanetzaDisableBeaconing) {
152 if (m_mib.vanetzaDeferInitialBeacon > Clock::duration::zero()) {
153 // defer initial Beacon transmission by given duration plus jitter
154 std::uniform_real_distribution<double> dist_jitter(0.0, 1.0);
155 const auto jitter = clock_cast(dist_jitter(m_random_gen) * m_mib.itsGnBeaconServiceMaxJitter);
156 reset_beacon_timer(m_mib.vanetzaDeferInitialBeacon + jitter);
157 } else {
158 // send Beacon immediately after start-up at next runtime trigger invocation
159 reset_beacon_timer(Clock::duration::zero());
160 }
161 }
162
163 m_gbc_memory.capacity(m_mib.vanetzaGbcMemoryCapacity);
164}
165
166Router::~Router()
167{
168 m_runtime.cancel(this);
169}
170
171void Router::update_position(const PositionFix& position_fix)
172{
173 // EN 302 636-4-1 v1.3.1 is a little bit fuzzy regarding the time stamp:
174 // "Expresses the time (...) at which the latitude and longitude (...) were acquired by the GeoAdhoc router."
175 // My reading: use the current time stamp (now) when update_position is called (not the position fix time stamp)
176 m_local_position_vector.timestamp = m_runtime.now();
177 m_local_position_vector.latitude = static_cast<geo_angle_i32t>(position_fix.latitude);
178 m_local_position_vector.longitude = static_cast<geo_angle_i32t>(position_fix.longitude);
179 if (m_mib.itsGnIsMobile) {
180 m_local_position_vector.speed = static_cast<LongPositionVector::speed_u15t>(position_fix.speed.value());
181 m_local_position_vector.heading = static_cast<heading_u16t>(position_fix.course.value() - units::TrueNorth::from_value(0.0));
182 } else {
183 m_local_position_vector.speed = static_cast<LongPositionVector::speed_u15t>(0);
184 m_local_position_vector.heading = static_cast<heading_u16t>(0);
185 }
186 // see field 5 (PAI) in table 2 (long position vector)
187 m_local_position_vector.position_accuracy_indicator =
188 position_fix.confidence.semi_major * 2.0 < m_mib.itsGnPaiInterval;
189}
190
191void Router::set_transport_handler(UpperProtocol proto, TransportInterface* ifc)
192{
193 m_transport_ifcs[proto] = ifc;
194}
195
197{
198 m_security_entity = entity;
199}
200
202{
203 m_request_interface = (ifc == nullptr ? get_default_request_interface() : ifc);
204 assert(m_request_interface != nullptr);
205}
206
208{
209 m_dcc_field_generator = (dcc == nullptr) ? get_default_dcc_field_generator() : dcc;
210 assert(m_dcc_field_generator != nullptr);
211}
212
213void Router::set_address(const Address& addr)
214{
215 m_local_position_vector.gn_addr = addr;
216}
217
218void Router::set_random_seed(std::uint_fast32_t seed)
219{
220 m_random_gen.seed(seed);
221}
222
223DataConfirm Router::request(const ShbDataRequest& request, DownPacketPtr payload)
224{
225 DataConfirm result;
226 result ^= validate_data_request(request, m_mib);
227 result ^= validate_payload(payload, m_mib);
228
229 if (result.accepted()) {
230 using PendingPacket = PendingPacket<ShbPdu>;
231
232 // step 4: set up packet repetition (NOTE 4 on page 57 requires re-execution of source operations)
233 if (request.repetition) {
234 // plaintext payload needs to get passed
235 m_repeater.add(request, *payload);
236 }
237
238 // step 1: create PDU
239 auto pdu = create_shb_pdu(request);
240 pdu->common().payload = payload->size();
241
242 ControlInfo ctrl(request);
243 auto transmit = [this, ctrl](PendingPacket::Packet&& packet) {
244 std::unique_ptr<ShbPdu> pdu;
245 std::unique_ptr<DownPacket> payload;
246 std::tie(pdu, payload) = std::move(packet);
247
248 // update SO PV before actual transmission
249 pdu->extended().source_position = m_local_position_vector;
250
251 // step 2: encapsulate packet by security
252 if (m_mib.itsGnSecurity) {
253 payload = encap_packet(ctrl.its_aid, ctrl.permissions, *pdu, std::move(payload));
254 if (!payload) {
255 // stop because encapsulation failed
256 return;
257 }
258 }
259
260 // step 5: execute media-dependent procedures
261 execute_media_procedures(ctrl.communication_profile);
262
263 // step 6: pass packet down to link layer with broadcast destination
264 pass_down(cBroadcastMacAddress, std::move(pdu), std::move(payload));
265
266 // step 7: reset beacon timer
268 };
269
270 PendingPacket packet(std::make_tuple(std::move(pdu), std::move(payload)), transmit);
271
272 // step 3: store & carry forwarding
273 if (request.traffic_class.store_carry_forward() && !m_location_table.has_neighbours()) {
274 PacketBuffer::data_ptr data { new PendingPacketBufferData<ShbPdu>(std::move(packet)) };
275 m_bc_forward_buffer.push(std::move(data), m_runtime.now());
276 } else {
277 // tranmsit immediately
278 packet.process();
279 }
280 }
281
282 return result;
283}
284
285DataConfirm Router::request(const GbcDataRequest& request, DownPacketPtr payload)
286{
287 DataConfirm result;
288 result ^= validate_data_request(request, m_mib);
289 result ^= validate_payload(payload, m_mib);
290
291 if (!result.accepted())
292 return result;
293
294 // step 6: set up packet repetition
295 // packet repetition is done first because of "NOTE 2" on page 60:
296 // "For every retransmission, the source operations need to be re-executed".
297 // Hence, all routing decisions and security encapsulation have to be performed again.
298 // Assumption: "omit execution of further steps" does not cancel the repetition procedure.
299 if (request.repetition) {
300 m_repeater.add(request, *payload);
301 }
302
303 using PendingPacket = PendingPacket<GbcPdu>;
304 using Packet = PendingPacket::Packet;
305
306 // step 1: create PDU and set header fields
307 auto pdu = create_gbc_pdu(request);
308 pdu->common().payload = payload->size();
309
310 ControlInfo ctrl(request);
311 auto transmit = [this, ctrl](Packet&& packet, const MacAddress& mac) {
312 std::unique_ptr<GbcPdu> pdu;
313 std::unique_ptr<DownPacket> payload;
314 std::tie(pdu, payload) = std::move(packet);
315
316 // update SO PV before actual transmission
317 pdu->extended().source_position = m_local_position_vector;
318
319 // step 5: apply security
320 if (m_mib.itsGnSecurity) {
321 assert(pdu->basic().next_header == NextHeaderBasic::Secured);
322 payload = encap_packet(ctrl.its_aid, ctrl.permissions, *pdu, std::move(payload));
323 if (!payload) {
324 // stop because encapsulation failed
325 return;
326 }
327 }
328
329 // step 6: repetition is already set-up before
330
331 // step 7: execute media-dependent procedures
332 execute_media_procedures(ctrl.communication_profile);
333
334 // step 8: pass PDU to link layer
335 pass_down(mac, std::move(pdu), std::move(payload));
336 };
337
338 auto forwarding = [this, transmit](Packet&& packet) {
339 // step 3: forwarding algorithm selection procedure
340 NextHop nh = forwarding_algorithm_selection(PendingPacketForwarding(std::move(packet), transmit), nullptr);
341
342 // step 4: omit execution of further steps when packet if buffered or discarded
343 std::move(nh).process();
344 };
345
346 PendingPacket packet(std::make_tuple(std::move(pdu), std::move(payload)), forwarding);
347
348 // step 2: check if neighbours are present
349 const bool scf = request.traffic_class.store_carry_forward();
350 if (scf && !m_location_table.has_neighbours()) {
351 PacketBuffer::data_ptr data { new PendingPacketBufferData<GbcPdu>(std::move(packet)) };
352 m_bc_forward_buffer.push(std::move(data), m_runtime.now());
353 } else {
354 packet.process();
355 }
356
357 return result;
358}
359
360DataConfirm Router::request(const GacDataRequest&, DownPacketPtr)
361{
362 return DataConfirm(DataConfirm::ResultCode::Rejected_Unspecified);
363}
364
365DataConfirm Router::request(const GucDataRequest&, DownPacketPtr)
366{
367 return DataConfirm(DataConfirm::ResultCode::Rejected_Unspecified);
368}
369
370DataConfirm Router::request(const TsbDataRequest&, DownPacketPtr)
371{
372 return DataConfirm(DataConfirm::ResultCode::Rejected_Unspecified);
373}
374
375void Router::indicate(UpPacketPtr packet, const MacAddress& sender, const MacAddress& destination)
376{
377 assert(packet);
378 IndicationContext::LinkLayer link_layer;
379 link_layer.sender = sender;
380 link_layer.destination = destination;
381
382 if (auto cohesive = boost::get<CohesivePacket>(packet.get())) {
383 IndicationContextDeserialize ctx(std::move(packet), *cohesive, link_layer);
384 indicate_basic(ctx);
385 } else if (auto chunk = boost::get<ChunkPacket>(packet.get())) {
386 IndicationContextCast ctx(std::move(packet), *chunk, link_layer);
387 indicate_basic(ctx);
388 } else {
389 packet_dropped(PacketDropReason::Internal_Error);
390 }
391}
392
394{
395 const BasicHeader* basic = ctx.parse_basic();
396 if (!basic) {
397 packet_dropped(PacketDropReason::Parse_Basic_Header);
398 } else if (basic->version.raw() != m_mib.itsGnProtocolVersion) {
399 packet_dropped(PacketDropReason::ITS_Protocol_Version);
400 } else {
401 DataIndication& indication = ctx.service_primitive();
402 indication.remaining_packet_lifetime = basic->lifetime;
403 indication.remaining_hop_limit = basic->hop_limit;
404
405 if (basic->next_header == NextHeaderBasic::Secured) {
406 indicate_secured(ctx, *basic);
407 } else if (basic->next_header == NextHeaderBasic::Common) {
408 if (!m_mib.itsGnSecurity || SecurityDecapHandling::Non_Strict == m_mib.itsGnSnDecapResultHandling) {
409 indication.security_report = boost::blank {}; /*< not secured at all*/
410 indicate_common(ctx, *basic);
411 } else {
412 packet_dropped(PacketDropReason::Decap_Unsuccessful_Strict);
413 }
414 }
415 }
416}
417
419{
420 const CommonHeader* common = ctx.parse_common();
421 if (!common) {
422 packet_dropped(PacketDropReason::Parse_Common_Header);
423 } else if (common->maximum_hop_limit < basic.hop_limit) {
424 // step 1) check the MHL field
425 packet_dropped(PacketDropReason::Hop_Limit);
426 } else {
427 DataIndication& indication = ctx.service_primitive();
428 indication.traffic_class = common->traffic_class;
429 switch (common->next_header)
430 {
431 case NextHeaderCommon::BTP_A:
432 indication.upper_protocol = UpperProtocol::BTP_A;
433 break;
434 case NextHeaderCommon::BTP_B:
435 indication.upper_protocol = UpperProtocol::BTP_B;
436 break;
437 case NextHeaderCommon::IPv6:
438 indication.upper_protocol = UpperProtocol::IPv6;
439 break;
440 default:
441 indication.upper_protocol = UpperProtocol::Unknown;
442 break;
443 }
444
445 // clean up location table at packet indication (nothing else creates entries)
446 m_location_table.drop_expired();
447
448 // step 2) process BC forwarding packet buffer
450
451 // step 3) execute steps depending on extended header type
452 indicate_extended(ctx, *common);
453
454 // NOTE: There is a good chance that processing of extended header updated the location table.
455 // Thus, a routing decision may be possible for some packets in the BC packet forwarding buffer now, e.g.
456 // those buffered due to greedy forwarding's SCF behaviour. However, flushing twice would induce additional
457 // processing overhead. For now, we stick quite conservatively to the standard.
458 }
459}
460
462{
463 struct secured_payload_visitor : public boost::static_visitor<>
464 {
465 secured_payload_visitor(Router& router, IndicationContextBasic& ctx, const BasicHeader& basic) :
466 m_router(router), m_context(ctx), m_basic(basic)
467 {
468 }
469
470 void operator()(ChunkPacket& packet)
471 {
472 IndicationContextSecuredCast ctx(m_context, packet);
473 m_router.indicate_common(ctx, m_basic);
474 }
475
476 void operator()(CohesivePacket& packet)
477 {
478 IndicationContextSecuredDeserialize ctx(m_context, packet);
479 m_router.indicate_common(ctx, m_basic);
480 }
481
482 Router& m_router;
483 IndicationContextBasic& m_context;
484 const BasicHeader& m_basic;
485 };
486
487 auto secured_message = ctx.parse_secured();
488 if (!secured_message) {
489 packet_dropped(PacketDropReason::Parse_Secured_Header);
490 } else if (m_security_entity) {
491 // Decap packet
492 using namespace vanetza::security;
493 DecapConfirm decap_confirm = m_security_entity->decapsulate_packet(SecuredMessageView { *secured_message });
494 ctx.service_primitive().security_report = decap_confirm.report;
495 ctx.service_primitive().its_aid = decap_confirm.its_aid;
496 ctx.service_primitive().permissions = decap_confirm.permissions;
497 secured_payload_visitor visitor(*this, ctx, basic);
498
499 // check whether the received packet is valid
500 if (is_successful(decap_confirm.report)) {
501 boost::apply_visitor(visitor, decap_confirm.plaintext_payload);
502 } else if (SecurityDecapHandling::Non_Strict == m_mib.itsGnSnDecapResultHandling) {
503 // Any packet is passed up with NON-STRICT decapsulation handling
504 // -> see ETSI EN 302 636-4-1 v1.4.1 Section 10.3.3 Note 3
505 if (!decap_confirm.plaintext_payload.empty()) {
506 boost::apply_visitor(visitor, decap_confirm.plaintext_payload);
507 } else {
508 // no payload extracted from secured message to pass up
509 packet_dropped(PacketDropReason::Decap_Unsuccessful_Non_Strict);
510 }
511 } else {
512 // discard packet
513 packet_dropped(PacketDropReason::Decap_Unsuccessful_Strict);
514 }
515 } else {
516 packet_dropped(PacketDropReason::Security_Entity_Missing);
517 }
518}
519
521{
522 struct extended_header_visitor : public boost::static_visitor<bool>
523 {
524 extended_header_visitor(Router& router, IndicationContext& ctx, const UpPacket& packet) :
525 m_router(router), m_context(ctx), m_packet(packet)
526 {
527 }
528
529 bool operator()(const ShbHeader& shb)
530 {
531 DataIndication& indication = m_context.service_primitive();
532 indication.transport_type = TransportType::SHB;
533 indication.source_position = static_cast<ShortPositionVector>(shb.source_position);
534
535 auto& pdu = m_context.pdu();
536 ExtendedPduConstRefs<ShbHeader> shb_pdu(pdu.basic(), pdu.common(), shb, pdu.secured());
537 return m_router.process_extended(shb_pdu, m_packet, m_context.link_layer());
538 }
539
540 bool operator()(const TsbHeader& tsb)
541 {
542 DataIndication& indication = m_context.service_primitive();
543 indication.transport_type = TransportType::TSB;
544 indication.source_position = static_cast<ShortPositionVector>(tsb.source_position);
545
546 auto& pdu = m_context.pdu();
547 ExtendedPduConstRefs<TsbHeader> tsb_pdu(pdu.basic(), pdu.common(), tsb, pdu.secured());
548 return m_router.process_extended(tsb_pdu, m_packet, m_context.link_layer());
549 }
550
551 bool operator()(const GeoBroadcastHeader& gbc)
552 {
553 DataIndication& indication = m_context.service_primitive();
554 indication.transport_type = TransportType::GBC;
555 indication.source_position = static_cast<ShortPositionVector>(gbc.source_position);
556 indication.destination = gbc.destination(m_context.pdu().common().header_type);
557
558 auto& pdu = m_context.pdu();
559 ExtendedPduConstRefs<GeoBroadcastHeader> gbc_pdu(pdu.basic(), pdu.common(), gbc, pdu.secured());
560 return m_router.process_extended(gbc_pdu, m_packet, m_context.link_layer());
561 }
562
563 bool operator()(const BeaconHeader& beacon)
564 {
565 auto& pdu = m_context.pdu();
566 ExtendedPduConstRefs<BeaconHeader> beacon_pdu(pdu.basic(), pdu.common(), beacon, pdu.secured());
567 return m_router.process_extended(beacon_pdu, m_packet, m_context.link_layer());
568 }
569
570 Router& m_router;
571 IndicationContext& m_context;
572 const UpPacket& m_packet;
573 };
574
575 auto extended = ctx.parse_extended(common.header_type);
576 UpPacketPtr packet = ctx.finish();
577 assert(packet);
578
579 if (!extended) {
580 packet_dropped(PacketDropReason::Parse_Extended_Header);
581 } else if (common.payload != size(*packet, OsiLayer::Transport, max_osi_layer())) {
582 packet_dropped(PacketDropReason::Payload_Size);
583 } else {
584 extended_header_visitor visitor(*this, ctx, *packet);
585 if (boost::apply_visitor(visitor, *extended)) {
586 pass_up(ctx.service_primitive(), std::move(packet));
587 }
588 }
589}
590
591NextHop Router::forwarding_algorithm_selection(PendingPacketForwarding&& packet, const LinkLayer* ll)
592{
593 NextHop nh;
594 const Area& destination = packet.pdu().extended().destination(packet.pdu().common().header_type);
595 if (inside_or_at_border(destination, m_local_position_vector.position())) {
596 switch (m_mib.itsGnAreaForwardingAlgorithm) {
597 case BroadcastForwarding::Unspecified:
598 // do simple forwarding
599 case BroadcastForwarding::SIMPLE:
600 // Simple always returns link-layer broadcast address (see Annex F.2)
601 nh.transmit(std::move(packet), cBroadcastMacAddress);
602 break;
603 case BroadcastForwarding::CBF:
604 nh = area_contention_based_forwarding(std::move(packet), ll ? &ll->sender : nullptr);
605 break;
606 case BroadcastForwarding::Advanced:
607 nh = area_advanced_forwarding(std::move(packet), ll);
608 break;
609 default:
610 throw std::runtime_error("unhandled area forwarding algorithm");
611 break;
612 };
613 } else {
614 // packets received from senders located inside destination area are not meant for non-area forwarding
615 const LongPositionVector* pv_se = ll ? m_location_table.get_position(ll->sender) : nullptr;
616 if (pv_se && pv_se->position_accuracy_indicator && inside_or_at_border(destination, pv_se->position())) {
617 nh.discard();
618 forwarding_stopped(ForwardingStopReason::Outside_Destination_Area);
619 } else {
620 switch (m_mib.itsGnNonAreaForwardingAlgorithm) {
621 case UnicastForwarding::Unspecified:
622 // fall through to greedy forwarding
623 case UnicastForwarding::Greedy:
624 nh = greedy_forwarding(std::move(packet));
625 break;
626 case UnicastForwarding::CBF:
627 nh = non_area_contention_based_forwarding(std::move(packet), ll ? &ll->sender : nullptr);
628 break;
629 default:
630 throw std::runtime_error("unhandled non-area forwarding algorithm");
631 break;
632 };
633 }
634 }
635
636 return nh;
637}
638
639void Router::execute_media_procedures(CommunicationProfile com_profile)
640{
641 switch (com_profile) {
642 case CommunicationProfile::ITS_G5:
644 break;
645 case CommunicationProfile::Unspecified:
646 case CommunicationProfile::LTE_V2X:
647 // do nothing
648 break;
649 default:
650 throw std::runtime_error("Unhandled communication profile");
651 break;
652 }
653}
654
656{
657 // TODO: implement ITS_G5A procedures, see EN 302636-4-2
658}
659
660void Router::pass_down(const dcc::DataRequest& request, PduPtr pdu, DownPacketPtr payload)
661{
662 assert(pdu);
663 assert(payload);
664 if (pdu->secured()) {
665 if (pdu->basic().next_header != NextHeaderBasic::Secured) {
666 throw std::runtime_error("PDU with secured message but Secured not set in basic header");
667 }
668 if (payload->size(OsiLayer::Transport, max_osi_layer()) > 0) {
669 throw std::runtime_error("PDU with secured message and illegal upper layer payload");
670 }
671 } else {
672 if (pdu->basic().next_header == NextHeaderBasic::Secured) {
673 throw std::runtime_error("PDU without secured message but Secured set in basic header");
674 }
675 }
676
677 (*payload)[OsiLayer::Network] = ByteBufferConvertible(std::move(pdu));
678 assert(m_request_interface);
679 m_request_interface->request(request, std::move(payload));
680}
681
682void Router::pass_down(const MacAddress& addr, PduPtr pdu, DownPacketPtr payload)
683{
684 assert(pdu);
685
686 dcc::DataRequest request;
687 request.destination = addr;
688 request.source = m_local_position_vector.gn_addr.mid();
689 request.dcc_profile = map_tc_onto_profile(pdu->common().traffic_class);
690 request.ether_type = geonet::ether_type;
691 request.lifetime = clock_cast(pdu->basic().lifetime.decode());
692
693 pass_down(request, std::move(pdu), std::move(payload));
694}
695
696void Router::pass_up(const DataIndication& ind, UpPacketPtr packet)
697{
698 TransportInterface* transport = m_transport_ifcs[ind.upper_protocol];
699 if (transport != nullptr) {
700 transport->indicate(ind, std::move(packet));
701 }
702}
703
705{
706 if (m_mib.vanetzaDisableBeaconing) {
707 // bail out immediately if beaconing has been disabled
708 return;
709 }
710
711 // Beacons originate in GeoNet layer, therefore no upper layer payload
712 DownPacketPtr payload { new DownPacket() };
713 auto pdu = create_beacon_pdu();
714
715 if (m_mib.itsGnSecurity) {
716 pdu->basic().next_header = NextHeaderBasic::Secured;
717 payload = encap_packet(aid::GN_MGMT, ByteBuffer {}, *pdu, std::move(payload));
718 if (!payload) {
719 // stop because encapsulation failed
720 return;
721 }
722 } else {
723 pdu->basic().next_header = NextHeaderBasic::Common;
724 }
725
726 execute_media_procedures(m_mib.itsGnIfType);
727 pass_down(cBroadcastMacAddress, std::move(pdu), std::move(payload));
729}
730
732{
733 using duration_t = decltype(m_mib.itsGnBeaconServiceRetransmitTimer);
734 using real_t = duration_t::value_type;
735 static_assert(std::is_floating_point<real_t>::value, "floating point type expected");
736
737 std::uniform_real_distribution<real_t> dist_jitter(0.0, 1.0);
738 const auto jitter = dist_jitter(m_random_gen);
739 const duration_t next_beacon = m_mib.itsGnBeaconServiceRetransmitTimer +
740 jitter * m_mib.itsGnBeaconServiceMaxJitter;
741 reset_beacon_timer(clock_cast(next_beacon));
742}
743
744void Router::reset_beacon_timer(Clock::duration next_beacon)
745{
746 m_runtime.cancel(this);
747 m_runtime.schedule(next_beacon, [this](Clock::time_point) {
749 }, this);
750}
751
752void Router::dispatch_repetition(const DataRequestVariant& request, std::unique_ptr<DownPacket> payload)
753{
754 RepetitionDispatcher dispatcher(*this, std::move(payload));
755 boost::apply_visitor(dispatcher, request);
756}
757
758NextHop Router::greedy_forwarding(PendingPacketForwarding&& packet)
759{
760 NextHop nh;
761 GeodeticPosition dest = packet.pdu().extended().position();
762 const units::Length own = distance(dest, m_local_position_vector.position());
763 units::Length mfr_dist = own;
764
765 MacAddress mfr_addr;
766 for (const LocationTableEntry& neighbour : m_location_table.neighbours()) {
767 if (neighbour.has_position_vector()) {
768 const units::Length dist = distance(dest, neighbour.get_position_vector().position());
769 if (dist < mfr_dist) {
770 mfr_addr = neighbour.link_layer_address();
771 mfr_dist = dist;
772 }
773 }
774 }
775
776 if (mfr_dist < own) {
777 nh.transmit(std::move(packet), mfr_addr);
778 } else {
779 const bool scf = packet.pdu().common().traffic_class.store_carry_forward();
780 if (scf) {
781 std::function<void(PendingPacketForwarding&&)> greedy_fwd = [this](PendingPacketForwarding&& packet) {
782 NextHop nh = greedy_forwarding(std::move(packet));
783 std::move(nh).process();
784 };
785 PendingPacket<GbcPdu> greedy_packet(std::move(packet), greedy_fwd);
786 PacketBuffer::data_ptr data { new PendingPacketBufferData<GbcPdu>(std::move(greedy_packet)) };
787 m_bc_forward_buffer.push(std::move(data), m_runtime.now());
788 nh.buffer();
789 } else {
790 nh.transmit(std::move(packet), cBroadcastMacAddress);
791 }
792 }
793
794 return nh;
795}
796
797NextHop Router::non_area_contention_based_forwarding(PendingPacketForwarding&& packet, const MacAddress* sender)
798{
799 NextHop nh;
800 const GeoBroadcastHeader& gbc = packet.pdu().extended();
801 const auto cbf_id = identifier(gbc.source_position.gn_addr, gbc.sequence_number);
802
803 // immediately broadcast packet if it is originating from local router
804 if (!sender) {
805 nh.transmit(std::move(packet), cBroadcastMacAddress);
806 } else if (m_cbf_buffer.remove(cbf_id)) {
807 // packet has been in CBF buffer (and is now dropped)
808 nh.discard();
809 } else {
810 const HeaderType ht = packet.pdu().common().header_type;
811 const Area destination = gbc.destination(ht);
812 const auto& epv = m_local_position_vector;
813 const LongPositionVector* pv_se = sender ? m_location_table.get_position(*sender) : nullptr;
814 // condition "PV_SE = EPV" is omitted here
815 if (pv_se && pv_se->position_accuracy_indicator) {
816 const auto& pv_p = destination.position;
817 const units::Length dist_sender = distance(pv_p, pv_se->position());
818 const units::Length dist_local = distance(pv_p, epv.position());
819 if (dist_sender > dist_local) {
820 CbfPacket cbf { std::move(packet), *sender };
821 const auto progress = dist_sender - dist_local;
822 m_cbf_buffer.add(std::move(cbf), clock_cast(timeout_cbf(progress)));
823 nh.buffer();
824
825 } else {
826 nh.discard();
827 }
828 } else {
829 CbfPacket cbf { std::move(packet), *sender };
830 const auto to_cbf_max = m_mib.itsGnCbfMaxTime;
831 m_cbf_buffer.add(std::move(cbf), clock_cast(to_cbf_max));
832 nh.buffer();
833 }
834 }
835 return nh;
836}
837
838NextHop Router::area_contention_based_forwarding(PendingPacketForwarding&& packet, const MacAddress* sender)
839{
840 NextHop nh;
841 const GeoBroadcastHeader& gbc = packet.pdu().extended();
842 const auto cbf_id = identifier(gbc.source_position.gn_addr, gbc.sequence_number);
843
844 if (!sender) {
845 nh.transmit(std::move(packet), cBroadcastMacAddress);
846 } else if (m_cbf_buffer.remove(cbf_id) || m_cbf_buffer.counter(cbf_id) >= m_mib.vanetzaCbfMaxCounter) {
847 nh.discard();
848 } else {
849 const units::Duration timeout = timeout_cbf(*sender);
850 m_cbf_buffer.add(CbfPacket { std::move(packet), *sender }, clock_cast(timeout));
851 nh.buffer();
852 }
853 return nh;
854}
855
856units::Duration Router::timeout_cbf(units::Length prog) const
857{
858 // TODO: media-dependent maximum communication range
859 const auto dist_max = m_mib.itsGnDefaultMaxCommunicationRange;
860 const auto to_cbf_min = m_mib.itsGnCbfMinTime;
861 const auto to_cbf_max = m_mib.itsGnCbfMaxTime;
862
863 if (prog > dist_max) {
864 return to_cbf_min;
865 } else if (prog > 0.0 * units::si::meter) {
866 return to_cbf_max + (to_cbf_min - to_cbf_max) / dist_max * prog;
867 } else {
868 return to_cbf_max;
869 }
870}
871
872units::Duration Router::timeout_cbf(const MacAddress& sender) const
873{
874 // use maximum CBF time as fallback value
875 units::Duration timeout = m_mib.itsGnCbfMaxTime;
876 const LongPositionVector* pv_se = m_location_table.get_position(sender);
877 if (pv_se && pv_se->position_accuracy_indicator) {
878 units::Length dist = distance(pv_se->position(), m_local_position_vector.position());
879 timeout = timeout_cbf(dist);
880 }
881 return timeout;
882}
883
884NextHop Router::area_advanced_forwarding(PendingPacketForwarding&& packet, const LinkLayer* ll)
885{
886 NextHop nh;
887 if (!ll) {
888 // packet is from local node (source operations)
889 nh.transmit(std::move(packet), cBroadcastMacAddress);
890 } else {
891 const GeoBroadcastHeader& gbc = packet.pdu().extended();
892 const HeaderType ht = packet.pdu().common().header_type;
893 const Area destination_area = gbc.destination(ht);
894 const std::size_t max_counter = m_mib.vanetzaCbfMaxCounter;
895 const auto cbf_id = identifier(gbc.source_position.gn_addr, gbc.sequence_number);
896 const CbfPacket* cbf_packet = m_cbf_buffer.find(cbf_id);
897
898 if (cbf_packet) {
899 // packet is already buffered
900 if (m_cbf_buffer.counter(cbf_id) >= max_counter) {
901 // stop contending if counter is exceeded
902 m_cbf_buffer.remove(cbf_id);
903 nh.discard();
904 } else if (!outside_sectorial_contention_area(cbf_packet->sender(), ll->sender)) {
905 // within sectorial area
906 // - sender S = sender of buffered packet
907 // - forwarder F = sender of now received packet
908 m_cbf_buffer.remove(cbf_id);
909 nh.discard();
910 } else {
911 m_cbf_buffer.update(cbf_id, clock_cast(timeout_cbf(ll->sender)));
912 nh.buffer();
913 }
914 } else {
915 if (ll->destination == m_local_position_vector.gn_addr.mid()) {
916 // continue with greedy forwarding
917 nh = greedy_forwarding(packet.duplicate());
918 // optimization: avoid "double broadcast"
919 if (nh.valid() && nh.mac() == cBroadcastMacAddress) {
920 // contending without further broadcasting
921 static const PendingPacketForwarding::Function noop_fn =
922 [](PendingPacketForwarding::Packet&&, const MacAddress&) {};
923 PendingPacketForwarding noop { std::move(packet).packet(), noop_fn };
924 CbfPacket cbf { std::move(noop), ll->sender };
925 m_cbf_buffer.add(std::move(cbf), clock_cast(m_mib.itsGnCbfMaxTime));
926 } else {
927 // no immediate broadcast by greedy forwarding
928 CbfPacket cbf { std::move(packet), ll->sender };
929 m_cbf_buffer.add(std::move(cbf), clock_cast(m_mib.itsGnCbfMaxTime));
930 }
931 // next hop (nh) conveys result of greedy forwarding algorithm
932 } else {
933 // classical CBF (timeout_cbf_gbc looks up sender's position)
934 nh.buffer();
935 CbfPacket cbf { std::move(packet), ll->sender };
936 m_cbf_buffer.add(std::move(cbf), clock_cast(timeout_cbf(ll->sender)));
937 }
938 }
939 }
940
941 return nh;
942}
943
944bool Router::outside_sectorial_contention_area(const MacAddress& sender, const MacAddress& forwarder) const
945{
946 using units::si::meter;
947 auto position_sender = m_location_table.get_position(sender);
948 auto position_forwarder = m_location_table.get_position(forwarder);
949
950 // Assumption: if any position is missing, then sectorial area becomes infinite small
951 // As a result of this assumption, everything lays outside then
952 if (position_sender && position_forwarder) {
953 auto dist_r = distance(position_sender->position(), m_local_position_vector.position());
954 auto dist_f = distance(position_forwarder->position(), position_sender->position());
955 const auto dist_max = m_mib.itsGnDefaultMaxCommunicationRange;
956
957 auto dist_rf = distance(position_forwarder->position(), m_local_position_vector.position());
958 auto angle_fsr = 0.0 * units::si::radians;
959 if (dist_r > 0.0 * meter && dist_f > 0.0 * meter) {
960 auto cos_fsr = (dist_rf * dist_rf - dist_r * dist_r - dist_f * dist_f) /
961 (-2.0 * dist_r * dist_f);
962 angle_fsr = boost::units::acos(cos_fsr);
963 }
964 const auto angle_th = m_mib.itsGnBroadcastCBFDefSectorAngle;
965
966 return !(dist_r < dist_f && dist_f < dist_max && angle_fsr < angle_th);
967 } else {
968 return true;
969 }
970}
971
972bool Router::process_extended(const ExtendedPduConstRefs<ShbHeader>& pdu, const UpPacket& packet, const LinkLayer& ll)
973{
974 const ShbHeader& shb = pdu.extended();
975 const Address& source_addr = shb.source_position.gn_addr;
976
977 // step 3: execute duplicate address detection (see 9.2.1.5)
978 detect_duplicate_address(source_addr, ll.sender);
979
980 // step 4: update location table with SO.PV (see C.2)
981 auto& source_entry = m_location_table.update(shb.source_position);
982 // NOTE: position vector (PV) may still be missing in location table when received PV has been invalid
983 assert(source_entry.has_position_vector() || !is_valid(shb.source_position));
984
985 // step 5: update SO.PDR in location table (see B.2)
986 const std::size_t packet_size = size(packet, OsiLayer::Network, OsiLayer::Application);
987 source_entry.update_pdr(packet_size, m_mib.itsGnMaxPacketDataRateEmaBeta);
988
989 // step 6: set SO LocTE to neighbour
990 source_entry.set_neighbour(true, m_mib.vanetzaNeighbourFlagExpiry);
991
992 // media-dependent update of LocTEX_G5 (see TS 102 636-4-2 V1.1.1, section 6.1.2)
993 if (m_mib.itsGnIfType == InterfaceType::ITS_G5) {
994 boost::optional<DccMcoField> dcc_mco = get_dcc_mco(shb.dcc);
995 if (dcc_mco) {
996 auto& loctex = source_entry.extensions.get<LocTEX_G5>();
997 loctex.local_update = m_runtime.now();
998 loctex.source_update = shb.source_position.timestamp;
999 loctex.dcc_mco = *dcc_mco;
1000 }
1001 }
1002
1003 // step 7: pass up SHB packet anyways
1004 return true;
1005}
1006
1007bool Router::process_extended(const ExtendedPduConstRefs<TsbHeader>& pdu, const UpPacket& packet, const LinkLayer& ll)
1008{
1009 const TsbHeader& tsb = pdu.extended();
1010 const Address& source_addr = tsb.source_position.gn_addr;
1011
1012 // remember if LocTE(SO) exists (5) before duplicate packet detection might (3) silently create an entry
1013 const bool locte_exists = m_location_table.has_entry(source_addr);
1014
1015 // step 3: execute duplicate packet detection
1016 if (detect_duplicate_packet(source_addr, tsb.sequence_number)) {
1017 // discard packet and omit execution of further steps
1018 return false;
1019 }
1020
1021 // step 4: execute duplicate address detection
1022 if (m_mib.vanetzaMultiHopDuplicateAddressDetection) {
1023 // Be careful, DAD is broken with address mode AUTO for multi-hop communication
1024 detect_duplicate_address(source_addr, ll.sender);
1025 }
1026
1027 // step 5a & step 6a (make sure IS_NEIGHBOUR is false for new location table entry)
1028 auto& source_entry = m_location_table.update(tsb.source_position);
1029 if (!locte_exists) {
1030 // step 5b only
1031 source_entry.set_neighbour(false);
1032 }
1033
1034 // step 5c and step 6b
1035 const std::size_t packet_size = size(packet, OsiLayer::Network, OsiLayer::Application);
1036 source_entry.update_pdr(packet_size, m_mib.itsGnMaxPacketDataRateEmaBeta);
1037
1038 // step 7: packet is passed up depending on return value of this method
1039
1040 // step 8a: TODO: flush SO LS packet buffer if LS_pending, reset LS_pending
1041 // step 8b: flush UC forwarding packet buffer
1043
1044 // step 9: discard packet (no forwarding) if hop limit is reached
1045 if (pdu.basic().hop_limit <= 1) {
1046 // step 9a: discard packet and omit execution of further steps
1047 forwarding_stopped(ForwardingStopReason::Hop_Limit);
1048 return true;
1049 } else if (m_mib.itsGnMaxPacketDataRate < std::numeric_limits<decltype(m_mib.itsGnMaxPacketDataRate)>::max()) {
1050 // do packet data rate checks (annex B.2) if set maximum rate is not "infinity" (i.e. max unsigned value)
1051 if (source_entry.get_pdr() > m_mib.itsGnMaxPacketDataRate * 1000.0) {
1052 forwarding_stopped(ForwardingStopReason::Source_PDR);
1053 return true; // omit forwarding, source exceeds PDR limit
1054 } else if (const auto* sender_entry = m_location_table.get_entry(ll.sender)) {
1055 if (sender_entry->get_pdr() > m_mib.itsGnMaxPacketDataRate * 1000.0) {
1056 forwarding_stopped(ForwardingStopReason::Sender_PDR);
1057 return true; // omit forwarding, sender exceeds PDR limit
1058 }
1059 }
1060 }
1061
1062 // step 9b: update hop limit in basic header
1063 auto fwd_dup = create_forwarding_duplicate(pdu, packet);
1064 TsbPdu& fwd_pdu = get_pdu(fwd_dup);
1065 --fwd_pdu.basic().hop_limit;
1066 assert(fwd_pdu.basic().hop_limit + 1 == pdu.basic().hop_limit);
1067
1068 auto transmit = [this](PendingPacket<TsbPdu>::Packet&& packet) {
1069 // step 11: execute media-dependent procedures
1070 execute_media_procedures(m_mib.itsGnIfType);
1071
1072 // step 12: pass down to link-layer
1073 std::unique_ptr<Pdu> pdu;
1074 std::unique_ptr<DownPacket> payload;
1075 std::tie(pdu, payload) = std::move(packet);
1076
1077 dcc::DataRequest request;
1078 request.destination = cBroadcastMacAddress;
1079 request.source = m_local_position_vector.gn_addr.mid();
1080 request.dcc_profile = dcc::Profile::DP3;
1081 request.ether_type = geonet::ether_type;
1082 request.lifetime = clock_cast(pdu->basic().lifetime.decode());
1083 pass_down(request, std::move(pdu), std::move(payload));
1084 };
1085
1086 PendingPacket<TsbPdu> fwd_packet(std::move(fwd_dup), transmit);
1087
1088 // step 10: store & carry forwarding procedure
1089 const bool scf = pdu.common().traffic_class.store_carry_forward();
1090 if (scf && !m_location_table.has_neighbours()) {
1091 PacketBuffer::data_ptr data { new PendingPacketBufferData<TsbPdu>(std::move(fwd_packet)) };
1092 m_bc_forward_buffer.push(std::move(data), m_runtime.now());
1093 return true; // step 10a: buffer packet and omit further steps
1094 }
1095
1096 // immediately execute steps 11 & 12
1097 std::move(fwd_packet).process();
1098
1099 // step 7: pass up TSB finally
1100 return true;
1101}
1102
1103bool Router::process_extended(const ExtendedPduConstRefs<BeaconHeader>& pdu, const UpPacket& packet, const LinkLayer& ll)
1104{
1105 const BeaconHeader& beacon = pdu.extended();
1106 const Address& source_addr = beacon.source_position.gn_addr;
1107
1108 // step 3: execute duplicate address detection (see 9.2.1.5)
1109 detect_duplicate_address(source_addr, ll.sender);
1110
1111 // step 4: update location table with SO.PV (see C.2)
1112 auto& source_entry = m_location_table.update(beacon.source_position);
1113
1114 // step 5: update SO.PDR in location table (see B.2)
1115 const std::size_t packet_size = size(packet, OsiLayer::Network, OsiLayer::Application);
1116 source_entry.update_pdr(packet_size, m_mib.itsGnMaxPacketDataRateEmaBeta);
1117
1118 // step 6: set SO LocTE to neighbour
1119 source_entry.set_neighbour(true, m_mib.vanetzaNeighbourFlagExpiry);
1120
1121 // step 7: never pass up Beacons
1122 return false;
1123}
1124
1125bool Router::process_extended(const ExtendedPduConstRefs<GeoBroadcastHeader>& pdu, const UpPacket& packet, const LinkLayer& ll)
1126{
1127 // GBC forwarder and receiver operations (section 9.3.11.3 in EN 302 636-4-1 V1.2.1)
1128 const GeoBroadcastHeader& gbc = pdu.extended();
1129 const Address& source_addr = gbc.source_position.gn_addr;
1130 const Area dest_area = gbc.destination(pdu.common().header_type);
1131
1132 // remember if LocTE(SO) exists (5) before duplicate packet detection might (3) silently create an entry
1133 const bool locte_exists = m_location_table.has_entry(source_addr);
1134
1135 // step 3: determine position relative to destination area
1136 const bool within_destination = inside_or_at_border(dest_area, m_local_position_vector.position());
1137 // step 3a
1138 bool duplicate_packet = false;
1139 if (!within_destination) {
1140 if (m_mib.itsGnNonAreaForwardingAlgorithm == UnicastForwarding::Unspecified ||
1141 m_mib.itsGnNonAreaForwardingAlgorithm == UnicastForwarding::Greedy) {
1142 duplicate_packet = detect_duplicate_packet(source_addr, gbc.sequence_number);
1143 }
1144 // step 3b
1145 } else {
1146 if (m_mib.itsGnAreaForwardingAlgorithm == BroadcastForwarding::Unspecified ||
1147 m_mib.itsGnAreaForwardingAlgorithm == BroadcastForwarding::SIMPLE) {
1148 duplicate_packet = detect_duplicate_packet(source_addr, gbc.sequence_number);
1149 }
1150 }
1151 // step 3a & 3b
1152 if (duplicate_packet) {
1153 // omit execution of further steps
1154 return false;
1155 }
1156
1157 // step 4: execute DAD
1158 if (m_mib.vanetzaMultiHopDuplicateAddressDetection) {
1159 // Be careful, DAD is broken with address mode AUTO for multi-hop communication
1160 detect_duplicate_address(source_addr, ll.sender);
1161 }
1162
1163 // step 5 & step 6 (make sure IS_NEIGHBOUR is false for new location table entry)
1164 const std::size_t packet_size = size(packet, OsiLayer::Network, OsiLayer::Application);
1165 auto& source_entry = m_location_table.update(gbc.source_position);
1166 source_entry.update_pdr(packet_size, m_mib.itsGnMaxPacketDataRateEmaBeta);
1167 if (!locte_exists) {
1168 // step 5b only
1169 source_entry.set_neighbour(false);
1170 }
1171
1172 // step 7: pass packet to upper layer if router is within destination area, return value
1173
1174 // step 8a: TODO: flush SO LS packet buffer if LS_pending, reset LS_pending
1175 // step 8b: flush UC forwarding packet buffer
1177
1178 // step 9: discard packet (no forwarding) if hop limit is reached
1179 if (pdu.basic().hop_limit <= 1) {
1180 forwarding_stopped(ForwardingStopReason::Hop_Limit);
1181 return decide_pass_up(within_destination, gbc); // discard packet (step 9a)
1182 } else if (m_mib.itsGnMaxPacketDataRate < std::numeric_limits<decltype(m_mib.itsGnMaxPacketDataRate)>::max()) {
1183 // do packet data rate checks (annex B.2) if set maximum rate is not "infinity" (i.e. max unsigned value)
1184 if (source_entry.get_pdr() > m_mib.itsGnMaxPacketDataRate * 1000.0) {
1185 forwarding_stopped(ForwardingStopReason::Source_PDR);
1186 return decide_pass_up(within_destination, gbc); // omit forwarding, source exceeds PDR limit
1187 } else if (const auto* sender_entry = m_location_table.get_entry(ll.sender)) {
1188 if (sender_entry->get_pdr() > m_mib.itsGnMaxPacketDataRate * 1000.0) {
1189 forwarding_stopped(ForwardingStopReason::Sender_PDR);
1190 return decide_pass_up(within_destination, gbc); // omit forwarding, sender exceeds PDR limit
1191 }
1192 }
1193 }
1194
1195 // step 9b: update hop limit in basic header
1196 auto fwd_dup = create_forwarding_duplicate(pdu, packet);
1197 GbcPdu& fwd_pdu = get_pdu(fwd_dup);
1198 --fwd_pdu.basic().hop_limit;
1199 assert(fwd_pdu.basic().hop_limit + 1 == pdu.basic().hop_limit);
1200
1201 using Packet = PendingPacketGbc::Packet;
1202
1203 auto transmit = [this](Packet&& packet, const MacAddress& mac) {
1204 // step 13: execute media-dependent procedures
1205 execute_media_procedures(m_mib.itsGnIfType);
1206
1207 // step 14: pass down to link-layer
1208 std::unique_ptr<Pdu> pdu;
1209 std::unique_ptr<DownPacket> payload;
1210 std::tie(pdu, payload) = std::move(packet);
1211
1212 dcc::DataRequest request;
1213 request.destination = mac;
1214 request.source = m_local_position_vector.gn_addr.mid();
1215 request.dcc_profile = dcc::Profile::DP3;
1216 request.ether_type = geonet::ether_type;
1217 request.lifetime = clock_cast(pdu->basic().lifetime.decode());
1218
1219 pass_down(request, std::move(pdu), std::move(payload));
1220 };
1221
1222 auto forwarding = [this, transmit, ll](Packet&& packet) {
1223 // step 11: execute forwarding algorithm
1224 PendingPacket<GbcPdu, const MacAddress&> tmp(std::move(packet), transmit);
1225 NextHop forwarding = forwarding_algorithm_selection(std::move(tmp), &ll);
1226
1227 // step 12: transmit immediately if not buffered or discarded
1228 std::move(forwarding).process();
1229 };
1230
1231 PendingPacketGbc fwd_packet(std::move(fwd_dup), forwarding);
1232
1233 // step 10: store & carry forwarding procedure
1234 const bool scf = pdu.common().traffic_class.store_carry_forward();
1235 if (scf && !m_location_table.has_neighbours()) {
1236 PacketBuffer::data_ptr data { new PendingPacketBufferData<GbcPdu>(std::move(fwd_packet)) };
1237 m_bc_forward_buffer.push(std::move(data), m_runtime.now());
1238 } else {
1239 fwd_packet.process();
1240 }
1241
1242 // step 7: pass up decision
1243 return decide_pass_up(within_destination, gbc);
1244}
1245
1246bool Router::decide_pass_up(bool within_destination, const GeoBroadcastHeader& gbc)
1247{
1248 // accept only GBC within destination area if not explicitly requested
1249 const bool accept = within_destination || m_mib.vanetzaGbcPassUpOutsideDestination;
1250
1251 if (m_mib.vanetzaGbcMemoryCapacity == 0) {
1252 // classic pass up: suppress only GBCs outside of destination area
1253 return accept;
1254 } else if (accept) {
1255 // modified pass up: suppress passing up duplicate GBC packets
1256 return !m_gbc_memory.remember(std::make_tuple(gbc.source_position.gn_addr, gbc.sequence_number));
1257 } else {
1258 return false;
1259 }
1260}
1261
1263{
1264 m_bc_forward_buffer.flush(m_runtime.now());
1265}
1266
1268{
1269 // TODO flush only packets for given source address (required for GUC packets)
1270 mark_unused(source);
1271 m_uc_forward_buffer.flush(m_runtime.now());
1272}
1273
1274void Router::detect_duplicate_address(const Address& source, const MacAddress& sender)
1275{
1276 // EN 302 636-4-1 V1.3.1 10.2.1.5: DAD is only applied for Auto
1277 if (m_mib.itsGnLocalAddrConfMethod == AddrConfMethod::Auto) {
1278 const Address& local = m_local_position_vector.gn_addr;
1279 if (source == local || sender == local.mid()) {
1280 MacAddress random_mac_addr;
1281 std::uniform_int_distribution<unsigned> octet_dist;
1282 for (auto& octet : random_mac_addr.octets) {
1283 octet = octet_dist(m_random_gen);
1284 }
1285
1286 m_local_position_vector.gn_addr.mid(random_mac_addr);
1287 }
1288 }
1289}
1290
1292{
1293 bool is_duplicate = false;
1294 ObjectContainer& so_ext = m_location_table.get_or_create_entry(addr_so).extensions;
1295 DuplicatePacketList* dpl = so_ext.find<DuplicatePacketList>();
1296 if (dpl) {
1297 is_duplicate = dpl->check(sn);
1298 } else {
1299 std::unique_ptr<DuplicatePacketList> dpl { new DuplicatePacketList(m_mib.itsGnDPLLength) };
1300 is_duplicate = dpl->check(sn);
1301 so_ext.insert(std::move(dpl));
1302 }
1303 return is_duplicate;
1304}
1305
1307{
1308 std::unique_ptr<ShbPdu> pdu { new ShbPdu(request, m_mib) };
1309 pdu->basic().hop_limit = 1;
1310 pdu->common().header_type = HeaderType::TSB_Single_Hop;
1311 pdu->common().maximum_hop_limit = 1;
1312 pdu->extended().source_position = m_local_position_vector;
1313 pdu->extended().dcc = m_dcc_field_generator->generate_dcc_field();
1314 return pdu;
1315}
1316
1318{
1319 std::unique_ptr<BeaconPdu> pdu { new BeaconPdu(m_mib) };
1320 pdu->basic().hop_limit = 1;
1321 pdu->common().next_header = NextHeaderCommon::Any;
1322 pdu->common().header_type = HeaderType::Beacon;
1323 pdu->common().maximum_hop_limit = 1;
1324 // TODO: Beacons are sent with itsGnDefaultTrafficClass (DP0) at the moment, but DP3 may be more appropriate?
1325 pdu->extended().source_position = m_local_position_vector;
1326 return pdu;
1327}
1328
1330{
1331 std::unique_ptr<GbcPdu> pdu { new GbcPdu(request, m_mib) };
1332 pdu->common().header_type = gbc_header_type(request.destination);
1333 pdu->extended().sequence_number = m_local_sequence_number++;
1334 pdu->extended().source_position = m_local_position_vector;
1335 pdu->extended().destination(request.destination);
1336 return pdu;
1337}
1338
1339Router::DownPacketPtr Router::encap_packet(ItsAid its_aid, ByteBuffer ssp, Pdu& pdu, DownPacketPtr packet)
1340{
1341 if (m_security_entity) {
1342 DownPacket sec_payload;
1343 sec_payload[OsiLayer::Network] = SecuredPdu(pdu);
1344 sec_payload.merge(*packet, OsiLayer::Transport, max_osi_layer());
1345
1346 security::SignRequest sign_request;
1347 sign_request.plain_message = std::move(sec_payload);
1348 sign_request.its_aid = its_aid;
1349 sign_request.permissions = std::move(ssp);
1350
1351 security::EncapConfirm confirm = m_security_entity->encapsulate_packet(std::move(sign_request));
1352
1353 struct Visitor : boost::static_visitor<DownPacketPtr>
1354 {
1355 Visitor(DownPacketPtr packet, Pdu& pdu) : m_packet(std::move(packet)), m_pdu(pdu)
1356 {
1357 assert(size(*m_packet, OsiLayer::Transport, max_osi_layer()) == 0);
1358 assert(m_pdu.basic().next_header == NextHeaderBasic::Secured);
1359 }
1360
1361 DownPacketPtr operator() (security::SecuredMessage& msg)
1362 {
1363 m_pdu.secured(std::move(msg));
1364 return std::move(m_packet);
1365 }
1366
1367 DownPacketPtr operator() (const security::SignConfirmError&)
1368 {
1369 // SN-SIGN encapsulation failed
1370 return nullptr;
1371 }
1372
1373 DownPacketPtr m_packet;
1374 Pdu& m_pdu;
1375 };
1376
1377 Visitor visitor(std::move(packet), pdu);
1378 return boost::apply_visitor(visitor, confirm);
1379 } else {
1380 // security entity is not available
1381 return nullptr;
1382 }
1383}
1384
1385std::string stringify(Router::PacketDropReason pdr)
1386{
1387 std::string reason_string;
1388
1389 // TODO replace this by something more elegant, e.g. https://github.com/aantron/better-enums
1390 switch (pdr) {
1391 case Router::PacketDropReason::Parse_Basic_Header:
1392 reason_string = "Parse_Basic_Header";
1393 break;
1394 case Router::PacketDropReason::Parse_Common_Header:
1395 reason_string = "Parse_Common_Header";
1396 break;
1397 case Router::PacketDropReason::Parse_Secured_Header:
1398 reason_string = "Parse_Secured_Header";
1399 break;
1400 case Router::PacketDropReason::Parse_Extended_Header:
1401 reason_string = "Parse_Extended_Header";
1402 break;
1403 case Router::PacketDropReason::ITS_Protocol_Version:
1404 reason_string = "ITS_Protocol_Version";
1405 break;
1406 case Router::PacketDropReason::Decap_Unsuccessful_Non_Strict:
1407 reason_string = "Decap_Unsuccessful_Non_Strict";
1408 break;
1409 case Router::PacketDropReason::Decap_Unsuccessful_Strict:
1410 reason_string = "Decap_Unsuccessful_Strict";
1411 break;
1412 case Router::PacketDropReason::Hop_Limit:
1413 reason_string = "Hop_Limit";
1414 break;
1415 case Router::PacketDropReason::Payload_Size:
1416 reason_string = "Payload_Size";
1417 break;
1418 case Router::PacketDropReason::Security_Entity_Missing:
1419 reason_string = "Security_Entity_Missing";
1420 break;
1421 default:
1422 reason_string = "UNKNOWN";
1423 break;
1424 }
1425
1426 return reason_string;
1427}
1428
1429} // namespace geonet
1430} // namespace vanetza
ChunckPacket is a packet consisting of several memory chunks.
ByteBufferConvertible & operator[](OsiLayer ol)
ChunkPacket & merge(ChunkPacket &packet, OsiLayer from, OsiLayer to)
virtual void cancel(const void *scope)=0
virtual Clock::time_point now() const =0
const MacAddress & sender() const
const MacAddress & mac() const
Definition next_hop.cpp:27
void transmit(Packet &&packet, const MacAddress &destination)
Definition next_hop.cpp:43
void reset_beacon_timer(Clock::duration next)
Reschedule timer for next Beacon transmission.
Definition router.cpp:744
NextHop area_advanced_forwarding(PendingPacketForwarding &&, const LinkLayer *sender)
Determine next hop for area advanced forwarding See EN 302 636-4-1 v1.3.1 Annex F....
Definition router.cpp:884
void flush_broadcast_forwarding_buffer()
Send all packets in the broadcast forwarding buffer with expired waiting time.
Definition router.cpp:1262
void indicate_extended(IndicationContext &, const CommonHeader &)
Process ExtendedHeader at packet indication.
Definition router.cpp:520
bool detect_duplicate_packet(const Address &source, SequenceNumber sn)
Detect duplicate packets See EN 302 636-4-1 v1.3.1 Annex A.2.
Definition router.cpp:1291
void pass_down(const dcc::DataRequest &, PduPtr, DownPacketPtr)
Send packet using the information in the DataRequest. The packet is formed using the data in PDU and ...
Definition router.cpp:660
NextHop greedy_forwarding(PendingPacketForwarding &&)
Determine next hop for greedy forwarding. See EN 302 636-4-1 v1.3.1 Annex E.2.
Definition router.cpp:758
bool process_extended(const ExtendedPduConstRefs< ShbHeader > &, const UpPacket &, const LinkLayer &ll)
Process ExtendedHeader information. Update router's LocationTable and neighbour relationship....
Definition router.cpp:972
void pass_up(const DataIndication &, UpPacketPtr)
Pass packet up to the transport layer.
Definition router.cpp:696
units::Duration timeout_cbf(units::Length distance) const
Determine CBF buffering time for a packet. Complies to EN 302 636-4-1 v1.3.1 Annex E....
Definition router.cpp:856
void on_beacon_timer_expired()
Send Beacon packet to all neighbours with updated position vector. Only to be called when the beacon ...
Definition router.cpp:704
void indicate_common(IndicationContext &, const BasicHeader &)
Process CommonHeader at packet indication.
Definition router.cpp:418
DownPacketPtr encap_packet(ItsAid aid, ByteBuffer ssp, Pdu &pdu, DownPacketPtr packet)
Encaspulate a packet according to security profile.
Definition router.cpp:1339
bool decide_pass_up(bool within_destination, const GeoBroadcastHeader &gbc)
Decide if GBC packet shall be passed up to transport layer.
Definition router.cpp:1246
void set_access_interface(dcc::RequestInterface *ifc)
Register access layer interface.
Definition router.cpp:201
void set_random_seed(std::uint_fast32_t seed)
Set seed for internal random number generator (RNG) RNG is used e.g. for random Beacon jitter.
Definition router.cpp:218
units::Duration timeout_cbf(const MacAddress &sender) const
Determine (area) CBF buffering time for a packet from a sender.
Definition router.cpp:872
NextHop area_contention_based_forwarding(PendingPacketForwarding &&, const MacAddress *sender)
Determine next hop for area contention-based forwarding See EN 302 636-4-1 v1.3.1 Annex F....
Definition router.cpp:838
std::unique_ptr< ShbPdu > create_shb_pdu(const ShbDataRequest &)
Create an initialized Single-Hop-Broadcast PDU.
Definition router.cpp:1306
void flush_unicast_forwarding_buffer(const Address &addr)
Send all matching packets in the unicast forwarding buffer with expired waiting time.
Definition router.cpp:1267
void detect_duplicate_address(const Address &source, const MacAddress &sender)
Helper method to handle duplicate addresses. If own address collides with the address of a received p...
Definition router.cpp:1274
std::unique_ptr< BeaconPdu > create_beacon_pdu()
Create an initialzed Beacon PDU.
Definition router.cpp:1317
void indicate_basic(IndicationContextBasic &)
Process BasicHeader at packet indication.
Definition router.cpp:393
void set_dcc_field_generator(DccFieldGenerator *dcc)
Register generator for DCC-MCO fields.
Definition router.cpp:207
bool process_extended(const ExtendedPduConstRefs< TsbHeader > &, const UpPacket &, const LinkLayer &ll)
packet handling of received TSB packet
Definition router.cpp:1007
PacketDropReason
Reason for packet drop used by drop hook.
Definition router.hpp:85
DataConfirm request(const ShbDataRequest &, DownPacketPtr)
Request to send payload per single hop broadcast (SHB). If security is enabled, the message gets enca...
Definition router.cpp:223
void pass_down(const MacAddress &, PduPtr, DownPacketPtr)
Pass down the packet to the access layer.
Definition router.cpp:682
void dispatch_repetition(const DataRequestVariant &, DownPacketPtr)
Callback function for dispatching a packet repetition. Invoked by Repeater when a scheduled repetitio...
Definition router.cpp:752
NextHop non_area_contention_based_forwarding(PendingPacketForwarding &&, const MacAddress *sender)
Determine next hop for non-area contention-based forwarding See EN 302 636-4-1 v1....
Definition router.cpp:797
bool process_extended(const ExtendedPduConstRefs< GeoBroadcastHeader > &, const UpPacket &, const LinkLayer &ll)
Process ExtendedHeader information. Update router's LocationTable and neighbour relationship....
Definition router.cpp:1125
void indicate(UpPacketPtr, const MacAddress &sender, const MacAddress &destination)
Handle the received packet on network layer. Packet handling involves these steps:
Definition router.cpp:375
void set_transport_handler(UpperProtocol proto, TransportInterface *ifc)
Register a transport protocol handler.
Definition router.cpp:191
void reset_beacon_timer()
Reschedule timer for next Beacon transmission Timer will be scheduled according to MIB's Beacon timer...
Definition router.cpp:731
void update_position(const PositionFix &)
Update router's local position vector.
Definition router.cpp:171
void execute_media_procedures(CommunicationProfile)
Executes media specific functionalities Details are described in TS 102 636-4-2.
Definition router.cpp:639
void set_security_entity(security::SecurityEntity *entity)
Register security entity used when itsGnSecurity is enabled.
Definition router.cpp:196
std::unique_ptr< GbcPdu > create_gbc_pdu(const GbcDataRequest &)
Create an initialized GeoBroadcast PDU.
Definition router.cpp:1329
void set_address(const Address &)
Set Router's own GeoNetworking address.
Definition router.cpp:213
NextHop forwarding_algorithm_selection(PendingPacketForwarding &&, const LinkLayer *ll=nullptr)
Definition router.cpp:591
DataConfirm request(const GbcDataRequest &, DownPacketPtr)
Request to send payload per GeoBroadcast (GBC). If security is enabled, the message gets encapsulated...
Definition router.cpp:285
void execute_itsg5_procedures()
Executes ITS-G5 media specific procedures Details are described in TS 102 636-4-2.
Definition router.cpp:655
bool process_extended(const ExtendedPduConstRefs< BeaconHeader > &, const UpPacket &, const LinkLayer &ll)
Process ExtendedHeader information. Update router's LocationTable and neighbour relationship.
Definition router.cpp:1103
void indicate_secured(IndicationContextBasic &, const BasicHeader &)
Process SecuredMessage at packet indication.
Definition router.cpp:461
bool outside_sectorial_contention_area(const MacAddress &sender, const MacAddress &forwarder) const
Check if router is outside the sectorial contention area See TS 102 636-4-1 v1.2.3 section E....
Definition router.cpp:944
virtual EncapConfirm encapsulate_packet(EncapRequest &&request)=0
Creates a security envelope covering the given payload.
virtual DecapConfirm decapsulate_packet(DecapRequest &&request)=0
Decapsulates the payload within a SecuredMessage.
BasicHeader specified in ETSI EN 302 636-4-1 v1.2.1, section 8.6.