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