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