join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
ndp.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_FABRIC_NDP_HPP
26#define JOIN_FABRIC_NDP_HPP
27
28// libjoin.
30#include <join/ndp_protocol.hpp>
31#include <join/ndp_message.hpp>
32#include <join/condition.hpp>
33#include <join/function.hpp>
34#include <join/reactor.hpp>
35#include <join/error.hpp>
36
37// C++.
38#include <system_error>
39#include <algorithm>
40#include <chrono>
41#include <memory>
42#include <string>
43#include <vector>
44
45// C.
46#include <netinet/icmp6.h>
47#include <net/if.h>
48
49namespace join
50{
54 template <class Protocol>
55 class BasicNdp : public EventHandler
56 {
57 public:
58 using Socket = typename Protocol::Socket;
59 using Endpoint = typename Protocol::Endpoint;
60
62 using NeighborSolicitationNotify = Function<void (const NeighborSolicitation& solicitation)>;
63
66
70 BasicNdp () = delete;
71
80 BasicNdp (const std::string& interface, uint8_t filter, const IpAddress& group, Reactor& reactor)
81 : _socket (Protocol::hopLimit)
82 , _buffer (std::make_unique<char[]> (Protocol::maxMsgSize))
86 , _reactor (reactor)
87 {
88 if (_socket.open (Protocol::Transport::v6 ()) == -1)
89 {
90 throw std::system_error (lastError, "ndp socket open failed"); // LCOV_EXCL_LINE
91 }
92
93 if (_socket.bindToDevice (_interface) == -1)
94 {
95 throw std::system_error (lastError, "ndp socket bind to device failed"); // LCOV_EXCL_LINE
96 }
97
98 int on = 1;
99
100 if (::setsockopt (_socket.handle (), IPPROTO_IPV6, IPV6_MULTICAST_IF, &_index, sizeof (_index)) == -1)
101 {
102 // LCOV_EXCL_START
103 throw std::system_error (errno, std::generic_category (), "ndp multicast setup failed");
104 // LCOV_EXCL_STOP
105 }
106
107 if (::setsockopt (_socket.handle (), IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof (on)) == -1)
108 {
109 // LCOV_EXCL_START
110 throw std::system_error (errno, std::generic_category (), "ndp hop limit setup failed");
111 // LCOV_EXCL_STOP
112 }
113
114 if (::setsockopt (_socket.handle (), IPPROTO_IPV6, IPV6_DONTFRAG, &on, sizeof (on)) == -1)
115 {
116 // LCOV_EXCL_START
117 throw std::system_error (errno, std::generic_category (), "ndp dontfrag setup failed");
118 // LCOV_EXCL_STOP
119 }
120
121 ICMP6_FILTER_SETBLOCKALL (&_filter);
122
123 if (applyFilter (filter, true) == -1)
124 {
125 throw std::system_error (lastError, "ndp icmp6 filter setup failed"); // LCOV_EXCL_LINE
126 }
127
128 if (!group.isWildcard ())
129 {
130 struct ipv6_mreq mreq = {};
131 ::memcpy (&mreq.ipv6mr_multiaddr, group.addr (), group.length ());
132 mreq.ipv6mr_interface = _index;
133
134 if (::setsockopt (_socket.handle (), IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof (mreq)) == -1)
135 {
136 // LCOV_EXCL_START
137 throw std::system_error (errno, std::generic_category (), "ndp multicast membership setup failed");
138 // LCOV_EXCL_STOP
139 }
140 }
141 }
142
147 BasicNdp (const BasicNdp& other) = delete;
148
154 BasicNdp& operator= (const BasicNdp& other) = delete;
155
160 BasicNdp (BasicNdp&& other) = delete;
161
167 BasicNdp& operator= (BasicNdp&& other) = delete;
168
172 virtual ~BasicNdp () = default;
173
182 std::chrono::milliseconds timeout = std::chrono::seconds (1)) noexcept
183 {
185 {
186 lastError = std::make_error_code (std::errc::resource_deadlock_would_occur);
187 return -1;
188 }
189
191 out.target = target;
192 out.link = _hardware;
193
195 ssize_t size = _message.serialize (out, payload, sizeof (payload));
196 if (size == -1)
197 {
198 return -1;
199 }
200
201 struct in6_addr group;
202 ::memcpy (&group, IpAddress::ipv6SolicitedNodes.addr (), sizeof (group));
203 ::memcpy (&group.s6_addr[13], static_cast<const uint8_t*> (target.addr ()) + 13, 3);
204
205 NeighborRequest pending;
206 pending.target = IpAddress (target.addr (), target.length ());
207 pending.advert = &advert;
208
209 Reactor::InvokeHandler addFilter = [this, &pending] () {
210 _neighborPending.push_back (&pending);
212 };
213
214 Reactor::InvokeHandler delFilter = [this, &pending] () {
215 _neighborPending.erase (std::find (_neighborPending.begin (), _neighborPending.end (), &pending));
217 };
218
219 if (_reactor.invoke (&addFilter) == -1)
220 {
221 return -1; // LCOV_EXCL_LINE
222 }
223
224 if (send (payload, static_cast<size_t> (size), IpAddress (&group, sizeof (group))) == -1)
225 {
226 // LCOV_EXCL_START
227 _reactor.invoke (&delFilter);
228 return -1;
229 // LCOV_EXCL_STOP
230 }
231
232 {
234 pending.cond.timedWait (lock, timeout, [&pending] {
235 return pending.done;
236 });
237 }
238
239 _reactor.invoke (&delFilter);
240
241 if (!pending.done)
242 {
243 lastError = make_error_code (Errc::TimedOut);
244 return -1;
245 }
246
247 return 0;
248 }
249
257 const IpAddress& destination = IpAddress::ipv6AllNodes) noexcept
258 {
260 ssize_t size = _message.serialize (advert, payload, sizeof (payload),
261 advert.link.isWildcard () ? _hardware : advert.link);
262 if (size == -1)
263 {
264 return -1;
265 }
266
267 return send (payload, static_cast<size_t> (size), destination);
268 }
269
276 int neighborAdvertise (const NeighborAdvertisement& advert, const NeighborSolicitation& solicitation) noexcept
277 {
279 ssize_t size = _message.serialize (advert, payload, sizeof (payload),
280 advert.link.isWildcard () ? _hardware : advert.link);
281 if (size == -1)
282 {
283 return -1;
284 }
285
286 struct nd_neighbor_advert na;
287 ::memcpy (&na, payload, sizeof (na));
288
289 if (solicitation.src.isWildcard ())
290 {
291 na.nd_na_flags_reserved &= ~ND_NA_FLAG_SOLICITED;
292 }
293 else
294 {
295 na.nd_na_flags_reserved |= ND_NA_FLAG_SOLICITED;
296 }
297
298 ::memcpy (payload, &na, sizeof (na));
299
300 return send (payload, static_cast<size_t> (size),
301 solicitation.src.isWildcard () ? IpAddress::ipv6AllNodes : solicitation.src);
302 }
303
310 {
311 bool busy = false;
312
313 Reactor::InvokeHandler fn = [this, &cb, &busy] () {
315 if (!busy)
316 {
317 _neighborSolicitationListener = std::move (cb);
319 }
320 };
321
322 if (_reactor.invoke (&fn) == -1)
323 {
324 return -1; // LCOV_EXCL_LINE
325 }
326
327 if (busy)
328 {
329 lastError = make_error_code (Errc::InUse);
330 return -1;
331 }
332
333 return 0;
334 }
335
341 {
342 Reactor::InvokeHandler fn = [this] () {
346 };
347
348 return _reactor.invoke (&fn);
349 }
350
357 {
358 bool busy = false;
359
360 Reactor::InvokeHandler fn = [this, &cb, &busy] () {
362 if (!busy)
363 {
364 _neighborAdvertisementListener = std::move (cb);
366 }
367 };
368
369 if (_reactor.invoke (&fn) == -1)
370 {
371 return -1; // LCOV_EXCL_LINE
372 }
373
374 if (busy)
375 {
376 lastError = make_error_code (Errc::InUse);
377 return -1;
378 }
379
380 return 0;
381 }
382
388 {
389 Reactor::InvokeHandler fn = [this] () {
393 };
394
395 return _reactor.invoke (&fn);
396 }
397
402 const std::string& interface () const noexcept
403 {
404 return _interface;
405 }
406
411 unsigned int index () const noexcept
412 {
413 return _index;
414 }
415
420 const MacAddress& hardware () const noexcept
421 {
422 return _hardware;
423 }
424
425 protected:
430 void attach ()
431 {
432 if (_reactor.addHandler (_socket.handle (), this) == -1)
433 {
434 throw std::system_error (lastError, "ndp reactor registration failed"); // LCOV_EXCL_LINE
435 }
436 }
437
441 void detach () noexcept
442 {
443 _reactor.delHandler (_socket.handle ());
444 }
445
452 int applyFilter (uint8_t type, bool pass) noexcept
453 {
454 if (ICMP6_FILTER_WILLPASS (type, &_filter) == pass)
455 {
456 return 0;
457 }
458
459 struct icmp6_filter filter = _filter;
460
461 if (pass)
462 {
463 ICMP6_FILTER_SETPASS (type, &filter);
464 }
465 else
466 {
467 ICMP6_FILTER_SETBLOCK (type, &filter);
468 }
469
470 if (::setsockopt (_socket.handle (), IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (filter)) == -1)
471 {
472 // LCOV_EXCL_START
473 lastError = std::error_code (errno, std::generic_category ());
474 return -1;
475 // LCOV_EXCL_STOP
476 }
477
478 _filter = filter;
479
480 return 0;
481 }
482
490 int send (const char* data, size_t size, const IpAddress& destination)
491 {
492 if (destination.family () != AF_INET6)
493 {
495 return -1;
496 }
497
498 if (size > Protocol::maxMsgSize)
499 {
500 // LCOV_EXCL_START
502 return -1;
503 // LCOV_EXCL_STOP
504 }
505
506 Endpoint endpoint (IpAddress (destination.addr (), destination.length (), _index));
507
508 return (_socket.writeTo (data, size, endpoint) == -1) ? -1 : 0;
509 }
510
518 ssize_t receive (char* data, size_t maxSize, IpAddress& from)
519 {
520 Endpoint endpoint;
521 char control[CMSG_SPACE (sizeof (int))];
522 size_t controlSize = sizeof (control);
523
524 ssize_t size = _socket.readFrom (data, maxSize, &endpoint, control, &controlSize);
525 if (size <= 0)
526 {
527 return -1; // LCOV_EXCL_LINE
528 }
529
530 struct msghdr msg = {};
531 msg.msg_control = control;
532 msg.msg_controllen = controlSize;
533
534 int hop = 0;
535
536 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR (&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR (&msg, cmsg))
537 {
538 if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_HOPLIMIT))
539 {
540 ::memcpy (&hop, CMSG_DATA (cmsg), sizeof (hop));
541 }
542 }
543
544 if (hop != Protocol::hopLimit)
545 {
546 return -1;
547 }
548
549 from = endpoint.ip ();
550
551 return size;
552 }
553
561 bool onNeighborMessage (size_t size, const IpAddress& from) noexcept
562 {
563 const uint8_t type = static_cast<uint8_t> (_buffer[0]);
564
565 if (type == NdpMessage::NeighborSolicit)
566 {
568 {
569 return true; // LCOV_EXCL_LINE
570 }
571
572 NeighborSolicitation solicitation;
573 if ((_message.deserialize (solicitation, _buffer.get (), size) == 0) &&
574 (!from.isWildcard () || solicitation.link.isWildcard ()))
575 {
576 solicitation.src = from;
577
579
581 listener (solicitation);
582
584 {
585 _neighborSolicitationListener = std::move (listener);
587 }
588 }
589
590 return true;
591 }
592
593 if (type != NdpMessage::NeighborAdvert)
594 {
595 return false;
596 }
597
599 {
600 return true; // LCOV_EXCL_LINE
601 }
602
604 if (_message.deserialize (advert, _buffer.get (), size) == 0)
605 {
606 advert.src = from;
607
609 {
611
613 listener (advert);
614
616 {
617 _neighborAdvertisementListener = std::move (listener);
619 }
620 }
621
622 if (!_neighborPending.empty ())
623 {
625
626 for (NeighborRequest* pending : _neighborPending)
627 {
628 if (!pending->done && !advert.link.isWildcard () && (pending->target == advert.target))
629 {
630 *pending->advert = advert;
631 pending->done = true;
632 pending->cond.signal ();
633 }
634 }
635 }
636 }
637
638 return true;
639 }
640
647 static unsigned int lookup (const std::string& interface)
648 {
649 unsigned int index = ::if_nametoindex (interface.c_str ());
650 if (index == 0)
651 {
652 throw std::system_error (errno, std::generic_category (), "ndp interface lookup failed");
653 }
654
655 return index;
656 }
657
660
663
665 std::unique_ptr<char[]> _buffer;
666
668 const std::string _interface;
669
671 const unsigned int _index;
672
675
678
680 struct icmp6_filter _filter;
681
686 {
689
691 IpAddress target{AF_INET6};
692
695
697 bool done = false;
698 };
699
701 std::vector<NeighborRequest*> _neighborPending;
702
705
708
712
715
719 };
720
724 template <class Protocol>
725 class BasicNdpClient final : protected BasicNdp<Protocol>
726 {
727 public:
728 using BasicNdp<Protocol>::interface;
729 using BasicNdp<Protocol>::hardware;
730 using BasicNdp<Protocol>::index;
731 using BasicNdp<Protocol>::neighborSolicit;
732 using BasicNdp<Protocol>::neighborAdvertise;
739
742
746 BasicNdpClient () = delete;
747
754 explicit BasicNdpClient (const std::string& interface, Reactor& reactor = ReactorThread::reactor ())
755 : BasicNdp<Protocol> (interface, NdpMessage::RouterAdvert, IpAddress::ipv6Wildcard, reactor)
756 {
757 this->attach ();
758 }
759
764 {
765 this->detach ();
766 }
767
772 int routerSolicit () noexcept
773 {
775 out.link = hardware ();
776
778 ssize_t size = this->_message.serialize (out, payload, sizeof (payload));
779 if (size == -1)
780 {
781 return -1; // LCOV_EXCL_LINE
782 }
783
784 return this->send (payload, static_cast<size_t> (size), IpAddress::ipv6Routers);
785 }
786
794 std::chrono::milliseconds timeout = std::chrono::seconds (1)) noexcept
795 {
796 if (this->_reactor.isReactorThread ())
797 {
798 lastError = std::make_error_code (std::errc::resource_deadlock_would_occur);
799 return -1;
800 }
801
802 RouterRequest pending;
803 pending.advert = &advert;
804
805 Reactor::InvokeHandler addRequest = [this, &pending] () {
806 _pending.push_back (&pending);
807 };
808
809 Reactor::InvokeHandler delRequest = [this, &pending] () {
810 _pending.erase (std::find (_pending.begin (), _pending.end (), &pending));
811 };
812
813 if (this->_reactor.invoke (&addRequest) == -1)
814 {
815 return -1; // LCOV_EXCL_LINE
816 }
817
818 if (routerSolicit () == -1)
819 {
820 // LCOV_EXCL_START
821 this->_reactor.invoke (&delRequest);
822 return -1;
823 // LCOV_EXCL_STOP
824 }
825
826 {
827 ScopedLock<Mutex> lock (_routerMutex);
828 pending.cond.timedWait (lock, timeout, [&pending] {
829 return pending.done;
830 });
831 }
832
833 this->_reactor.invoke (&delRequest);
834
835 if (!pending.done)
836 {
837 lastError = make_error_code (Errc::TimedOut);
838 return -1;
839 }
840
841 return 0;
842 }
843
850 {
851 bool busy = false;
852
853 Reactor::InvokeHandler fn = [this, &cb, &busy] () {
854 busy = _routerAdvertisementCalling || _routerAdvertisementListener;
855 if (!busy)
856 {
857 _routerAdvertisementListener = std::move (cb);
858 }
859 };
860
861 if (this->_reactor.invoke (&fn) == -1)
862 {
863 return -1; // LCOV_EXCL_LINE
864 }
865
866 if (busy)
867 {
868 lastError = make_error_code (Errc::InUse);
869 return -1;
870 }
871
872 return 0;
873 }
874
880 {
881 Reactor::InvokeHandler fn = [this] () {
882 _routerAdvertisementListener = nullptr;
883 _routerAdvertisementCalling = false;
884 };
885
886 return this->_reactor.invoke (&fn);
887 }
888
889 private:
894 void onReadable ([[maybe_unused]] int fd) override final
895 {
896 IpAddress from;
897 ssize_t size = this->receive (this->_buffer.get (), Protocol::maxMsgSize, from);
898 if (size == -1)
899 {
900 return;
901 }
902
903 if (this->onNeighborMessage (static_cast<size_t> (size), from))
904 {
905 return;
906 }
907
908 if (!from.isLinkLocal ())
909 {
910 return;
911 }
912
913 RouterAdvertisement advert;
914 if (this->_message.deserialize (advert, this->_buffer.get (), static_cast<size_t> (size)) == -1)
915 {
916 return;
917 }
918
919 advert.src = from;
920
921 if (_routerAdvertisementListener)
922 {
923 RouterAdvertisementNotify listener = std::move (_routerAdvertisementListener);
924
925 _routerAdvertisementCalling = true;
926 listener (advert);
927
928 if (_routerAdvertisementCalling)
929 {
930 _routerAdvertisementListener = std::move (listener);
931 _routerAdvertisementCalling = false;
932 }
933 }
934
935 if (!_pending.empty ())
936 {
937 ScopedLock<Mutex> lock (_routerMutex);
938
939 for (RouterRequest* pending : _pending)
940 {
941 if (!pending->done)
942 {
943 *pending->advert = advert;
944 pending->done = true;
945 pending->cond.signal ();
946 }
947 }
948 }
949 }
950
954 struct RouterRequest
955 {
957 Condition cond;
958
960 RouterAdvertisement* advert = nullptr;
961
963 bool done = false;
964 };
965
967 std::vector<RouterRequest*> _pending;
968
970 Mutex _routerMutex;
971
973 RouterAdvertisementNotify _routerAdvertisementListener;
974
977 bool _routerAdvertisementCalling = false;
978 };
979
983 template <class Protocol>
984 class BasicNdpServer final : protected BasicNdp<Protocol>
985 {
986 public:
987 using BasicNdp<Protocol>::interface;
988 using BasicNdp<Protocol>::hardware;
989 using BasicNdp<Protocol>::index;
990 using BasicNdp<Protocol>::neighborSolicit;
991 using BasicNdp<Protocol>::neighborAdvertise;
998
1000 using RouterSolicitationNotify = Function<void (const RouterSolicitation& solicitation)>;
1001
1005 BasicNdpServer () = delete;
1006
1013 explicit BasicNdpServer (const std::string& interface, Reactor& reactor = ReactorThread::reactor ())
1014 : BasicNdp<Protocol> (interface, NdpMessage::RouterSolicit, IpAddress::ipv6Routers, reactor)
1015 {
1016 this->attach ();
1017 }
1018
1023 {
1024 this->detach ();
1025 }
1026
1033 {
1034 bool busy = false;
1035
1036 Reactor::InvokeHandler fn = [this, &cb, &busy] () {
1037 busy = _routerSolicitationCalling || _routerSolicitationListener;
1038 if (!busy)
1039 {
1040 _routerSolicitationListener = std::move (cb);
1041 }
1042 };
1043
1044 if (this->_reactor.invoke (&fn) == -1)
1045 {
1046 return -1; // LCOV_EXCL_LINE
1047 }
1048
1049 if (busy)
1050 {
1051 lastError = make_error_code (Errc::InUse);
1052 return -1;
1053 }
1054
1055 return 0;
1056 }
1057
1063 {
1064 Reactor::InvokeHandler fn = [this] () {
1065 _routerSolicitationListener = nullptr;
1066 _routerSolicitationCalling = false;
1067 };
1068
1069 return this->_reactor.invoke (&fn);
1070 }
1071
1079 const IpAddress& destination = IpAddress::ipv6AllNodes) noexcept
1080 {
1081 char payload[Protocol::maxMsgSize];
1082 ssize_t size = this->_message.serialize (advert, payload, sizeof (payload),
1083 advert.link.isWildcard () ? hardware () : advert.link);
1084 if (size == -1)
1085 {
1086 return -1;
1087 }
1088
1089 return this->send (payload, static_cast<size_t> (size), destination);
1090 }
1091
1098 int routerAdvertise (const RouterAdvertisement& advert, const RouterSolicitation& solicitation) noexcept
1099 {
1100 return routerAdvertise (advert,
1101 solicitation.src.isWildcard () ? IpAddress::ipv6AllNodes : solicitation.src);
1102 }
1103
1104 private:
1109 void onReadable ([[maybe_unused]] int fd) override final
1110 {
1111 IpAddress from;
1112 ssize_t size = this->receive (this->_buffer.get (), Protocol::maxMsgSize, from);
1113 if (size == -1)
1114 {
1115 return;
1116 }
1117
1118 if (this->onNeighborMessage (static_cast<size_t> (size), from))
1119 {
1120 return;
1121 }
1122
1123 RouterSolicitation solicitation;
1124 if (this->_message.deserialize (solicitation, this->_buffer.get (), static_cast<size_t> (size)) == -1)
1125 {
1126 return;
1127 }
1128
1129 if (from.isWildcard () && !solicitation.link.isWildcard ())
1130 {
1131 return;
1132 }
1133
1134 solicitation.src = from;
1135
1136 if (_routerSolicitationListener)
1137 {
1138 RouterSolicitationNotify listener = std::move (_routerSolicitationListener);
1139
1140 _routerSolicitationCalling = true;
1141 listener (solicitation);
1142
1143 if (_routerSolicitationCalling)
1144 {
1145 _routerSolicitationListener = std::move (listener);
1146 _routerSolicitationCalling = false;
1147 }
1148 }
1149 }
1150
1152 RouterSolicitationNotify _routerSolicitationListener;
1153
1156 bool _routerSolicitationCalling = false;
1157 };
1158}
1159
1160#endif
NDP client, solicits routers and receives their advertisements.
Definition ndp_protocol.hpp:37
int unsetRouterAdvertisementListener() noexcept
unset the router advertisement callback, it is no longer called once this returns.
Definition ndp.hpp:879
int routerSolicit(RouterAdvertisement &advert, std::chrono::milliseconds timeout=std::chrono::seconds(1)) noexcept
send a router solicitation and wait for the first advertisement.
Definition ndp.hpp:793
Function< void(const RouterAdvertisement &advert)> RouterAdvertisementNotify
router advertisement notification callback.
Definition ndp.hpp:741
BasicNdpClient(const std::string &interface, Reactor &reactor=ReactorThread::reactor())
create the instance bound to the given interface and start receiving advertisements.
Definition ndp.hpp:754
int setRouterAdvertisementListener(RouterAdvertisementNotify cb) noexcept
set the callback called on every router advertisement received, solicited or not.
Definition ndp.hpp:849
~BasicNdpClient()
stop receiving advertisements and destroy the instance.
Definition ndp.hpp:763
int routerSolicit() noexcept
send a router solicitation.
Definition ndp.hpp:772
BasicNdpClient()=delete
create the BasicNdpClient instance.
int routerAdvertise(const RouterAdvertisement &advert, const IpAddress &destination=IpAddress::ipv6AllNodes) noexcept
send a router advertisement.
Definition ndp.hpp:1078
Function< void(const RouterSolicitation &solicitation)> RouterSolicitationNotify
router solicitation notification callback.
Definition ndp.hpp:1000
int routerAdvertise(const RouterAdvertisement &advert, const RouterSolicitation &solicitation) noexcept
answer a router solicitation, to the solicitor or to all the nodes of the link if it has no address.
Definition ndp.hpp:1098
BasicNdpServer(const std::string &interface, Reactor &reactor=ReactorThread::reactor())
create the instance bound to the given interface and start receiving solicitations.
Definition ndp.hpp:1013
~BasicNdpServer()
stop receiving solicitations and destroy the instance.
Definition ndp.hpp:1022
BasicNdpServer()=delete
create the BasicNdpServer instance.
int setRouterSolicitationListener(RouterSolicitationNotify cb) noexcept
set the callback called on every router solicitation received.
Definition ndp.hpp:1032
int unsetRouterSolicitationListener() noexcept
unset the router solicitation callback, it is no longer called once this returns.
Definition ndp.hpp:1062
carries NDP messages over an ICMPv6 socket.
Definition ndp_protocol.hpp:34
void detach() noexcept
unregister from the reactor, to be called by the final class before destruction starts.
Definition ndp.hpp:441
const std::string _interface
interface name.
Definition ndp.hpp:668
Mutex _neighborMutex
neighbor solicitations protection mutex.
Definition ndp.hpp:704
typename Protocol::Endpoint Endpoint
Definition ndp.hpp:59
NeighborAdvertisementNotify _neighborAdvertisementListener
neighbor advertisement listener, only accessed from the reactor thread.
Definition ndp.hpp:714
ssize_t receive(char *data, size_t maxSize, IpAddress &from)
read a message that passed the checks common to every NDP message.
Definition ndp.hpp:518
BasicNdp(const std::string &interface, uint8_t filter, const IpAddress &group, Reactor &reactor)
create the instance bound to the given interface.
Definition ndp.hpp:80
std::vector< NeighborRequest * > _neighborPending
neighbor solicitations waiting for an advertisement, only accessed from the reactor thread.
Definition ndp.hpp:701
bool _neighborAdvertisementCalling
Definition ndp.hpp:718
Function< void(const NeighborSolicitation &solicitation)> NeighborSolicitationNotify
neighbor solicitation notification callback.
Definition ndp.hpp:62
static unsigned int lookup(const std::string &interface)
get the index of the given interface.
Definition ndp.hpp:647
int neighborSolicit(const IpAddress &target, NeighborAdvertisement &advert, std::chrono::milliseconds timeout=std::chrono::seconds(1)) noexcept
send a neighbor solicitation and wait for the advertisement of the target.
Definition ndp.hpp:181
Socket _socket
underlying socket.
Definition ndp.hpp:659
NdpMessage _message
NDP message codec.
Definition ndp.hpp:662
unsigned int index() const noexcept
get the index of the interface the instance is bound to.
Definition ndp.hpp:411
BasicNdp(const BasicNdp &other)=delete
create instance by copy.
const MacAddress _hardware
hardware address of the interface.
Definition ndp.hpp:674
BasicNdp(BasicNdp &&other)=delete
create instance by move.
bool _neighborSolicitationCalling
Definition ndp.hpp:711
int applyFilter(uint8_t type, bool pass) noexcept
pass or block a message type in the ICMPv6 filter.
Definition ndp.hpp:452
int unsetNeighborSolicitationListener() noexcept
unset the neighbor solicitation callback, it is no longer called once this returns.
Definition ndp.hpp:340
bool onNeighborMessage(size_t size, const IpAddress &from) noexcept
hand a received neighbor message to its listener, and an advertisement to the solicitations waiting f...
Definition ndp.hpp:561
int send(const char *data, size_t size, const IpAddress &destination)
write a message on the interface.
Definition ndp.hpp:490
Reactor & _reactor
event loop reactor.
Definition ndp.hpp:677
virtual ~BasicNdp()=default
destroy the instance.
int unsetNeighborAdvertisementListener() noexcept
unset the neighbor advertisement callback, it is no longer called once this returns.
Definition ndp.hpp:387
int neighborAdvertise(const NeighborAdvertisement &advert, const IpAddress &destination=IpAddress::ipv6AllNodes) noexcept
send a neighbor advertisement, the interface hardware address is used if it carries none.
Definition ndp.hpp:256
int setNeighborAdvertisementListener(NeighborAdvertisementNotify cb) noexcept
set the callback called on every neighbor advertisement received, solicited or not.
Definition ndp.hpp:356
void attach()
register with the reactor, to be called by the final class once fully constructed.
Definition ndp.hpp:430
BasicNdp & operator=(const BasicNdp &other)=delete
assign instance by copy.
const unsigned int _index
interface index.
Definition ndp.hpp:671
typename Protocol::Socket Socket
Definition ndp.hpp:58
struct icmp6_filter _filter
ICMPv6 filter applied to the socket, only accessed from the reactor thread once constructed.
Definition ndp.hpp:680
int setNeighborSolicitationListener(NeighborSolicitationNotify cb) noexcept
set the callback called on every neighbor solicitation received.
Definition ndp.hpp:309
NeighborSolicitationNotify _neighborSolicitationListener
neighbor solicitation listener, only accessed from the reactor thread.
Definition ndp.hpp:707
BasicNdp()=delete
create the BasicNdp instance.
std::unique_ptr< char[]> _buffer
receive buffer.
Definition ndp.hpp:665
const MacAddress & hardware() const noexcept
get the hardware address of the interface the instance is bound to.
Definition ndp.hpp:420
const std::string & interface() const noexcept
get the name of the interface the instance is bound to.
Definition ndp.hpp:402
int neighborAdvertise(const NeighborAdvertisement &advert, const NeighborSolicitation &solicitation) noexcept
answer a neighbor solicitation, to the solicitor or to all the nodes of the link if it has no address...
Definition ndp.hpp:276
Function< void(const NeighborAdvertisement &advert)> NeighborAdvertisementNotify
neighbor advertisement notification callback.
Definition ndp.hpp:65
condition variable class.
Definition condition.hpp:42
bool timedWait(Lock &lock, std::chrono::duration< Rep, Period > timeout)
wait on a condition until timeout expire.
Definition condition.hpp:121
IPv6, IPv4 address class.
Definition ip_address.hpp:52
bool isLinkLocal() const
check if IP address is link local.
Definition ip_address.cpp:1313
static const IpAddress ipv6Routers
routers multicast IPv6 address.
Definition ip_address.hpp:364
static const IpAddress ipv6AllNodes
all nodes multicast IPv6 address.
Definition ip_address.hpp:358
static const IpAddress ipv6SolicitedNodes
solicited nodes multicast IPv6 address.
Definition ip_address.hpp:361
int family() const
get address family.
Definition ip_address.cpp:1250
socklen_t length() const
get the size in byte of the internal address structure.
Definition ip_address.cpp:1268
bool isWildcard() const
check if IP address is a wildcard address.
Definition ip_address.cpp:1295
const void * addr() const
get the internal address structure.
Definition ip_address.cpp:1259
MAC address class.
Definition mac_address.hpp:47
bool isWildcard() const
check if MAC address is a wildcard address.
Definition mac_address.cpp:182
class used to protect shared data from being simultaneously accessed by multiple threads.
Definition mutex.hpp:37
NDP message codec.
Definition ndp_message.hpp:163
static constexpr size_t maxNeighborAdvertisementSize
biggest neighbor advertisement the codec writes, link layer address option included.
Definition ndp_message.hpp:702
static constexpr size_t maxRouterSolicitationSize
biggest router solicitation the codec writes, link layer address option included.
Definition ndp_message.hpp:694
ssize_t serialize(const RouterSolicitation &packet, char *data, size_t maxSize) const
serialize a router solicitation into a buffer.
Definition ndp_message.hpp:195
@ NeighborAdvert
Definition ndp_message.hpp:173
@ NeighborSolicit
Definition ndp_message.hpp:172
static constexpr size_t maxNeighborSolicitationSize
biggest neighbor solicitation the codec writes, link layer address option included.
Definition ndp_message.hpp:698
int deserialize(RouterSolicitation &packet, const char *data, size_t size) const
deserialize a router solicitation from a buffer.
Definition ndp_message.hpp:398
static Reactor & reactor()
get the global Reactor instance.
Definition reactor.cpp:612
Reactor class.
Definition reactor.hpp:159
bool isReactorThread() const noexcept
check if the calling thread is the reactor thread.
Definition reactor.cpp:337
int delHandler(int fd, bool sync=true) noexcept
delete handler from reactor.
Definition reactor.cpp:156
int addHandler(int fd, EventHandler *handler, bool wantRead=true, bool wantWrite=false, bool sync=true) noexcept
add handler to reactor.
Definition reactor.cpp:101
int invoke(InvokeHandler *fn, bool sync=true) noexcept
invoke a function from the reactor thread.
Definition reactor.cpp:199
class owning a mutex for the duration of a scoped block.
Definition mutex.hpp:249
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
Definition error.hpp:144
neighbor solicitation waiting for the advertisement of its target.
Definition ndp.hpp:686
Condition cond
answer notification.
Definition ndp.hpp:688
bool done
set once the advertisement has been received.
Definition ndp.hpp:697
NeighborAdvertisement * advert
receives the advertisement.
Definition ndp.hpp:694
IpAddress target
address of the solicited neighbor.
Definition ndp.hpp:691
neighbor advertisement, RFC 4861 section 4.4.
Definition ndp_message.hpp:145
IpAddress src
address the advertisement came from, set by the transport.
Definition ndp_message.hpp:147
IpAddress target
address the advertisement is about.
Definition ndp_message.hpp:153
MacAddress link
link layer address of the target, wildcard if not carried.
Definition ndp_message.hpp:156
neighbor solicitation, RFC 4861 section 4.3.
Definition ndp_message.hpp:130
MacAddress link
link layer address of the sender, wildcard if not carried.
Definition ndp_message.hpp:138
IpAddress src
address the solicitation came from, set by the transport.
Definition ndp_message.hpp:132
IpAddress target
address of the solicited neighbor.
Definition ndp_message.hpp:135
router advertisement, RFC 4861 section 4.2.
Definition ndp_message.hpp:94
IpAddress src
address the advertisement came from, set by the transport.
Definition ndp_message.hpp:96
router solicitation, RFC 4861 section 4.1.
Definition ndp_message.hpp:82
MacAddress link
link layer address of the sender, wildcard if not carried.
Definition ndp_message.hpp:87
IpAddress address
Definition tcp_acceptor_test.cpp:35