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