#include "netif.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/locator-getters.hpp"
#include "common/message.hpp"
#include "net/ip6.hpp"
namespace ot {
namespace Ip6 {
const otNetifMulticastAddress Netif::kRealmLocalAllMplForwardersMulticastAddress = {
{{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc}}},
NULL};
const otNetifMulticastAddress Netif::kRealmLocalAllNodesMulticastAddress = {
{{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}},
&Netif::kRealmLocalAllMplForwardersMulticastAddress};
const otNetifMulticastAddress Netif::kLinkLocalAllNodesMulticastAddress = {
{{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}},
&Netif::kRealmLocalAllNodesMulticastAddress};
const otNetifMulticastAddress Netif::kRealmLocalAllRoutersMulticastAddress = {
{{{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}},
&Netif::kLinkLocalAllNodesMulticastAddress};
const otNetifMulticastAddress Netif::kLinkLocalAllRoutersMulticastAddress = {
{{{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}}},
&Netif::kRealmLocalAllRoutersMulticastAddress};
Netif::Netif(Instance &aInstance)
: InstanceLocator(aInstance)
, mUnicastAddresses()
, mMulticastAddresses()
, mMulticastPromiscuous(false)
, mAddressCallback(NULL)
, mAddressCallbackContext(NULL)
{
for (NetifUnicastAddress *entry = &mExtUnicastAddresses[0]; entry < OT_ARRAY_END(mExtUnicastAddresses); entry++)
{
entry->MarkAsNotInUse();
}
for (NetifMulticastAddress *entry = &mExtMulticastAddresses[0]; entry < OT_ARRAY_END(mExtMulticastAddresses);
entry++)
{
entry->MarkAsNotInUse();
}
}
bool Netif::IsMulticastSubscribed(const Address &aAddress) const
{
bool rval = false;
for (const NetifMulticastAddress *cur = mMulticastAddresses.GetHead(); cur; cur = cur->GetNext())
{
if (cur->GetAddress() == aAddress)
{
ExitNow(rval = true);
}
}
exit:
return rval;
}
void Netif::SubscribeAllNodesMulticast(void)
{
NetifMulticastAddress *tail;
NetifMulticastAddress &linkLocalAllNodesAddress =
static_cast<NetifMulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
VerifyOrExit(!mMulticastAddresses.Contains(linkLocalAllNodesAddress), OT_NOOP);
tail = mMulticastAddresses.GetTail();
if (tail == NULL)
{
mMulticastAddresses.SetHead(&linkLocalAllNodesAddress);
}
else
{
tail->SetNext(&linkLocalAllNodesAddress);
}
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
for (const NetifMulticastAddress *entry = &linkLocalAllNodesAddress; entry; entry = entry->GetNext())
{
mAddressCallback(&entry->GetAddress(), kMulticastPrefixLength, true, mAddressCallbackContext);
}
exit:
return;
}
void Netif::UnsubscribeAllNodesMulticast(void)
{
NetifMulticastAddress * prev;
const NetifMulticastAddress &linkLocalAllNodesAddress =
static_cast<NetifMulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
SuccessOrExit(mMulticastAddresses.Find(linkLocalAllNodesAddress, prev));
OT_ASSERT(prev != static_cast<NetifMulticastAddress *>(
const_cast<otNetifMulticastAddress *>(&kRealmLocalAllRoutersMulticastAddress)));
if (prev == NULL)
{
mMulticastAddresses.Clear();
}
else
{
prev->SetNext(NULL);
}
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
for (const NetifMulticastAddress *entry = &linkLocalAllNodesAddress; entry; entry = entry->GetNext())
{
mAddressCallback(&entry->GetAddress(), kMulticastPrefixLength, false, mAddressCallbackContext);
}
exit:
return;
}
void Netif::SubscribeAllRoutersMulticast(void)
{
otError error = OT_ERROR_NONE;
NetifMulticastAddress *prev = NULL;
NetifMulticastAddress &linkLocalAllRoutersAddress = static_cast<NetifMulticastAddress &>(
const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
NetifMulticastAddress &linkLocalAllNodesAddress =
static_cast<NetifMulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
NetifMulticastAddress &realmLocalAllRoutersAddress = static_cast<NetifMulticastAddress &>(
const_cast<otNetifMulticastAddress &>(kRealmLocalAllRoutersMulticastAddress));
error = mMulticastAddresses.Find(linkLocalAllNodesAddress, prev);
OT_ASSERT(error == OT_ERROR_NONE);
OT_UNUSED_VARIABLE(error);
VerifyOrExit(prev != &realmLocalAllRoutersAddress, OT_NOOP);
if (prev == NULL)
{
mMulticastAddresses.SetHead(&linkLocalAllRoutersAddress);
}
else
{
prev->SetNext(&linkLocalAllRoutersAddress);
}
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
for (const NetifMulticastAddress *entry = &linkLocalAllRoutersAddress; entry != &linkLocalAllNodesAddress;
entry = entry->GetNext())
{
mAddressCallback(&entry->GetAddress(), kMulticastPrefixLength, true, mAddressCallbackContext);
}
exit:
return;
}
void Netif::UnsubscribeAllRoutersMulticast(void)
{
NetifMulticastAddress *prev;
NetifMulticastAddress &linkLocalAllRoutersAddress = static_cast<NetifMulticastAddress &>(
const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
NetifMulticastAddress &linkLocalAllNodesAddress =
static_cast<NetifMulticastAddress &>(const_cast<otNetifMulticastAddress &>(kLinkLocalAllNodesMulticastAddress));
SuccessOrExit(mMulticastAddresses.Find(linkLocalAllRoutersAddress, prev));
if (prev == NULL)
{
mMulticastAddresses.SetHead(&linkLocalAllNodesAddress);
}
else
{
prev->SetNext(&linkLocalAllNodesAddress);
}
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
for (const NetifMulticastAddress *entry = &linkLocalAllRoutersAddress; entry != &linkLocalAllNodesAddress;
entry = entry->GetNext())
{
mAddressCallback(&entry->GetAddress(), kMulticastPrefixLength, false, mAddressCallbackContext);
}
exit:
return;
}
void Netif::SubscribeMulticast(NetifMulticastAddress &aAddress)
{
SuccessOrExit(mMulticastAddresses.Add(aAddress));
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
mAddressCallback(&aAddress.mAddress, kMulticastPrefixLength, true, mAddressCallbackContext);
exit:
return;
}
void Netif::UnsubscribeMulticast(const NetifMulticastAddress &aAddress)
{
SuccessOrExit(mMulticastAddresses.Remove(aAddress));
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
mAddressCallback(&aAddress.mAddress, kMulticastPrefixLength, false, mAddressCallbackContext);
exit:
return;
}
otError Netif::GetNextExternalMulticast(uint8_t &aIterator, Address &aAddress) const
{
otError error = OT_ERROR_NOT_FOUND;
size_t num = OT_ARRAY_LENGTH(mExtMulticastAddresses);
VerifyOrExit(aIterator < num, OT_NOOP);
for (uint8_t i = aIterator; i < num; i++)
{
const NetifMulticastAddress &entry = mExtMulticastAddresses[i];
if (entry.IsInUse())
{
aAddress = entry.GetAddress();
aIterator = i + 1;
ExitNow(error = OT_ERROR_NONE);
}
}
exit:
return error;
}
otError Netif::SubscribeExternalMulticast(const Address &aAddress)
{
otError error = OT_ERROR_NONE;
NetifMulticastAddress *entry;
NetifMulticastAddress &linkLocalAllRoutersAddress = static_cast<NetifMulticastAddress &>(
const_cast<otNetifMulticastAddress &>(kLinkLocalAllRoutersMulticastAddress));
VerifyOrExit(!IsMulticastSubscribed(aAddress), error = OT_ERROR_ALREADY);
for (const NetifMulticastAddress *cur = &linkLocalAllRoutersAddress; cur; cur = cur->GetNext())
{
VerifyOrExit(cur->GetAddress() != aAddress, error = OT_ERROR_INVALID_ARGS);
}
for (entry = &mExtMulticastAddresses[0]; entry < OT_ARRAY_END(mExtMulticastAddresses); entry++)
{
if (!entry->IsInUse())
{
entry->mAddress = aAddress;
mMulticastAddresses.Push(*entry);
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_SUBSCRIBED);
ExitNow();
}
}
error = OT_ERROR_NO_BUFS;
exit:
return error;
}
otError Netif::UnsubscribeExternalMulticast(const Address &aAddress)
{
otError error = OT_ERROR_NONE;
NetifMulticastAddress *entry;
NetifMulticastAddress *last = NULL;
for (entry = mMulticastAddresses.GetHead(); entry; entry = entry->GetNext())
{
if (entry->GetAddress() == aAddress)
{
VerifyOrExit((entry >= &mExtMulticastAddresses[0]) && (entry < OT_ARRAY_END(mExtMulticastAddresses)),
error = OT_ERROR_INVALID_ARGS);
mMulticastAddresses.PopAfter(last);
break;
}
last = entry;
}
VerifyOrExit(entry != NULL, error = OT_ERROR_NOT_FOUND);
entry->MarkAsNotInUse();
Get<Notifier>().Signal(OT_CHANGED_IP6_MULTICAST_UNSUBSCRIBED);
exit:
return error;
}
void Netif::UnsubscribeAllExternalMulticastAddresses(void)
{
for (NetifMulticastAddress *entry = &mExtMulticastAddresses[0]; entry < OT_ARRAY_END(mExtMulticastAddresses);
entry++)
{
if (entry->IsInUse())
{
IgnoreError(UnsubscribeExternalMulticast(entry->GetAddress()));
}
}
}
void Netif::SetAddressCallback(otIp6AddressCallback aCallback, void *aCallbackContext)
{
mAddressCallback = aCallback;
mAddressCallbackContext = aCallbackContext;
}
void Netif::AddUnicastAddress(NetifUnicastAddress &aAddress)
{
SuccessOrExit(mUnicastAddresses.Add(aAddress));
Get<Notifier>().Signal(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_ADDED : OT_CHANGED_IP6_ADDRESS_ADDED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
mAddressCallback(&aAddress.mAddress, aAddress.mPrefixLength, true, mAddressCallbackContext);
exit:
return;
}
void Netif::RemoveUnicastAddress(const NetifUnicastAddress &aAddress)
{
SuccessOrExit(mUnicastAddresses.Remove(aAddress));
Get<Notifier>().Signal(aAddress.mRloc ? OT_CHANGED_THREAD_RLOC_REMOVED : OT_CHANGED_IP6_ADDRESS_REMOVED);
VerifyOrExit(mAddressCallback != NULL, OT_NOOP);
mAddressCallback(&aAddress.mAddress, aAddress.mPrefixLength, false, mAddressCallbackContext);
exit:
return;
}
otError Netif::AddExternalUnicastAddress(const NetifUnicastAddress &aAddress)
{
otError error = OT_ERROR_NONE;
NetifUnicastAddress *entry;
for (entry = mUnicastAddresses.GetHead(); entry; entry = entry->GetNext())
{
if (entry->GetAddress() == aAddress.GetAddress())
{
VerifyOrExit((entry >= &mExtUnicastAddresses[0]) && (entry < OT_ARRAY_END(mExtUnicastAddresses)),
error = OT_ERROR_ALREADY);
entry->mPrefixLength = aAddress.mPrefixLength;
entry->mPreferred = aAddress.mPreferred;
entry->mValid = aAddress.mValid;
ExitNow();
}
}
VerifyOrExit(!aAddress.GetAddress().IsLinkLocal(), error = OT_ERROR_INVALID_ARGS);
for (entry = &mExtUnicastAddresses[0]; entry < OT_ARRAY_END(mExtUnicastAddresses); entry++)
{
if (!entry->IsInUse())
{
*entry = aAddress;
mUnicastAddresses.Push(*entry);
Get<Notifier>().Signal(OT_CHANGED_IP6_ADDRESS_ADDED);
ExitNow();
}
}
error = OT_ERROR_NO_BUFS;
exit:
return error;
}
otError Netif::RemoveExternalUnicastAddress(const Address &aAddress)
{
otError error = OT_ERROR_NONE;
NetifUnicastAddress *entry;
NetifUnicastAddress *last = NULL;
for (entry = mUnicastAddresses.GetHead(); entry; entry = entry->GetNext())
{
if (entry->GetAddress() == aAddress)
{
VerifyOrExit((entry >= &mExtUnicastAddresses[0]) && (entry < OT_ARRAY_END(mExtUnicastAddresses)),
error = OT_ERROR_INVALID_ARGS);
mUnicastAddresses.PopAfter(last);
break;
}
last = entry;
}
VerifyOrExit(entry != NULL, error = OT_ERROR_NOT_FOUND);
entry->MarkAsNotInUse();
Get<Notifier>().Signal(OT_CHANGED_IP6_ADDRESS_REMOVED);
exit:
return error;
}
void Netif::RemoveAllExternalUnicastAddresses(void)
{
for (NetifUnicastAddress *entry = &mExtUnicastAddresses[0]; entry < OT_ARRAY_END(mExtUnicastAddresses); entry++)
{
if (entry->IsInUse())
{
IgnoreError(RemoveExternalUnicastAddress(entry->GetAddress()));
}
}
}
bool Netif::IsUnicastAddress(const Address &aAddress) const
{
bool rval = false;
for (const NetifUnicastAddress *cur = mUnicastAddresses.GetHead(); cur; cur = cur->GetNext())
{
if (cur->GetAddress() == aAddress)
{
ExitNow(rval = true);
}
}
exit:
return rval;
}
} }