blob: 61f6a76742ef94d43857a0023fb3618cef476433 [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file implements an InetLayer-portable object for an IPv6
* RFC4861-compliant Router Advertisement daemon.
*
*/
#include <string.h>//memcpy
#include <InetLayer/InetLayer.h>
#include <Weave/Core/WeaveEncoding.h>
#include "RADaemon.h"
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#else
#include <errno.h>
#include <string.h>
#include <stdlib.h> //rand(), srand()
#include <arpa/inet.h>
#endif
//Width of the fuzzy factor
#define RAD_FUZZY_FACTOR (3U * 1000U) //3 seconds
//Immediately after a link's prefix info is updated, freuently send RAs.
#define RAD_UNSOLICITED_STARTUP_PERIOD (15U * 1000U) //15 seconds
#define RAD_SHORT_UNSOLICITED_STARTUP_PERIOD (RAD_UNSOLICITED_STARTUP_PERIOD - RAD_FUZZY_FACTOR)
//NOTE: the above is done only few times after a link's prefix info is updated.
#define RAD_MAX_UNSOLICITED_STARTUP_PERIODS (4U)
//Every 100 secs send an RA (long after the last prefix info has been updated.)
#define RAD_UNSOLICITED_PERIOD (100U * 1000U) //100 seconds
#define RAD_SHORT_UNSOLICITED_PERIOD (RAD_UNSOLICITED_PERIOD - RAD_FUZZY_FACTOR)
//Try a previous failed attempt to send a periodic multicast RA.
#define RAD_UNSOLICITED_RETRY_PERIOD (RAD_UNSOLICITED_STARTUP_PERIOD / 3)
//At most reply to 4 RSes per minute.
#define RAD_MAX_RSES_PER_TIME_FRAME (4U)
#define RAD_MAX_RSES_PER_TIME_FRAME_PERIOD (60U * 1000U) //60 seconds
extern void DumpMemory(const uint8_t *mem, uint32_t len, const char *prefix, uint32_t rowWidth);
namespace nl {
namespace Inet {
using namespace nl::Weave::Encoding;
#define RAD_IPV6_ADDR_LEN (16U)
#define RAD_ICMP6_TYPE_RS 133
#define RAD_ICMP6_TYPE_RA 134
uint8_t RADaemon::ICMP6Types[] = { RAD_ICMP6_TYPE_RA };
uint8_t RADaemon::ICMP6TypesListen[] = { RAD_ICMP6_TYPE_RS };
uint8_t RADaemon::PeriodicRAsWorked;
void RADaemon::Init(Weave::System::Layer& aSystemLayer, InetLayer& aInetLayer)
{
SystemLayer = &aSystemLayer;
Inet = &aInetLayer;
PeriodicRAsWorked = 0;
memset(LinkInfo, 0, RAD_MAX_ADVERTISING_LINKS * sizeof(RADaemon::LinkInformation));
for (int j = 0; j < RAD_MAX_ADVERTISING_LINKS; ++j) { LinkInfo[j].Self = this; }
}
//Return a Standard Internet Checksum as described in RFC 1071.
//Code adapted from Section 4.0 "Implementation Examples", Subsection 4.1 "C".
//Verified correct behavior comparing to <http://ask.wireshark.org/questions/11061/icmp-checksum>
//And also comparing with <http://www.erg.abdn.ac.uk/~gorry/course/inet-pages/packet-dec2.html>
uint16_t RADaemon::CalculateChecksum(uint16_t *startpos, uint16_t checklen)
{
uint32_t sum = 0;
uint16_t answer = 0;
while (checklen > 1)
{
sum += *startpos++;
checklen -= 2;
}
if (checklen == 1)
{
*(uint8_t *)(&answer) = *(uint8_t *)startpos;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
struct PrefixInfoOption
{
uint8_t Type;
uint8_t Length;
uint8_t PrefixLength;
uint8_t L_A_Reserved1;
uint32_t ValidLifetime;
uint32_t PreferredLifetime;
uint32_t Reserved2;
uint8_t Prefix[RAD_IPV6_ADDR_LEN];
};
struct RouterAdvertisementHeader
{
uint8_t Type;
uint8_t Code;
uint16_t Checksum;
uint8_t CurHopLimit;
uint8_t M_O_Reserved;
uint16_t RouterLifetime;
uint32_t ReacheableTime;
uint32_t RetransTimer;
PrefixInfoOption PrefixInfoOpt[RAD_MAX_PREFIXES_PER_LINK];
};
struct half
{
uint64_t first;
uint64_t second;
};
//ipv6_addr is IPAddr part of the IPPrefix.
//prefix is the length part of the IPPrefix.
//masked is like ipv6_addr but without the (128-prefix) less significant bits.
void mask_ipv6_address (const uint8_t *ipv6_addr, uint8_t prefix, uint8_t *masked)
{
struct half halves;
uint64_t mask = 0;
unsigned char *p = masked;
memset(masked, 0, RAD_IPV6_ADDR_LEN);
memcpy(&halves, ipv6_addr, sizeof(halves));
if (prefix <= 64)
{
mask = nl::Weave::Encoding::Swap64(nl::Weave::Encoding::Swap64(halves.first) & ((uint64_t) (~0) << (64 - prefix)));
memcpy(masked, &mask, sizeof(uint64_t));
return;
}
prefix -= 64;
memcpy(masked, &(halves.first), sizeof(uint64_t));
p += sizeof(uint64_t);
mask = nl::Weave::Encoding::Swap64(nl::Weave::Encoding::Swap64(halves.second) & (uint64_t) (~0) << (64 - prefix));
memcpy(p, &mask, sizeof(uint64_t));
}
struct PseudoHeader {
uint16_t PayloadLength;
uint16_t NextHeader;
uint8_t SrcAddr[16];
uint8_t DstAddr[16];
};
void RADaemon::BuildRA(PacketBuffer *RAPacket, RADaemon::LinkInformation *linkInfo, const IPAddress &destAddr)
{
uint8_t index = 0;
RouterAdvertisementHeader *icmp6payload = (RouterAdvertisementHeader*)RAPacket->Start();
//Fill up the ICMPv6 header fields.
icmp6payload->Type = RAD_ICMP6_TYPE_RA;
icmp6payload->Code = 0;
icmp6payload->Checksum = 0;
icmp6payload->CurHopLimit = 0;
icmp6payload->M_O_Reserved = 0;
icmp6payload->RouterLifetime = BigEndian::HostSwap16(0);
icmp6payload->ReacheableTime = BigEndian::HostSwap32(0);
icmp6payload->RetransTimer = BigEndian::HostSwap32(0);
//Fill up the prefix options, if any.
for (int k = 0; k < RAD_MAX_PREFIXES_PER_LINK; ++k)
{
if (linkInfo->IPPrefixInfo[k].IPPrefx != IPPrefix::Zero)
{
PrefixInfoOption *prefixInfoOpt = &icmp6payload->PrefixInfoOpt[index];
prefixInfoOpt->Type = 3;
prefixInfoOpt->Length = 4;
prefixInfoOpt->PrefixLength = linkInfo->IPPrefixInfo[k].IPPrefx.Length;
prefixInfoOpt->L_A_Reserved1 = 0xC0; //L == 1, A == 1
prefixInfoOpt->ValidLifetime = BigEndian::HostSwap32(linkInfo->IPPrefixInfo[k].ValidLifetime);
prefixInfoOpt->PreferredLifetime = BigEndian::HostSwap32(linkInfo->IPPrefixInfo[k].PreferredLifetime);
prefixInfoOpt->Reserved2 = BigEndian::HostSwap32(0);
memcpy(prefixInfoOpt->Prefix, linkInfo->IPPrefixInfo[k].IPPrefx.IPAddr.Addr, RAD_IPV6_ADDR_LEN);
index++;
}
}//for k
uint16_t reqSize = sizeof(RouterAdvertisementHeader) - (RAD_MAX_PREFIXES_PER_LINK - index) * sizeof(PrefixInfoOption);
//Fill up IPv6 fields belonging to the pseudo header necessary to calculate the checksum.
PseudoHeader *ip6payload = (PseudoHeader *)((uint8_t *)icmp6payload - sizeof(PseudoHeader));
ip6payload->PayloadLength = BigEndian::HostSwap16(reqSize);
ip6payload->NextHeader = BigEndian::HostSwap16(kIPProtocol_ICMPv6);
memcpy(ip6payload->SrcAddr, &linkInfo->LLAddr, sizeof(ip6payload->SrcAddr));
memcpy(ip6payload->DstAddr, &destAddr, sizeof(ip6payload->DstAddr));
//NOTE: because the fields in the packets are already converted to BigEndian order,
// there is no need to convert the final result of the checksumming to such order.
icmp6payload->Checksum = CalculateChecksum((uint16_t*)ip6payload, sizeof(PseudoHeader) + reqSize);
//Tell the PacketBuffer about the length of the ICMP6 message.
RAPacket->SetDataLength(reqSize);
// Debugging
// ::DumpMemory((const uint8_t*)ip6payload, sizeof(PseudoHeader), "", 16);
// ::DumpMemory((const uint8_t*)icmp6payload, reqSize, "", 16);
}
void RADaemon::MulticastRA(InetLayer* inet, void* appState, INET_ERROR err)
{
if ( (inet == NULL) || (appState == NULL) || (err != INET_NO_ERROR) )
{
return;
}
RADaemon::LinkInformation *linkInfo = (RADaemon::LinkInformation*)appState;
IPAddress destAddr;
IPAddress::FromString("FF02::1", destAddr);
PacketBuffer *RAPacket = PacketBuffer::New();
if (RAPacket == NULL)
return;
PeriodicRAsWorked = RAPacket ? 1: 0;
if (PeriodicRAsWorked)
{
BuildRA(RAPacket, linkInfo, destAddr);
linkInfo->RawEP->SendTo(destAddr, RAPacket);
}
}
void RADaemon::MulticastPeriodicRA(Weave::System::Layer* aSystemLayer, void* aAppState, Weave::System::Error aError)
{
RADaemon::LinkInformation* lLinkInfo = reinterpret_cast<RADaemon::LinkInformation*>(aAppState);
INET_ERROR lError = static_cast<INET_ERROR>(aError);
uint32_t lTimeout = RAD_UNSOLICITED_RETRY_PERIOD;
uint32_t lFuzz = 0;
if (lError != INET_NO_ERROR)
{
return;
}
MulticastRA(lLinkInfo->Self->Inet, aAppState, lError);
//Reschedule a new periodic mcast of RAs.
if (PeriodicRAsWorked)
{
lFuzz = rand() % (RAD_FUZZY_FACTOR * 2);
lTimeout = RAD_SHORT_UNSOLICITED_PERIOD;
if (lLinkInfo->NumRAsSentSoFar++ < RAD_MAX_UNSOLICITED_STARTUP_PERIODS)
{
lTimeout = RAD_SHORT_UNSOLICITED_STARTUP_PERIOD;
}
}
aSystemLayer->StartTimer(lTimeout + lFuzz, MulticastPeriodicRA, lLinkInfo);
}
void RADaemon::TrackRSes(Weave::System::Layer* aSystemLayer, void* aAppState, Weave::System::Error aError)
{
RADaemon::LinkInformation* lLinkInfo = reinterpret_cast<RADaemon::LinkInformation*>(aAppState);
INET_ERROR lError = static_cast<INET_ERROR>(aError);
if (lError != INET_NO_ERROR)
{
return;
}
lLinkInfo->RSesDownCounter = RAD_MAX_RSES_PER_TIME_FRAME;
lLinkInfo->Self->SystemLayer->StartTimer(RAD_MAX_RSES_PER_TIME_FRAME_PERIOD, TrackRSes, lLinkInfo);
}
void RADaemon::UpdateLinkLocalAddr(RADaemon::LinkInformation *linkInfo, IPAddress *llAddr)
{
//Multicast an RA with the current Link Local Address.
MulticastRA(linkInfo->Self->Inet, linkInfo, INET_NO_ERROR);
//Update the Link Local address of this link
linkInfo->LLAddr = *llAddr;
//Multicast an RA with the new Link Local Address.
MulticastRA(linkInfo->Self->Inet, linkInfo, INET_NO_ERROR);
linkInfo->NumRAsSentSoFar = 0;
}
void RADaemon::McastAllPrefixes(RADaemon::LinkInformation *linkInfo)
{
//Multicast an RA.
MulticastRA(linkInfo->Self->Inet, linkInfo, INET_NO_ERROR);
linkInfo->NumRAsSentSoFar = 0;
}
void RADaemon::HandleReceiveError2(RawEndPoint *endPoint, INET_ERROR err, IPAddress senderAddr)
{
}
void RADaemon::HandleReceiveError(RawEndPoint *endPoint, INET_ERROR err, IPAddress senderAddr)
{
}
struct RSPacketHdr
{
uint8_t Type;
uint8_t Code;
uint16_t Checksum;
uint32_t Reserved;
};
struct RSOpt
{
uint8_t OptType;
uint8_t OptLen;
};
void RADaemon::HandleMessageReceived2(RawEndPoint *RawEPListen, PacketBuffer *msg, IPAddress senderAddr)
{
}
void RADaemon::HandleMessageReceived(RawEndPoint *RawEPListen, PacketBuffer *msg, IPAddress senderAddr)
{
uint8_t msgDataLen = msg->DataLength();
RSPacketHdr *RSPacket = (RSPacketHdr *)msg->Start();
RSPacketHdr *RSPacketEnd = (RSPacketHdr *)((uint8_t *)RSPacket + msgDataLen);
LinkInformation *currLinkInfo = NULL;
PacketBuffer *RAPacket = NULL;
// Debugging
// char senderAddrStr[64];
// senderAddr.ToString(senderAddrStr, sizeof(senderAddrStr));
// printf("Raw message received from %s (%ld bytes)\n", senderAddrStr, msgDataLen);
// ::DumpMemory((const uint8_t *)RSPacket, msgDataLen, " ", 16);
//Error checks
if (
(RSPacket->Type != RAD_ICMP6_TYPE_RS) ||
(RSPacket->Code != 0)
//TODO: verify checksum
)
{
goto finalize;
}
currLinkInfo = (RADaemon::LinkInformation *)RawEPListen->AppState;
if (currLinkInfo->RSesDownCounter-- == 0)
{
currLinkInfo->RSesDownCounter = 0;
goto finalize;
}
if (msgDataLen <= sizeof(RSPacketHdr))
{
//No options present
}
else
{
RSOpt *rsOpt = (RSOpt *)((uint8_t *)RSPacket + sizeof(RSPacketHdr));
while (((uint8_t *)rsOpt < (uint8_t *)RSPacketEnd) && (rsOpt->OptType != 1))
{
rsOpt = (RSOpt *)((uint8_t *)rsOpt + rsOpt->OptLen);
}
if (((uint8_t *)rsOpt < (uint8_t *)RSPacketEnd) && (rsOpt->OptType == 1))
{
// For the time being the Mac addr is not used to decide how to send
// the RA, but it is printed here, to prove that its parsing works.
// printf("Source Link Layer Address Option: %x:%x:%x:%x:%x:%x\n",
// (&rsOpt->OptType+2)[0], (&rsOpt->OptType+2)[1], (&rsOpt->OptType+2)[2],
// (&rsOpt->OptType+2)[3], (&rsOpt->OptType+2)[4], (&rsOpt->OptType+2)[5]);
}
else
{
//No 'Source Link Layer Address' found.
}
}
RAPacket = PacketBuffer::New();
if (RAPacket == NULL)
goto finalize;
if (senderAddr == IPAddress::Any)
{
uint32_t lTimeout = RAD_SHORT_UNSOLICITED_PERIOD;
const uint32_t lFuzz = rand() % (RAD_FUZZY_FACTOR * 2);
IPAddress mcastAddr;
IPAddress::FromString("FF02::1", mcastAddr);
RADaemon::BuildRA(RAPacket, currLinkInfo, mcastAddr);
currLinkInfo->RawEP->SendTo(mcastAddr, RAPacket);
//Since mcast has been used to reply to this RS, reschedule a new periodic mcast of RAs.
RADaemon *self = currLinkInfo->Self;
Weave::System::Layer* lSystemLayer = self->SystemLayer;
if (currLinkInfo->NumRAsSentSoFar < RAD_MAX_UNSOLICITED_STARTUP_PERIODS)
{
lTimeout = RAD_SHORT_UNSOLICITED_STARTUP_PERIOD;
}
lSystemLayer->StartTimer(lTimeout + lFuzz, MulticastPeriodicRA, currLinkInfo);
}
else
{
RADaemon::BuildRA(RAPacket, currLinkInfo, senderAddr);
currLinkInfo->RawEP->SendTo(senderAddr, RAPacket);
}
finalize:
PacketBuffer::Free(msg);
}
INET_ERROR RADaemon::SetPrefixInfo(InterfaceId link, IPAddress llAddr, IPPrefix ipPrefix, uint32_t validLifetime,
uint32_t preferredLifetime)
{
// char buf[IFNAMSIZE];
IPPrefixInformation *currIPPrefixInfo;
IPPrefixInformation *freeIPPrefixInfo = NULL;
RADaemon::LinkInformation *currLinkInfo;
RADaemon::LinkInformation *freeLinkInfo = NULL;
INET_ERROR err = INET_NO_ERROR;
if ( !IsInterfaceIdPresent(link) || (ipPrefix == IPPrefix::Zero) )
{
return INET_ERROR_BAD_ARGS;
}
if (llAddr == IPAddress::Any)
{
err = Inet->GetLinkLocalAddr(link, &llAddr);
if (err != INET_NO_ERROR)
{
return err;
}
}
//Reset the bits in the ipPrefix that fall outside its length.
IPAddress tmpPrefix;
mask_ipv6_address((const uint8_t *)&ipPrefix.IPAddr, ipPrefix.Length, (uint8_t *)&tmpPrefix);
ipPrefix.IPAddr = tmpPrefix;
for (int j = 0; j < RAD_MAX_ADVERTISING_LINKS; ++j)
{//Try updating an EXISTING entry
currLinkInfo = &LinkInfo[j];
if (currLinkInfo->FSMState != FSM_NO_PREFIX)
{
if ( link == currLinkInfo->Link )
{
if (currLinkInfo->LLAddr != llAddr)
{
//RFC 4861, Section 6.2.8. 'Link Local Address Change':
// "If a router changes the link-local address for one of its interfaces,
// it SHOULD inform hosts of this change. The router SHOULD multicast a
// few Router Advertisements from the old link-local address with the
// Router Lifetime field set to zero and also multicast a few Router
// Advertisements from the new link-local address."
UpdateLinkLocalAddr(currLinkInfo, &llAddr);
}
for (int k = 0; k < RAD_MAX_PREFIXES_PER_LINK; ++k)
{//Look for the passed prefix
currIPPrefixInfo = &currLinkInfo->IPPrefixInfo[k];
if (currIPPrefixInfo->IPPrefx == ipPrefix)
{//Update existing prefix with latest info
currIPPrefixInfo->ValidLifetime = validLifetime;
currIPPrefixInfo->PreferredLifetime = preferredLifetime;
//RFC 4861, Section 4.2 'Router Advertisement Message Format', Subsection 'Prefix Information':
// "A router SHOULD include all its on-link prefixes (except the link-local prefix) so
// that multihomed hosts have complete prefix information about on-link destinations for the
// links to which they attach."
McastAllPrefixes(currLinkInfo);
goto out;
}
else if (freeIPPrefixInfo == NULL && currIPPrefixInfo->IPPrefx == IPPrefix::Zero)
{//Keep track of the first free prefix, in case is needed later
freeIPPrefixInfo = currIPPrefixInfo;
}
}//for k
if (freeIPPrefixInfo == NULL)
{//No free space to store passed prefix info
err = INET_ERROR_NO_MEMORY;
}
else
{//Save passed prefix with its associated info
freeIPPrefixInfo->IPPrefx = ipPrefix;
freeIPPrefixInfo->ValidLifetime = validLifetime;
freeIPPrefixInfo->PreferredLifetime = preferredLifetime;
McastAllPrefixes(currLinkInfo);
}
goto out;
}
}
else if (freeLinkInfo == NULL)
{//Keep track of the first free entry, in case is needed later
freeLinkInfo = currLinkInfo;
}
}//for j
if (freeLinkInfo == NULL)
{//No free space for passed interface
err = INET_ERROR_NO_MEMORY;
goto out;
}
//Use free space to store passed information.
err = Inet->NewRawEndPoint(kIPVersion_6, kIPProtocol_ICMPv6, &freeLinkInfo->RawEP);
if (err != INET_NO_ERROR)
{
goto out;
}
err = Inet->NewRawEndPoint(kIPVersion_6, kIPProtocol_ICMPv6, &freeLinkInfo->RawEPListen);
if (err != INET_NO_ERROR)
{
goto release_first_rawep;
}
freeLinkInfo->RawEP->AppState = freeLinkInfo;
freeLinkInfo->RawEP->OnMessageReceived = RADaemon::HandleMessageReceived2;
freeLinkInfo->RawEP->OnReceiveError = RADaemon::HandleReceiveError2;
freeLinkInfo->RawEPListen->AppState = freeLinkInfo;
freeLinkInfo->RawEPListen->OnMessageReceived = RADaemon::HandleMessageReceived;
freeLinkInfo->RawEPListen->OnReceiveError = RADaemon::HandleReceiveError;
err = freeLinkInfo->RawEP->BindIPv6LinkLocal(link, llAddr);
if (err != INET_NO_ERROR)
{
goto release_both_raweps;
}
err = freeLinkInfo->RawEP->SetICMPFilter(sizeof(ICMP6Types) / sizeof(uint8_t), ICMP6Types);
if (err != INET_NO_ERROR)
{
goto release_both_raweps;
}
err = freeLinkInfo->RawEPListen->BindIPv6LinkLocal(link, llAddr);
if (err != INET_NO_ERROR)
{
goto release_both_raweps;
}
err = freeLinkInfo->RawEPListen->SetICMPFilter(sizeof(ICMP6TypesListen) / sizeof(uint8_t), ICMP6TypesListen);
if (err != INET_NO_ERROR)
{
goto release_both_raweps;
}
err = freeLinkInfo->RawEPListen->Listen();
if (err != INET_NO_ERROR)
{
goto release_both_raweps;
}
freeLinkInfo->FSMState = FSM_ADVERTISING;
freeLinkInfo->Link = link;
freeLinkInfo->LLAddr = llAddr;
freeLinkInfo->IPPrefixInfo[0].IPPrefx = ipPrefix;
freeLinkInfo->IPPrefixInfo[0].ValidLifetime = validLifetime;
freeLinkInfo->IPPrefixInfo[0].PreferredLifetime = preferredLifetime;
freeLinkInfo->NumRAsSentSoFar = 0;
MulticastPeriodicRA(SystemLayer, freeLinkInfo, WEAVE_SYSTEM_NO_ERROR);
TrackRSes(SystemLayer, freeLinkInfo, WEAVE_SYSTEM_NO_ERROR);
goto out;
release_both_raweps:
freeLinkInfo->RawEPListen->Free();
freeLinkInfo->RawEPListen = NULL;
release_first_rawep:
freeLinkInfo->RawEP->Free();
freeLinkInfo->RawEP = NULL;
out:
return err;
}
//Delete the prefix associated with the passed interface.
void RADaemon::DelPrefixInfo(InterfaceId link, IPPrefix ipPrefix)
{
IPPrefixInformation *currIPPrefixInfo;
RADaemon::LinkInformation *currLinkInfo;
uint8_t num_free_prefixes = 0;
uint8_t prefix_removed = 0;
if ( !IsInterfaceIdPresent(link) || (ipPrefix == IPPrefix::Zero) )
{
return;
}
for (int j = 0; j < RAD_MAX_ADVERTISING_LINKS; ++j)
{
currLinkInfo = &LinkInfo[j];
if ( link == currLinkInfo->Link )
{
for (int k = 0; k < RAD_MAX_PREFIXES_PER_LINK; ++k)
{
currIPPrefixInfo = &currLinkInfo->IPPrefixInfo[k];
if (currIPPrefixInfo->IPPrefx == ipPrefix)
{
memset(&currIPPrefixInfo->IPPrefx, 0, sizeof(IPPrefix));
prefix_removed = 1;
num_free_prefixes++;
}
else if (LinkInfo[j].IPPrefixInfo[k].IPPrefx == IPPrefix::Zero)
{
num_free_prefixes++;
}
}//for k
if (num_free_prefixes == RAD_MAX_PREFIXES_PER_LINK)
{
DelLinkInfo(link);
}
break;//from for j
}
}//for j
if (prefix_removed == 1 && num_free_prefixes != RAD_MAX_PREFIXES_PER_LINK)
{
McastAllPrefixes(currLinkInfo);
}
}
//Free all the information associated with the passed interface.
void RADaemon::DelLinkInfo(InterfaceId link)
{
if ( !IsInterfaceIdPresent(link) )
{
return;
}
for (int j = 0; j < RAD_MAX_ADVERTISING_LINKS; ++j)
{
if ( link == LinkInfo[j].Link )
{
RADaemon::LinkInformation *currLinkInfo = &LinkInfo[j];
currLinkInfo->RawEPListen->Free();
currLinkInfo->RawEPListen = NULL;
currLinkInfo->RawEP->Free();
currLinkInfo->RawEP = NULL;
SystemLayer->CancelTimer(MulticastPeriodicRA, currLinkInfo);
SystemLayer->CancelTimer(TrackRSes, currLinkInfo);
memset(currLinkInfo, 0, sizeof(RADaemon::LinkInformation));
currLinkInfo->Self = this;
break;
}
}
}
} /* namespace Inet */
} /* namespace nl */