1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements IPv6 addresses.
32 */
33
34 #include "ip6_address.hpp"
35
36 #include <stdio.h>
37
38 #include "common/code_utils.hpp"
39 #include "common/encoding.hpp"
40 #include "common/instance.hpp"
41 #include "common/numeric_limits.hpp"
42 #include "common/random.hpp"
43 #include "net/ip4_address.hpp"
44 #include "net/netif.hpp"
45
46 using ot::Encoding::BigEndian::HostSwap32;
47
48 namespace ot {
49 namespace Ip6 {
50
51 //---------------------------------------------------------------------------------------------------------------------
52 // NetworkPrefix methods
53
GenerateRandomUla(void)54 Error NetworkPrefix::GenerateRandomUla(void)
55 {
56 m8[0] = 0xfd;
57
58 return Random::Crypto::FillBuffer(&m8[1], kSize - 1);
59 }
60
61 //---------------------------------------------------------------------------------------------------------------------
62 // Prefix methods
63
Set(const uint8_t * aPrefix,uint8_t aLength)64 void Prefix::Set(const uint8_t *aPrefix, uint8_t aLength)
65 {
66 memcpy(mPrefix.mFields.m8, aPrefix, SizeForLength(aLength));
67 mLength = aLength;
68 }
69
IsEqual(const uint8_t * aPrefixBytes,uint8_t aPrefixLength) const70 bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
71 {
72 return (mLength == aPrefixLength) && (MatchLength(GetBytes(), aPrefixBytes, GetBytesSize()) >= mLength);
73 }
74
operator <(const Prefix & aOther) const75 bool Prefix::operator<(const Prefix &aOther) const
76 {
77 bool isSmaller;
78 uint8_t matchedLength;
79
80 VerifyOrExit(GetLength() == aOther.GetLength(), isSmaller = GetLength() < aOther.GetLength());
81
82 matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize());
83
84 VerifyOrExit(matchedLength < GetLength(), isSmaller = false);
85
86 isSmaller = GetBytes()[matchedLength / CHAR_BIT] < aOther.GetBytes()[matchedLength / CHAR_BIT];
87
88 exit:
89 return isSmaller;
90 }
91
MatchLength(const uint8_t * aPrefixA,const uint8_t * aPrefixB,uint8_t aMaxSize)92 uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize)
93 {
94 uint8_t matchedLength = 0;
95
96 OT_ASSERT(aMaxSize <= Address::kSize);
97
98 for (uint8_t i = 0; i < aMaxSize; i++)
99 {
100 uint8_t diff = aPrefixA[i] ^ aPrefixB[i];
101
102 if (diff == 0)
103 {
104 matchedLength += CHAR_BIT;
105 }
106 else
107 {
108 while ((diff & 0x80) == 0)
109 {
110 matchedLength++;
111 diff <<= 1;
112 }
113
114 break;
115 }
116 }
117
118 return matchedLength;
119 }
120
IsValidNat64(void) const121 bool Prefix::IsValidNat64(void) const
122 {
123 return (mLength == 32) || (mLength == 40) || (mLength == 48) || (mLength == 56) || (mLength == 64) ||
124 (mLength == 96);
125 }
126
ToString(void) const127 Prefix::InfoString Prefix::ToString(void) const
128 {
129 InfoString string;
130
131 ToString(string);
132
133 return string;
134 }
135
ToString(char * aBuffer,uint16_t aSize) const136 void Prefix::ToString(char *aBuffer, uint16_t aSize) const
137 {
138 StringWriter writer(aBuffer, aSize);
139
140 ToString(writer);
141 }
142
ToString(StringWriter & aWriter) const143 void Prefix::ToString(StringWriter &aWriter) const
144 {
145 uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t);
146
147 static_cast<const Address &>(mPrefix).AppendHexWords(aWriter, sizeInUint16);
148
149 if (GetBytesSize() < Address::kSize - 1)
150 {
151 aWriter.Append("::");
152 }
153
154 aWriter.Append("/%d", mLength);
155 }
156
157 //---------------------------------------------------------------------------------------------------------------------
158 // InterfaceIdentifier methods
159
IsUnspecified(void) const160 bool InterfaceIdentifier::IsUnspecified(void) const
161 {
162 return (mFields.m32[0] == 0) && (mFields.m32[1] == 0);
163 }
164
IsReserved(void) const165 bool InterfaceIdentifier::IsReserved(void) const
166 {
167 return IsSubnetRouterAnycast() || IsReservedSubnetAnycast() || IsAnycastLocator();
168 }
169
IsSubnetRouterAnycast(void) const170 bool InterfaceIdentifier::IsSubnetRouterAnycast(void) const
171 {
172 return (mFields.m32[0] == 0) && (mFields.m32[1] == 0);
173 }
174
IsReservedSubnetAnycast(void) const175 bool InterfaceIdentifier::IsReservedSubnetAnycast(void) const
176 {
177 // Format of IID in a Reserved Subnet Anycast Address (RFC 2526)
178 //
179 // | 57 bits | 7 bits |
180 // +------------------+------------+
181 // | 1111110111...111 | anycast ID |
182 // +------------------+------------+
183
184 return (mFields.m32[0] == HostSwap32(0xfdffffff) && mFields.m16[2] == HostSwap16(0xffff) && mFields.m8[6] == 0xff &&
185 mFields.m8[7] >= 0x80);
186 }
187
GenerateRandom(void)188 void InterfaceIdentifier::GenerateRandom(void)
189 {
190 Error error;
191
192 OT_UNUSED_VARIABLE(error);
193
194 error = Random::Crypto::FillBuffer(mFields.m8, kSize);
195
196 OT_ASSERT(error == kErrorNone);
197 }
198
SetBytes(const uint8_t * aBuffer)199 void InterfaceIdentifier::SetBytes(const uint8_t *aBuffer)
200 {
201 memcpy(mFields.m8, aBuffer, kSize);
202 }
203
SetFromExtAddress(const Mac::ExtAddress & aExtAddress)204 void InterfaceIdentifier::SetFromExtAddress(const Mac::ExtAddress &aExtAddress)
205 {
206 Mac::ExtAddress addr;
207
208 addr = aExtAddress;
209 addr.ToggleLocal();
210 addr.CopyTo(mFields.m8);
211 }
212
ConvertToExtAddress(Mac::ExtAddress & aExtAddress) const213 void InterfaceIdentifier::ConvertToExtAddress(Mac::ExtAddress &aExtAddress) const
214 {
215 aExtAddress.Set(mFields.m8);
216 aExtAddress.ToggleLocal();
217 }
218
ConvertToMacAddress(Mac::Address & aMacAddress) const219 void InterfaceIdentifier::ConvertToMacAddress(Mac::Address &aMacAddress) const
220 {
221 aMacAddress.SetExtended(mFields.m8);
222 aMacAddress.GetExtended().ToggleLocal();
223 }
224
SetToLocator(uint16_t aLocator)225 void InterfaceIdentifier::SetToLocator(uint16_t aLocator)
226 {
227 // Locator IID pattern `0000:00ff:fe00:xxxx`
228 mFields.m32[0] = HostSwap32(0x000000ff);
229 mFields.m16[2] = HostSwap16(0xfe00);
230 mFields.m16[3] = HostSwap16(aLocator);
231 }
232
IsLocator(void) const233 bool InterfaceIdentifier::IsLocator(void) const
234 {
235 // Locator IID pattern 0000:00ff:fe00:xxxx
236 return (mFields.m32[0] == HostSwap32(0x000000ff) && mFields.m16[2] == HostSwap16(0xfe00));
237 }
238
IsRoutingLocator(void) const239 bool InterfaceIdentifier::IsRoutingLocator(void) const
240 {
241 return (IsLocator() && (mFields.m8[6] < kAloc16Mask) && ((mFields.m8[6] & kRloc16ReservedBitMask) == 0));
242 }
243
IsAnycastLocator(void) const244 bool InterfaceIdentifier::IsAnycastLocator(void) const
245 {
246 // Anycast locator range 0xfc00- 0xfcff (`kAloc16Mask` is 0xfc)
247 return (IsLocator() && (mFields.m8[6] == kAloc16Mask));
248 }
249
IsAnycastServiceLocator(void) const250 bool InterfaceIdentifier::IsAnycastServiceLocator(void) const
251 {
252 uint16_t locator = GetLocator();
253
254 return (IsLocator() && (locator >= Mle::kAloc16ServiceStart) && (locator <= Mle::kAloc16ServiceEnd));
255 }
256
ToString(void) const257 InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
258 {
259 InfoString string;
260
261 string.AppendHexBytes(mFields.m8, kSize);
262
263 return string;
264 }
265
266 //---------------------------------------------------------------------------------------------------------------------
267 // Address methods
268
IsUnspecified(void) const269 bool Address::IsUnspecified(void) const
270 {
271 return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 && mFields.m32[3] == 0);
272 }
273
IsLoopback(void) const274 bool Address::IsLoopback(void) const
275 {
276 return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 && mFields.m32[3] == HostSwap32(1));
277 }
278
IsLinkLocal(void) const279 bool Address::IsLinkLocal(void) const
280 {
281 return (mFields.m16[0] & HostSwap16(0xffc0)) == HostSwap16(0xfe80);
282 }
283
SetToLinkLocalAddress(const Mac::ExtAddress & aExtAddress)284 void Address::SetToLinkLocalAddress(const Mac::ExtAddress &aExtAddress)
285 {
286 mFields.m32[0] = HostSwap32(0xfe800000);
287 mFields.m32[1] = 0;
288 GetIid().SetFromExtAddress(aExtAddress);
289 }
290
SetToLinkLocalAddress(const InterfaceIdentifier & aIid)291 void Address::SetToLinkLocalAddress(const InterfaceIdentifier &aIid)
292 {
293 mFields.m32[0] = HostSwap32(0xfe800000);
294 mFields.m32[1] = 0;
295 SetIid(aIid);
296 }
297
IsLinkLocalMulticast(void) const298 bool Address::IsLinkLocalMulticast(void) const
299 {
300 return IsMulticast() && (GetScope() == kLinkLocalScope);
301 }
302
IsLinkLocalAllNodesMulticast(void) const303 bool Address::IsLinkLocalAllNodesMulticast(void) const
304 {
305 return (*this == GetLinkLocalAllNodesMulticast());
306 }
307
SetToLinkLocalAllNodesMulticast(void)308 void Address::SetToLinkLocalAllNodesMulticast(void)
309 {
310 *this = GetLinkLocalAllNodesMulticast();
311 }
312
IsLinkLocalAllRoutersMulticast(void) const313 bool Address::IsLinkLocalAllRoutersMulticast(void) const
314 {
315 return (*this == GetLinkLocalAllRoutersMulticast());
316 }
317
SetToLinkLocalAllRoutersMulticast(void)318 void Address::SetToLinkLocalAllRoutersMulticast(void)
319 {
320 *this = GetLinkLocalAllRoutersMulticast();
321 }
322
IsRealmLocalMulticast(void) const323 bool Address::IsRealmLocalMulticast(void) const
324 {
325 return IsMulticast() && (GetScope() == kRealmLocalScope);
326 }
327
IsMulticastLargerThanRealmLocal(void) const328 bool Address::IsMulticastLargerThanRealmLocal(void) const
329 {
330 return IsMulticast() && (GetScope() > kRealmLocalScope);
331 }
332
IsRealmLocalAllNodesMulticast(void) const333 bool Address::IsRealmLocalAllNodesMulticast(void) const
334 {
335 return (*this == GetRealmLocalAllNodesMulticast());
336 }
337
SetToRealmLocalAllNodesMulticast(void)338 void Address::SetToRealmLocalAllNodesMulticast(void)
339 {
340 *this = GetRealmLocalAllNodesMulticast();
341 }
342
IsRealmLocalAllRoutersMulticast(void) const343 bool Address::IsRealmLocalAllRoutersMulticast(void) const
344 {
345 return (*this == GetRealmLocalAllRoutersMulticast());
346 }
347
SetToRealmLocalAllRoutersMulticast(void)348 void Address::SetToRealmLocalAllRoutersMulticast(void)
349 {
350 *this = GetRealmLocalAllRoutersMulticast();
351 }
352
IsRealmLocalAllMplForwarders(void) const353 bool Address::IsRealmLocalAllMplForwarders(void) const
354 {
355 return (*this == GetRealmLocalAllMplForwarders());
356 }
357
SetToRealmLocalAllMplForwarders(void)358 void Address::SetToRealmLocalAllMplForwarders(void)
359 {
360 *this = GetRealmLocalAllMplForwarders();
361 }
362
MatchesPrefix(const Prefix & aPrefix) const363 bool Address::MatchesPrefix(const Prefix &aPrefix) const
364 {
365 return Prefix::MatchLength(mFields.m8, aPrefix.GetBytes(), aPrefix.GetBytesSize()) >= aPrefix.GetLength();
366 }
367
MatchesPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const368 bool Address::MatchesPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
369 {
370 return Prefix::MatchLength(mFields.m8, aPrefix, Prefix::SizeForLength(aPrefixLength)) >= aPrefixLength;
371 }
372
SetPrefix(const NetworkPrefix & aNetworkPrefix)373 void Address::SetPrefix(const NetworkPrefix &aNetworkPrefix)
374 {
375 mFields.mComponents.mNetworkPrefix = aNetworkPrefix;
376 }
377
SetPrefix(const Prefix & aPrefix)378 void Address::SetPrefix(const Prefix &aPrefix)
379 {
380 SetPrefix(0, aPrefix.GetBytes(), aPrefix.GetLength());
381 }
382
SetPrefix(uint8_t aOffset,const uint8_t * aPrefix,uint8_t aPrefixLength)383 void Address::SetPrefix(uint8_t aOffset, const uint8_t *aPrefix, uint8_t aPrefixLength)
384 {
385 uint8_t bytes = aPrefixLength / CHAR_BIT;
386 uint8_t extraBits = aPrefixLength % CHAR_BIT;
387
388 OT_ASSERT(aPrefixLength <= (sizeof(Address) - aOffset) * CHAR_BIT);
389
390 memcpy(mFields.m8 + aOffset, aPrefix, bytes);
391
392 if (extraBits > 0)
393 {
394 uint8_t index = aOffset + bytes;
395 uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
396
397 // `mask` has its higher (msb) `extraBits` bits as `0` and the remaining as `1`.
398 // Example with `extraBits` = 3:
399 // ((0x80 >> 2) - 1) = (0b0010_0000 - 1) = 0b0001_1111
400
401 mFields.m8[index] &= mask;
402 mFields.m8[index] |= (aPrefix[index] & ~mask);
403 }
404 }
405
SetMulticastNetworkPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength)406 void Address::SetMulticastNetworkPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength)
407 {
408 SetPrefix(kMulticastNetworkPrefixOffset, aPrefix, aPrefixLength);
409 mFields.m8[kMulticastNetworkPrefixLengthOffset] = aPrefixLength;
410 }
411
SetToLocator(const NetworkPrefix & aNetworkPrefix,uint16_t aLocator)412 void Address::SetToLocator(const NetworkPrefix &aNetworkPrefix, uint16_t aLocator)
413 {
414 SetPrefix(aNetworkPrefix);
415 GetIid().SetToLocator(aLocator);
416 }
417
GetScope(void) const418 uint8_t Address::GetScope(void) const
419 {
420 uint8_t rval;
421
422 if (IsMulticast())
423 {
424 rval = mFields.m8[1] & 0xf;
425 }
426 else if (IsLinkLocal())
427 {
428 rval = kLinkLocalScope;
429 }
430 else if (IsLoopback())
431 {
432 rval = kNodeLocalScope;
433 }
434 else
435 {
436 rval = kGlobalScope;
437 }
438
439 return rval;
440 }
441
PrefixMatch(const Address & aOther) const442 uint8_t Address::PrefixMatch(const Address &aOther) const
443 {
444 return Prefix::MatchLength(mFields.m8, aOther.mFields.m8, sizeof(Address));
445 }
446
MatchesFilter(TypeFilter aFilter) const447 bool Address::MatchesFilter(TypeFilter aFilter) const
448 {
449 bool matches = true;
450
451 switch (aFilter)
452 {
453 case kTypeAny:
454 break;
455
456 case kTypeUnicast:
457 matches = !IsUnspecified() && !IsMulticast();
458 break;
459
460 case kTypeMulticast:
461 matches = IsMulticast();
462 break;
463
464 case kTypeMulticastLargerThanRealmLocal:
465 matches = IsMulticastLargerThanRealmLocal();
466 break;
467 }
468
469 return matches;
470 }
471
SynthesizeFromIp4Address(const Prefix & aPrefix,const Ip4::Address & aIp4Address)472 void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
473 {
474 // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
475 // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
476 // which must be set to zero. The suffix is set to zero (per RFC 6502).
477 //
478 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
479 // |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
480 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
481 // |32| prefix |v4(32) | u | suffix |
482 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
483 // |40| prefix |v4(24) | u |(8)| suffix |
484 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
485 // |48| prefix |v4(16) | u | (16) | suffix |
486 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
487 // |56| prefix |(8)| u | v4(24) | suffix |
488 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
489 // |64| prefix | u | v4(32) | suffix |
490 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
491 // |96| prefix | v4(32) |
492 // +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
493
494 constexpr uint8_t kSkipIndex = 8;
495
496 uint8_t ip6Index;
497
498 OT_ASSERT(aPrefix.IsValidNat64());
499
500 Clear();
501 SetPrefix(aPrefix);
502
503 ip6Index = aPrefix.GetLength() / CHAR_BIT;
504
505 for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
506 {
507 if (ip6Index == kSkipIndex)
508 {
509 ip6Index++;
510 }
511
512 mFields.m8[ip6Index++] = aIp4Address.GetBytes()[i];
513 }
514 }
515
FromString(const char * aString)516 Error Address::FromString(const char *aString)
517 {
518 constexpr uint8_t kInvalidIndex = 0xff;
519 constexpr char kColonChar = ':';
520 constexpr char kDotChar = '.';
521 constexpr char kNullChar = '\0';
522
523 Error error = kErrorParse;
524 uint8_t index = 0;
525 uint8_t endIndex = kSize / sizeof(uint16_t);
526 uint8_t colonIndex = kInvalidIndex;
527 bool hasIp4 = false;
528
529 // Check if the string starts with "::".
530
531 if (*aString == kColonChar)
532 {
533 aString++;
534 VerifyOrExit(*aString == kColonChar);
535 aString++;
536 colonIndex = index;
537 }
538
539 while (*aString != kNullChar)
540 {
541 const char *start = aString;
542 uint32_t value = 0;
543
544 // Parse hex number
545
546 while (true)
547 {
548 char c = *aString;
549 uint8_t digit;
550
551 if (('A' <= c) && (c <= 'F'))
552 {
553 digit = static_cast<uint8_t>(c - 'A' + 10);
554 }
555 else if (('a' <= c) && (c <= 'f'))
556 {
557 digit = static_cast<uint8_t>(c - 'a' + 10);
558 }
559 else if (('0' <= c) && (c <= '9'))
560 {
561 digit = static_cast<uint8_t>(c - '0');
562 }
563 else
564 {
565 break;
566 }
567
568 aString++;
569 value = (value << 4) + digit;
570
571 VerifyOrExit(value <= NumericLimits<uint16_t>::kMax);
572 }
573
574 VerifyOrExit(aString != start);
575
576 if (*aString == kDotChar)
577 {
578 // IPv6 address contains an embedded IPv4 address.
579 aString = start;
580 hasIp4 = true;
581 endIndex -= Ip4::Address::kSize / sizeof(uint16_t);
582 VerifyOrExit(index <= endIndex);
583 break;
584 }
585
586 VerifyOrExit((*aString == kColonChar) || (*aString == kNullChar));
587
588 VerifyOrExit(index < endIndex);
589 mFields.m16[index++] = HostSwap16(static_cast<uint16_t>(value));
590
591 if (*aString == kColonChar)
592 {
593 aString++;
594
595 if (*aString == kColonChar)
596 {
597 VerifyOrExit(colonIndex == kInvalidIndex);
598 colonIndex = index;
599 aString++;
600 }
601 }
602 }
603
604 if (index < endIndex)
605 {
606 uint8_t wordsToCopy;
607
608 VerifyOrExit(colonIndex != kInvalidIndex);
609
610 wordsToCopy = index - colonIndex;
611
612 memmove(&mFields.m16[endIndex - wordsToCopy], &mFields.m16[colonIndex], wordsToCopy * sizeof(uint16_t));
613 memset(&mFields.m16[colonIndex], 0, (endIndex - index) * sizeof(uint16_t));
614 }
615
616 if (hasIp4)
617 {
618 Ip4::Address ip4Addr;
619
620 SuccessOrExit(error = ip4Addr.FromString(aString));
621 memcpy(OT_ARRAY_END(mFields.m8) - Ip4::Address::kSize, ip4Addr.GetBytes(), Ip4::Address::kSize);
622 }
623
624 error = kErrorNone;
625
626 exit:
627 return error;
628 }
629
ToString(void) const630 Address::InfoString Address::ToString(void) const
631 {
632 InfoString string;
633
634 ToString(string);
635
636 return string;
637 }
638
ToString(char * aBuffer,uint16_t aSize) const639 void Address::ToString(char *aBuffer, uint16_t aSize) const
640 {
641 StringWriter writer(aBuffer, aSize);
642 ToString(writer);
643 }
644
ToString(StringWriter & aWriter) const645 void Address::ToString(StringWriter &aWriter) const
646 {
647 AppendHexWords(aWriter, OT_ARRAY_LENGTH(mFields.m16));
648 }
649
AppendHexWords(StringWriter & aWriter,uint8_t aLength) const650 void Address::AppendHexWords(StringWriter &aWriter, uint8_t aLength) const
651 {
652 // Appends the first `aLength` elements in `mFields.m16[]` array
653 // as hex words.
654
655 for (uint8_t index = 0; index < aLength; index++)
656 {
657 if (index > 0)
658 {
659 aWriter.Append(":");
660 }
661
662 aWriter.Append("%x", HostSwap16(mFields.m16[index]));
663 }
664 }
665
GetLinkLocalAllNodesMulticast(void)666 const Address &Address::GetLinkLocalAllNodesMulticast(void)
667 {
668 return static_cast<const Address &>(Netif::kLinkLocalAllNodesMulticastAddress.mAddress);
669 }
670
GetLinkLocalAllRoutersMulticast(void)671 const Address &Address::GetLinkLocalAllRoutersMulticast(void)
672 {
673 return static_cast<const Address &>(Netif::kLinkLocalAllRoutersMulticastAddress.mAddress);
674 }
675
GetRealmLocalAllNodesMulticast(void)676 const Address &Address::GetRealmLocalAllNodesMulticast(void)
677 {
678 return static_cast<const Address &>(Netif::kRealmLocalAllNodesMulticastAddress.mAddress);
679 }
680
GetRealmLocalAllRoutersMulticast(void)681 const Address &Address::GetRealmLocalAllRoutersMulticast(void)
682 {
683 return static_cast<const Address &>(Netif::kRealmLocalAllRoutersMulticastAddress.mAddress);
684 }
685
GetRealmLocalAllMplForwarders(void)686 const Address &Address::GetRealmLocalAllMplForwarders(void)
687 {
688 return static_cast<const Address &>(Netif::kRealmLocalAllMplForwardersMulticastAddress.mAddress);
689 }
690
691 } // namespace Ip6
692 } // namespace ot
693