• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/array.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/code_utils.hpp"
41 #include "common/encoding.hpp"
42 #include "common/instance.hpp"
43 #include "common/numeric_limits.hpp"
44 #include "common/random.hpp"
45 #include "net/ip4_types.hpp"
46 #include "net/netif.hpp"
47 
48 using ot::Encoding::BigEndian::HostSwap32;
49 
50 namespace ot {
51 namespace Ip6 {
52 
53 //---------------------------------------------------------------------------------------------------------------------
54 // NetworkPrefix methods
55 
GenerateRandomUla(void)56 Error NetworkPrefix::GenerateRandomUla(void)
57 {
58     m8[0] = 0xfd;
59 
60     return Random::Crypto::FillBuffer(&m8[1], kSize - 1);
61 }
62 
63 //---------------------------------------------------------------------------------------------------------------------
64 // Prefix methods
65 
Set(const uint8_t * aPrefix,uint8_t aLength)66 void Prefix::Set(const uint8_t *aPrefix, uint8_t aLength)
67 {
68     memcpy(mPrefix.mFields.m8, aPrefix, SizeForLength(aLength));
69     mLength = aLength;
70 }
71 
IsEqual(const uint8_t * aPrefixBytes,uint8_t aPrefixLength) const72 bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
73 {
74     return (mLength == aPrefixLength) && (MatchLength(GetBytes(), aPrefixBytes, GetBytesSize()) >= mLength);
75 }
76 
operator <(const Prefix & aOther) const77 bool Prefix::operator<(const Prefix &aOther) const
78 {
79     bool    isSmaller;
80     uint8_t minLength;
81     uint8_t matchedLength;
82 
83     minLength     = OT_MIN(GetLength(), aOther.GetLength());
84     matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength));
85 
86     if (matchedLength >= minLength)
87     {
88         isSmaller = (GetLength() < aOther.GetLength());
89         ExitNow();
90     }
91 
92     isSmaller = GetBytes()[matchedLength / CHAR_BIT] < aOther.GetBytes()[matchedLength / CHAR_BIT];
93 
94 exit:
95     return isSmaller;
96 }
97 
MatchLength(const uint8_t * aPrefixA,const uint8_t * aPrefixB,uint8_t aMaxSize)98 uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize)
99 {
100     uint8_t matchedLength = 0;
101 
102     OT_ASSERT(aMaxSize <= Address::kSize);
103 
104     for (uint8_t i = 0; i < aMaxSize; i++)
105     {
106         uint8_t diff = aPrefixA[i] ^ aPrefixB[i];
107 
108         if (diff == 0)
109         {
110             matchedLength += CHAR_BIT;
111         }
112         else
113         {
114             while ((diff & 0x80) == 0)
115             {
116                 matchedLength++;
117                 diff <<= 1;
118             }
119 
120             break;
121         }
122     }
123 
124     return matchedLength;
125 }
126 
IsValidNat64PrefixLength(uint8_t aLength)127 bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
128 {
129     return (aLength == 32) || (aLength == 40) || (aLength == 48) || (aLength == 56) || (aLength == 64) ||
130            (aLength == 96);
131 }
132 
ToString(void) const133 Prefix::InfoString Prefix::ToString(void) const
134 {
135     InfoString string;
136 
137     ToString(string);
138 
139     return string;
140 }
141 
ToString(char * aBuffer,uint16_t aSize) const142 void Prefix::ToString(char *aBuffer, uint16_t aSize) const
143 {
144     StringWriter writer(aBuffer, aSize);
145 
146     ToString(writer);
147 }
148 
ToString(StringWriter & aWriter) const149 void Prefix::ToString(StringWriter &aWriter) const
150 {
151     uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t);
152 
153     AsCoreType(&mPrefix).AppendHexWords(aWriter, sizeInUint16);
154 
155     if (GetBytesSize() < Address::kSize - 1)
156     {
157         aWriter.Append("::");
158     }
159 
160     aWriter.Append("/%d", mLength);
161 }
162 
163 //---------------------------------------------------------------------------------------------------------------------
164 // InterfaceIdentifier methods
165 
IsUnspecified(void) const166 bool InterfaceIdentifier::IsUnspecified(void) const
167 {
168     return (mFields.m32[0] == 0) && (mFields.m32[1] == 0);
169 }
170 
IsReserved(void) const171 bool InterfaceIdentifier::IsReserved(void) const
172 {
173     return IsSubnetRouterAnycast() || IsReservedSubnetAnycast() || IsAnycastLocator();
174 }
175 
IsSubnetRouterAnycast(void) const176 bool InterfaceIdentifier::IsSubnetRouterAnycast(void) const
177 {
178     return (mFields.m32[0] == 0) && (mFields.m32[1] == 0);
179 }
180 
IsReservedSubnetAnycast(void) const181 bool InterfaceIdentifier::IsReservedSubnetAnycast(void) const
182 {
183     // Format of IID in a Reserved Subnet Anycast Address (RFC 2526)
184     //
185     // |      57 bits     |   7 bits   |
186     // +------------------+------------+
187     // | 1111110111...111 | anycast ID |
188     // +------------------+------------+
189 
190     return (mFields.m32[0] == HostSwap32(0xfdffffff) && mFields.m16[2] == HostSwap16(0xffff) && mFields.m8[6] == 0xff &&
191             mFields.m8[7] >= 0x80);
192 }
193 
GenerateRandom(void)194 void InterfaceIdentifier::GenerateRandom(void)
195 {
196     SuccessOrAssert(Random::Crypto::FillBuffer(mFields.m8, kSize));
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(GetArrayEnd(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, static_cast<uint8_t>(GetArrayLength(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 AsCoreType(&Netif::kLinkLocalAllNodesMulticastAddress.mAddress);
669 }
670 
GetLinkLocalAllRoutersMulticast(void)671 const Address &Address::GetLinkLocalAllRoutersMulticast(void)
672 {
673     return AsCoreType(&Netif::kLinkLocalAllRoutersMulticastAddress.mAddress);
674 }
675 
GetRealmLocalAllNodesMulticast(void)676 const Address &Address::GetRealmLocalAllNodesMulticast(void)
677 {
678     return AsCoreType(&Netif::kRealmLocalAllNodesMulticastAddress.mAddress);
679 }
680 
GetRealmLocalAllRoutersMulticast(void)681 const Address &Address::GetRealmLocalAllRoutersMulticast(void)
682 {
683     return AsCoreType(&Netif::kRealmLocalAllRoutersMulticastAddress.mAddress);
684 }
685 
GetRealmLocalAllMplForwarders(void)686 const Address &Address::GetRealmLocalAllMplForwarders(void)
687 {
688     return AsCoreType(&Netif::kRealmLocalAllMplForwardersMulticastAddress.mAddress);
689 }
690 
691 } // namespace Ip6
692 } // namespace ot
693