IPv6 API cleanup.
diff --git a/etc/visual-studio/libopenthread.vcxproj b/etc/visual-studio/libopenthread.vcxproj
index 4acbeba..392c027 100644
--- a/etc/visual-studio/libopenthread.vcxproj
+++ b/etc/visual-studio/libopenthread.vcxproj
@@ -57,6 +57,7 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\core\api\commissioner_api.cpp" />
     <ClCompile Include="..\..\src\core\api\dhcp6_api.cpp" />
+    <ClCompile Include="..\..\src\core\api\ip6_api.cpp" />
     <ClCompile Include="..\..\src\core\api\joiner_api.cpp" />
     <ClCompile Include="..\..\src\core\api\link_raw_api.cpp" />
     <ClCompile Include="..\..\src\core\api\message_api.cpp" />
diff --git a/etc/visual-studio/libopenthread.vcxproj.filters b/etc/visual-studio/libopenthread.vcxproj.filters
index 0179554..353b84c 100644
--- a/etc/visual-studio/libopenthread.vcxproj.filters
+++ b/etc/visual-studio/libopenthread.vcxproj.filters
@@ -66,6 +66,9 @@
     <ClCompile Include="..\..\src\core\api\dhcp6_api.cpp">
       <Filter>Source Files\api</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\api\ip6_api.cpp">
+      <Filter>Source Files\api</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\api\joiner_api.cpp">
       <Filter>Source Files\api</Filter>
     </ClCompile>
diff --git a/etc/visual-studio/libopenthread_k.vcxproj b/etc/visual-studio/libopenthread_k.vcxproj
index 9881ca7..620b9b0 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj
+++ b/etc/visual-studio/libopenthread_k.vcxproj
@@ -66,6 +66,7 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\core\api\commissioner_api.cpp" />
     <ClCompile Include="..\..\src\core\api\dhcp6_api.cpp" />
+    <ClCompile Include="..\..\src\core\api\ip6_api.cpp" />
     <ClCompile Include="..\..\src\core\api\joiner_api.cpp" />
     <ClCompile Include="..\..\src\core\api\message_api.cpp" />
     <ClCompile Include="..\..\src\core\api\tasklet_api.cpp" />
diff --git a/etc/visual-studio/libopenthread_k.vcxproj.filters b/etc/visual-studio/libopenthread_k.vcxproj.filters
index 1d9e9b3..9243bfb 100644
--- a/etc/visual-studio/libopenthread_k.vcxproj.filters
+++ b/etc/visual-studio/libopenthread_k.vcxproj.filters
@@ -66,6 +66,9 @@
     <ClCompile Include="..\..\src\core\api\dhcp6_api.cpp">
       <Filter>Source Files\api</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\api\ip6_api.cpp">
+      <Filter>Source Files\api</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\api\joiner_api.cpp">
       <Filter>Source Files\api</Filter>
     </ClCompile>
diff --git a/examples/apps/windows/MainPage.xaml.cpp b/examples/apps/windows/MainPage.xaml.cpp
index 3975baa..c2bc7c0 100644
--- a/examples/apps/windows/MainPage.xaml.cpp
+++ b/examples/apps/windows/MainPage.xaml.cpp
@@ -379,7 +379,7 @@
     // Bring up the interface and start the Thread logic
     //
 
-    otInterfaceUp(device);
+    otIp6SetEnabled(device, true);
 
     otThreadStart(device);
 
@@ -400,7 +400,7 @@
 
     otThreadStop(device);
 
-    otInterfaceDown(device);
+    otIp6SetEnabled(device, false);
 
     // Cleanup
     otFreeMemory(device);
diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp
index f9e7966..c8f007d 100644
--- a/examples/drivers/windows/otApi/otApi.cpp
+++ b/examples/drivers/windows/otApi/otApi.cpp
@@ -1191,29 +1191,19 @@
 OTAPI 
 ThreadError 
 OTCALL
-otInterfaceUp(
-    _In_ otInstance *aInstance
+otIp6SetEnabled(
+    _In_ otInstance *aInstance,
+    bool aEnabled
     )
 {
     if (aInstance == nullptr) return kThreadError_InvalidArgs;
-    return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, (BOOLEAN)TRUE));
-}
-
-OTAPI 
-ThreadError 
-OTCALL
-otInterfaceDown(
-    _In_ otInstance *aInstance
-    )
-{
-    if (aInstance == nullptr) return kThreadError_InvalidArgs;
-    return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, (BOOLEAN)FALSE));
+    return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_INTERFACE, (BOOLEAN)aEnabled));
 }
 
 OTAPI 
 bool 
 OTCALL
-otIsInterfaceUp(
+otIp6IsEnabled(
     _In_ otInstance *aInstance
     )
 {
@@ -1924,7 +1914,7 @@
 OTAPI
 const otNetifAddress *
 OTCALL
-otGetUnicastAddresses(
+otIp6GetUnicastAddresses(
     _In_ otInstance *aInstance
     )
 {
@@ -2039,7 +2029,7 @@
 OTAPI
 ThreadError
 OTCALL
-otAddUnicastAddress(
+otIp6AddUnicastAddress(
     _In_ otInstance *aInstance, 
     const otNetifAddress *aAddress
     )
@@ -2106,7 +2096,7 @@
 OTAPI
 ThreadError
 OTCALL
-otRemoveUnicastAddress(
+otIp6RemoveUnicastAddress(
     _In_ otInstance *aInstance, 
     const otIp6Address *aAddress
     )
@@ -3688,7 +3678,7 @@
 OTAPI 
 ThreadError 
 OTCALL 
-otSendMgmtCommissionerGet(
+otCommissionerSendMgmtGet(
     _In_ otInstance *aInstance, 
     const uint8_t *aTlvs, 
     uint8_t aLength
@@ -3716,7 +3706,7 @@
 OTAPI 
 ThreadError 
 OTCALL 
-otSendMgmtCommissionerSet(
+otCommissionerSendMgmtSet(
     _In_ otInstance *aInstance,
     const otCommissioningDataset *aDataset,
     const uint8_t *aTlvs,
diff --git a/examples/drivers/windows/otLwf/address.c b/examples/drivers/windows/otLwf/address.c
index 1d9b504..084f1d3 100644
--- a/examples/drivers/windows/otLwf/address.c
+++ b/examples/drivers/windows/otLwf/address.c
@@ -343,10 +343,10 @@
                 LogInfo(DRIVER_DEFAULT, "Filter %p trying to add/update address: %!IPV6ADDR!", pFilter, pAddr);
 
                 // Add (or update) the address to OpenThread
-                ThreadError otError = otAddUnicastAddress(pFilter->otCtx, &otAddr);
+                ThreadError otError = otIp6AddUnicastAddress(pFilter->otCtx, &otAddr);
                 if (otError != kThreadError_None)
                 {
-                    LogError(DRIVER_DEFAULT, "otAddUnicastAddress failed, %!otError!", otError);
+                    LogError(DRIVER_DEFAULT, "otIp6AddUnicastAddress failed, %!otError!", otError);
                     ShouldDelete = otError == kThreadError_NoBufs ? TRUE : FALSE;
                 }
             }
@@ -378,7 +378,7 @@
             LogInfo(DRIVER_DEFAULT, "Filter %p trying to remove address: %!IPV6ADDR!", pFilter, pAddr);
 
             // Find the correct address from OpenThread to remove (best effort)
-            (void)otRemoveUnicastAddress(pFilter->otCtx, (otIp6Address*)pAddr);
+            (void)otIp6RemoveUnicastAddress(pFilter->otCtx, (otIp6Address*)pAddr);
         }
     }
 
@@ -398,7 +398,7 @@
     
     NT_ASSERT(pFilter->DeviceStatus == OTLWF_DEVICE_STATUS_RADIO_MODE);
 
-    const otNetifAddress* addr = otGetUnicastAddresses(pFilter->otCtx);
+    const otNetifAddress* addr = otIp6GetUnicastAddresses(pFilter->otCtx);
 
     // Process the addresses
     while (addr)
diff --git a/examples/drivers/windows/otLwf/eventprocessing.c b/examples/drivers/windows/otLwf/eventprocessing.c
index 519b35a..87df010 100644
--- a/examples/drivers/windows/otLwf/eventprocessing.c
+++ b/examples/drivers/windows/otLwf/eventprocessing.c
@@ -790,7 +790,7 @@
 
     // Register callbacks with OpenThread
     otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter);
-    otSetReceiveIp6DatagramCallback(pFilter->otCtx, otLwfReceiveIp6DatagramCallback, pFilter);
+    otIp6SetReceiveCallback(pFilter->otCtx, otLwfReceiveIp6DatagramCallback, pFilter);
 
     // Query the current addresses from TCPIP and cache them
     (void)otLwfInitializeAddresses(pFilter);
@@ -904,7 +904,7 @@
                                 ThreadError error = kThreadError_None;
 
                                 // Create a new message
-                                otMessage message = otNewIp6Message(pFilter->otCtx, TRUE);
+                                otMessage *message = otIp6NewMessage(pFilter->otCtx, TRUE);
                                 if (message)
                                 {
                                     // Write to the message
@@ -927,7 +927,7 @@
 #endif
 
                                         // Send message (it will free 'message')
-                                        error = otSendIp6Datagram(pFilter->otCtx, message);
+                                        error = otIp6Send(pFilter->otCtx, message);
                                         if (error != kThreadError_None)
                                         {
                                             LogError(DRIVER_DATA_PATH, "otSendIp6Datagram failed with %!otError!", error);
diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c
index b776d46..dc2aaf0 100644
--- a/examples/drivers/windows/otLwf/iocontrol.c
+++ b/examples/drivers/windows/otLwf/iocontrol.c
@@ -134,8 +134,8 @@
     { "IOCTL_OTLWF_OT_SEND_ACTIVE_SET",             REF_IOCTL_FUNC(otSendActiveSet) },
     { "IOCTL_OTLWF_OT_SEND_PENDING_GET",            REF_IOCTL_FUNC(otSendPendingGet) },
     { "IOCTL_OTLWF_OT_SEND_PENDING_SET",            REF_IOCTL_FUNC(otSendPendingSet) },
-    { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET",  REF_IOCTL_FUNC(otSendMgmtCommissionerGet) },
-    { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET",  REF_IOCTL_FUNC(otSendMgmtCommissionerSet) },
+    { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET",  REF_IOCTL_FUNC(otCommissionerSendMgmtGet) },
+    { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET",  REF_IOCTL_FUNC(otCommissionerSendMgmtSet) },
     { "IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME",        REF_IOCTL_FUNC_WITH_TUN(otKeySwitchGuardtime) },
     { "IOCTL_OTLWF_OT_FACTORY_RESET",               REF_IOCTL_FUNC(otFactoryReset) },
     { "IOCTL_OTLWF_OT_THREAD_AUTO_START",           REF_IOCTL_FUNC(otThreadAutoStart) }
@@ -456,19 +456,14 @@
             // Make sure our addresses are in sync
             (void)otLwfInitializeAddresses(pFilter);
             otLwfRadioAddressesUpdated(pFilter);
+	}
 
-            status = ThreadErrorToNtstatus(otInterfaceUp(pFilter->otCtx));
-        }
-        else
-        {
-            status = ThreadErrorToNtstatus(otInterfaceDown(pFilter->otCtx));
-        }
-        
+        status = ThreadErrorToNtstatus(otIp6SetEnabled(pFilter->otCtx, IsEnabled));
         *OutBufferLength = 0;
     }
     else if (*OutBufferLength >= sizeof(BOOLEAN))
     {
-        *(BOOLEAN*)OutBuffer = otIsInterfaceUp(pFilter->otCtx) ? TRUE : FALSE;
+        *(BOOLEAN*)OutBuffer = otIp6IsEnabled(pFilter->otCtx) ? TRUE : FALSE;
         *OutBufferLength = sizeof(BOOLEAN);
         status = STATUS_SUCCESS;
     }
@@ -5903,7 +5898,7 @@
 
 _IRQL_requires_max_(PASSIVE_LEVEL)
 NTSTATUS
-otLwfIoCtl_otSendMgmtCommissionerGet(
+otLwfIoCtl_otCommissionerSendMgmtGet(
     _In_ PMS_FILTER         pFilter,
     _In_reads_bytes_(InBufferLength)
             PUCHAR          InBuffer,
@@ -5926,7 +5921,7 @@
         if (InBufferLength >= sizeof(uint8_t) + aLength)
         {
             status = ThreadErrorToNtstatus(
-                otSendMgmtCommissionerGet(
+                otCommissionerSendMgmtGet(
                     pFilter->otCtx,
                     aTlvs,
                     aLength)
@@ -5939,7 +5934,7 @@
 
 _IRQL_requires_max_(PASSIVE_LEVEL)
 NTSTATUS
-otLwfIoCtl_otSendMgmtCommissionerSet(
+otLwfIoCtl_otCommissionerSendMgmtSet(
     _In_ PMS_FILTER         pFilter,
     _In_reads_bytes_(InBufferLength)
             PUCHAR          InBuffer,
@@ -5963,7 +5958,7 @@
         if (InBufferLength >= sizeof(otCommissioningDataset) + sizeof(uint8_t) + aLength)
         {
             status = ThreadErrorToNtstatus(
-                otSendMgmtCommissionerSet(
+                otCommissionerSendMgmtSet(
                     pFilter->otCtx,
                     aDataset,
                     aTlvs,
diff --git a/examples/drivers/windows/otLwf/iocontrol.h b/examples/drivers/windows/otLwf/iocontrol.h
index 2b3d58e..f1ffd87 100644
--- a/examples/drivers/windows/otLwf/iocontrol.h
+++ b/examples/drivers/windows/otLwf/iocontrol.h
@@ -220,8 +220,8 @@
 DECL_IOCTL_FUNC(otSendActiveSet);
 DECL_IOCTL_FUNC(otSendPendingGet);
 DECL_IOCTL_FUNC(otSendPendingSet);
-DECL_IOCTL_FUNC(otSendMgmtCommissionerGet);
-DECL_IOCTL_FUNC(otSendMgmtCommissionerSet);
+DECL_IOCTL_FUNC(otCommissionerSendMgmtGet);
+DECL_IOCTL_FUNC(otCommissionerSendMgmtSet);
 DECL_IOCTL_FUNC_WITH_TUN2(otKeySwitchGuardtime);
 DECL_IOCTL_FUNC(otFactoryReset);
 DECL_IOCTL_FUNC(otThreadAutoStart);
diff --git a/examples/drivers/windows/otLwf/precomp.h b/examples/drivers/windows/otLwf/precomp.h
index fee305b..f787d41 100644
--- a/examples/drivers/windows/otLwf/precomp.h
+++ b/examples/drivers/windows/otLwf/precomp.h
@@ -63,7 +63,7 @@
 #include <openthread-core-config.h>
 #include <openthread.h>
 #include <openthread-icmp6.h>
-#include <openthread-ip6.h>
+#include <openthread/ip6.h>
 #include <openthread/tasklet.h>
 #include <openthread/commissioner.h>
 #include <openthread/joiner.h>
diff --git a/examples/drivers/windows/otLwf/radio.c b/examples/drivers/windows/otLwf/radio.c
index e9dea3c..7b5d043 100644
--- a/examples/drivers/windows/otLwf/radio.c
+++ b/examples/drivers/windows/otLwf/radio.c
@@ -87,7 +87,7 @@
 
     // Register callbacks with OpenThread
     otSetStateChangedCallback(pFilter->otCtx, otLwfStateChangedCallback, pFilter);
-    otSetReceiveIp6DatagramCallback(pFilter->otCtx, otLwfReceiveIp6DatagramCallback, pFilter);
+    otIp6SetReceiveCallback(pFilter->otCtx, otLwfReceiveIp6DatagramCallback, pFilter);
 
     // Query the current addresses from TCPIP and cache them
     (void)otLwfInitializeAddresses(pFilter);
diff --git a/examples/drivers/windows/otLwf/thread.c b/examples/drivers/windows/otLwf/thread.c
index 337cd4e..03e3dc5 100644
--- a/examples/drivers/windows/otLwf/thread.c
+++ b/examples/drivers/windows/otLwf/thread.c
@@ -376,7 +376,7 @@
     if ((aFlags & OT_THREAD_NETDATA_UPDATED) != 0)
     {
         LogVerbose(DRIVER_DEFAULT, "Filter %p received OT_THREAD_NETDATA_UPDATED", pFilter);
-        otSlaacUpdate(pFilter->otCtx, pFilter->otAutoAddresses, ARRAYSIZE(pFilter->otAutoAddresses), otCreateRandomIid, NULL);
+        otIp6SlaacUpdate(pFilter->otCtx, pFilter->otAutoAddresses, ARRAYSIZE(pFilter->otAutoAddresses), otIp6CreateRandomIid, NULL);
 
 #if OPENTHREAD_ENABLE_DHCP6_SERVER
         otDhcp6ServerUpdate(pFilter->otCtx);
diff --git a/examples/drivers/windows/otNodeApi/otNodeApi.cpp b/examples/drivers/windows/otNodeApi/otNodeApi.cpp
index 1bade11..0fa581c 100644
--- a/examples/drivers/windows/otNodeApi/otNodeApi.cpp
+++ b/examples/drivers/windows/otNodeApi/otNodeApi.cpp
@@ -642,7 +642,7 @@
 void HandleAddressChanges(otNode *aNode)
 {
     otLogFuncEntry();
-    auto addrs = otGetUnicastAddresses(aNode->mInstance);
+    auto addrs = otIp6GetUnicastAddresses(aNode->mInstance);
 
     EnterCriticalSection(&aNode->mCS);
         
@@ -955,7 +955,7 @@
     otLogFuncEntryMsg("[%d]", aNode->mId);
     printf("%d: ifconfig up\r\n", aNode->mId);
 
-    auto error = otInterfaceUp(aNode->mInstance);
+    auto error = otIp6SetEnabled(aNode->mInstance, true);
     
     otLogFuncExit();
     return error;
@@ -966,7 +966,7 @@
     otLogFuncEntryMsg("[%d]", aNode->mId);
     printf("%d: ifconfig down\r\n", aNode->mId);
 
-    (void)otInterfaceDown(aNode->mInstance);
+    (void)otIp6SetEnabled(aNode->mInstance, false);
     
     otLogFuncExit();
     return 0;
@@ -1436,7 +1436,7 @@
     aAddress.mPrefixLength = 64;
     aAddress.mPreferred = true;
     aAddress.mValid = true;
-    auto result = otAddUnicastAddress(aNode->mInstance, &aAddress);
+    auto result = otIp6AddUnicastAddress(aNode->mInstance, &aAddress);
     otLogFuncExit();
     return result;
 }
@@ -1453,7 +1453,7 @@
     otLogFuncEntryMsg("[%d]", aNode->mId);
     printf("%d: ipaddr\r\n", aNode->mId);
 
-    auto addrs = otGetUnicastAddresses(aNode->mInstance);
+    auto addrs = otIp6GetUnicastAddresses(aNode->mInstance);
     if (addrs == nullptr) return nullptr;
 
     char* str = (char*)malloc(512);
diff --git a/include/Makefile.am b/include/Makefile.am
index 6e3e1e9..db02a3d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -60,7 +60,6 @@
     openthread.h                          \
     openthread-diag.h                     \
     openthread-icmp6.h                    \
-    openthread-ip6.h                      \
     openthread-types.h                    \
     $(NULL)
 
diff --git a/include/openthread-ip6.h b/include/openthread-ip6.h
deleted file mode 100644
index 6a720d8..0000000
--- a/include/openthread-ip6.h
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- *  Copyright (c) 2016, The OpenThread Authors.
- *  All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions are met:
- *  1. Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *  2. Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *  3. Neither the name of the copyright holder nor the
- *     names of its contributors may be used to endorse or promote products
- *     derived from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file
- * @brief
- *  This file defines the top-level ip6 functions for the OpenThread library.
- */
-
-#ifndef OPENTHREAD_IP6_H_
-#define OPENTHREAD_IP6_H_
-
-#include "openthread/message.h"
-#include <platform/radio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @defgroup api  API
- * @brief
- *   This module includes the application programming interface to the OpenThread stack.
- *
- * @{
- *
- * @defgroup execution Execution
- * @defgroup commands Commands
- * @defgroup config Configuration
- * @defgroup diags Diagnostics
- * @defgroup messages Message Buffers
- * @defgroup ip6 IPv6
- * @defgroup udp UDP
- * @defgroup coap CoAP
- *
- * @}
- *
- */
-
-/**
- * @addtogroup diags  Diagnostics
- *
- * @brief
- *   This module includes functions that expose internal state.
- *
- * @{
- *
- */
-
-/**
- * This function pointer is called when an IEEE 802.15.4 frame is received.
- *
- * @note This callback is called after FCS processing and @p aFrame may not contain the actual FCS that was received.
- *
- * @note This callback is called before IEEE 802.15.4 security processing and mSecurityValid in @p aFrame will
- * always be false.
- *
- * @param[in]  aFrame    A pointer to the received IEEE 802.15.4 frame.
- * @param[in]  aContext  A pointer to application-specific context.
- *
- */
-typedef void (*otLinkPcapCallback)(const RadioPacket *aFrame, void *aContext);
-
-/**
- * This function registers a callback to provide received raw IEEE 802.15.4 frames.
- *
- * @param[in]  aInstance         A pointer to an OpenThread instance.
- * @param[in]  aPcapCallback     A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or
- *                               NULL to disable the callback.
- * @param[in]  aCallbackContext  A pointer to application-specific context.
- *
- */
-void otSetLinkPcapCallback(otInstance *aInstance, otLinkPcapCallback aPcapCallback, void *aCallbackContext);
-
-/**
- * This function indicates whether or not promiscuous mode is enabled at the link layer.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @retval true   Promiscuous mode is enabled.
- * @retval false  Promiscuous mode is not enabled.
- *
- */
-bool otIsLinkPromiscuous(otInstance *aInstance);
-
-/**
- * This function enables or disables the link layer promiscuous mode.
- *
- * @note Promiscuous mode may only be enabled when the Thread interface is disabled.
- *
- * @param[in]  aInstance     A pointer to an OpenThread instance.
- * @param[in]  aPromiscuous  true to enable promiscuous mode, or false otherwise.
- *
- * @retval kThreadError_None          Successfully enabled promiscuous mode.
- * @retval kThreadError_InvalidState  Could not enable promiscuous mode because
- *                                    the Thread interface is enabled.
- *
- */
-ThreadError otSetLinkPromiscuous(otInstance *aInstance, bool aPromiscuous);
-
-/**
- * @}
- *
- */
-
-/**
- * @addtogroup ip6  IPv6
- *
- * @brief
- *   This module includes functions that control IPv6 communication.
- *
- * @{
- *
- */
-
-/**
- * Get the list of IPv6 multicast addresses subscribed to the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @returns A pointer to the first Network Interface Multicast Address.
- */
-const otNetifMulticastAddress *otGetMulticastAddresses(otInstance *aInstance);
-
-/**
- * Subscribe the Thread interface to a Network Interface Multicast Address.
- *
- * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only
- * supports a fixed number of externally added multicast addresses. See OPENTHREAD_CONFIG_MAX_EXT_MULTICAST_IP_ADDRS.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aAddress  A pointer to an IP Address.
- *
- * @retval kThreadErrorNone          Successfully subscribed to the Network Interface Multicast Address.
- * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is invalid address.
- * @retval kThreadError_NoBufs       The Network Interface is already storing the maximum allowed external multicast addresses.
- */
-ThreadError otSubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress);
-
-/**
- * Unsubscribe the Thread interface to a Network Interface Multicast Address.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aAddress  A pointer to an IP Address.
- *
- * @retval kThreadErrorNone          Successfully unsubscribed to the Network Interface Multicast Address.
- * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
- * @retval kThreadError_NotFound     The IP Address indicated by @p aAddress was not found.
- */
-ThreadError otUnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress);
-
-/**
- * Check if multicast promiscuous mode is enabled on the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @sa otEnableMulticastPromiscuousMode
- * @sa otDisableMulticastPromiscuousMode
- */
-bool otIsMulticastPromiscuousModeEnabled(otInstance *aInstance);
-
-/**
- * Enable multicast promiscuous mode on the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @sa otIsMulticastPromiscuousModeEnabled
- * @sa otDisableMulticastPromiscuousMode
- */
-void otEnableMulticastPromiscuousMode(otInstance *aInstance);
-
-/**
- * Disable multicast promiscuous mode on the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @sa otIsMulticastPromiscuousModeEnabled
- * @sa otEnableMulticastPromiscuousMode
- */
-void otDisableMulticastPromiscuousMode(otInstance *aInstance);
-
-/**
- * This function pointer is called to create IPv6 IID during SLAAC procedure.
- *
- * @param[in]     aInstance  A pointer to an OpenThread instance.
- * @param[inout]  aAddress   A pointer to structure containing IPv6 address for which IID is being created.
- * @param[inout]  aContext   A pointer to creator-specific context.
- *
- * @retval kThreadError_None                        Created valid IID for given IPv6 address.
- * @retval kThreadError_Ipv6AddressCreationFailure  Creation of valid IID for given IPv6 address failed.
- *
- */
-typedef ThreadError(*otSlaacIidCreate)(otInstance *aInstance, otNetifAddress *aAddress, void *aContext);
-
-/**
- * Update all automatically created IPv6 addresses for prefixes from current Network Data with SLAAC procedure.
- *
- * @param[in]     aInstance      A pointer to an OpenThread instance.
- * @param[inout]  aAddresses     A pointer to an array of automatically created IPv6 addresses.
- * @param[in]     aNumAddresses  The number of slots in aAddresses array.
- * @param[in]     aIidCreate     A pointer to a function that is called to create IPv6 IIDs.
- * @param[in]     aContext       A pointer to data passed to aIidCreate function.
- *
- */
-void otSlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses,
-                   otSlaacIidCreate aIidCreate, void *aContext);
-
-/**
- * Create random IID for given IPv6 address.
- *
- * @param[in]     aInstance  A pointer to an OpenThread instance.
- * @param[inout]  aAddress   A pointer to structure containing IPv6 address for which IID is being created.
- * @param[in]     aContext   A pointer to unused data.
- *
- * @retval kThreadError_None  Created valid IID for given IPv6 address.
- *
- */
-ThreadError otCreateRandomIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
-
-/**
- * Create IID for given IPv6 address using extended MAC address.
- *
- * @param[in]     aInstance  A pointer to an OpenThread instance.
- * @param[inout]  aAddress   A pointer to structure containing IPv6 address for which IID is being created.
- * @param[in]     aContext   A pointer to unused data.
- *
- * @retval kThreadError_None  Created valid IID for given IPv6 address.
- *
- */
-ThreadError otCreateMacIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
-
-/**
- * Create semantically opaque IID for given IPv6 address.
- *
- * @param[in]     aInstance  A pointer to an OpenThread instance.
- * @param[inout]  aAddress   A pointer to structure containing IPv6 address for which IID is being created.
- * @param[inout]  aContext   A pointer to a otSemanticallyOpaqueIidGeneratorData structure.
- *
- * @retval kThreadError_None                        Created valid IID for given IPv6 address.
- * @retval kThreadError_Ipv6AddressCreationFailure  Could not create valid IID for given IPv6 address.
- *
- */
-ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
-
-/**
- * Allocate a new message buffer for sending an IPv6 message.
- *
- * @param[in]  aInstance             A pointer to an OpenThread instance.
- * @param[in]  aLinkSecurityEnabled  TRUE if the message should be secured at Layer 2
- *
- * @returns A pointer to the message buffer or NULL if no message buffers are available.
- *
- * @sa otFreeMessage
- */
-otMessage otNewIp6Message(otInstance *aInstance, bool aLinkSecurityEnabled);
-
-/**
- * This function pointer is called when an IPv6 datagram is received.
- *
- * @param[in]  aMessage  A pointer to the message buffer containing the received IPv6 datagram.
- * @param[in]  aContext  A pointer to application-specific context.
- *
- */
-typedef void (*otReceiveIp6DatagramCallback)(otMessage aMessage, void *aContext);
-
-/**
- * This function registers a callback to provide received IPv6 datagrams.
- *
- * By default, this callback does not pass Thread control traffic.  See otSetReceiveIp6DatagramFilterEnabled() to
- * change the Thread control traffic filter setting.
- *
- * @param[in]  aInstance         A pointer to an OpenThread instance.
- * @param[in]  aCallback         A pointer to a function that is called when an IPv6 datagram is received or
- *                               NULL to disable the callback.
- * @param[in]  aCallbackContext  A pointer to application-specific context.
- *
- * @sa otIsReceiveIp6DatagramFilterEnabled
- * @sa otSetReceiveIp6DatagramFilterEnabled
- *
- */
-void otSetReceiveIp6DatagramCallback(otInstance *aInstance, otReceiveIp6DatagramCallback aCallback,
-                                     void *aCallbackContext);
-
-/**
- * This function indicates whether or not Thread control traffic is filtered out when delivering IPv6 datagrams
- * via the callback specified in otSetReceiveIp6DatagramCallback().
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @returns  TRUE if Thread control traffic is filtered out, FALSE otherwise.
- *
- * @sa otSetReceiveIp6DatagramCallback
- * @sa otSetReceiveIp6DatagramFilterEnabled
- *
- */
-bool otIsReceiveIp6DatagramFilterEnabled(otInstance *aInstance);
-
-/**
- * This function sets whether or not Thread control traffic is filtered out when delivering IPv6 datagrams
- * via the callback specified in otSetReceiveIp6DatagramCallback().
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aEnabled  TRUE if Thread control traffic is filtered out, FALSE otherwise.
- *
- * @sa otSetReceiveIp6DatagramCallback
- * @sa otIsReceiveIp6DatagramFilterEnabled
- *
- */
-void otSetReceiveIp6DatagramFilterEnabled(otInstance *aInstance, bool aEnabled);
-
-/**
- * This function sends an IPv6 datagram via the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aMessage  A pointer to the message buffer containing the IPv6 datagram.
- *
- */
-ThreadError otSendIp6Datagram(otInstance *aInstance, otMessage aMessage);
-
-/**
- * @}
- *
- */
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif  // OPENTHREAD_IP6_H_
diff --git a/include/openthread.h b/include/openthread.h
index d1e5785..3cbd383 100644
--- a/include/openthread.h
+++ b/include/openthread.h
@@ -38,6 +38,7 @@
 #include <openthread-types.h>
 
 #include "openthread/crypto.h"
+#include "openthread/ip6.h"
 #include "openthread/message.h"
 #include "openthread/tasklet.h"
 
@@ -260,43 +261,6 @@
 #endif
 
 /**
- * This function brings up the IPv6 interface.
- *
- * Call this function to bring up the IPv6 interface and enables IPv6 communication.
- *
- * @param[in] aInstance A pointer to an OpenThread instance.
- *
- * @retval kThreadError_None          Successfully enabled the IPv6 interface,
- *                                    or the interface was already enabled.
- *
- */
-OTAPI ThreadError OTCALL otInterfaceUp(otInstance *aInstance);
-
-/**
- * This function brings down the IPv6 interface.
- *
- * Call this function to bring down the IPv6 interface and disable all IPv6 communication.
- *
- * @param[in] aInstance A pointer to an OpenThread instance.
- *
- * @retval kThreadError_None          Successfully brought the interface down,
- *                                    or the interface was already down.
- *
- */
-OTAPI ThreadError OTCALL otInterfaceDown(otInstance *aInstance);
-
-/**
- * This function indicates whether or not the IPv6 interface is up.
- *
- * @param[in] aInstance A pointer to an OpenThread instance.
- *
- * @retval TRUE   The IPv6 interface is up.
- * @retval FALSE  The IPv6 interface is down.
- *
- */
-OTAPI bool OTCALL otIsInterfaceUp(otInstance *aInstance);
-
-/**
  * This function starts Thread protocol operation.
  *
  * The interface must be up when calling this function.
@@ -853,42 +817,6 @@
 OTAPI otShortAddress OTCALL otGetShortAddress(otInstance *aInstance);
 
 /**
- * Get the list of IPv6 addresses assigned to the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- *
- * @returns A pointer to the first Network Interface Address.
- */
-OTAPI const otNetifAddress *OTCALL otGetUnicastAddresses(otInstance *aInstance);
-
-/**
- * Add a Network Interface Address to the Thread interface.
- *
- * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only
- * supports a fixed number of externally added unicast addresses. See OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aAddress  A pointer to a Network Interface Address.
- *
- * @retval kThreadErrorNone          Successfully added (or updated) the Network Interface Address.
- * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
- * @retval kThreadError_NoBufs       The Network Interface is already storing the maximum allowed external addresses.
- */
-OTAPI ThreadError OTCALL otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress);
-
-/**
- * Remove a Network Interface Address from the Thread interface.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aAddress  A pointer to an IP Address.
- *
- * @retval kThreadErrorNone          Successfully removed the Network Interface Address.
- * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
- * @retval kThreadError_NotFound     The IP Address indicated by @p aAddress was not found.
- */
-OTAPI ThreadError OTCALL otRemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress);
-
-/**
  * This function registers a callback to indicate when certain configuration or state changes within OpenThread.
  *
  * @param[in]  aInstance  A pointer to an OpenThread instance.
@@ -1236,43 +1164,6 @@
 OTAPI ThreadError OTCALL otSendServerData(otInstance *aInstance);
 
 /**
- * This function adds a port to the allowed unsecured port list.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aPort     The port value.
- *
- * @retval kThreadError_None    The port was successfully added to the allowed unsecure port list.
- * @retval kThreadError_NoBufs  The unsecure port list is full.
- *
- */
-ThreadError otAddUnsecurePort(otInstance *aInstance, uint16_t aPort);
-
-/**
- * This function removes a port from the allowed unsecure port list.
- *
- * @param[in]  aInstance A pointer to an OpenThread instance.
- * @param[in]  aPort     The port value.
- *
- * @retval kThreadError_None      The port was successfully removed from the allowed unsecure port list.
- * @retval kThreadError_NotFound  The port was not found in the unsecure port list.
- *
- */
-ThreadError otRemoveUnsecurePort(otInstance *aInstance, uint16_t aPort);
-
-/**
- * This function returns a pointer to the unsecure port list.
- *
- * @note Port value 0 is used to indicate an invalid entry.
- *
- * @param[in]   aInstance    A pointer to an OpenThread instance.
- * @param[out]  aNumEntries  The number of entries in the list.
- *
- * @returns A pointer to the unsecure port list.
- *
- */
-const uint16_t *otGetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries);
-
-/**
  * @}
  *
  */
@@ -2012,39 +1903,6 @@
  */
 
 /**
- * Test if two IPv6 addresses are the same.
- *
- * @param[in]  a  A pointer to the first IPv6 address to compare.
- * @param[in]  b  A pointer to the second IPv6 address to compare.
- *
- * @retval TRUE   The two IPv6 addresses are the same.
- * @retval FALSE  The two IPv6 addresses are not the same.
- */
-OTAPI bool OTCALL otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b);
-
-/**
- * Convert a human-readable IPv6 address string into a binary representation.
- *
- * @param[in]   aString   A pointer to a NULL-terminated string.
- * @param[out]  aAddress  A pointer to an IPv6 address.
- *
- * @retval kThreadErrorNone        Successfully parsed the string.
- * @retval kThreadErrorInvalidArg  Failed to parse the string.
- */
-OTAPI ThreadError OTCALL otIp6AddressFromString(const char *aString, otIp6Address *aAddress);
-
-/**
- * This function returns the prefix match length (bits) for two IPv6 addresses.
- *
- * @param[in]  aFirst   A pointer to the first IPv6 address.
- * @param[in]  aSecond  A pointer to the second IPv6 address.
- *
- * @returns  The prefix match length in bits.
- *
- */
-OTAPI uint8_t OTCALL otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond);
-
-/**
  * This function converts a ThreadError enum into a string.
  *
  * @param[in]  aError     A ThreadError enum.
diff --git a/include/openthread/Makefile.am b/include/openthread/Makefile.am
index d567bc5..fe1041b 100644
--- a/include/openthread/Makefile.am
+++ b/include/openthread/Makefile.am
@@ -34,6 +34,7 @@
     crypto.h                              \
     dhcp6_client.h                        \
     dhcp6_server.h                        \
+    ip6.h                                 \
     jam_detection.h                       \
     joiner.h                              \
     message.h                             \
diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h
new file mode 100644
index 0000000..9b70a2f
--- /dev/null
+++ b/include/openthread/ip6.h
@@ -0,0 +1,453 @@
+/*
+ *  Copyright (c) 2016, The OpenThread Authors.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief
+ *  This file defines the OpenThread IPv6 API.
+ */
+
+#ifndef OPENTHREAD_IP6_H_
+#define OPENTHREAD_IP6_H_
+
+#include "openthread/message.h"
+#include "platform/radio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup diags  Diagnostics
+ *
+ * @brief
+ *   This module includes functions that expose internal state.
+ *
+ * @{
+ *
+ */
+
+/**
+ * This function pointer is called when an IEEE 802.15.4 frame is received.
+ *
+ * @note This callback is called after FCS processing and @p aFrame may not contain the actual FCS that was received.
+ *
+ * @note This callback is called before IEEE 802.15.4 security processing and mSecurityValid in @p aFrame will
+ * always be false.
+ *
+ * @param[in]  aFrame    A pointer to the received IEEE 802.15.4 frame.
+ * @param[in]  aContext  A pointer to application-specific context.
+ *
+ */
+typedef void (*otLinkPcapCallback)(const RadioPacket *aFrame, void *aContext);
+
+/**
+ * This function registers a callback to provide received raw IEEE 802.15.4 frames.
+ *
+ * @param[in]  aInstance         A pointer to an OpenThread instance.
+ * @param[in]  aPcapCallback     A pointer to a function that is called when receiving an IEEE 802.15.4 link frame or
+ *                               NULL to disable the callback.
+ * @param[in]  aCallbackContext  A pointer to application-specific context.
+ *
+ */
+void otSetLinkPcapCallback(otInstance *aInstance, otLinkPcapCallback aPcapCallback, void *aCallbackContext);
+
+/**
+ * This function indicates whether or not promiscuous mode is enabled at the link layer.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ *
+ * @retval true   Promiscuous mode is enabled.
+ * @retval false  Promiscuous mode is not enabled.
+ *
+ */
+bool otIsLinkPromiscuous(otInstance *aInstance);
+
+/**
+ * This function enables or disables the link layer promiscuous mode.
+ *
+ * @note Promiscuous mode may only be enabled when the Thread interface is disabled.
+ *
+ * @param[in]  aInstance     A pointer to an OpenThread instance.
+ * @param[in]  aPromiscuous  true to enable promiscuous mode, or false otherwise.
+ *
+ * @retval kThreadError_None          Successfully enabled promiscuous mode.
+ * @retval kThreadError_InvalidState  Could not enable promiscuous mode because
+ *                                    the Thread interface is enabled.
+ *
+ */
+ThreadError otSetLinkPromiscuous(otInstance *aInstance, bool aPromiscuous);
+
+/**
+ * @}
+ *
+ */
+
+/**
+ * @addtogroup ip6  IPv6
+ *
+ * @brief
+ *   This module includes functions that control IPv6 communication.
+ *
+ * @{
+ *
+ */
+
+/**
+ * This function brings up the IPv6 interface.
+ *
+ * Call this function to enable/disable IPv6 communication.
+ *
+ * @param[in] aInstance A pointer to an OpenThread instance.
+ * @param[in] aEnabled  TRUE to enable IPv6, FALSE otherwise.
+ *
+ * @retval kThreadError_None          Successfully enabled the IPv6 interface,
+ *                                    or the interface was already enabled.
+ *
+ */
+OTAPI ThreadError OTCALL otIp6SetEnabled(otInstance *aInstance, bool aEnabled);
+
+/**
+ * This function indicates whether or not the IPv6 interface is up.
+ *
+ * @param[in] aInstance A pointer to an OpenThread instance.
+ *
+ * @retval TRUE   The IPv6 interface is enabled.
+ * @retval FALSE  The IPv6 interface is disabled.
+ *
+ */
+OTAPI bool OTCALL otIp6IsEnabled(otInstance *aInstance);
+
+/**
+ * Add a Network Interface Address to the Thread interface.
+ *
+ * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only
+ * supports a fixed number of externally added unicast addresses. See OPENTHREAD_CONFIG_MAX_EXT_IP_ADDRS.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aAddress  A pointer to a Network Interface Address.
+ *
+ * @retval kThreadErrorNone          Successfully added (or updated) the Network Interface Address.
+ * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
+ * @retval kThreadError_NoBufs       The Network Interface is already storing the maximum allowed external addresses.
+ */
+OTAPI ThreadError OTCALL otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *aAddress);
+
+/**
+ * Remove a Network Interface Address from the Thread interface.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aAddress  A pointer to an IP Address.
+ *
+ * @retval kThreadErrorNone          Successfully removed the Network Interface Address.
+ * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
+ * @retval kThreadError_NotFound     The IP Address indicated by @p aAddress was not found.
+ */
+OTAPI ThreadError OTCALL otIp6RemoveUnicastAddress(otInstance *aInstance, const otIp6Address *aAddress);
+
+/**
+ * Get the list of IPv6 addresses assigned to the Thread interface.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ *
+ * @returns A pointer to the first Network Interface Address.
+ */
+OTAPI const otNetifAddress *OTCALL otIp6GetUnicastAddresses(otInstance *aInstance);
+
+/**
+ * Subscribe the Thread interface to a Network Interface Multicast Address.
+ *
+ * The passed in instance @p aAddress will be copied by the Thread interface. The Thread interface only
+ * supports a fixed number of externally added multicast addresses. See OPENTHREAD_CONFIG_MAX_EXT_MULTICAST_IP_ADDRS.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aAddress  A pointer to an IP Address.
+ *
+ * @retval kThreadErrorNone          Successfully subscribed to the Network Interface Multicast Address.
+ * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is invalid address.
+ * @retval kThreadError_NoBufs       The Network Interface is already storing the maximum allowed external multicast addresses.
+ */
+ThreadError otIp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress);
+
+/**
+ * Unsubscribe the Thread interface to a Network Interface Multicast Address.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aAddress  A pointer to an IP Address.
+ *
+ * @retval kThreadErrorNone          Successfully unsubscribed to the Network Interface Multicast Address.
+ * @retval kThreadError_InvalidArgs  The IP Address indicated by @p aAddress is an internal address.
+ * @retval kThreadError_NotFound     The IP Address indicated by @p aAddress was not found.
+ */
+ThreadError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress);
+
+/**
+ * Get the list of IPv6 multicast addresses subscribed to the Thread interface.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ *
+ * @returns A pointer to the first Network Interface Multicast Address.
+ */
+const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance);
+
+/**
+ * Check if multicast promiscuous mode is enabled on the Thread interface.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ *
+ * @sa otIp6SetMulticastPromiscuousEnabled
+ */
+bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance);
+
+/**
+ * Enable multicast promiscuous mode on the Thread interface.
+ *
+ * @param[in]  aInstance  A pointer to an OpenThread instance.
+ * @param[in]  aEnabled   TRUE to enable Multicast Promiscuous mode, FALSE otherwise.
+ *
+ * @sa otIp6IsMulticastPromiscuousEnabled
+ */
+void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled);
+
+/**
+ * This function pointer is called to create IPv6 IID during SLAAC procedure.
+ *
+ * @param[in]     aInstance  A pointer to an OpenThread instance.
+ * @param[inout]  aAddress   A pointer to structure containing IPv6 address for which IID is being created.
+ * @param[inout]  aContext   A pointer to creator-specific context.
+ *
+ * @retval kThreadError_None                        Created valid IID for given IPv6 address.
+ * @retval kThreadError_Ipv6AddressCreationFailure  Creation of valid IID for given IPv6 address failed.
+ *
+ */
+typedef ThreadError(*otIp6SlaacIidCreate)(otInstance *aInstance, otNetifAddress *aAddress, void *aContext);
+
+/**
+ * Update all automatically created IPv6 addresses for prefixes from current Network Data with SLAAC procedure.
+ *
+ * @param[in]     aInstance      A pointer to an OpenThread instance.
+ * @param[inout]  aAddresses     A pointer to an array of automatically created IPv6 addresses.
+ * @param[in]     aNumAddresses  The number of slots in aAddresses array.
+ * @param[in]     aIidCreate     A pointer to a function that is called to create IPv6 IIDs.
+ * @param[in]     aContext       A pointer to data passed to aIidCreate function.
+ *
+ */
+void otIp6SlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses,
+                      otIp6SlaacIidCreate aIidCreate, void *aContext);
+
+/**
+ * Create random IID for given IPv6 address.
+ *
+ * @param[in]     aInstance   A pointer to an OpenThread instance.
+ * @param[inout]  aAddresses  A pointer to structure containing IPv6 address for which IID is being created.
+ * @param[in]     aContext    A pointer to unused data.
+ *
+ * @retval kThreadError_None  Created valid IID for given IPv6 address.
+ *
+ */
+ThreadError otIp6CreateRandomIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
+
+/**
+ * Create IID for given IPv6 address using extended MAC address.
+ *
+ * @param[in]     aInstance   A pointer to an OpenThread instance.
+ * @param[inout]  aAddresses  A pointer to structure containing IPv6 address for which IID is being created.
+ * @param[in]     aContext    A pointer to unused data.
+ *
+ * @retval kThreadError_None  Created valid IID for given IPv6 address.
+ *
+ */
+ThreadError otIp6CreateMacIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
+
+/**
+ * Create semantically opaque IID for given IPv6 address.
+ *
+ * @param[in]     aInstance   A pointer to an OpenThread instance.
+ * @param[inout]  aAddresses  A pointer to structure containing IPv6 address for which IID is being created.
+ * @param[inout]  aContext    A pointer to a otSemanticallyOpaqueIidGeneratorData structure.
+ *
+ * @retval kThreadError_None                        Created valid IID for given IPv6 address.
+ * @retval kThreadError_Ipv6AddressCreationFailure  Could not create valid IID for given IPv6 address.
+ *
+ */
+ThreadError otIp6CreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddresses, void *aContext);
+
+/**
+ * Allocate a new message buffer for sending an IPv6 message.
+ *
+ * @param[in]  aInstance             A pointer to an OpenThread instance.
+ * @param[in]  aLinkSecurityEnabled  TRUE if the message should be secured at Layer 2
+ *
+ * @returns A pointer to the message buffer or NULL if no message buffers are available.
+ *
+ * @sa otFreeMessage
+ */
+otMessage otIp6NewMessage(otInstance *aInstance, bool aLinkSecurityEnabled);
+
+/**
+ * This function pointer is called when an IPv6 datagram is received.
+ *
+ * @param[in]  aMessage  A pointer to the message buffer containing the received IPv6 datagram.
+ * @param[in]  aContext  A pointer to application-specific context.
+ *
+ */
+typedef void (*otIp6ReceiveCallback)(otMessage aMessage, void *aContext);
+
+/**
+ * This function registers a callback to provide received IPv6 datagrams.
+ *
+ * By default, this callback does not pass Thread control traffic.  See otIp6SetReceiveFilterEnabled() to
+ * change the Thread control traffic filter setting.
+ *
+ * @param[in]  aInstance         A pointer to an OpenThread instance.
+ * @param[in]  aCallback         A pointer to a function that is called when an IPv6 datagram is received or
+ *                               NULL to disable the callback.
+ * @param[in]  aCallbackContext  A pointer to application-specific context.
+ *
+ * @sa otIp6IsReceiveFilterEnabled
+ * @sa otIp6SetReceiveFilterEnabled
+ *
+ */
+void otIp6SetReceiveCallback(otInstance *aInstance, otIp6ReceiveCallback aCallback, void *aCallbackContext);
+
+/**
+ * This function indicates whether or not Thread control traffic is filtered out when delivering IPv6 datagrams
+ * via the callback specified in otIp6SetReceiveCallback().
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ *
+ * @returns  TRUE if Thread control traffic is filtered out, FALSE otherwise.
+ *
+ * @sa otIp6SetReceiveCallback
+ * @sa otIp6SetReceiveFilterEnabled
+ *
+ */
+bool otIp6IsReceiveFilterEnabled(otInstance *aInstance);
+
+/**
+ * This function sets whether or not Thread control traffic is filtered out when delivering IPv6 datagrams
+ * via the callback specified in otIp6SetReceiveCallback().
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aEnabled  TRUE if Thread control traffic is filtered out, FALSE otherwise.
+ *
+ * @sa otIp6SetReceiveCallback
+ * @sa otIsReceiveIp6FilterEnabled
+ *
+ */
+void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled);
+
+/**
+ * This function sends an IPv6 datagram via the Thread interface.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aMessage  A pointer to the message buffer containing the IPv6 datagram.
+ *
+ */
+ThreadError otIp6Send(otInstance *aInstance, otMessage aMessage);
+
+/**
+ * This function adds a port to the allowed unsecured port list.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aPort     The port value.
+ *
+ * @retval kThreadError_None    The port was successfully added to the allowed unsecure port list.
+ * @retval kThreadError_NoBufs  The unsecure port list is full.
+ *
+ */
+ThreadError otIp6AddUnsecurePort(otInstance *aInstance, uint16_t aPort);
+
+/**
+ * This function removes a port from the allowed unsecure port list.
+ *
+ * @param[in]  aInstance A pointer to an OpenThread instance.
+ * @param[in]  aPort     The port value.
+ *
+ * @retval kThreadError_None      The port was successfully removed from the allowed unsecure port list.
+ * @retval kThreadError_NotFound  The port was not found in the unsecure port list.
+ *
+ */
+ThreadError otIp6RemoveUnsecurePort(otInstance *aInstance, uint16_t aPort);
+
+/**
+ * This function returns a pointer to the unsecure port list.
+ *
+ * @note Port value 0 is used to indicate an invalid entry.
+ *
+ * @param[in]   aInstance    A pointer to an OpenThread instance.
+ * @param[out]  aNumEntries  The number of entries in the list.
+ *
+ * @returns A pointer to the unsecure port list.
+ *
+ */
+const uint16_t *otIp6GetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries);
+
+/**
+ * Test if two IPv6 addresses are the same.
+ *
+ * @param[in]  a  A pointer to the first IPv6 address to compare.
+ * @param[in]  b  A pointer to the second IPv6 address to compare.
+ *
+ * @retval TRUE   The two IPv6 addresses are the same.
+ * @retval FALSE  The two IPv6 addresses are not the same.
+ */
+OTAPI bool OTCALL otIp6IsAddressEqual(const otIp6Address *a, const otIp6Address *b);
+
+/**
+ * Convert a human-readable IPv6 address string into a binary representation.
+ *
+ * @param[in]   aString   A pointer to a NULL-terminated string.
+ * @param[out]  aAddress  A pointer to an IPv6 address.
+ *
+ * @retval kThreadErrorNone        Successfully parsed the string.
+ * @retval kThreadErrorInvalidArg  Failed to parse the string.
+ */
+OTAPI ThreadError OTCALL otIp6AddressFromString(const char *aString, otIp6Address *aAddress);
+
+/**
+ * This function returns the prefix match length (bits) for two IPv6 addresses.
+ *
+ * @param[in]  aFirst   A pointer to the first IPv6 address.
+ * @param[in]  aSecond  A pointer to the second IPv6 address.
+ *
+ * @returns  The prefix match length in bits.
+ *
+ */
+OTAPI uint8_t OTCALL otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond);
+
+/**
+ * @}
+ *
+ */
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // OPENTHREAD_IP6_H_
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index 6622672..b5a3d66 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -839,7 +839,7 @@
 
     if (argc == 0)
     {
-        if (otIsInterfaceUp(mInstance))
+        if (otIp6IsEnabled(mInstance))
         {
             sServer->OutputFormat("up\r\n");
         }
@@ -850,11 +850,11 @@
     }
     else if (strcmp(argv[0], "up") == 0)
     {
-        SuccessOrExit(error = otInterfaceUp(mInstance));
+        SuccessOrExit(error = otIp6SetEnabled(mInstance, true));
     }
     else if (strcmp(argv[0], "down") == 0)
     {
-        SuccessOrExit(error = otInterfaceDown(mInstance));
+        SuccessOrExit(error = otIp6SetEnabled(mInstance, false));
     }
 
 exit:
@@ -872,7 +872,7 @@
     aAddress.mPrefixLength = 64;
     aAddress.mPreferred = true;
     aAddress.mValid = true;
-    error = otAddUnicastAddress(mInstance, &aAddress);
+    error = otIp6AddUnicastAddress(mInstance, &aAddress);
 
 exit:
     return error;
@@ -886,7 +886,7 @@
     VerifyOrExit(argc > 0, error = kThreadError_Parse);
 
     SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
-    error = otRemoveUnicastAddress(mInstance, &address);
+    error = otIp6RemoveUnicastAddress(mInstance, &address);
 
 exit:
     return error;
@@ -898,7 +898,7 @@
 
     if (argc == 0)
     {
-        otNetifAddressPtr unicastAddrs(otGetUnicastAddresses(mInstance));
+        otNetifAddressPtr unicastAddrs(otIp6GetUnicastAddresses(mInstance));
 
         for (const otNetifAddress *addr = unicastAddrs; addr; addr = addr->mNext)
         {
@@ -938,7 +938,7 @@
     VerifyOrExit(argc > 0, error = kThreadError_Parse);
 
     SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
-    error = otSubscribeMulticastAddress(mInstance, &address);
+    error = otIp6SubscribeMulticastAddress(mInstance, &address);
 
 exit:
     return error;
@@ -952,7 +952,7 @@
     VerifyOrExit(argc > 0, error = kThreadError_Parse);
 
     SuccessOrExit(error = otIp6AddressFromString(argv[0], &address));
-    error = otUnsubscribeMulticastAddress(mInstance, &address);
+    error = otIp6UnsubscribeMulticastAddress(mInstance, &address);
 
 exit:
     return error;
@@ -964,7 +964,7 @@
 
     if (argc == 0)
     {
-        if (otIsMulticastPromiscuousModeEnabled(mInstance))
+        if (otIp6IsMulticastPromiscuousEnabled(mInstance))
         {
             sServer->OutputFormat("Enabled\r\n");
         }
@@ -977,11 +977,11 @@
     {
         if (strcmp(argv[0], "enable") == 0)
         {
-            otEnableMulticastPromiscuousMode(mInstance);
+            otIp6SetMulticastPromiscuousEnabled(mInstance, true);
         }
         else if (strcmp(argv[0], "disable") == 0)
         {
-            otDisableMulticastPromiscuousMode(mInstance);
+            otIp6SetMulticastPromiscuousEnabled(mInstance, false);
         }
         else
         {
@@ -999,7 +999,7 @@
 
     if (argc == 0)
     {
-        for (const otNetifMulticastAddress *addr = otGetMulticastAddresses(mInstance); addr; addr = addr->mNext)
+        for (const otNetifMulticastAddress *addr = otIp6GetMulticastAddresses(mInstance); addr; addr = addr->mNext)
         {
             sServer->OutputFormat("%x:%x:%x:%x:%x:%x:%x:%x\r\n",
                                   HostSwap16(addr->mAddress.mFields.m16[0]),
@@ -1442,7 +1442,7 @@
     otMessage message;
     const otMessageInfo *messageInfo = static_cast<const otMessageInfo *>(&sMessageInfo);
 
-    VerifyOrExit((message = otNewIp6Message(mInstance, true)) != NULL, error = kThreadError_NoBufs);
+    VerifyOrExit((message = otIp6NewMessage(mInstance, true)) != NULL, error = kThreadError_NoBufs);
     SuccessOrExit(error = otMessageAppend(message, &timestamp, sizeof(timestamp)));
     SuccessOrExit(error = otMessageSetLength(message, sLength));
     SuccessOrExit(error = otIcmp6SendEchoRequest(mInstance, message, messageInfo, 1));
@@ -2796,8 +2796,8 @@
     VerifyOrExit((aFlags & OT_THREAD_NETDATA_UPDATED) != 0, ;);
 
 #ifndef OTDLL
-    otSlaacUpdate(mInstance, mSlaacAddresses, sizeof(mSlaacAddresses) / sizeof(mSlaacAddresses[0]), otCreateRandomIid,
-                  NULL);
+    otIp6SlaacUpdate(mInstance, mSlaacAddresses, sizeof(mSlaacAddresses) / sizeof(mSlaacAddresses[0]),
+                     otIp6CreateRandomIid, NULL);
 #if OPENTHREAD_ENABLE_DHCP6_SERVER
     otDhcp6ServerUpdate(mInstance);
 #endif  // OPENTHREAD_ENABLE_DHCP6_SERVER
diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp
index af97404..8f31c47 100644
--- a/src/cli/cli.hpp
+++ b/src/cli/cli.hpp
@@ -42,7 +42,7 @@
 #include <openthread.h>
 
 #include <stdarg.h>
-#include <openthread-ip6.h>
+#include "openthread/ip6.h"
 #include "openthread/udp.h"
 
 #include <cli/cli_server.hpp>
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index a7c7fe5..1f2a49b 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -41,6 +41,7 @@
 SOURCES_COMMON                      = \
     openthread.cpp                    \
     api/crypto_api.cpp                \
+    api/ip6_api.cpp                   \
     api/message_api.cpp               \
     api/tasklet_api.cpp               \
     api/udp_api.cpp                   \
diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp
new file mode 100644
index 0000000..b4adf73
--- /dev/null
+++ b/src/core/api/ip6_api.cpp
@@ -0,0 +1,226 @@
+/*
+ *  Copyright (c) 2016, The OpenThread Authors.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ *   This file implements the OpenThread UDP API.
+ */
+
+#define WPP_NAME "ip6_api.tmh"
+
+#include "openthread/ip6.h"
+
+#include "openthread-instance.h"
+#include "common/logging.hpp"
+#include "utils/slaac_address.hpp"
+
+using namespace Thread;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ThreadError otIp6SetEnabled(otInstance *aInstance, bool aEnabled)
+{
+    ThreadError error = kThreadError_None;
+
+    otLogFuncEntry();
+
+    if (aEnabled)
+    {
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+        VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState);
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+        error = aInstance->mThreadNetif.Up();
+    }
+    else
+    {
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+        VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState);
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+        error = aInstance->mThreadNetif.Down();
+    }
+
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+exit:
+#endif // OPENTHREAD_ENABLE_RAW_LINK_API
+    otLogFuncExitErr(error);
+    return error;
+}
+
+bool otIp6IsEnabled(otInstance *aInstance)
+{
+    return aInstance->mThreadNetif.IsUp();
+}
+
+const otNetifAddress *otIp6GetUnicastAddresses(otInstance *aInstance)
+{
+    return aInstance->mThreadNetif.GetUnicastAddresses();
+}
+
+ThreadError otIp6AddUnicastAddress(otInstance *aInstance, const otNetifAddress *address)
+{
+    return aInstance->mThreadNetif.AddExternalUnicastAddress(*static_cast<const Ip6::NetifUnicastAddress *>(address));
+}
+
+ThreadError otIp6RemoveUnicastAddress(otInstance *aInstance, const otIp6Address *address)
+{
+    return aInstance->mThreadNetif.RemoveExternalUnicastAddress(*static_cast<const Ip6::Address *>(address));
+}
+
+const otNetifMulticastAddress *otIp6GetMulticastAddresses(otInstance *aInstance)
+{
+    return aInstance->mThreadNetif.GetMulticastAddresses();
+}
+
+ThreadError otIp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
+{
+    return aInstance->mThreadNetif.SubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
+}
+
+ThreadError otIp6UnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
+{
+    return aInstance->mThreadNetif.UnsubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
+}
+
+bool otIp6IsMulticastPromiscuousEnabled(otInstance *aInstance)
+{
+    return aInstance->mThreadNetif.IsMulticastPromiscuousEnabled();
+}
+
+void otIp6SetMulticastPromiscuousEnabled(otInstance *aInstance, bool aEnabled)
+{
+    aInstance->mThreadNetif.SetMulticastPromiscuous(aEnabled);
+}
+
+void otIp6SlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses,
+                      otIp6SlaacIidCreate aIidCreate, void *aContext)
+{
+    Utils::Slaac::UpdateAddresses(aInstance, aAddresses, aNumAddresses, aIidCreate, aContext);
+}
+
+ThreadError otIp6CreateRandomIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext)
+{
+    return Utils::Slaac::CreateRandomIid(aInstance, aAddress, aContext);
+}
+
+ThreadError otIp6CreateMacIid(otInstance *aInstance, otNetifAddress *aAddress, void *)
+{
+    memcpy(&aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE],
+           aInstance->mThreadNetif.GetMac().GetExtAddress(), OT_IP6_IID_SIZE);
+    aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE] ^= 0x02;
+
+    return kThreadError_None;
+}
+
+ThreadError otIp6CreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext)
+{
+    return static_cast<Utils::SemanticallyOpaqueIidGenerator *>(aContext)->CreateIid(aInstance, aAddress);
+}
+
+void otIp6SetReceiveCallback(otInstance *aInstance, otIp6ReceiveCallback aCallback, void *aCallbackContext)
+{
+    aInstance->mIp6.SetReceiveDatagramCallback(aCallback, aCallbackContext);
+}
+
+bool otIp6IsReceiveFilterEnabled(otInstance *aInstance)
+{
+    return aInstance->mIp6.IsReceiveIp6FilterEnabled();
+}
+
+void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled)
+{
+    aInstance->mIp6.SetReceiveIp6FilterEnabled(aEnabled);
+}
+
+ThreadError otIp6Send(otInstance *aInstance, otMessage aMessage)
+{
+    ThreadError error;
+
+    otLogFuncEntry();
+
+    error = aInstance->mIp6.HandleDatagram(*static_cast<Message *>(aMessage), NULL,
+                                           aInstance->mThreadNetif.GetInterfaceId(), NULL, true);
+
+    otLogFuncExitErr(error);
+
+    return error;
+}
+
+otMessage otIp6NewMessage(otInstance *aInstance, bool aLinkSecurityEnabled)
+{
+    Message *message = aInstance->mIp6.mMessagePool.New(Message::kTypeIp6, 0);
+
+    if (message)
+    {
+        message->SetLinkSecurityEnabled(aLinkSecurityEnabled);
+    }
+
+    return message;
+}
+
+ThreadError otIp6AddUnsecurePort(otInstance *aInstance, uint16_t aPort)
+{
+    return aInstance->mThreadNetif.GetIp6Filter().AddUnsecurePort(aPort);
+}
+
+ThreadError otIp6RemoveUnsecurePort(otInstance *aInstance, uint16_t aPort)
+{
+    return aInstance->mThreadNetif.GetIp6Filter().RemoveUnsecurePort(aPort);
+}
+
+const uint16_t *otIp6GetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries)
+{
+    return aInstance->mThreadNetif.GetIp6Filter().GetUnsecurePorts(*aNumEntries);
+}
+
+bool otIp6IsAddressEqual(const otIp6Address *a, const otIp6Address *b)
+{
+    return *static_cast<const Ip6::Address *>(a) == *static_cast<const Ip6::Address *>(b);
+}
+
+ThreadError otIp6AddressFromString(const char *str, otIp6Address *address)
+{
+    return static_cast<Ip6::Address *>(address)->FromString(str);
+}
+
+uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond)
+{
+    uint8_t rval;
+
+    VerifyOrExit(aFirst != NULL && aSecond != NULL, rval = 0);
+
+    rval = static_cast<const Ip6::Address *>(aFirst)->PrefixMatch(*static_cast<const Ip6::Address *>(aSecond));
+
+exit:
+    return rval;
+}
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/src/core/net/dhcp6_client.cpp b/src/core/net/dhcp6_client.cpp
index e7e0b88..ad79744 100644
--- a/src/core/net/dhcp6_client.cpp
+++ b/src/core/net/dhcp6_client.cpp
@@ -113,7 +113,7 @@
 
         if (!found)
         {
-            otRemoveUnicastAddress(aInstance, &(address->mAddress.mAddress));
+            otIp6RemoveUnicastAddress(aInstance, &(address->mAddress.mAddress));
             RemoveIdentityAssociation(config.mRloc16, config.mPrefix);
             memset(address, 0, sizeof(*address));
         }
@@ -688,7 +688,7 @@
             address->mValidLifetime = option.GetValidLifetime();
             address->mAddress.mPreferred = address->mPreferredLifetime != 0;
             address->mAddress.mValid = address->mValidLifetime != 0;
-            otAddUnicastAddress(mNetif.GetInstance(), &address->mAddress);
+            otIp6AddUnicastAddress(mNetif.GetInstance(), &address->mAddress);
             break;
         }
     }
diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp
index 0bcc36a..f1e3849 100644
--- a/src/core/net/ip6.cpp
+++ b/src/core/net/ip6.cpp
@@ -113,7 +113,7 @@
     return checksum;
 }
 
-void Ip6::SetReceiveDatagramCallback(otReceiveIp6DatagramCallback aCallback, void *aCallbackContext)
+void Ip6::SetReceiveDatagramCallback(otIp6ReceiveCallback aCallback, void *aCallbackContext)
 {
     mReceiveIp6DatagramCallback = aCallback;
     mReceiveIp6DatagramCallbackContext = aCallbackContext;
@@ -696,7 +696,7 @@
             {
                 receive = true;
             }
-            else if (netif->IsMulticastPromiscuousModeEnabled())
+            else if (netif->IsMulticastPromiscuousEnabled())
             {
                 multicastPromiscuous = true;
             }
diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp
index 22d926a..762024a 100644
--- a/src/core/net/ip6.hpp
+++ b/src/core/net/ip6.hpp
@@ -36,7 +36,7 @@
 
 #include <stddef.h>
 
-#include <openthread-ip6.h>
+#include "openthread/ip6.h"
 #include "openthread/udp.h"
 
 #include <common/encoding.hpp>
@@ -218,7 +218,7 @@
      * @sa SetReceiveIp6FilterEnabled
      *
      */
-    void SetReceiveDatagramCallback(otReceiveIp6DatagramCallback aCallback, void *aCallbackContext);
+    void SetReceiveDatagramCallback(otIp6ReceiveCallback aCallback, void *aCallbackContext);
 
     /**
      * This method indicates whether or not Thread control traffic is filtered out when delivering IPv6 datagrams
@@ -377,7 +377,7 @@
     PriorityQueue mSendQueue;
     Tasklet mSendQueueTask;
 
-    otReceiveIp6DatagramCallback mReceiveIp6DatagramCallback;
+    otIp6ReceiveCallback mReceiveIp6DatagramCallback;
     void *mReceiveIp6DatagramCallbackContext;
     bool mIsReceiveIp6FilterEnabled;
 
diff --git a/src/core/net/netif.cpp b/src/core/net/netif.cpp
index cd6895c..56dd97c 100644
--- a/src/core/net/netif.cpp
+++ b/src/core/net/netif.cpp
@@ -47,7 +47,7 @@
     mMulticastAddresses(NULL),
     mInterfaceId(aInterfaceId),
     mAllRoutersSubscribed(false),
-    mMulticastPromiscuousMode(false),
+    mMulticastPromiscuous(false),
     mStateChangedTask(aIp6.mTaskletScheduler, &Netif::HandleStateChangedTask, this),
     mNext(NULL),
     mStateChangedFlags(0)
@@ -305,19 +305,14 @@
     }
 }
 
-bool Netif::IsMulticastPromiscuousModeEnabled(void)
+bool Netif::IsMulticastPromiscuousEnabled(void)
 {
-    return mMulticastPromiscuousMode;
+    return mMulticastPromiscuous;
 }
 
-void Netif::EnableMulticastPromiscuousMode(void)
+void Netif::SetMulticastPromiscuous(bool aEnabled)
 {
-    mMulticastPromiscuousMode = true;
-}
-
-void Netif::DisableMulticastPromiscuousMode(void)
-{
-    mMulticastPromiscuousMode = false;
+    mMulticastPromiscuous = aEnabled;
 }
 
 const NetifUnicastAddress *Netif::GetUnicastAddresses() const
diff --git a/src/core/net/netif.hpp b/src/core/net/netif.hpp
index c2508f6..917b232 100644
--- a/src/core/net/netif.hpp
+++ b/src/core/net/netif.hpp
@@ -447,19 +447,15 @@
      * @retval TRUE   If the multicast promiscuous mode is enabled.
      * @retval FALSE  If the multicast promiscuous mode is disabled.
      */
-    bool IsMulticastPromiscuousModeEnabled(void);
+    bool IsMulticastPromiscuousEnabled(void);
 
     /**
      * This method enables multicast promiscuous mode on the network interface.
      *
-     */
-    void EnableMulticastPromiscuousMode(void);
-
-    /**
-     * This method disables multicast promiscuous mode on the network interface.
+     * @param[in]  aEnabled  TRUE if Multicast Promiscuous mode is enabled, FALSE otherwise.
      *
      */
-    void DisableMulticastPromiscuousMode(void);
+    void SetMulticastPromiscuous(bool aEnabled);
 
     /**
      * This method registers a network interface callback.
@@ -545,7 +541,7 @@
     NetifMulticastAddress *mMulticastAddresses;
     int8_t mInterfaceId;
     bool mAllRoutersSubscribed;
-    bool mMulticastPromiscuousMode;
+    bool mMulticastPromiscuous;
     Tasklet mStateChangedTask;
     Netif *mNext;
 
diff --git a/src/core/openthread-instance.h b/src/core/openthread-instance.h
index 88b1486..9f08318 100644
--- a/src/core/openthread-instance.h
+++ b/src/core/openthread-instance.h
@@ -59,7 +59,7 @@
 
     Thread::Ip6::NetifCallback mNetifCallback[OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS];
 
-    otReceiveIp6DatagramCallback mReceiveIp6DatagramCallback;
+    otIp6ReceiveCallback mReceiveIp6DatagramCallback;
     void *mReceiveIp6DatagramCallbackContext;
 
     otHandleActiveScanResult mActiveScanCallback;
diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp
index ea52bb3..0934744 100644
--- a/src/core/openthread.cpp
+++ b/src/core/openthread.cpp
@@ -57,7 +57,6 @@
 #include <platform/misc.h>
 #include <thread/thread_netif.hpp>
 #include <thread/thread_uris.hpp>
-#include <utils/slaac_address.hpp>
 #include <openthread-instance.h>
 #include <coap/coap_server.hpp>
 
@@ -468,21 +467,6 @@
     return aInstance->mThreadNetif.GetNetworkDataLocal().SendServerDataNotification();
 }
 
-ThreadError otAddUnsecurePort(otInstance *aInstance, uint16_t aPort)
-{
-    return aInstance->mThreadNetif.GetIp6Filter().AddUnsecurePort(aPort);
-}
-
-ThreadError otRemoveUnsecurePort(otInstance *aInstance, uint16_t aPort)
-{
-    return aInstance->mThreadNetif.GetIp6Filter().RemoveUnsecurePort(aPort);
-}
-
-const uint16_t *otGetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries)
-{
-    return aInstance->mThreadNetif.GetIp6Filter().GetUnsecurePorts(*aNumEntries);
-}
-
 uint32_t otGetContextIdReuseDelay(otInstance *aInstance)
 {
     return aInstance->mThreadNetif.GetNetworkDataLeader().GetContextIdReuseDelay();
@@ -951,86 +935,6 @@
     return &aInstance->mThreadNetif.GetMac().GetCounters();
 }
 
-bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b)
-{
-    return *static_cast<const Ip6::Address *>(a) == *static_cast<const Ip6::Address *>(b);
-}
-
-ThreadError otIp6AddressFromString(const char *str, otIp6Address *address)
-{
-    return static_cast<Ip6::Address *>(address)->FromString(str);
-}
-
-const otNetifAddress *otGetUnicastAddresses(otInstance *aInstance)
-{
-    return aInstance->mThreadNetif.GetUnicastAddresses();
-}
-
-ThreadError otAddUnicastAddress(otInstance *aInstance, const otNetifAddress *address)
-{
-    return aInstance->mThreadNetif.AddExternalUnicastAddress(*static_cast<const Ip6::NetifUnicastAddress *>(address));
-}
-
-ThreadError otRemoveUnicastAddress(otInstance *aInstance, const otIp6Address *address)
-{
-    return aInstance->mThreadNetif.RemoveExternalUnicastAddress(*static_cast<const Ip6::Address *>(address));
-}
-
-const otNetifMulticastAddress *otGetMulticastAddresses(otInstance *aInstance)
-{
-    return aInstance->mThreadNetif.GetMulticastAddresses();
-}
-
-ThreadError otSubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
-{
-    return aInstance->mThreadNetif.SubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
-}
-
-ThreadError otUnsubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aAddress)
-{
-    return aInstance->mThreadNetif.UnsubscribeExternalMulticast(*static_cast<const Ip6::Address *>(aAddress));
-}
-
-bool otIsMulticastPromiscuousModeEnabled(otInstance *aInstance)
-{
-    return aInstance->mThreadNetif.IsMulticastPromiscuousModeEnabled();
-}
-
-void otEnableMulticastPromiscuousMode(otInstance *aInstance)
-{
-    aInstance->mThreadNetif.EnableMulticastPromiscuousMode();
-}
-
-void otDisableMulticastPromiscuousMode(otInstance *aInstance)
-{
-    aInstance->mThreadNetif.DisableMulticastPromiscuousMode();
-}
-
-void otSlaacUpdate(otInstance *aInstance, otNetifAddress *aAddresses, uint32_t aNumAddresses,
-                   otSlaacIidCreate aIidCreate, void *aContext)
-{
-    Utils::Slaac::UpdateAddresses(aInstance, aAddresses, aNumAddresses, aIidCreate, aContext);
-}
-
-ThreadError otCreateRandomIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext)
-{
-    return Utils::Slaac::CreateRandomIid(aInstance, aAddress, aContext);
-}
-
-ThreadError otCreateMacIid(otInstance *aInstance, otNetifAddress *aAddress, void *)
-{
-    memcpy(&aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE],
-           aInstance->mThreadNetif.GetMac().GetExtAddress(), OT_IP6_IID_SIZE);
-    aAddress->mAddress.mFields.m8[OT_IP6_ADDRESS_SIZE - OT_IP6_IID_SIZE] ^= 0x02;
-
-    return kThreadError_None;
-}
-
-ThreadError otCreateSemanticallyOpaqueIid(otInstance *aInstance, otNetifAddress *aAddress, void *aContext)
-{
-    return static_cast<Utils::SemanticallyOpaqueIidGenerator *>(aContext)->CreateIid(aInstance, aAddress);
-}
-
 ThreadError otSetStateChangedCallback(otInstance *aInstance, otStateChangedCallback aCallback, void *aCallbackContext)
 {
     ThreadError error = kThreadError_NoBufs;
@@ -1126,13 +1030,13 @@
     // If auto start is configured, do that now
     if (otThreadGetAutoStart(aInstance))
     {
-        if (otInterfaceUp(aInstance) == kThreadError_None)
+        if (otIp6SetEnabled(aInstance, true) == kThreadError_None)
         {
             // Only try to start Thread if we could bring up the interface
             if (otThreadStart(aInstance) != kThreadError_None)
             {
                 // Bring the interface down if Thread failed to start
-                otInterfaceDown(aInstance);
+                otIp6SetEnabled(aInstance, false);
             }
         }
     }
@@ -1223,7 +1127,7 @@
 
     // Ensure we are disabled
     (void)otThreadStop(aInstance);
-    (void)otInterfaceDown(aInstance);
+    (void)otIp6SetEnabled(aInstance, false);
 
 #ifndef OPENTHREAD_MULTIPLE_INSTANCE
     sInstance = NULL;
@@ -1231,49 +1135,6 @@
     otLogFuncExit();
 }
 
-ThreadError otInterfaceUp(otInstance *aInstance)
-{
-    ThreadError error = kThreadError_None;
-
-    otLogFuncEntry();
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-    VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState);
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-    error = aInstance->mThreadNetif.Up();
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-exit:
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-    otLogFuncExitErr(error);
-    return error;
-}
-
-ThreadError otInterfaceDown(otInstance *aInstance)
-{
-    ThreadError error = kThreadError_None;
-
-    otLogFuncEntry();
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-    VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState);
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-
-    error = aInstance->mThreadNetif.Down();
-
-#if OPENTHREAD_ENABLE_RAW_LINK_API
-exit:
-#endif // OPENTHREAD_ENABLE_RAW_LINK_API
-    otLogFuncExitErr(error);
-    return error;
-}
-
-bool otIsInterfaceUp(otInstance *aInstance)
-{
-    return aInstance->mThreadNetif.IsUp();
-}
-
 ThreadError otThreadStart(otInstance *aInstance)
 {
     ThreadError error = kThreadError_None;
@@ -1429,48 +1290,6 @@
     return aInstance->mThreadNetif.GetMeshForwarder().SendMacDataRequest();
 }
 
-void otSetReceiveIp6DatagramCallback(otInstance *aInstance, otReceiveIp6DatagramCallback aCallback,
-                                     void *aCallbackContext)
-{
-    aInstance->mIp6.SetReceiveDatagramCallback(aCallback, aCallbackContext);
-}
-
-bool otIsReceiveIp6DatagramFilterEnabled(otInstance *aInstance)
-{
-    return aInstance->mIp6.IsReceiveIp6FilterEnabled();
-}
-
-void otSetReceiveIp6DatagramFilterEnabled(otInstance *aInstance, bool aEnabled)
-{
-    aInstance->mIp6.SetReceiveIp6FilterEnabled(aEnabled);
-}
-
-ThreadError otSendIp6Datagram(otInstance *aInstance, otMessage aMessage)
-{
-    ThreadError error;
-
-    otLogFuncEntry();
-
-    error = aInstance->mIp6.HandleDatagram(*static_cast<Message *>(aMessage), NULL,
-                                           aInstance->mThreadNetif.GetInterfaceId(), NULL, true);
-
-    otLogFuncExitErr(error);
-
-    return error;
-}
-
-otMessage otNewIp6Message(otInstance *aInstance, bool aLinkSecurityEnabled)
-{
-    Message *message = aInstance->mIp6.mMessagePool.New(Message::kTypeIp6, 0);
-
-    if (message)
-    {
-        message->SetLinkSecurityEnabled(aLinkSecurityEnabled);
-    }
-
-    return message;
-}
-
 bool otIcmp6IsEchoEnabled(otInstance *aInstance)
 {
     return aInstance->mIp6.mIcmp.IsEchoEnabled();
@@ -1494,18 +1313,6 @@
                                                  aIdentifier);
 }
 
-uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond)
-{
-    uint8_t rval;
-
-    VerifyOrExit(aFirst != NULL && aSecond != NULL, rval = 0);
-
-    rval = static_cast<const Ip6::Address *>(aFirst)->PrefixMatch(*static_cast<const Ip6::Address *>(aSecond));
-
-exit:
-    return rval;
-}
-
 ThreadError otGetActiveDataset(otInstance *aInstance, otOperationalDataset *aDataset)
 {
     ThreadError error = kThreadError_None;
diff --git a/src/core/utils/slaac_address.cpp b/src/core/utils/slaac_address.cpp
index a0f814d..3502476 100644
--- a/src/core/utils/slaac_address.cpp
+++ b/src/core/utils/slaac_address.cpp
@@ -87,7 +87,7 @@
 
         if (!found)
         {
-            otRemoveUnicastAddress(aInstance, &address->mAddress);
+            otIp6RemoveUnicastAddress(aInstance, &address->mAddress);
             address->mValid = false;
         }
     }
@@ -144,7 +144,7 @@
                     CreateRandomIid(aInstance, address, aContext);
                 }
 
-                otAddUnicastAddress(aInstance, address);
+                otIp6AddUnicastAddress(aInstance, address);
                 break;
             }
         }
@@ -217,7 +217,7 @@
 bool SemanticallyOpaqueIidGenerator::IsAddressRegistered(otInstance *aInstance, otNetifAddress *aCreatedAddress)
 {
     bool result = false;
-    const otNetifAddress *address = otGetUnicastAddresses(aInstance);
+    const otNetifAddress *address = otIp6GetUnicastAddresses(aInstance);
 
     while (address != NULL)
     {
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 76bb099..e56fd3a 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -535,10 +535,10 @@
     sNcpContext = this;
 
     otSetStateChangedCallback(mInstance, &NcpBase::HandleNetifStateChanged, this);
-    otSetReceiveIp6DatagramCallback(mInstance, &NcpBase::HandleDatagramFromStack, this);
+    otIp6SetReceiveCallback(mInstance, &NcpBase::HandleDatagramFromStack, this);
     otSetLinkPcapCallback(mInstance, &NcpBase::HandleRawFrame, static_cast<void*>(this));
     otIcmp6SetEchoEnabled(mInstance, false);
-    otSetReceiveIp6DatagramFilterEnabled(mInstance, true);
+    otIp6SetReceiveFilterEnabled(mInstance, true);
 
     mUpdateChangedPropsTask.Post();
 
@@ -1525,7 +1525,7 @@
     // In such a case we fake it.
 
     otThreadStop(mInstance);
-    otInterfaceDown(mInstance);
+    otIp6SetEnabled(mInstance, false);
 
     errorCode = SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_STATUS_RESET_SOFTWARE);
 
@@ -2066,7 +2066,7 @@
                SPINEL_CMD_PROP_VALUE_IS,
                key,
                SPINEL_DATATYPE_BOOL_S,
-               otIsInterfaceUp(mInstance)
+               otIp6IsEnabled(mInstance)
            );
 }
 
@@ -2529,7 +2529,7 @@
 {
     ThreadError errorCode = kThreadError_None;
     uint8_t num_entries = 0;
-    const uint16_t *ports = otGetUnsecurePorts(mInstance, &num_entries);
+    const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &num_entries);
 
     SuccessOrExit(errorCode = OutboundFrameBegin());
     SuccessOrExit(errorCode = OutboundFrameFeedPacked("Cii", header, SPINEL_CMD_PROP_VALUE_IS, key));
@@ -2723,7 +2723,7 @@
     SuccessOrExit(errorCode = OutboundFrameBegin());
     SuccessOrExit(errorCode = OutboundFrameFeedPacked("Cii", header, SPINEL_CMD_PROP_VALUE_IS, key));
 
-    for (const otNetifAddress *address = otGetUnicastAddresses(mInstance); address; address = address->mNext)
+    for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext)
     {
 
         SuccessOrExit(errorCode = OutboundFrameFeedPacked(
@@ -2769,7 +2769,7 @@
                SPINEL_CMD_PROP_VALUE_IS,
                key,
                SPINEL_DATATYPE_BOOL_S,
-	       !otIsReceiveIp6DatagramFilterEnabled(mInstance)
+	       !otIp6IsReceiveFilterEnabled(mInstance)
            );
 }
 
@@ -3985,14 +3985,7 @@
 
     if (parsedLength > 0)
     {
-        if (value == false)
-        {
-            errorCode = otInterfaceDown(mInstance);
-        }
-        else
-        {
-            errorCode = otInterfaceUp(mInstance);
-        }
+	errorCode = otIp6SetEnabled(mInstance, value);
     }
     else
     {
@@ -4337,7 +4330,7 @@
     unsigned int meta_len(0);
 
     // STREAM_NET_INSECURE packets are not secured at layer 2.
-    otMessage message = otNewIp6Message(mInstance, false);
+    otMessage message = otIp6NewMessage(mInstance, false);
 
     if (message == NULL)
     {
@@ -4369,7 +4362,7 @@
         // Ensure the insecure message is forwarded using direct transmission.
         otMessageSetDirectTransmission(message, true);
 
-        errorCode = otSendIp6Datagram(mInstance, message);
+        errorCode = otIp6Send(mInstance, message);
     }
     else if (message)
     {
@@ -4410,7 +4403,7 @@
     unsigned int meta_len(0);
 
     // STREAM_NET requires layer 2 security.
-    otMessage message = otNewIp6Message(mInstance, true);
+    otMessage message = otIp6NewMessage(mInstance, true);
 
     if (message == NULL)
     {
@@ -4439,7 +4432,7 @@
 
     if (errorCode == kThreadError_None)
     {
-        errorCode = otSendIp6Datagram(mInstance, message);
+        errorCode = otIp6Send(mInstance, message);
     }
     else if (message)
     {
@@ -4542,7 +4535,7 @@
     if (parsedLength > 0)
     {
         // Note reverse logic: passthru enabled = filter disabled
-        otSetReceiveIp6DatagramFilterEnabled(mInstance, !isEnabled);
+        otIp6SetReceiveFilterEnabled(mInstance, !isEnabled);
 
         errorCode = HandleCommandPropertyGet(header, key);
     }
@@ -4559,14 +4552,14 @@
 {
     ThreadError errorCode = kThreadError_None;
     uint8_t num_entries = 0;
-    const uint16_t *ports = otGetUnsecurePorts(mInstance, &num_entries);
+    const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &num_entries);
     spinel_ssize_t parsedLength = 1;
     int ports_changed = 0;
 
     // First, we need to remove all of the current assisting ports.
     for (; num_entries != 0; ports++, num_entries--)
     {
-        errorCode = otRemoveUnsecurePort(mInstance, *ports);
+        errorCode = otIp6RemoveUnsecurePort(mInstance, *ports);
 
         if (errorCode != kThreadError_None)
         {
@@ -4592,7 +4585,7 @@
 
         if (parsedLength > 0)
         {
-            errorCode = otAddUnsecurePort(mInstance, port);
+            errorCode = otIp6AddUnsecurePort(mInstance, port);
         }
         else
         {
@@ -5649,7 +5642,7 @@
     netif_addr.mPreferred = preferred_lifetime != 0;
     netif_addr.mValid = valid_lifetime != 0;
 
-    errorCode = otAddUnicastAddress(mInstance, &netif_addr);
+    errorCode = otIp6AddUnicastAddress(mInstance, &netif_addr);
 
     VerifyOrExit(errorCode == kThreadError_None,
                  errorStatus = ThreadErrorToSpinelStatus(errorCode));
@@ -5827,7 +5820,7 @@
 
     if (parsedLength > 0)
     {
-        errorCode = otAddUnsecurePort(mInstance, port);
+        errorCode = otIp6AddUnsecurePort(mInstance, port);
 
         if (errorCode == kThreadError_None)
         {
@@ -6021,7 +6014,7 @@
 
     if (parsedLength > 0)
     {
-        errorCode = otRemoveUnicastAddress(mInstance, addr_ptr);
+        errorCode = otIp6RemoveUnicastAddress(mInstance, addr_ptr);
 
         if (errorCode == kThreadError_None)
         {
@@ -6166,7 +6159,7 @@
 
     if (parsedLength > 0)
     {
-        errorCode = otRemoveUnsecurePort(mInstance, port);
+        errorCode = otIp6RemoveUnsecurePort(mInstance, port);
 
         if (errorCode == kThreadError_None)
         {
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index 9684260..47dcdcc 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -40,8 +40,8 @@
 #endif
 
 #include <openthread-types.h>
+#include "openthread/ip6.h"
 #include "openthread/message.h"
-#include <openthread-ip6.h>
 #include <common/tasklet.hpp>
 #include <ncp/ncp.h>
 #include <ncp/ncp_buffer.hpp>
diff --git a/tests/unit/test_fuzz.cpp b/tests/unit/test_fuzz.cpp
index 27148f8..6576926 100644
--- a/tests/unit/test_fuzz.cpp
+++ b/tests/unit/test_fuzz.cpp
@@ -131,7 +131,7 @@
 
     // Start the Thread network
     otSetPanId(aInstance, (otPanId)0xFACE);
-    otInterfaceUp(aInstance);
+    otIp6SetEnabled(aInstance, true);
     otThreadStart(aInstance);
 
     uint32_t countRecv = 0;
diff --git a/tests/unit/test_message_queue.cpp b/tests/unit/test_message_queue.cpp
index e02d361..83fa49e 100644
--- a/tests/unit/test_message_queue.cpp
+++ b/tests/unit/test_message_queue.cpp
@@ -29,8 +29,8 @@
 #include "test_util.h"
 
 #include <openthread.h>
+#include "openthread/ip6.h"
 #include "openthread/message.h"
-#include <openthread-ip6.h>
 
 #include <common/debug.hpp>
 #include <common/message.hpp>
@@ -213,8 +213,8 @@
 
     for (int i = 0; i < kNumTestMessages; i++)
     {
-        msg[i] = otNewIp6Message(instance, true);
-        VerifyOrQuit(msg[i] != NULL, "otNewIp6Message() failed.\n");
+        msg[i] = otIp6NewMessage(instance, true);
+        VerifyOrQuit(msg[i] != NULL, "otIp6NewMessage() failed.\n");
     }
 
     otMessageQueueInit(&queue);