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 includes definitions for IPv6 network interfaces. 32 */ 33 34 #ifndef NET_NETIF_HPP_ 35 #define NET_NETIF_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include "common/as_core_type.hpp" 40 #include "common/clearable.hpp" 41 #include "common/code_utils.hpp" 42 #include "common/const_cast.hpp" 43 #include "common/iterator_utils.hpp" 44 #include "common/linked_list.hpp" 45 #include "common/locator.hpp" 46 #include "common/message.hpp" 47 #include "common/non_copyable.hpp" 48 #include "common/tasklet.hpp" 49 #include "mac/mac_types.hpp" 50 #include "net/ip6_address.hpp" 51 #include "net/socket.hpp" 52 #include "thread/mlr_types.hpp" 53 54 namespace ot { 55 namespace Ip6 { 56 57 class Ip6; 58 59 /** 60 * @addtogroup core-ip6-netif 61 * 62 * @brief 63 * This module includes definitions for IPv6 network interfaces. 64 * 65 * @{ 66 * 67 */ 68 69 /** 70 * This class implements an IPv6 network interface. 71 * 72 */ 73 class Netif : public InstanceLocator, private NonCopyable 74 { 75 friend class Ip6; 76 friend class Address; 77 78 public: 79 /** 80 * This enumeration represent an address event (added or removed) 81 * 82 * The boolean values are used for `aIsAdded` parameter in the call of `otIp6AddressCallback`. 83 * 84 */ 85 enum AddressEvent : bool 86 { 87 kAddressRemoved = false, ///< Indicates that address was added. 88 kAddressAdded = true, ///< Indicates that address was removed. 89 }; 90 91 /** 92 * This enumeration represents the address origin. 93 * 94 */ 95 enum AddressOrigin : uint8_t 96 { 97 kOriginThread = OT_ADDRESS_ORIGIN_THREAD, ///< Thread assigned address (ALOC, RLOC, MLEID, etc) 98 kOriginSlaac = OT_ADDRESS_ORIGIN_SLAAC, ///< SLAAC assigned address 99 kOriginDhcp6 = OT_ADDRESS_ORIGIN_DHCPV6, ///< DHCPv6 assigned address 100 kOriginManual = OT_ADDRESS_ORIGIN_MANUAL, ///< Manually assigned address 101 }; 102 103 /** 104 * This class implements an IPv6 network interface unicast address. 105 * 106 */ 107 class UnicastAddress : public otNetifAddress, 108 public LinkedListEntry<UnicastAddress>, 109 public Clearable<UnicastAddress> 110 { 111 friend class LinkedList<UnicastAddress>; 112 113 public: 114 /** 115 * This method clears and initializes the unicast address as a preferred, valid, thread-origin address with 116 * 64-bit prefix length. 117 * 118 * @param[in] aPreferred Whether to initialize as a preferred address. 119 * 120 */ 121 void InitAsThreadOrigin(bool aPreferred = false); 122 123 /** 124 * This method clears and initializes the unicast address as a valid (but not preferred), thread-origin, 125 * realm-local scope (overridden) address with 64-bit prefix length. 126 * 127 */ 128 void InitAsThreadOriginRealmLocalScope(void); 129 130 /** 131 * This method clears and initializes the unicast address as a valid (but not preferred), thread-origin, global 132 * scope address. 133 * 134 */ 135 void InitAsThreadOriginGlobalScope(void); 136 137 /** 138 * This method clears and initializes the unicast address as a valid, SLAAC-origin address with a given 139 * preferred flag and a given prefix length. 140 * 141 * @param[in] aPrefixLength The prefix length (in bits). 142 * @param[in] aPreferred The preferred flag. 143 * 144 */ 145 void InitAsSlaacOrigin(uint8_t aPrefixLength, bool aPreferred); 146 147 /** 148 * This method returns the unicast address. 149 * 150 * @returns The unicast address. 151 * 152 */ GetAddress(void) const153 const Address &GetAddress(void) const { return AsCoreType(&mAddress); } 154 155 /** 156 * This method returns the unicast address. 157 * 158 * @returns The unicast address. 159 * 160 */ GetAddress(void)161 Address &GetAddress(void) { return AsCoreType(&mAddress); } 162 163 /** 164 * This method returns the address's prefix length (in bits). 165 * 166 * @returns The prefix length (in bits). 167 * 168 */ GetPrefixLength(void) const169 uint8_t GetPrefixLength(void) const { return mPrefixLength; } 170 171 /** 172 * This method indicates whether the address has a given prefix (i.e. same prefix length and matches the 173 * prefix). 174 * 175 * @param[in] aPrefix A prefix to check against. 176 * 177 * @retval TRUE The address has and fully matches the @p aPrefix. 178 * @retval FALSE The address does not contain or match the @p aPrefix. 179 * 180 */ HasPrefix(const Prefix & aPrefix) const181 bool HasPrefix(const Prefix &aPrefix) const 182 { 183 return (mPrefixLength == aPrefix.GetLength()) && GetAddress().MatchesPrefix(aPrefix); 184 } 185 186 /** 187 * This method returns the IPv6 scope value. 188 * 189 * @returns The IPv6 scope value. 190 * 191 */ GetScope(void) const192 uint8_t GetScope(void) const 193 { 194 return mScopeOverrideValid ? static_cast<uint8_t>(mScopeOverride) : GetAddress().GetScope(); 195 } 196 197 /** 198 * This method sets the IPv6 scope override value. 199 * 200 * @param[in] aScope The IPv6 scope value. 201 * 202 */ SetScopeOverride(uint8_t aScope)203 void SetScopeOverride(uint8_t aScope) 204 { 205 mScopeOverride = aScope; 206 mScopeOverrideValid = true; 207 } 208 209 /** 210 * This method gets the IPv6 address origin. 211 * 212 * @returns The address origin. 213 * 214 */ GetOrigin(void) const215 AddressOrigin GetOrigin(void) const { return static_cast<AddressOrigin>(mAddressOrigin); } 216 217 private: Matches(const Address & aAddress) const218 bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; } 219 }; 220 221 /** 222 * This class implements an IPv6 network interface multicast address. 223 * 224 */ 225 class MulticastAddress : public otNetifMulticastAddress, 226 public LinkedListEntry<MulticastAddress>, 227 public Clearable<MulticastAddress> 228 { 229 friend class LinkedList<MulticastAddress>; 230 231 public: 232 /** 233 * This method returns the multicast address. 234 * 235 * @returns The multicast address. 236 * 237 */ GetAddress(void) const238 const Address &GetAddress(void) const { return AsCoreType(&mAddress); } 239 240 /** 241 * This method returns the multicast address. 242 * 243 * @returns The multicast address. 244 * 245 */ GetAddress(void)246 Address &GetAddress(void) { return AsCoreType(&mAddress); } 247 248 /** 249 * This method returns the next multicast address subscribed to the interface. 250 * 251 * @returns A pointer to the next multicast address. 252 * 253 */ GetNext(void) const254 const MulticastAddress *GetNext(void) const { return static_cast<const MulticastAddress *>(mNext); } 255 256 /** 257 * This method returns the next multicast address subscribed to the interface. 258 * 259 * @returns A pointer to the next multicast address. 260 * 261 */ GetNext(void)262 MulticastAddress *GetNext(void) { return static_cast<MulticastAddress *>(AsNonConst(mNext)); } 263 264 private: Matches(const Address & aAddress) const265 bool Matches(const Address &aAddress) const { return GetAddress() == aAddress; } 266 }; 267 268 class ExternalMulticastAddress : public MulticastAddress 269 { 270 friend class Netif; 271 friend class LinkedList<ExternalMulticastAddress>; 272 273 public: 274 /** 275 * This class represents an iterator for iterating external multicast addresses in a `Netif` instance. 276 * 277 */ 278 class Iterator : public ItemPtrIterator<ExternalMulticastAddress, Iterator> 279 { 280 friend class ItemPtrIterator<ExternalMulticastAddress, Iterator>; 281 friend class Netif; 282 283 public: 284 /** 285 * This constructor initializes an `Iterator` instance to start from the first external multicast address 286 * that matches a given IPv6 address type filter. 287 * 288 * @param[in] aNetif A reference to the `Netif` instance. 289 * @param[in] aFilter The IPv6 address type filter. 290 * 291 */ 292 explicit Iterator(const Netif &aNetif, Address::TypeFilter aFilter = Address::kTypeAny); 293 294 private: 295 class Builder 296 { 297 public: Builder(const Netif & aNetif,Address::TypeFilter aFilter)298 Builder(const Netif &aNetif, Address::TypeFilter aFilter) 299 : mNetif(aNetif) 300 , mFilter(aFilter) 301 { 302 } 303 begin(void)304 Iterator begin(void) { return Iterator(mNetif, mFilter); } end(void)305 Iterator end(void) { return Iterator(mNetif, Iterator::kEndIterator); } 306 307 private: 308 const Netif & mNetif; 309 Address::TypeFilter mFilter; 310 }; 311 312 enum IteratorType : uint8_t 313 { 314 kEndIterator, 315 }; 316 Iterator(const Netif & aNetif,IteratorType)317 Iterator(const Netif &aNetif, IteratorType) 318 : mNetif(aNetif) 319 { 320 } 321 322 void AdvanceFrom(const MulticastAddress *aAddr); Advance(void)323 void Advance(void) { AdvanceFrom(mItem->GetNext()); } 324 325 const Netif & mNetif; 326 Address::TypeFilter mFilter; 327 }; 328 329 #if OPENTHREAD_CONFIG_MLR_ENABLE 330 /** 331 * This method returns the current Multicast Listener Registration (MLR) state. 332 * 333 * @returns The current Multicast Listener Registration state. 334 * 335 */ GetMlrState(void) const336 MlrState GetMlrState(void) const { return mMlrState; } 337 338 /** 339 * This method sets the Multicast Listener Registration (MLR) state. 340 * 341 * @param[in] aState The new Multicast Listener Registration state. 342 * 343 */ SetMlrState(MlrState aState)344 void SetMlrState(MlrState aState) { mMlrState = aState; } 345 #endif 346 347 private: GetNext(void)348 ExternalMulticastAddress *GetNext(void) { return static_cast<ExternalMulticastAddress *>(AsNonConst(mNext)); } 349 350 #if OPENTHREAD_CONFIG_MLR_ENABLE 351 MlrState mMlrState; 352 #endif 353 }; 354 355 /** 356 * This constructor initializes the network interface. 357 * 358 * @param[in] aInstance A reference to the OpenThread instance. 359 * 360 */ 361 explicit Netif(Instance &aInstance); 362 363 /** 364 * This method registers a callback to notify internal IPv6 address changes. 365 * 366 * @param[in] aCallback A pointer to a function that is called when an IPv6 address is added or removed. 367 * @param[in] aCallbackContext A pointer to application-specific context. 368 * 369 */ 370 void SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext); 371 372 /** 373 * This method returns the linked list of unicast addresses. 374 * 375 * @returns The linked list of unicast addresses. 376 * 377 */ GetUnicastAddresses(void) const378 const LinkedList<UnicastAddress> &GetUnicastAddresses(void) const { return mUnicastAddresses; } 379 380 /** 381 * This method adds a unicast address to the network interface. 382 * 383 * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly added in the 384 * unicast address linked list. 385 * 386 * If @p aAddress is already added, the call to `AddUnicastAddress()` with the same address will perform no action. 387 * 388 * @param[in] aAddress A reference to the unicast address. 389 * 390 */ 391 void AddUnicastAddress(UnicastAddress &aAddress); 392 393 /** 394 * This method removes a unicast address from the network interface. 395 * 396 * This method is intended for addresses internal to OpenThread. The @p aAddress instance is removed from the 397 * unicast address linked list. 398 * 399 * If @p aAddress is not in the list, the call to `RemoveUnicastAddress()` will perform no action. 400 * 401 * @param[in] aAddress A reference to the unicast address. 402 * 403 */ 404 void RemoveUnicastAddress(const UnicastAddress &aAddress); 405 406 /** 407 * This method indicates whether or not an address is assigned to the interface. 408 * 409 * @param[in] aAddress A reference to the unicast address. 410 * 411 * @retval TRUE If @p aAddress is assigned to the network interface, 412 * @retval FALSE If @p aAddress is not assigned to the network interface. 413 * 414 */ 415 bool HasUnicastAddress(const Address &aAddress) const; 416 417 /** 418 * This method indicates whether or not a unicast address is assigned to the network interface. 419 * 420 * @param[in] aAddress A reference to the unicast address. 421 * 422 * @retval TRUE If @p aAddress is assigned to the network interface, 423 * @retval FALSE If @p aAddress is not assigned to the network interface. 424 * 425 */ HasUnicastAddress(const UnicastAddress & aAddress) const426 bool HasUnicastAddress(const UnicastAddress &aAddress) const { return mUnicastAddresses.Contains(aAddress); } 427 428 /** 429 * This method indicates whether a unicast address is an external or internal address. 430 * 431 * @param[in] aAddress A reference to the unicast address. 432 * 433 * @retval TRUE The address is an external address. 434 * @retval FALSE The address is not an external address (it is an OpenThread internal address). 435 * 436 */ 437 bool IsUnicastAddressExternal(const UnicastAddress &aAddress) const; 438 439 /** 440 * This method adds an external (to OpenThread) unicast address to the network interface. 441 * 442 * For external address, the @p aAddress instance is not directly used (i.e., it can be temporary). It is copied 443 * into a local entry (allocated from an internal pool) before being added in the unicast address linked list. 444 * The maximum number of external addresses is specified by `OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS`. 445 * 446 * @param[in] aAddress A reference to the unicast address. 447 * 448 * @retval kErrorNone Successfully added (or updated) the unicast address. 449 * @retval kErrorInvalidArgs The address indicated by @p aAddress is an internal address. 450 * @retval kErrorNoBufs The maximum number of allowed external addresses are already added. 451 * 452 */ 453 Error AddExternalUnicastAddress(const UnicastAddress &aAddress); 454 455 /** 456 * This method removes a external (to OpenThread) unicast address from the network interface. 457 * 458 * @param[in] aAddress A reference to the unicast address. 459 * 460 * @retval kErrorNone Successfully removed the unicast address. 461 * @retval kErrorInvalidArgs The address indicated by @p aAddress is an internal address. 462 * @retval kErrorNotFound The unicast address was not found. 463 * 464 */ 465 Error RemoveExternalUnicastAddress(const Address &aAddress); 466 467 /** 468 * This method removes all the previously added external (to OpenThread) unicast addresses from the 469 * network interface. 470 * 471 */ 472 void RemoveAllExternalUnicastAddresses(void); 473 474 /** 475 * This method indicates whether or not the network interface is subscribed to a multicast address. 476 * 477 * @param[in] aAddress The multicast address to check. 478 * 479 * @retval TRUE If the network interface is subscribed to @p aAddress. 480 * @retval FALSE If the network interface is not subscribed to @p aAddress. 481 * 482 */ 483 bool IsMulticastSubscribed(const Address &aAddress) const; 484 485 /** 486 * This method subscribes the network interface to the link-local and realm-local all routers addresses. 487 * 488 * @note This method MUST be called after `SubscribeAllNodesMulticast()` or its behavior is undefined. 489 * 490 */ 491 void SubscribeAllRoutersMulticast(void); 492 493 /** 494 * This method unsubscribes the network interface to the link-local and realm-local all routers address. 495 * 496 */ 497 void UnsubscribeAllRoutersMulticast(void); 498 499 /** 500 * This method returns the linked list of multicast addresses. 501 * 502 * @returns The linked list of multicast addresses. 503 * 504 */ GetMulticastAddresses(void) const505 const LinkedList<MulticastAddress> &GetMulticastAddresses(void) const { return mMulticastAddresses; } 506 507 /** 508 * This method indicates whether a multicast address is an external or internal address. 509 * 510 * @param[in] aAddress A reference to the multicast address. 511 * 512 * @retval TRUE The address is an external address. 513 * @retval FALSE The address is not an external address (it is an OpenThread internal address). 514 * 515 */ 516 bool IsMulticastAddressExternal(const MulticastAddress &aAddress) const; 517 518 /** 519 * This method subscribes the network interface to a multicast address. 520 * 521 * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly added in the 522 * multicast address linked list. 523 * 524 * @param[in] aAddress A reference to the multicast address. 525 * 526 */ 527 void SubscribeMulticast(MulticastAddress &aAddress); 528 529 /** 530 * This method unsubscribes the network interface to a multicast address. 531 * 532 * This method is intended for addresses internal to OpenThread. The @p aAddress instance is directly removed from 533 * the multicast address linked list. 534 * 535 * @param[in] aAddress A reference to the multicast address. 536 * 537 */ 538 void UnsubscribeMulticast(const MulticastAddress &aAddress); 539 540 /** 541 * This method subscribes the network interface to the external (to OpenThread) multicast address. 542 * 543 * For external address, the @p aAddress instance is not directly used (i.e., it can be temporary). It is copied 544 * into a local entry (allocated from an internal pool) before being added in the multicast address linked list. 545 * The maximum number of external addresses is specified by `OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS`. 546 * 547 * @param[in] aAddress A reference to the multicast address. 548 * 549 * @retval kErrorNone Successfully subscribed to @p aAddress. 550 * @retval kErrorAlready The multicast address is already subscribed. 551 * @retval kErrorInvalidArgs The IP Address indicated by @p aAddress is an invalid multicast address. 552 * @retval kErrorRejected The IP Address indicated by @p aAddress is an internal multicast address. 553 * @retval kErrorNoBufs The maximum number of allowed external multicast addresses are already added. 554 * 555 */ 556 Error SubscribeExternalMulticast(const Address &aAddress); 557 558 /** 559 * This method unsubscribes the network interface to the external (to OpenThread) multicast address. 560 * 561 * @param[in] aAddress A reference to the multicast address. 562 * 563 * @retval kErrorNone Successfully unsubscribed to the unicast address. 564 * @retval kErrorRejected The address indicated by @p aAddress is an internal address. 565 * @retval kErrorNotFound The multicast address was not found. 566 * 567 */ 568 Error UnsubscribeExternalMulticast(const Address &aAddress); 569 570 /** 571 * This method unsubscribes the network interface from all previously added external (to OpenThread) multicast 572 * addresses. 573 * 574 */ 575 void UnsubscribeAllExternalMulticastAddresses(void); 576 577 /** 578 * This method checks if multicast promiscuous mode is enabled on the network interface. 579 * 580 * @retval TRUE If the multicast promiscuous mode is enabled. 581 * @retval FALSE If the multicast promiscuous mode is disabled. 582 * 583 */ IsMulticastPromiscuousEnabled(void) const584 bool IsMulticastPromiscuousEnabled(void) const { return mMulticastPromiscuous; } 585 586 /** 587 * This method enables multicast promiscuous mode on the network interface. 588 * 589 * @param[in] aEnabled TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise. 590 * 591 */ SetMulticastPromiscuous(bool aEnabled)592 void SetMulticastPromiscuous(bool aEnabled) { mMulticastPromiscuous = aEnabled; } 593 594 /** 595 * This method enables range-based `for` loop iteration over external multicast addresses on the Netif that matches 596 * a given IPv6 address type filter. 597 * 598 * This method should be used like follows: to iterate over all external multicast addresses 599 * 600 * for (Ip6::Netif::ExternalMulticastAddress &addr : Get<ThreadNetif>().IterateExternalMulticastAddresses()) 601 * { ... } 602 * 603 * or to iterate over a subset of external multicast addresses determined by a given address type filter 604 * 605 * for (Ip6::Netif::ExternalMulticastAddress &addr : 606 * Get<ThreadNetif>().IterateExternalMulticastAddresses(Ip6::Address::kTypeMulticastLargerThanRealmLocal)) 607 * { ... } 608 * 609 * @param[in] aFilter The IPv6 address type filter. 610 * 611 * @returns An `ExternalMulticastAddress::Iterator::Builder` instance. 612 * 613 */ IterateExternalMulticastAddresses(Address::TypeFilter aFilter=Address::kTypeAny)614 ExternalMulticastAddress::Iterator::Builder IterateExternalMulticastAddresses( 615 Address::TypeFilter aFilter = Address::kTypeAny) 616 { 617 return ExternalMulticastAddress::Iterator::Builder(*this, aFilter); 618 } 619 620 /** 621 * This method indicates whether or not the network interfaces is subscribed to any external multicast address. 622 * 623 * @retval TRUE The network interface is subscribed to at least one external multicast address. 624 * @retval FALSE The network interface is not subscribed to any external multicast address. 625 * 626 */ HasAnyExternalMulticastAddress(void) const627 bool HasAnyExternalMulticastAddress(void) const { return !ExternalMulticastAddress::Iterator(*this).IsDone(); } 628 629 protected: 630 /** 631 * This method subscribes the network interface to the realm-local all MPL forwarders, link-local, and realm-local 632 * all nodes address. 633 * 634 */ 635 void SubscribeAllNodesMulticast(void); 636 637 /** 638 * This method unsubscribes the network interface from the realm-local all MPL forwarders, link-local and 639 * realm-local all nodes address. 640 * 641 * @note This method MUST be called after `UnsubscribeAllRoutersMulticast()` or its behavior is undefined 642 * 643 */ 644 void UnsubscribeAllNodesMulticast(void); 645 646 private: 647 LinkedList<UnicastAddress> mUnicastAddresses; 648 LinkedList<MulticastAddress> mMulticastAddresses; 649 bool mMulticastPromiscuous; 650 651 otIp6AddressCallback mAddressCallback; 652 void * mAddressCallbackContext; 653 654 Pool<UnicastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS> mExtUnicastAddressPool; 655 Pool<ExternalMulticastAddress, OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS> mExtMulticastAddressPool; 656 657 static const otNetifMulticastAddress kRealmLocalAllMplForwardersMulticastAddress; 658 static const otNetifMulticastAddress kLinkLocalAllNodesMulticastAddress; 659 static const otNetifMulticastAddress kRealmLocalAllNodesMulticastAddress; 660 static const otNetifMulticastAddress kLinkLocalAllRoutersMulticastAddress; 661 static const otNetifMulticastAddress kRealmLocalAllRoutersMulticastAddress; 662 }; 663 664 /** 665 * @} 666 * 667 */ 668 669 } // namespace Ip6 670 671 DefineCoreType(otNetifAddress, Ip6::Netif::UnicastAddress); 672 DefineCoreType(otNetifMulticastAddress, Ip6::Netif::MulticastAddress); 673 674 } // namespace ot 675 676 #endif // NET_NETIF_HPP_ 677