mirror of
https://github.com/espressif/openthread.git
synced 2026-09-08 18:20:06 +00:00
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:
committed by
Jonathan Hui
parent
7edada12e4
commit
dc30d433c7
+98
-42
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) &&
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user