A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
dhcp6-client.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 NITK Surathkal
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Kavya Bhat <kavyabhat@gmail.com>
7 *
8 */
9
10#include "dhcp6-client.h"
11
12#include "dhcp6-duid.h"
13
14#include "ns3/address-utils.h"
15#include "ns3/icmpv6-l4-protocol.h"
16#include "ns3/ipv6-interface.h"
17#include "ns3/ipv6-l3-protocol.h"
18#include "ns3/ipv6-packet-info-tag.h"
19#include "ns3/ipv6.h"
20#include "ns3/log.h"
21#include "ns3/loopback-net-device.h"
22#include "ns3/mac48-address.h"
23#include "ns3/net-device-container.h"
24#include "ns3/object.h"
25#include "ns3/pointer.h"
26#include "ns3/ptr.h"
27#include "ns3/random-variable-stream.h"
28#include "ns3/simulator.h"
29#include "ns3/socket.h"
30#include "ns3/string.h"
31#include "ns3/trace-source-accessor.h"
32#include "ns3/traced-value.h"
33#include "ns3/trickle-timer.h"
34
35#include <algorithm>
36
37namespace ns3
38{
39
40NS_LOG_COMPONENT_DEFINE("Dhcp6Client");
41
42TypeId
44{
45 static TypeId tid =
46 TypeId("ns3::Dhcp6Client")
48 .AddConstructor<Dhcp6Client>()
49 .SetGroupName("InternetApps")
50 .AddAttribute("Transactions",
51 "A value to be used as the transaction ID.",
52 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
55 .AddAttribute("SolicitJitter",
56 "The jitter in ms that a node waits before sending any solicitation. By "
57 "default, the model will wait for a duration in ms defined by a uniform "
58 "random-variable between 0 and SolicitJitter. This is equivalent to"
59 "SOL_MAX_DELAY (RFC 8415, Section 7.6).",
60 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=1000.0]"),
63 .AddAttribute("IaidValue",
64 "The identifier for a new IA created by a client.",
65 StringValue("ns3::UniformRandomVariable[Min=0.0|Max=1000000.0]"),
68 .AddAttribute("SolicitInterval",
69 "Time after which the client resends the Solicit."
70 "Equivalent to SOL_MAX_RT (RFC 8415, Section 7.6)",
71 TimeValue(Seconds(100)),
74 .AddTraceSource("NewLease",
75 "The client has obtained a lease",
77 "ns3::Ipv6Address::TracedCallback");
78 return tid;
79}
80
85
86void
88{
89 NS_LOG_FUNCTION(this);
90
91 for (auto& itr : m_interfaces)
92 {
93 itr.second->Cleanup();
94 itr.second = nullptr;
95 }
96 m_interfaces.clear();
97 m_iaidMap.clear();
98
100}
101
102int64_t
104{
105 NS_LOG_FUNCTION(this << stream);
106 m_solicitJitter->SetStream(stream);
107 m_transactionId->SetStream(stream + 1);
108 m_iaidStream->SetStream(stream + 2);
109 return 3;
110}
111
112bool
114{
115 Ptr<Packet> packet = Create<Packet>();
116 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
117 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
118 uint32_t clientTransactId = m_interfaces[ifIndex]->m_transactId;
119 uint32_t receivedTransactId = header.GetTransactId();
120
121 if (clientTransactId != receivedTransactId)
122 {
123 return false;
124 }
125
126 Duid clientDuid = header.GetClientIdentifier().GetDuid();
127 NS_ASSERT_MSG(clientDuid == m_clientDuid, "Client DUID mismatch.");
128
129 m_interfaces[ifIndex]->m_serverDuid = header.GetServerIdentifier().GetDuid();
130 return true;
131}
132
133void
135{
136 NS_LOG_FUNCTION(this << iDev << header << server);
137
138 Ptr<Packet> packet = Create<Packet>();
139 Dhcp6Header requestHeader;
140 requestHeader.ResetOptions();
142
143 // TODO: Use min, max for GetValue
144 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
145 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
146 const auto& dhcpInterface = m_interfaces[ifIndex];
147 dhcpInterface->m_transactId = static_cast<uint32_t>(m_transactionId->GetValue());
148 requestHeader.SetTransactId(dhcpInterface->m_transactId);
149
150 // Add Client Identifier Option.
151 requestHeader.AddClientIdentifier(m_clientDuid);
152
153 // Add Server Identifier Option, copied from the received header.
154 Duid serverDuid = header.GetServerIdentifier().GetDuid();
155 requestHeader.AddServerIdentifier(serverDuid);
156
157 // Add Elapsed Time Option.
158 uint32_t actualElapsedTime =
159 (Simulator::Now() - dhcpInterface->m_msgStartTime).GetMilliSeconds() / 10;
160 uint16_t elapsed = actualElapsedTime > 65535 ? 65535 : actualElapsedTime;
161 requestHeader.AddElapsedTime(elapsed);
162
163 // Add IA_NA option.
164 // Request all addresses from the Advertise message.
165 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
166
167 for (const auto& iaOpt : ianaOptionsList)
168 {
169 // Iterate through the offered addresses.
170 // Current approach: Try to accept all offers.
171 for (const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
172 {
173 requestHeader.AddIanaOption(iaOpt.GetIaid(), iaOpt.GetT1(), iaOpt.GetT2());
174 requestHeader.AddAddress(iaOpt.GetIaid(),
175 iaAddrOpt.GetIaAddress(),
176 iaAddrOpt.GetPreferredLifetime(),
177 iaAddrOpt.GetValidLifetime());
178
179 NS_LOG_DEBUG("Requesting " << iaAddrOpt.GetIaAddress());
180 }
181 }
182
183 // Add Option Request.
185
186 packet->AddHeader(requestHeader);
187
188 // TODO: Handle server unicast option.
189
190 // Send the request message.
191 dhcpInterface->m_state = State::WAIT_REPLY;
192 if (dhcpInterface->m_socket->SendTo(
193 packet,
194 0,
196 {
197 NS_LOG_INFO("DHCPv6 client: Request sent.");
198 }
199 else
200 {
201 NS_LOG_INFO("DHCPv6 client: Error while sending Request.");
202 }
203}
204
213
215{
216 std::cout << "InterfaceConfig::~InterfaceConfig" << std::endl;
217
218 m_socket = nullptr;
219 m_client = nullptr;
220
221 m_iaids.clear();
222 m_solicitTimer.Stop();
223 m_declinedAddresses.clear();
224
225 m_renewEvent.Cancel();
226 m_rebindEvent.Cancel();
227
228 for (auto& itr : m_releaseEvent)
229 {
230 itr.Cancel();
231 }
232}
233
234void
236{
237 NS_LOG_DEBUG("Accepting address " << offeredAddress);
238
239 // Check that the offered address is from DHCPv6.
240 bool found = false;
241 for (auto& addr : m_offeredAddresses)
242 {
243 if (addr == offeredAddress)
244 {
245 found = true;
246 break;
247 }
248 }
249
250 if (found)
251 {
252 m_nAcceptedAddresses += 1;
253
254 // Notify the new lease.
255 m_client->m_newLease(offeredAddress);
256 std::cerr << "* got a new lease " << offeredAddress << std::endl;
257 }
258}
259
260void
262{
263 NS_LOG_DEBUG("Address to be declined " << offeredAddress);
264
265 // Check that the offered address is from DHCPv6.
266 bool found = false;
267 for (auto& addr : m_offeredAddresses)
268 {
269 if (addr == offeredAddress)
270 {
271 found = true;
272 break;
273 }
274 }
275
276 if (found)
277 {
278 m_declinedAddresses.emplace_back(offeredAddress);
279 if (m_declinedAddresses.size() + m_nAcceptedAddresses == m_offeredAddresses.size())
280 {
281 DeclineOffer();
282 }
283 }
284}
285
286void
288{
289 if (m_declinedAddresses.empty())
290 {
291 return;
292 }
293
294 // Cancel all scheduled Release, Renew, Rebind events.
295 m_renewEvent.Cancel();
296 m_rebindEvent.Cancel();
297 for (auto itr : m_releaseEvent)
298 {
299 itr.Cancel();
300 }
301
302 Dhcp6Header declineHeader;
303 Ptr<Packet> packet = Create<Packet>();
304
305 // Remove address associations.
306 for (const auto& offer : m_declinedAddresses)
307 {
308 uint32_t iaid = m_client->m_iaidMap[offer];
309
310 // IA_NA option, IA address option
311 declineHeader.AddIanaOption(iaid, m_renewTime.GetSeconds(), m_rebindTime.GetSeconds());
312 declineHeader.AddAddress(iaid,
313 offer,
314 m_prefLifetime.GetSeconds(),
315 m_validLifetime.GetSeconds());
316 NS_LOG_DEBUG("Declining address " << offer);
317 }
318
319 m_transactId = static_cast<uint32_t>(m_client->m_transactionId->GetValue());
320 declineHeader.SetTransactId(m_transactId);
322
323 // Add client identifier option
324 declineHeader.AddClientIdentifier(m_client->m_clientDuid);
325
326 // Add server identifier option
327 declineHeader.AddServerIdentifier(m_serverDuid);
328
329 m_msgStartTime = Simulator::Now();
330 declineHeader.AddElapsedTime(0);
331
332 packet->AddHeader(declineHeader);
333 if ((m_socket->SendTo(packet,
334 0,
337 {
338 NS_LOG_INFO("DHCPv6 client: Decline sent");
339 }
340 else
341 {
342 NS_LOG_INFO("DHCPv6 client: Error while sending Decline");
343 }
344
346}
347
348void
350{
351 m_solicitTimer.Stop();
352
353 for (auto& releaseEvent : m_releaseEvent)
354 {
355 releaseEvent.Cancel();
356 }
357
358 m_renewEvent.Cancel();
359 m_rebindEvent.Cancel();
360
361 m_socket->SetRecvCallback(MakeNullCallback<void, Ptr<Socket>>());
362 m_socket->Close();
363
364 Ptr<Ipv6> ipv6 = m_client->GetNode()->GetObject<Ipv6>();
365
366 // Remove the offered IPv6 addresses from the interface.
367 for (uint32_t i = 0; i < ipv6->GetNAddresses(m_interfaceIndex); i++)
368 {
369 for (const auto& addr : m_offeredAddresses)
370 {
371 if (ipv6->GetAddress(m_interfaceIndex, i) == addr)
372 {
373 ipv6->RemoveAddress(m_interfaceIndex, i);
374 break;
375 }
376 }
377 }
378 m_offeredAddresses.clear();
379
381 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), m_interfaceIndex));
382
383 icmpv6->TraceDisconnectWithoutContext("DadSuccess", m_acceptedAddressCb.value());
384 m_acceptedAddressCb = MakeNullCallback<void, const Ipv6Address&>();
385 icmpv6->TraceDisconnectWithoutContext("DadFailure", m_declinedAddressCb.value());
386 m_declinedAddressCb = MakeNullCallback<void, const Ipv6Address&>();
387}
388
389void
391 Dhcp6Header header,
392 Inet6SocketAddress server) const
393{
394 // Read Status Code option.
396
397 NS_LOG_DEBUG("Received status " << (uint16_t)statusCode << " from DHCPv6 server");
398 if (statusCode == Options::StatusCodeValues::Success)
399 {
400 NS_LOG_INFO("DHCPv6 client: Server bindings updated successfully.");
401 }
402 else
403 {
404 NS_LOG_INFO("DHCPv6 client: Server bindings update failed.");
405 }
406}
407
408void
410{
411 NS_LOG_FUNCTION(this << iDev << header << server);
412
413 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
414 int32_t ifIndex = ipv6->GetInterfaceForDevice(iDev);
415
416 Ptr<InterfaceConfig> dhcpInterface = m_interfaces[ifIndex];
417
418 // Read IA_NA options.
419 std::vector<IaOptions> ianaOptionsList = header.GetIanaOptions();
420
421 dhcpInterface->m_declinedAddresses.clear();
422
423 Time earliestRebind{Time::Max()};
424 Time earliestRenew{Time::Max()};
425 std::vector<uint32_t> iaidList;
426
427 for (const auto& iaOpt : ianaOptionsList)
428 {
429 // Iterate through the offered addresses.
430 // Current approach: Try to accept all offers.
431 for (const auto& iaAddrOpt : iaOpt.m_iaAddressOption)
432 {
433 Ipv6Address offeredAddress = iaAddrOpt.GetIaAddress();
434
435 // TODO: In Linux, all leased addresses seem to be /128. Double-check this.
436 Ipv6InterfaceAddress addr(offeredAddress, 128);
437 ipv6->AddAddress(ifIndex, addr);
438 ipv6->SetUp(ifIndex);
439
440 // Set the preferred and valid lifetimes.
441 dhcpInterface->m_prefLifetime = Seconds(iaAddrOpt.GetPreferredLifetime());
442 dhcpInterface->m_validLifetime = Seconds(iaAddrOpt.GetValidLifetime());
443
444 // Add the IPv6 address - IAID association.
445 m_iaidMap[offeredAddress] = iaOpt.GetIaid();
446
447 // TODO: Check whether Release event happens for each address.
448 dhcpInterface->m_releaseEvent.emplace_back(
449 Simulator::Schedule(dhcpInterface->m_validLifetime,
451 this,
452 offeredAddress));
453
454 dhcpInterface->m_offeredAddresses.push_back(offeredAddress);
455 }
456
457 earliestRenew = std::min(earliestRenew, Seconds(iaOpt.GetT1()));
458 earliestRebind = std::min(earliestRebind, Seconds(iaOpt.GetT2()));
459 iaidList.emplace_back(iaOpt.GetIaid());
460 }
461
462 // The renew and rebind events are scheduled for the earliest time across
463 // all IA_NA options. RFC 8415, Section 18.2.4.
464 dhcpInterface->m_renewTime = earliestRenew;
465 dhcpInterface->m_renewEvent.Cancel();
466 dhcpInterface->m_renewEvent =
467 Simulator::Schedule(dhcpInterface->m_renewTime, &Dhcp6Client::SendRenew, this, ifIndex);
468
469 // Set the rebind timer and schedule the event.
470 dhcpInterface->m_rebindTime = earliestRebind;
471 dhcpInterface->m_rebindEvent.Cancel();
472 dhcpInterface->m_rebindEvent =
473 Simulator::Schedule(dhcpInterface->m_rebindTime, &Dhcp6Client::SendRebind, this, ifIndex);
474
475 int32_t interfaceId = ipv6->GetInterfaceForDevice(iDev);
477 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), interfaceId));
478
479 // If DAD fails, the offer is declined.
480
481 if (!dhcpInterface->m_acceptedAddressCb.has_value())
482 {
483 dhcpInterface->m_acceptedAddressCb =
485 icmpv6->TraceConnectWithoutContext("DadSuccess",
486 dhcpInterface->m_acceptedAddressCb.value());
487 }
488
489 if (!dhcpInterface->m_declinedAddressCb.has_value())
490 {
491 dhcpInterface->m_declinedAddressCb =
493 icmpv6->TraceConnectWithoutContext("DadFailure",
494 dhcpInterface->m_declinedAddressCb.value());
495 }
496}
497
498void
500{
501 NS_LOG_FUNCTION(this);
502
503 Dhcp6Header header;
504 Ptr<Packet> packet = Create<Packet>();
505
506 m_interfaces[dhcpInterfaceIndex]->m_transactId =
507 static_cast<uint32_t>(m_transactionId->GetValue());
508
509 header.SetTransactId(m_interfaces[dhcpInterfaceIndex]->m_transactId);
511
512 // Add client identifier option
514
515 // Add server identifier option
516 header.AddServerIdentifier(m_interfaces[dhcpInterfaceIndex]->m_serverDuid);
517
518 m_interfaces[dhcpInterfaceIndex]->m_msgStartTime = Simulator::Now();
519 header.AddElapsedTime(0);
520
521 // Add IA_NA options.
522 for (const auto& iaidRenew : m_interfaces[dhcpInterfaceIndex]->m_iaids)
523 {
524 header.AddIanaOption(iaidRenew,
525 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
526 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
527
528 // Iterate through the IPv6Address - IAID map, and add all addresses
529 // that match the IAID to be renewed.
530 for (const auto& itr : m_iaidMap)
531 {
532 Ipv6Address address = itr.first;
533 uint32_t iaid = itr.second;
534 if (iaid == iaidRenew)
535 {
536 header.AddAddress(iaidRenew,
537 address,
538 m_interfaces[dhcpInterfaceIndex]->m_prefLifetime.GetSeconds(),
539 m_interfaces[dhcpInterfaceIndex]->m_validLifetime.GetSeconds());
540 }
541 }
542
543 NS_LOG_DEBUG("Renewing addresses in IAID " << iaidRenew);
544 }
545
546 // Add Option Request option.
548
549 packet->AddHeader(header);
550 if ((m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
551 packet,
552 0,
554 0)
555 {
556 NS_LOG_INFO("DHCPv6 client: Renew sent");
557 }
558 else
559 {
560 NS_LOG_INFO("DHCPv6 client: Error while sending Renew");
561 }
562
563 m_interfaces[dhcpInterfaceIndex]->m_state = State::WAIT_REPLY;
564}
565
566void
568{
569 NS_LOG_FUNCTION(this);
570
571 Dhcp6Header header;
572 Ptr<Packet> packet = Create<Packet>();
573
574 m_interfaces[dhcpInterfaceIndex]->m_transactId =
575 static_cast<uint32_t>(m_transactionId->GetValue());
576
577 header.SetTransactId(m_interfaces[dhcpInterfaceIndex]->m_transactId);
579
580 // Add client identifier option
582
583 m_interfaces[dhcpInterfaceIndex]->m_msgStartTime = Simulator::Now();
584 header.AddElapsedTime(0);
585
586 // Add IA_NA options.
587 for (const auto& iaid : m_interfaces[dhcpInterfaceIndex]->m_iaids)
588 {
589 header.AddIanaOption(iaid,
590 m_interfaces[dhcpInterfaceIndex]->m_renewTime.GetSeconds(),
591 m_interfaces[dhcpInterfaceIndex]->m_rebindTime.GetSeconds());
592
593 NS_LOG_DEBUG("Rebinding addresses in IAID " << iaid);
594 }
595
596 // Add Option Request option.
598
599 packet->AddHeader(header);
600 if ((m_interfaces[dhcpInterfaceIndex]->m_socket->SendTo(
601 packet,
602 0,
604 0)
605 {
606 NS_LOG_INFO("DHCPv6 client: Rebind sent.");
607 }
608 else
609 {
610 NS_LOG_INFO("DHCPv6 client: Error while sending Rebind");
611 }
612
613 m_interfaces[dhcpInterfaceIndex]->m_state = State::WAIT_REPLY;
614}
615
616void
618{
619 NS_LOG_FUNCTION(this);
620
621 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
622
623 Dhcp6Header header;
624 Ptr<Packet> packet = Create<Packet>();
625
626 for (const auto& itr : m_interfaces)
627 {
628 uint32_t ifIndex = itr.first;
629 Ptr<InterfaceConfig> dhcpInterface = itr.second;
630
631 dhcpInterface->m_transactId = static_cast<uint32_t>(m_transactionId->GetValue());
632 bool removed = ipv6->RemoveAddress(ifIndex, address);
633
634 if (!removed)
635 {
636 continue;
637 }
638
639 header.SetTransactId(dhcpInterface->m_transactId);
640 header.SetMessageType(Dhcp6Header::MessageType::RELEASE);
641
642 // Add client identifier option
643 header.AddClientIdentifier(m_clientDuid);
644
645 // Add server identifier option
646 header.AddServerIdentifier(dhcpInterface->m_serverDuid);
647
648 dhcpInterface->m_msgStartTime = Simulator::Now();
649 header.AddElapsedTime(0);
650
651 // IA_NA option, IA address option
652 uint32_t iaid = m_iaidMap[address];
653 header.AddIanaOption(iaid,
654 dhcpInterface->m_renewTime.GetSeconds(),
655 dhcpInterface->m_rebindTime.GetSeconds());
656 header.AddAddress(iaid,
657 address,
658 dhcpInterface->m_prefLifetime.GetSeconds(),
659 dhcpInterface->m_validLifetime.GetSeconds());
660
661 NS_LOG_DEBUG("Releasing address " << address);
662
663 packet->AddHeader(header);
664 if ((dhcpInterface->m_socket->SendTo(packet,
665 0,
668 {
669 NS_LOG_INFO("DHCPv6 client: Release sent.");
670 }
671 else
672 {
673 NS_LOG_INFO("DHCPv6 client: Error while sending Release");
674 }
675
676 dhcpInterface->m_state = State::WAIT_REPLY_AFTER_RELEASE;
677 }
678}
679
680void
682{
683 NS_LOG_FUNCTION(this << socket);
684
685 Address from;
686 Ptr<Packet> packet = socket->RecvFrom(from);
687 Dhcp6Header header;
688
690
691 Ipv6PacketInfoTag interfaceInfo;
692 NS_ASSERT_MSG(packet->RemovePacketTag(interfaceInfo),
693 "No incoming interface on DHCPv6 message.");
694
695 uint32_t incomingIf = interfaceInfo.GetRecvIf();
696 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
697 Ptr<NetDevice> iDev = GetNode()->GetDevice(incomingIf);
698 uint32_t iIf = ipv6->GetInterfaceForDevice(iDev);
699 Ptr<InterfaceConfig> dhcpInterface = m_interfaces[iIf];
700
701 if (packet->RemoveHeader(header) == 0 || !dhcpInterface)
702 {
703 return;
704 }
705 if (dhcpInterface->m_state == State::WAIT_ADVERTISE &&
707 {
708 NS_LOG_INFO("DHCPv6 client: Received Advertise.");
709 dhcpInterface->m_solicitTimer.Stop();
710 bool check = ValidateAdvertise(header, iDev);
711 if (check)
712 {
713 SendRequest(iDev, header, senderAddr);
714 }
715 }
716 if (dhcpInterface->m_state == State::WAIT_REPLY &&
718 {
719 NS_LOG_INFO("DHCPv6 client: Received Reply.");
720
721 dhcpInterface->m_renewEvent.Cancel();
722 dhcpInterface->m_rebindEvent.Cancel();
723 for (auto itr : dhcpInterface->m_releaseEvent)
724 {
725 itr.Cancel();
726 }
727
728 ProcessReply(iDev, header, senderAddr);
729 }
730 if ((dhcpInterface->m_state == State::WAIT_REPLY_AFTER_DECLINE ||
731 dhcpInterface->m_state == State::WAIT_REPLY_AFTER_RELEASE) &&
733 {
734 NS_LOG_INFO("DHCPv6 client: Received Reply.");
735 CheckLeaseStatus(iDev, header, senderAddr);
736 }
737}
738
739void
741{
742 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
743 Ptr<InterfaceConfig> dhcpInterface = m_interfaces[ifIndex];
744 if (isUp)
745 {
746 NS_LOG_DEBUG("DHCPv6 client: Link up at " << Simulator::Now().As(Time::S));
748 }
749 else
750 {
751 dhcpInterface->Cleanup();
752 m_interfaces[ifIndex] = nullptr;
753 NS_LOG_DEBUG("DHCPv6 client: Link down at " << Simulator::Now().As(Time::S));
754 }
755}
756
757Duid
759{
760 return m_clientDuid;
761}
762
763void
765{
766 Ptr<Node> node = GetNode();
767
768 NS_ASSERT_MSG(node, "Dhcp6Client::StartApplication: cannot get the node from the device.");
769
770 Ptr<Ipv6> ipv6 = node->GetObject<Ipv6>();
771 NS_ASSERT_MSG(ipv6, "Dhcp6Client::StartApplication: node does not have IPv6.");
772
773 NS_LOG_DEBUG("Starting DHCPv6 application on node " << node->GetId());
774
775 // Set DHCPv6 callback for each interface of the node.
776 uint32_t nInterfaces = ipv6->GetNInterfaces();
777
778 // We skip interface 0 because it's the Loopback.
779 for (uint32_t ifIndex = 1; ifIndex < nInterfaces; ifIndex++)
780 {
781 Ptr<NetDevice> device = ipv6->GetNetDevice(ifIndex);
783 ipv6->GetProtocol(Icmpv6L4Protocol::GetStaticProtocolNumber(), ifIndex));
784
785 // If the RA message contains an M flag, the client starts sending Solicits.
786 icmpv6->SetDhcpv6Callback(MakeCallback(&Dhcp6Client::ReceiveMflag, this));
787 }
788}
789
790void
792{
793 NS_LOG_FUNCTION(this);
794
795 Ptr<Node> node = GetNode();
796 Ptr<Ipv6L3Protocol> ipv6l3 = node->GetObject<Ipv6L3Protocol>();
797
798 if (!m_interfaces[recvInterface])
799 {
800 // Create config object if M flag is received for the first time.
802 dhcpInterface->m_client = this;
803 dhcpInterface->m_interfaceIndex = recvInterface;
804 dhcpInterface->m_socket = nullptr;
805 m_interfaces[recvInterface] = dhcpInterface;
806
807 // Add an IAID to the client interface.
808 // Note: There may be multiple IAIDs per interface. We use only one.
809 std::vector<uint32_t> existingIaNaIds;
810 while (true)
811 {
813 if (std::find(existingIaNaIds.begin(), existingIaNaIds.end(), iaid) ==
814 existingIaNaIds.end())
815 {
816 dhcpInterface->m_iaids.push_back(iaid);
817 existingIaNaIds.emplace_back(iaid);
818 break;
819 }
820 }
821
822 Ptr<Ipv6Interface> ipv6Interface =
823 node->GetObject<Ipv6L3Protocol>()->GetInterface(recvInterface);
824 ipv6Interface->TraceConnectWithoutContext(
825 "InterfaceStatus",
827 }
828
829 for (const auto& itr : m_interfaces)
830 {
831 uint32_t interface = itr.first;
832 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
833 Ptr<NetDevice> device = ipv6->GetNetDevice(interface);
834 Ptr<InterfaceConfig> dhcpInterface = itr.second;
835
836 // Check that RA was received on this interface.
837 if (interface == recvInterface && m_interfaces[interface])
838 {
839 if (!m_interfaces[interface]->m_socket)
840 {
841 Ipv6Address linkLocal =
842 ipv6l3->GetInterface(interface)->GetLinkLocalAddress().GetAddress();
843 TypeId tid = TypeId::LookupByName("ns3::UdpSocketFactory");
844
845 Ptr<Socket> socket = Socket::CreateSocket(node, tid);
846 socket->Bind(Inet6SocketAddress(linkLocal, Dhcp6Header::CLIENT_PORT));
847 socket->BindToNetDevice(device);
848 socket->SetRecvPktInfo(true);
849 socket->SetRecvCallback(MakeCallback(&Dhcp6Client::NetHandler, this));
850
851 m_interfaces[interface]->m_socket = socket;
852
853 // Introduce a random delay before sending the Solicit message.
856 this,
857 device);
858
859 uint32_t minInterval = m_solicitInterval.GetSeconds() / 2;
860 dhcpInterface->m_solicitTimer = TrickleTimer(Seconds(minInterval), 4, 1);
861 dhcpInterface->m_solicitTimer.SetFunction(&Dhcp6Client::Boot, this);
862 dhcpInterface->m_solicitTimer.Enable();
863 break;
864 }
865 }
866 }
867}
868
869void
871{
872 Ptr<Ipv6> ipv6 = GetNode()->GetObject<Ipv6>();
873 int32_t ifIndex = ipv6->GetInterfaceForDevice(device);
874 Ptr<InterfaceConfig> dhcpInterface = m_interfaces[ifIndex];
875
876 Ptr<Node> node = GetNode();
878 {
880 }
881
882 Dhcp6Header header;
883 Ptr<Packet> packet = Create<Packet>();
884
885 // Create a unique transaction ID.
886 dhcpInterface->m_transactId = static_cast<uint32_t>(m_transactionId->GetValue());
887
888 header.SetTransactId(dhcpInterface->m_transactId);
890
891 // Store start time of the message exchange.
892 dhcpInterface->m_msgStartTime = Simulator::Now();
893
894 header.AddElapsedTime(0);
897
898 // Add IA_NA option.
899
900 for (auto iaid : dhcpInterface->m_iaids)
901 {
902 header.AddIanaOption(iaid,
903 dhcpInterface->m_renewTime.GetSeconds(),
904 dhcpInterface->m_rebindTime.GetSeconds());
905 }
906
907 packet->AddHeader(header);
908
909 if ((dhcpInterface->m_socket->SendTo(packet,
910 0,
913 {
914 NS_LOG_INFO("DHCPv6 client: Solicit sent");
915 }
916 else
917 {
918 NS_LOG_INFO("DHCPv6 client: Error while sending Solicit");
919 }
920
921 dhcpInterface->m_state = State::WAIT_ADVERTISE;
922}
923
924void
926{
927 NS_LOG_FUNCTION(this);
928
929 for (auto& itr : m_interfaces)
930 {
931 // Close sockets.
932 if (!itr.second)
933 {
934 continue;
935 }
936 itr.second->Cleanup();
937 }
938
939 m_interfaces.clear();
940 m_iaidMap.clear();
941}
942
943} // namespace ns3
a polymophic address class
Definition address.h:90
The base class for all ns3 applications.
Definition application.h:51
void DoDispose() override
Destructor implementation.
Ptr< Node > GetNode() const
void DeclineOffer()
Send a Decline message to the DHCPv6 server.
uint8_t m_nAcceptedAddresses
Number of addresses accepted by client.
Time m_prefLifetime
Preferred lifetime of the address.
Time m_rebindTime
REB_MAX_RT, Time after which client should send a Rebind message.
void AcceptedAddress(const Ipv6Address &offeredAddress)
Accept the DHCPv6 offer.
InterfaceConfig()
The default constructor.
void DeclinedAddress(const Ipv6Address &offeredAddress)
Add a declined address to the list maintained by the client.
void Cleanup()
Cleanup the internal callbacks and timers.
Time m_renewTime
REN_MAX_RT, Time after which lease should be renewed.
Time m_validLifetime
Valid lifetime of the address.
void CheckLeaseStatus(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server) const
Check lease status after sending a Decline or Release message.
Duid GetSelfDuid() const
Get the DUID.
std::unordered_map< uint32_t, Ptr< InterfaceConfig > > m_interfaces
Map each interface to its corresponding configuration details.
std::unordered_map< Ipv6Address, uint32_t, Ipv6AddressHash > m_iaidMap
Track the IPv6 Address - IAID association.
void ReceiveMflag(uint32_t recvInterface)
Callback for when an M flag is received.
void LinkStateHandler(bool isUp, int32_t ifIndex)
Handle changes in the link state.
Ptr< RandomVariableStream > m_solicitJitter
Random jitter before sending the first Solicit.
void SendRelease(Ipv6Address address)
Send a Release message to the DHCPv6 server.
static TypeId GetTypeId()
Get the type ID.
TracedCallback< const Ipv6Address & > m_newLease
Trace the new lease.
bool ValidateAdvertise(Dhcp6Header header, Ptr< NetDevice > iDev)
Verify the incoming advertise message.
void Boot(Ptr< NetDevice > device)
Used to send the Solicit message and start the DHCPv6 client.
void ProcessReply(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server)
Send a request to the DHCPv6 server.
Ptr< RandomVariableStream > m_transactionId
Random variable to set transaction ID.
void SendRequest(Ptr< NetDevice > iDev, Dhcp6Header header, Inet6SocketAddress server)
Send a request to the DHCPv6 server.
void StartApplication() override
Application specific startup code.
void StopApplication() override
Application specific shutdown code.
void NetHandler(Ptr< Socket > socket)
Handles incoming packets from the network.
int64_t AssignStreams(int64_t stream) override
Assign a fixed random variable stream number to the random variables used by this Application object.
Ptr< RandomVariableStream > m_iaidStream
Random variable used to create the IAID.
void SendRebind(uint32_t interfaceIndex)
Send a rebind message to the DHCPv6 server.
void SendRenew(uint32_t interfaceIndex)
Send a renew message to the DHCPv6 server.
Time m_solicitInterval
SOL_MAX_RT, time between solicitations.
Duid m_clientDuid
The client DUID.
void DoDispose() override
Destructor implementation.
Implements the DHCPv6 header.
IdentifierOption GetClientIdentifier()
Get the client identifier.
void AddElapsedTime(uint16_t timestamp)
Set the elapsed time option.
void AddServerIdentifier(Duid duid)
Add the server identifier option.
void ResetOptions()
Reset all options.
void AddClientIdentifier(Duid duid)
Add the client identifier option.
uint32_t GetTransactId() const
Get the transaction ID.
static const uint16_t CLIENT_PORT
The port number of the DHCPv6 client.
void AddAddress(uint32_t iaid, Ipv6Address address, uint32_t prefLifetime, uint32_t validLifetime)
Add IA address option to the IANA or IATA.
MessageType GetMessageType() const
Get the type of message.
static const uint16_t SERVER_PORT
The port number of the DHCPv6 server.
void AddOptionRequest(Options::OptionType optionType)
Request additional options.
void AddIanaOption(uint32_t iaid, uint32_t t1, uint32_t t2)
Add IANA option.
void SetMessageType(MessageType msgType)
Set the message type.
std::vector< IaOptions > GetIanaOptions()
Get the list of IA_NA options.
IdentifierOption GetServerIdentifier()
Get the server identifier.
StatusCodeOption GetStatusCodeOption()
Get the status code of the operation.
void SetTransactId(uint32_t transactId)
Set the transaction ID.
Implements the unique identifier for DHCPv6.
Definition dhcp6-duid.h:27
bool IsInvalid() const
Check if the DUID is invalid.
Definition dhcp6-duid.cc:63
void Initialize(Ptr< Node > node)
Initialize the DUID for a client or server.
static uint16_t GetStaticProtocolNumber()
Get ICMPv6 protocol number.
Duid GetDuid() const
Get the DUID object.
An Inet6 address class.
static Inet6SocketAddress ConvertFrom(const Address &addr)
Convert the address to a InetSocketAddress.
Describes an IPv6 address.
static Ipv6Address GetAllNodesMulticast()
Get the "all nodes multicast" address.
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition ipv6.h:71
IPv6 address associated with an interface.
IPv6 layer implementation.
This class implements a tag that carries socket ancillary data to the socket interface.
uint32_t GetRecvIf() const
Get the tag's receiving interface.
Ptr< NetDevice > GetDevice(uint32_t index) const
Retrieve the index-th NetDevice associated to this node.
Definition node.cc:138
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition object.h:511
StatusCodeValues
Enum to identify the status code of the operation.
Smart pointer class similar to boost::intrusive_ptr.
virtual double GetValue()=0
Get the next random value drawn from the distribution.
virtual uint32_t GetInteger()
Get the next random value drawn from the distribution.
void SetStream(int64_t stream)
Specifies the stream number for the RngStream.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static Ptr< Socket > CreateSocket(Ptr< Node > node, TypeId tid)
This method wraps the creation of sockets that is performed on a given node by a SocketFactory specif...
Definition socket.cc:61
StatusCodeValues GetStatusCode() const
Get the status code of the operation.
Hold variables of type string.
Definition string.h:45
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:392
@ S
second
Definition nstime.h:105
static Time Max()
Maximum representable Time Not to be confused with Max(Time,Time).
Definition nstime.h:286
AttributeValue implementation for Time.
Definition nstime.h:1432
A Trickle Timer following RFC 6206 .
a unique identifier for an interface.
Definition type-id.h:49
static TypeId LookupByName(std::string name)
Get a TypeId by name.
Definition type-id.cc:872
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeAccessor > MakePointerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition pointer.h:248
Ptr< AttributeChecker > MakePointerChecker()
Create a PointerChecker for a type.
Definition pointer.h:269
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Callback< R, Args... > MakeNullCallback()
Definition callback.h:727
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1357
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
-style-clang-format
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< T1 > DynamicCast(const Ptr< T2 > &p)
Cast a Ptr.
Definition ptr.h:580