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