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/num_utils.hpp"
44 #include "common/numeric_limits.hpp"
45 #include "common/random.hpp"
46 #include "net/ip4_types.hpp"
47 #include "net/netif.hpp"
48 
49 using ot::Encoding::BigEndian::HostSwap32;
50 
51 namespace ot {
52 namespace Ip6 {
53 
54 //---------------------------------------------------------------------------------------------------------------------
55 // NetworkPrefix methods
56 
GenerateRandomUla(void)57 Error NetworkPrefix::GenerateRandomUla(void)
58 {
59     m8[0] = 0xfd;
60 
61     return Random::Crypto::FillBuffer(&m8[1], kSize - 1);
62 }
63 
64 //---------------------------------------------------------------------------------------------------------------------
65 // Prefix methods
66 
Set(const uint8_t * aPrefix,uint8_t aLength)67 void Prefix::Set(const uint8_t *aPrefix, uint8_t aLength)
68 {
69     memcpy(mPrefix.mFields.m8, aPrefix, SizeForLength(aLength));
70     mLength = aLength;
71 }
72 
IsLinkLocal(void) const73 bool Prefix::IsLinkLocal(void) const
74 {
75     return (mLength >= 10) && ((mPrefix.mFields.m16[0] & HostSwap16(0xffc0)) == HostSwap16(0xfe80));
76 }
77 
IsMulticast(void) const78 bool Prefix::IsMulticast(void) const { return (mLength >= 8) && (mPrefix.mFields.m8[0] == 0xff); }
79 
IsUniqueLocal(void) const80 bool Prefix::IsUniqueLocal(void) const { return (mLength >= 7) && ((mPrefix.mFields.m8[0] & 0xfe) == 0xfc); }
81 
IsEqual(const uint8_t * aPrefixBytes,uint8_t aPrefixLength) const82 bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
83 {
84     return (mLength == aPrefixLength) && (MatchLength(GetBytes(), aPrefixBytes, GetBytesSize()) >= mLength);
85 }
86 
ContainsPrefix(const Prefix & aSubPrefix) const87 bool Prefix::ContainsPrefix(const Prefix &aSubPrefix) const
88 {
89     return (mLength >= aSubPrefix.mLength) &&
90            (MatchLength(GetBytes(), aSubPrefix.GetBytes(), aSubPrefix.GetBytesSize()) >= aSubPrefix.GetLength());
91 }
92 
ContainsPrefix(const NetworkPrefix & aSubPrefix) const93 bool Prefix::ContainsPrefix(const NetworkPrefix &aSubPrefix) const
94 {
95     return (mLength >= NetworkPrefix::kLength) &&
96            (MatchLength(GetBytes(), aSubPrefix.m8, NetworkPrefix::kSize) >= NetworkPrefix::kLength);
97 }
98 
Tidy(void)99 void Prefix::Tidy(void)
100 {
101     uint8_t byteLength      = GetBytesSize();
102     uint8_t lastByteBitMask = ~(static_cast<uint8_t>(1 << (byteLength * 8 - mLength)) - 1);
103 
104     if (byteLength != 0)
105     {
106         mPrefix.mFields.m8[byteLength - 1] &= lastByteBitMask;
107     }
108 
109     for (uint16_t i = byteLength; i < GetArrayLength(mPrefix.mFields.m8); i++)
110     {
111         mPrefix.mFields.m8[i] = 0;
112     }
113 }
114 
operator ==(const Prefix & aOther) const115 bool Prefix::operator==(const Prefix &aOther) const
116 {
117     return (mLength == aOther.mLength) && (MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize()) >= GetLength());
118 }
119 
operator <(const Prefix & aOther) const120 bool Prefix::operator<(const Prefix &aOther) const
121 {
122     bool    isSmaller;
123     uint8_t minLength;
124     uint8_t matchedLength;
125 
126     minLength     = Min(GetLength(), aOther.GetLength());
127     matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength));
128 
129     if (matchedLength >= minLength)
130     {
131         isSmaller = (GetLength() < aOther.GetLength());
132         ExitNow();
133     }
134 
135     isSmaller = GetBytes()[matchedLength / CHAR_BIT] < aOther.GetBytes()[matchedLength / CHAR_BIT];
136 
137 exit:
138     return isSmaller;
139 }
140 
MatchLength(const uint8_t * aPrefixA,const uint8_t * aPrefixB,uint8_t aMaxSize)141 uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize)
142 {
143     uint8_t matchedLength = 0;
144 
145     OT_ASSERT(aMaxSize <= Address::kSize);
146 
147     for (uint8_t i = 0; i < aMaxSize; i++)
148     {
149         uint8_t diff = aPrefixA[i] ^ aPrefixB[i];
150 
151         if (diff == 0)
152         {
153             matchedLength += CHAR_BIT;
154         }
155         else
156         {
157             while ((diff & 0x80) == 0)
158             {
159                 matchedLength++;
160                 diff <<= 1;
161             }
162 
163             break;
164         }
165     }
166 
167     return matchedLength;
168 }
169 
IsValidNat64PrefixLength(uint8_t aLength)170 bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
171 {
172     return (aLength == 32) || (aLength == 40) || (aLength == 48) || (aLength == 56) || (aLength == 64) ||
173            (aLength == 96);
174 }
175 
FromString(const char * aString)176 Error Prefix::FromString(const char *aString)
177 {
178     constexpr char kSlashChar = '/';
179     constexpr char kNullChar  = '\0';
180 
181     Error       error = kErrorParse;
182     const char *cur;
183 
184     VerifyOrExit(aString != nullptr);
185 
186     cur = StringFind(aString, kSlashChar);
187     VerifyOrExit(cur != nullptr);
188 
189     SuccessOrExit(AsCoreType(&mPrefix).ParseFrom(aString, kSlashChar));
190 
191     cur++;
192     SuccessOrExit(StringParseUint8(cur, mLength, kMaxLength));
193     VerifyOrExit(*cur == kNullChar);
194 
195     error = kErrorNone;
196 
197 exit:
198     return error;
199 }
200 
ToString(void) const201 Prefix::InfoString Prefix::ToString(void) const
202 {
203     InfoString string;
204 
205     ToString(string);
206 
207     return string;
208 }
209 
ToString(char * aBuffer,uint16_t aSize) const210 void Prefix::ToString(char *aBuffer, uint16_t aSize) const
211 {
212     StringWriter writer(aBuffer, aSize);
213 
214     ToString(writer);
215 }
216 
ToString(StringWriter & aWriter) const217 void Prefix::ToString(StringWriter &aWriter) const
218 {
219     uint8_t sizeInUint16 = (GetBytesSize() + sizeof(uint16_t) - 1) / sizeof(uint16_t);
220     Prefix  tidyPrefix   = *this;
221 
222     tidyPrefix.Tidy();
223     AsCoreType(&tidyPrefix.mPrefix).AppendHexWords(aWriter, sizeInUint16);
224 
225     if (GetBytesSize() < Address::kSize - 1)
226     {
227         aWriter.Append("::");
228     }
229 
230     aWriter.Append("/%d", mLength);
231 }
232 
233 //---------------------------------------------------------------------------------------------------------------------
234 // InterfaceIdentifier methods
235 
IsUnspecified(void) const236 bool InterfaceIdentifier::IsUnspecified(void) const { return (mFields.m32[0] == 0) && (mFields.m32[1] == 0); }
237 
IsReserved(void) const238 bool InterfaceIdentifier::IsReserved(void) const
239 {
240     return IsSubnetRouterAnycast() || IsReservedSubnetAnycast() || IsAnycastLocator();
241 }
242 
IsSubnetRouterAnycast(void) const243 bool InterfaceIdentifier::IsSubnetRouterAnycast(void) const { return (mFields.m32[0] == 0) && (mFields.m32[1] == 0); }
244 
IsReservedSubnetAnycast(void) const245 bool InterfaceIdentifier::IsReservedSubnetAnycast(void) const
246 {
247     // Format of IID in a Reserved Subnet Anycast Address (RFC 2526)
248     //
249     // |      57 bits     |   7 bits   |
250     // +------------------+------------+
251     // | 1111110111...111 | anycast ID |
252     // +------------------+------------+
253 
254     return (mFields.m32[0] == HostSwap32(0xfdffffff) && mFields.m16[2] == HostSwap16(0xffff) && mFields.m8[6] == 0xff &&
255             mFields.m8[7] >= 0x80);
256 }
257 
GenerateRandom(void)258 void InterfaceIdentifier::GenerateRandom(void) { SuccessOrAssert(Random::Crypto::Fill(*this)); }
259 
SetBytes(const uint8_t * aBuffer)260 void InterfaceIdentifier::SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); }
261 
SetFromExtAddress(const Mac::ExtAddress & aExtAddress)262 void InterfaceIdentifier::SetFromExtAddress(const Mac::ExtAddress &aExtAddress)
263 {
264     Mac::ExtAddress addr;
265 
266     addr = aExtAddress;
267     addr.ToggleLocal();
268     addr.CopyTo(mFields.m8);
269 }
270 
ConvertToExtAddress(Mac::ExtAddress & aExtAddress) const271 void InterfaceIdentifier::ConvertToExtAddress(Mac::ExtAddress &aExtAddress) const
272 {
273     aExtAddress.Set(mFields.m8);
274     aExtAddress.ToggleLocal();
275 }
276 
ConvertToMacAddress(Mac::Address & aMacAddress) const277 void InterfaceIdentifier::ConvertToMacAddress(Mac::Address &aMacAddress) const
278 {
279     aMacAddress.SetExtended(mFields.m8);
280     aMacAddress.GetExtended().ToggleLocal();
281 }
282 
SetToLocator(uint16_t aLocator)283 void InterfaceIdentifier::SetToLocator(uint16_t aLocator)
284 {
285     // Locator IID pattern `0000:00ff:fe00:xxxx`
286     mFields.m32[0] = HostSwap32(0x000000ff);
287     mFields.m16[2] = HostSwap16(0xfe00);
288     mFields.m16[3] = HostSwap16(aLocator);
289 }
290 
IsLocator(void) const291 bool InterfaceIdentifier::IsLocator(void) const
292 {
293     // Locator IID pattern 0000:00ff:fe00:xxxx
294     return (mFields.m32[0] == HostSwap32(0x000000ff) && mFields.m16[2] == HostSwap16(0xfe00));
295 }
296 
IsRoutingLocator(void) const297 bool InterfaceIdentifier::IsRoutingLocator(void) const
298 {
299     return (IsLocator() && (mFields.m8[6] < kAloc16Mask) && ((mFields.m8[6] & kRloc16ReservedBitMask) == 0));
300 }
301 
IsAnycastLocator(void) const302 bool InterfaceIdentifier::IsAnycastLocator(void) const
303 {
304     // Anycast locator range 0xfc00- 0xfcff (`kAloc16Mask` is 0xfc)
305     return (IsLocator() && (mFields.m8[6] == kAloc16Mask));
306 }
307 
IsAnycastServiceLocator(void) const308 bool InterfaceIdentifier::IsAnycastServiceLocator(void) const
309 {
310     uint16_t locator = GetLocator();
311 
312     return (IsLocator() && (locator >= Mle::kAloc16ServiceStart) && (locator <= Mle::kAloc16ServiceEnd));
313 }
314 
ApplyPrefix(const Prefix & aPrefix)315 void InterfaceIdentifier::ApplyPrefix(const Prefix &aPrefix)
316 {
317     if (aPrefix.GetLength() > NetworkPrefix::kLength)
318     {
319         Address::CopyBits(mFields.m8, aPrefix.GetBytes() + NetworkPrefix::kSize,
320                           aPrefix.GetLength() - NetworkPrefix::kLength);
321     }
322 }
323 
ToString(void) const324 InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
325 {
326     InfoString string;
327 
328     string.AppendHexBytes(mFields.m8, kSize);
329 
330     return string;
331 }
332 
333 //---------------------------------------------------------------------------------------------------------------------
334 // Address methods
335 
IsUnspecified(void) const336 bool Address::IsUnspecified(void) const
337 {
338     return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 && mFields.m32[3] == 0);
339 }
340 
IsLoopback(void) const341 bool Address::IsLoopback(void) const
342 {
343     return (mFields.m32[0] == 0 && mFields.m32[1] == 0 && mFields.m32[2] == 0 && mFields.m32[3] == HostSwap32(1));
344 }
345 
IsLinkLocal(void) const346 bool Address::IsLinkLocal(void) const { return (mFields.m16[0] & HostSwap16(0xffc0)) == HostSwap16(0xfe80); }
347 
SetToLinkLocalAddress(const Mac::ExtAddress & aExtAddress)348 void Address::SetToLinkLocalAddress(const Mac::ExtAddress &aExtAddress)
349 {
350     mFields.m32[0] = HostSwap32(0xfe800000);
351     mFields.m32[1] = 0;
352     GetIid().SetFromExtAddress(aExtAddress);
353 }
354 
SetToLinkLocalAddress(const InterfaceIdentifier & aIid)355 void Address::SetToLinkLocalAddress(const InterfaceIdentifier &aIid)
356 {
357     mFields.m32[0] = HostSwap32(0xfe800000);
358     mFields.m32[1] = 0;
359     SetIid(aIid);
360 }
361 
IsLinkLocalMulticast(void) const362 bool Address::IsLinkLocalMulticast(void) const { return IsMulticast() && (GetScope() == kLinkLocalScope); }
363 
IsLinkLocalAllNodesMulticast(void) const364 bool Address::IsLinkLocalAllNodesMulticast(void) const { return (*this == GetLinkLocalAllNodesMulticast()); }
365 
SetToLinkLocalAllNodesMulticast(void)366 void Address::SetToLinkLocalAllNodesMulticast(void) { *this = GetLinkLocalAllNodesMulticast(); }
367 
IsLinkLocalAllRoutersMulticast(void) const368 bool Address::IsLinkLocalAllRoutersMulticast(void) const { return (*this == GetLinkLocalAllRoutersMulticast()); }
369 
SetToLinkLocalAllRoutersMulticast(void)370 void Address::SetToLinkLocalAllRoutersMulticast(void) { *this = GetLinkLocalAllRoutersMulticast(); }
371 
IsRealmLocalMulticast(void) const372 bool Address::IsRealmLocalMulticast(void) const { return IsMulticast() && (GetScope() == kRealmLocalScope); }
373 
IsMulticastLargerThanRealmLocal(void) const374 bool Address::IsMulticastLargerThanRealmLocal(void) const { return IsMulticast() && (GetScope() > kRealmLocalScope); }
375 
IsRealmLocalAllNodesMulticast(void) const376 bool Address::IsRealmLocalAllNodesMulticast(void) const { return (*this == GetRealmLocalAllNodesMulticast()); }
377 
SetToRealmLocalAllNodesMulticast(void)378 void Address::SetToRealmLocalAllNodesMulticast(void) { *this = GetRealmLocalAllNodesMulticast(); }
379 
IsRealmLocalAllRoutersMulticast(void) const380 bool Address::IsRealmLocalAllRoutersMulticast(void) const { return (*this == GetRealmLocalAllRoutersMulticast()); }
381 
SetToRealmLocalAllRoutersMulticast(void)382 void Address::SetToRealmLocalAllRoutersMulticast(void) { *this = GetRealmLocalAllRoutersMulticast(); }
383 
IsRealmLocalAllMplForwarders(void) const384 bool Address::IsRealmLocalAllMplForwarders(void) const { return (*this == GetRealmLocalAllMplForwarders()); }
385 
SetToRealmLocalAllMplForwarders(void)386 void Address::SetToRealmLocalAllMplForwarders(void) { *this = GetRealmLocalAllMplForwarders(); }
387 
MatchesPrefix(const Prefix & aPrefix) const388 bool Address::MatchesPrefix(const Prefix &aPrefix) const
389 {
390     return Prefix::MatchLength(mFields.m8, aPrefix.GetBytes(), aPrefix.GetBytesSize()) >= aPrefix.GetLength();
391 }
392 
MatchesPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength) const393 bool Address::MatchesPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
394 {
395     return Prefix::MatchLength(mFields.m8, aPrefix, Prefix::SizeForLength(aPrefixLength)) >= aPrefixLength;
396 }
397 
SetPrefix(const NetworkPrefix & aNetworkPrefix)398 void Address::SetPrefix(const NetworkPrefix &aNetworkPrefix) { mFields.mComponents.mNetworkPrefix = aNetworkPrefix; }
399 
SetPrefix(const Prefix & aPrefix)400 void Address::SetPrefix(const Prefix &aPrefix) { CopyBits(mFields.m8, aPrefix.GetBytes(), aPrefix.GetLength()); }
401 
CopyBits(uint8_t * aDst,const uint8_t * aSrc,uint8_t aNumBits)402 void Address::CopyBits(uint8_t *aDst, const uint8_t *aSrc, uint8_t aNumBits)
403 {
404     // This method copies `aNumBits` from `aSrc` into `aDst` handling
405     // the case where `aNumBits` may not be a multiple of 8. It leaves the
406     // remaining bits beyond `aNumBits` in `aDst` unchanged.
407 
408     uint8_t numBytes  = aNumBits / CHAR_BIT;
409     uint8_t extraBits = aNumBits % CHAR_BIT;
410 
411     memcpy(aDst, aSrc, numBytes);
412 
413     if (extraBits > 0)
414     {
415         uint8_t mask = ((0x80 >> (extraBits - 1)) - 1);
416 
417         // `mask` has its higher (msb) `extraBits` bits as `0` and the remaining as `1`.
418         // Example with `extraBits` = 3:
419         // ((0x80 >> 2) - 1) = (0b0010_0000 - 1) = 0b0001_1111
420 
421         aDst[numBytes] &= mask;
422         aDst[numBytes] |= (aSrc[numBytes] & ~mask);
423     }
424 }
425 
SetMulticastNetworkPrefix(const uint8_t * aPrefix,uint8_t aPrefixLength)426 void Address::SetMulticastNetworkPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength)
427 {
428     CopyBits(&mFields.m8[kMulticastNetworkPrefixOffset], aPrefix, aPrefixLength);
429     mFields.m8[kMulticastNetworkPrefixLengthOffset] = aPrefixLength;
430 }
431 
SetToLocator(const NetworkPrefix & aNetworkPrefix,uint16_t aLocator)432 void Address::SetToLocator(const NetworkPrefix &aNetworkPrefix, uint16_t aLocator)
433 {
434     SetPrefix(aNetworkPrefix);
435     GetIid().SetToLocator(aLocator);
436 }
437 
GetScope(void) const438 uint8_t Address::GetScope(void) const
439 {
440     uint8_t rval;
441 
442     if (IsMulticast())
443     {
444         rval = mFields.m8[1] & 0xf;
445     }
446     else if (IsLinkLocal())
447     {
448         rval = kLinkLocalScope;
449     }
450     else if (IsLoopback())
451     {
452         rval = kNodeLocalScope;
453     }
454     else
455     {
456         rval = kGlobalScope;
457     }
458 
459     return rval;
460 }
461 
PrefixMatch(const Address & aOther) const462 uint8_t Address::PrefixMatch(const Address &aOther) const
463 {
464     return Prefix::MatchLength(mFields.m8, aOther.mFields.m8, sizeof(Address));
465 }
466 
MatchesFilter(TypeFilter aFilter) const467 bool Address::MatchesFilter(TypeFilter aFilter) const
468 {
469     bool matches = true;
470 
471     switch (aFilter)
472     {
473     case kTypeAny:
474         break;
475 
476     case kTypeUnicast:
477         matches = !IsUnspecified() && !IsMulticast();
478         break;
479 
480     case kTypeMulticast:
481         matches = IsMulticast();
482         break;
483 
484     case kTypeMulticastLargerThanRealmLocal:
485         matches = IsMulticastLargerThanRealmLocal();
486         break;
487     }
488 
489     return matches;
490 }
491 
SynthesizeFromIp4Address(const Prefix & aPrefix,const Ip4::Address & aIp4Address)492 void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
493 {
494     // The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
495     // after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
496     // which must be set to zero. The suffix is set to zero (per RFC 6052).
497     //
498     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
499     //    |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
500     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
501     //    |32|     prefix    |v4(32)         | u | suffix                    |
502     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
503     //    |40|     prefix        |v4(24)     | u |(8)| suffix                |
504     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
505     //    |48|     prefix            |v4(16) | u | (16)  | suffix            |
506     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
507     //    |56|     prefix                |(8)| u |  v4(24)   | suffix        |
508     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
509     //    |64|     prefix                    | u |   v4(32)      | suffix    |
510     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
511     //    |96|     prefix                                    |    v4(32)     |
512     //    +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
513 
514     constexpr uint8_t kSkipIndex = 8;
515 
516     uint8_t ip6Index;
517 
518     OT_ASSERT(aPrefix.IsValidNat64());
519 
520     Clear();
521     SetPrefix(aPrefix);
522 
523     ip6Index = aPrefix.GetLength() / CHAR_BIT;
524 
525     for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
526     {
527         if (ip6Index == kSkipIndex)
528         {
529             ip6Index++;
530         }
531 
532         mFields.m8[ip6Index++] = aIp4Address.GetBytes()[i];
533     }
534 }
535 
FromString(const char * aString)536 Error Address::FromString(const char *aString)
537 {
538     constexpr char kNullChar = '\0';
539 
540     return ParseFrom(aString, kNullChar);
541 }
542 
ParseFrom(const char * aString,char aTerminatorChar)543 Error Address::ParseFrom(const char *aString, char aTerminatorChar)
544 {
545     constexpr uint8_t kInvalidIndex = 0xff;
546     constexpr char    kColonChar    = ':';
547     constexpr char    kDotChar      = '.';
548 
549     Error   error      = kErrorParse;
550     uint8_t index      = 0;
551     uint8_t endIndex   = kSize / sizeof(uint16_t);
552     uint8_t colonIndex = kInvalidIndex;
553     bool    hasIp4     = false;
554 
555     // Check if the string starts with "::".
556 
557     if (*aString == kColonChar)
558     {
559         aString++;
560         VerifyOrExit(*aString == kColonChar);
561         aString++;
562         colonIndex = index;
563     }
564 
565     while (*aString != aTerminatorChar)
566     {
567         const char *start = aString;
568         uint32_t    value = 0;
569 
570         // Parse hex number
571 
572         while (true)
573         {
574             char    c = *aString;
575             uint8_t digit;
576 
577             if (('A' <= c) && (c <= 'F'))
578             {
579                 digit = static_cast<uint8_t>(c - 'A' + 10);
580             }
581             else if (('a' <= c) && (c <= 'f'))
582             {
583                 digit = static_cast<uint8_t>(c - 'a' + 10);
584             }
585             else if (('0' <= c) && (c <= '9'))
586             {
587                 digit = static_cast<uint8_t>(c - '0');
588             }
589             else
590             {
591                 break;
592             }
593 
594             aString++;
595             value = (value << 4) + digit;
596 
597             VerifyOrExit(value <= NumericLimits<uint16_t>::kMax);
598         }
599 
600         VerifyOrExit(aString != start);
601 
602         if (*aString == kDotChar)
603         {
604             // IPv6 address contains an embedded IPv4 address.
605             aString = start;
606             hasIp4  = true;
607             endIndex -= Ip4::Address::kSize / sizeof(uint16_t);
608             VerifyOrExit(index <= endIndex);
609             break;
610         }
611 
612         VerifyOrExit((*aString == kColonChar) || (*aString == aTerminatorChar));
613 
614         VerifyOrExit(index < endIndex);
615         mFields.m16[index++] = HostSwap16(static_cast<uint16_t>(value));
616 
617         if (*aString == kColonChar)
618         {
619             aString++;
620 
621             if (*aString == kColonChar)
622             {
623                 VerifyOrExit(colonIndex == kInvalidIndex);
624                 colonIndex = index;
625                 aString++;
626             }
627         }
628     }
629 
630     if (index < endIndex)
631     {
632         uint8_t wordsToCopy;
633 
634         VerifyOrExit(colonIndex != kInvalidIndex);
635 
636         wordsToCopy = index - colonIndex;
637 
638         memmove(&mFields.m16[endIndex - wordsToCopy], &mFields.m16[colonIndex], wordsToCopy * sizeof(uint16_t));
639         memset(&mFields.m16[colonIndex], 0, (endIndex - index) * sizeof(uint16_t));
640     }
641 
642     if (hasIp4)
643     {
644         Ip4::Address ip4Addr;
645 
646         SuccessOrExit(error = ip4Addr.FromString(aString, aTerminatorChar));
647         memcpy(GetArrayEnd(mFields.m8) - Ip4::Address::kSize, ip4Addr.GetBytes(), Ip4::Address::kSize);
648     }
649 
650     error = kErrorNone;
651 
652 exit:
653     return error;
654 }
655 
ToString(void) const656 Address::InfoString Address::ToString(void) const
657 {
658     InfoString string;
659 
660     ToString(string);
661 
662     return string;
663 }
664 
ToString(char * aBuffer,uint16_t aSize) const665 void Address::ToString(char *aBuffer, uint16_t aSize) const
666 {
667     StringWriter writer(aBuffer, aSize);
668     ToString(writer);
669 }
670 
ToString(StringWriter & aWriter) const671 void Address::ToString(StringWriter &aWriter) const
672 {
673     AppendHexWords(aWriter, static_cast<uint8_t>(GetArrayLength(mFields.m16)));
674 }
675 
AppendHexWords(StringWriter & aWriter,uint8_t aLength) const676 void Address::AppendHexWords(StringWriter &aWriter, uint8_t aLength) const
677 {
678     // Appends the first `aLength` elements in `mFields.m16[]` array
679     // as hex words.
680 
681     for (uint8_t index = 0; index < aLength; index++)
682     {
683         if (index > 0)
684         {
685             aWriter.Append(":");
686         }
687 
688         aWriter.Append("%x", HostSwap16(mFields.m16[index]));
689     }
690 }
691 
GetLinkLocalAllNodesMulticast(void)692 const Address &Address::GetLinkLocalAllNodesMulticast(void)
693 {
694     return AsCoreType(&Netif::kLinkLocalAllNodesMulticastAddress.mAddress);
695 }
696 
GetLinkLocalAllRoutersMulticast(void)697 const Address &Address::GetLinkLocalAllRoutersMulticast(void)
698 {
699     return AsCoreType(&Netif::kLinkLocalAllRoutersMulticastAddress.mAddress);
700 }
701 
GetRealmLocalAllNodesMulticast(void)702 const Address &Address::GetRealmLocalAllNodesMulticast(void)
703 {
704     return AsCoreType(&Netif::kRealmLocalAllNodesMulticastAddress.mAddress);
705 }
706 
GetRealmLocalAllRoutersMulticast(void)707 const Address &Address::GetRealmLocalAllRoutersMulticast(void)
708 {
709     return AsCoreType(&Netif::kRealmLocalAllRoutersMulticastAddress.mAddress);
710 }
711 
GetRealmLocalAllMplForwarders(void)712 const Address &Address::GetRealmLocalAllMplForwarders(void)
713 {
714     return AsCoreType(&Netif::kRealmLocalAllMplForwardersMulticastAddress.mAddress);
715 }
716 
717 } // namespace Ip6
718 } // namespace ot
719