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