IP: Add support to IP-in-IP in IPv6 layer (#893)

* IP: Add support for IP-in-IP tunneling.

This commit includes support for MPL for multicast scope larger than
realm-local scope.
This commit is contained in:
Łukasz Duda
2016-10-27 23:56:14 -07:00
committed by Jonathan Hui
parent 7edada12e4
commit dc30d433c7
5 changed files with 122 additions and 49 deletions
+98 -42
View File
@@ -125,14 +125,14 @@ void Ip6::SetReceiveIp6FilterEnabled(bool aEnabled)
mIsReceiveIp6FilterEnabled = aEnabled;
}
ThreadError Ip6::AddMplOption(Message &message, Header &header, IpProto nextHeader, uint16_t payloadLength)
ThreadError Ip6::AddMplOption(Message &message, Header &header)
{
ThreadError error = kThreadError_None;
HopByHopHeader hbhHeader;
OptionMpl mplOption;
OptionPadN padOption;
hbhHeader.SetNextHeader(nextHeader);
hbhHeader.SetNextHeader(header.GetNextHeader());
hbhHeader.SetLength(0);
mMpl.InitOption(mplOption, header.GetSource());
@@ -145,61 +145,98 @@ ThreadError Ip6::AddMplOption(Message &message, Header &header, IpProto nextHead
SuccessOrExit(error = message.Prepend(&mplOption, mplOption.GetTotalLength()));
SuccessOrExit(error = message.Prepend(&hbhHeader, sizeof(hbhHeader)));
header.SetPayloadLength(sizeof(hbhHeader) + sizeof(mplOption) + payloadLength);
header.SetPayloadLength(header.GetPayloadLength() + sizeof(hbhHeader) + sizeof(mplOption));
header.SetNextHeader(kProtoHopOpts);
exit:
return error;
}
ThreadError Ip6::InsertMplOption(Message &aMessage, Header &aIp6Header)
ThreadError Ip6::AddTunneledMplOption(Message &aMessage, Header &aHeader, MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
Header tunnelHeader;
const NetifUnicastAddress *source;
MessageInfo messageInfo(aMessageInfo);
// Use IP-in-IP encapsulation (RFC2473) and ALL_MPL_FORWARDERS address.
memset(&messageInfo.GetPeerAddr(), 0, sizeof(Address));
messageInfo.GetPeerAddr().mFields.m16[0] = HostSwap16(0xff03);
messageInfo.GetPeerAddr().mFields.m16[7] = HostSwap16(0x00fc);
tunnelHeader.Init();
tunnelHeader.SetHopLimit(static_cast<uint8_t>(kDefaultHopLimit));
tunnelHeader.SetPayloadLength(aHeader.GetPayloadLength() + sizeof(tunnelHeader));
tunnelHeader.SetDestination(messageInfo.GetPeerAddr());
tunnelHeader.SetNextHeader(kProtoIp6);
VerifyOrExit((source = SelectSourceAddress(messageInfo)) != NULL,
error = kThreadError_Error);
tunnelHeader.SetSource(source->GetAddress());
SuccessOrExit(error = AddMplOption(aMessage, tunnelHeader));
SuccessOrExit(error = aMessage.Prepend(&tunnelHeader, sizeof(tunnelHeader)));
exit:
return error;
}
ThreadError Ip6::InsertMplOption(Message &aMessage, Header &aIp6Header, MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aIp6Header.GetDestination().IsRealmLocalMulticast(),);
VerifyOrExit(aIp6Header.GetDestination().IsMulticast() &&
aIp6Header.GetDestination().GetScope() >= Address::kRealmLocalScope, ;);
aMessage.RemoveHeader(sizeof(aIp6Header));
if (aIp6Header.GetNextHeader() == kProtoHopOpts)
if (aIp6Header.GetDestination().IsRealmLocalMulticast())
{
HopByHopHeader hbh;
uint8_t hbhLength = 0;
OptionMpl mplOption;
aMessage.RemoveHeader(sizeof(aIp6Header));
// read existing hop-by-hop option header
aMessage.Read(0, sizeof(hbh), &hbh);
hbhLength = (hbh.GetLength() + 1) * 8;
// increase existing hop-by-hop option header length by 8 bytes
hbh.SetLength(hbh.GetLength() + 1);
aMessage.Write(0, sizeof(hbh), &hbh);
// make space for MPL Option + padding by shifting hop-by-hop option header
aMessage.Prepend(NULL, 8);
aMessage.CopyTo(8, 0, hbhLength, aMessage);
// insert MPL Option
mMpl.InitOption(mplOption, aIp6Header.GetSource());
aMessage.Write(hbhLength, mplOption.GetTotalLength(), &mplOption);
// insert Pad Option (if needed)
if (mplOption.GetTotalLength() % 8)
if (aIp6Header.GetNextHeader() == kProtoHopOpts)
{
OptionPadN padOption;
padOption.Init(8 - (mplOption.GetTotalLength() % 8));
aMessage.Write(hbhLength + mplOption.GetTotalLength(), padOption.GetTotalLength(), &padOption);
HopByHopHeader hbh;
uint8_t hbhLength = 0;
OptionMpl mplOption;
// read existing hop-by-hop option header
aMessage.Read(0, sizeof(hbh), &hbh);
hbhLength = (hbh.GetLength() + 1) * 8;
// increase existing hop-by-hop option header length by 8 bytes
hbh.SetLength(hbh.GetLength() + 1);
aMessage.Write(0, sizeof(hbh), &hbh);
// make space for MPL Option + padding by shifting hop-by-hop option header
aMessage.Prepend(NULL, 8);
aMessage.CopyTo(8, 0, hbhLength, aMessage);
// insert MPL Option
mMpl.InitOption(mplOption, aIp6Header.GetSource());
aMessage.Write(hbhLength, mplOption.GetTotalLength(), &mplOption);
// insert Pad Option (if needed)
if (mplOption.GetTotalLength() % 8)
{
OptionPadN padOption;
padOption.Init(8 - (mplOption.GetTotalLength() % 8));
aMessage.Write(hbhLength + mplOption.GetTotalLength(), padOption.GetTotalLength(), &padOption);
}
// increase IPv6 Payload Length
aIp6Header.SetPayloadLength(aIp6Header.GetPayloadLength() + 8);
}
else
{
SuccessOrExit(error = AddMplOption(aMessage, aIp6Header));
}
// increase IPv6 Payload Length
aIp6Header.SetPayloadLength(aIp6Header.GetPayloadLength() + 8);
SuccessOrExit(error = aMessage.Prepend(&aIp6Header, sizeof(aIp6Header)));
}
else
{
SuccessOrExit(error = AddMplOption(aMessage, aIp6Header, aIp6Header.GetNextHeader(),
aIp6Header.GetPayloadLength()));
SuccessOrExit(error = AddTunneledMplOption(aMessage, aIp6Header, aMessageInfo));
}
SuccessOrExit(error = aMessage.Prepend(&aIp6Header, sizeof(aIp6Header)));
exit:
return error;
}
@@ -336,7 +373,8 @@ ThreadError Ip6::SendDatagram(Message &message, MessageInfo &messageInfo, IpProt
if (messageInfo.GetSockAddr().IsUnspecified())
{
VerifyOrExit((source = SelectSourceAddress(messageInfo)) != NULL, error = kThreadError_Error);
VerifyOrExit((source = SelectSourceAddress(messageInfo)) != NULL,
error = kThreadError_Error);
header.SetSource(source->GetAddress());
}
else
@@ -353,11 +391,17 @@ ThreadError Ip6::SendDatagram(Message &message, MessageInfo &messageInfo, IpProt
if (messageInfo.GetPeerAddr().IsRealmLocalMulticast())
{
SuccessOrExit(error = AddMplOption(message, header, ipproto, payloadLength));
SuccessOrExit(error = AddMplOption(message, header));
}
SuccessOrExit(error = message.Prepend(&header, sizeof(header)));
if (messageInfo.GetPeerAddr().IsMulticast() &&
messageInfo.GetPeerAddr().GetScope() > Address::kRealmLocalScope)
{
SuccessOrExit(error = AddTunneledMplOption(message, header, messageInfo));
}
// compute checksum
checksum = ComputePseudoheaderChecksum(header.GetSource(), header.GetDestination(),
payloadLength, ipproto);
@@ -504,6 +548,8 @@ ThreadError Ip6::HandleExtensionHeaders(Message &message, Header &header, uint8_
break;
case kProtoIp6:
ExitNow();
case kProtoRouting:
case kProtoNone:
ExitNow(error = kThreadError_Drop);
@@ -599,6 +645,7 @@ ThreadError Ip6::HandleDatagram(Message &message, Netif *netif, int8_t interface
uint16_t payloadLength;
bool receive = false;
bool forward = false;
bool tunnel = false;
uint8_t nextHeader;
uint8_t hopLimit;
@@ -642,7 +689,7 @@ ThreadError Ip6::HandleDatagram(Message &message, Netif *netif, int8_t interface
if (fromLocalHost)
{
SuccessOrExit(error = InsertMplOption(message, header));
SuccessOrExit(error = InsertMplOption(message, header, messageInfo));
}
}
}
@@ -677,6 +724,15 @@ ThreadError Ip6::HandleDatagram(Message &message, Netif *netif, int8_t interface
// process IPv6 Payload
if (receive)
{
if (nextHeader == kProtoIp6)
{
// Remove encapsulating header.
message.RemoveHeader(message.GetOffset());
HandleDatagram(message, netif, interfaceId, linkMessageInfo, fromLocalHost);
ExitNow(tunnel = true);
}
if (fromLocalHost == false)
{
ProcessReceiveCallback(message, messageInfo, nextHeader);
@@ -707,7 +763,7 @@ ThreadError Ip6::HandleDatagram(Message &message, Netif *netif, int8_t interface
exit:
if (error != kThreadError_None || !forward)
if (!tunnel && (error != kThreadError_None || !forward))
{
message.Free();
}
+3 -2
View File
@@ -346,8 +346,9 @@ private:
ThreadError HandleExtensionHeaders(Message &message, Header &header, uint8_t &nextHeader, bool forward,
bool receive);
ThreadError HandleFragment(Message &message);
ThreadError AddMplOption(Message &message, Header &header, IpProto nextHeader, uint16_t payloadLength);
ThreadError InsertMplOption(Message &message, Header &header);
ThreadError AddMplOption(Message &message, Header &header);
ThreadError AddTunneledMplOption(Message &message, Header &header, MessageInfo &messageInfo);
ThreadError InsertMplOption(Message &message, Header &header, MessageInfo &messageInfo);
ThreadError RemoveMplOption(Message &aMessage);
ThreadError HandleOptions(Message &message, Header &header, bool &forward);
ThreadError HandlePayload(Message &message, MessageInfo &messageInfo, uint8_t ipproto);
+6
View File
@@ -105,6 +105,12 @@ bool Address::IsRealmLocalAllRoutersMulticast(void) const
mFields.m32[2] == 0 && mFields.m32[3] == HostSwap32(0x02));
}
bool Address::IsRealmLocalAllMplForwarders(void) const
{
return (mFields.m32[0] == HostSwap32(0xff030000) && mFields.m32[1] == 0 &&
mFields.m32[2] == 0 && mFields.m32[3] == HostSwap32(0xfc));
}
bool Address::IsRoutingLocator(void) const
{
return (mFields.m16[4] == HostSwap16(0x0000) && mFields.m16[5] == HostSwap16(0x00ff) &&
+13 -4
View File
@@ -138,7 +138,7 @@ public:
* This method indicates whether or not the IPv6 address is a link-local all nodes multicast address.
*
* @retval TRUE If the IPv6 address is a link-local all nodes multicast address.
* @retval FALSE If the IPv6 address scope is not a link-local all nodes multicast address.
* @retval FALSE If the IPv6 address is not a link-local all nodes multicast address.
*
*/
bool IsLinkLocalAllNodesMulticast(void) const;
@@ -147,7 +147,7 @@ public:
* This method indicates whether or not the IPv6 address is a link-local all routers multicast address.
*
* @retval TRUE If the IPv6 address is a link-local all routers multicast address.
* @retval FALSE If the IPv6 address scope is not a link-local all routers multicast address.
* @retval FALSE If the IPv6 address is not a link-local all routers multicast address.
*
*/
bool IsLinkLocalAllRoutersMulticast(void) const;
@@ -165,7 +165,7 @@ public:
* This method indicates whether or not the IPv6 address is a realm-local all nodes multicast address.
*
* @retval TRUE If the IPv6 address is a realm-local all nodes multicast address.
* @retval FALSE If the IPv6 address scope is not a realm-local all nodes multicast address.
* @retval FALSE If the IPv6 address is not a realm-local all nodes multicast address.
*
*/
bool IsRealmLocalAllNodesMulticast(void) const;
@@ -174,11 +174,20 @@ public:
* This method indicates whether or not the IPv6 address is a realm-local all routers multicast address.
*
* @retval TRUE If the IPv6 address is a realm-local all routers multicast address.
* @retval FALSE If the IPv6 address scope is not a realm-local all routers multicast address.
* @retval FALSE If the IPv6 address is not a realm-local all routers multicast address.
*
*/
bool IsRealmLocalAllRoutersMulticast(void) const;
/**
* This method indicates whether or not the IPv6 address is a realm-local all MPL forwarders address.
*
* @retval TRUE If the IPv6 address is a realm-local all MPL forwarders address.
* @retval FALSE If the IPv6 address is not a realm-local all MPL forwarders address.
*
*/
bool IsRealmLocalAllMplForwarders(void) const;
/**
* This method indicates whether or not the IPv6 address is a RLOC address.
*
+2 -1
View File
@@ -122,7 +122,8 @@ bool Netif::IsMulticastSubscribed(const Address &aAddress) const
{
bool rval = false;
if (aAddress.IsLinkLocalAllNodesMulticast() || aAddress.IsRealmLocalAllNodesMulticast())
if (aAddress.IsLinkLocalAllNodesMulticast() || aAddress.IsRealmLocalAllNodesMulticast() ||
aAddress.IsRealmLocalAllMplForwarders())
{
ExitNow(rval = true);
}