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