blob: 8af9ddc699c8f6b8d47125caf66d938668dc6b08 [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
* Implementation of network interface abstraction layer.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdio.h>
#include <string.h>
#include <Weave/Support/NLDLLUtil.h>
#include <InetLayer/InetLayer.h>
#include <InetLayer/InetLayerEvents.h>
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#include <lwip/sys.h>
#include <lwip/netif.h>
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#ifdef __ANDROID__
#include "ifaddrs-android.h"
#else // !defined(__ANDROID__)
#include <ifaddrs.h>
#endif // !defined(__ANDROID__)
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
namespace nl {
namespace Inet {
NL_DLL_EXPORT INET_ERROR GetInterfaceName(InterfaceId intfId, char *nameBuf, size_t nameBufSize)
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
int status;
if (intfId != INET_NULL_INTERFACEID)
{
status = snprintf(nameBuf, nameBufSize, "%c%c%d", intfId->name[0], intfId->name[1], intfId->num);
if (status >= static_cast<int>(nameBufSize))
return INET_ERROR_NO_MEMORY;
}
else
nameBuf[0] = 0;
return INET_NO_ERROR;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (intfId != INET_NULL_INTERFACEID)
{
char intfName[IF_NAMESIZE];
if (if_indextoname(intfId, intfName) == NULL)
return Weave::System::MapErrorPOSIX(errno);
if (strlen(intfName) >= nameBufSize)
return INET_ERROR_NO_MEMORY;
strcpy(nameBuf, intfName);
}
else
{
if (nameBufSize < 1)
return INET_ERROR_NO_MEMORY;
nameBuf[0] = 0;
}
return INET_NO_ERROR;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
NL_DLL_EXPORT INET_ERROR InterfaceNameToId(const char *intfName, InterfaceId& intfId)
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
if (strlen(intfName) < 3)
return INET_ERROR_UNKNOWN_INTERFACE;
char *parseEnd;
unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10);
if (*parseEnd != 0 || intfNum > UINT8_MAX)
return INET_ERROR_UNKNOWN_INTERFACE;
for (struct netif *intf = netif_list; intf != NULL; intf = intf->next)
if (intf->name[0] == intfName[0] && intf->name[1] == intfName[1] && intf->num == (uint8_t)intfNum)
{
intfId = intf;
return INET_NO_ERROR;
}
intfId = INET_NULL_INTERFACEID;
return INET_ERROR_UNKNOWN_INTERFACE;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
intfId = if_nametoindex(intfName);
if (intfId == 0)
return (errno == ENXIO) ? INET_ERROR_UNKNOWN_INTERFACE : Weave::System::MapErrorPOSIX(errno);
return INET_NO_ERROR;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
InterfaceIterator::InterfaceIterator()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
curIntf = netif_list;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
int rv;
rv = getifaddrs(&addrsList);
if (rv != -1)
curAddr = addrsList;
else
curAddr = addrsList = NULL;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
InterfaceIterator::~InterfaceIterator()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
curIntf = NULL;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (addrsList != NULL)
freeifaddrs(addrsList);
curAddr = addrsList = NULL;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
bool InterfaceIterator::Next()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
if (curIntf != NULL)
curIntf = curIntf->next;
return (curIntf != NULL);
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (curAddr != NULL)
{
const char *lastIntfName = curAddr->ifa_name;
do
curAddr = curAddr->ifa_next;
while (curAddr != NULL && strcmp(curAddr->ifa_name, lastIntfName) == 0);
}
return (curAddr != NULL);
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
InterfaceId InterfaceIterator::GetInterface()
{
InterfaceId rv = INET_NULL_INTERFACEID;
if (HasCurrent())
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
rv = curIntf;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
rv = if_nametoindex(curAddr->ifa_name);
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
return rv;
}
bool InterfaceIterator::SupportsMulticast()
{
if (HasCurrent())
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#if LWIP_VERSION_MAJOR > 1
return (curIntf->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6)) == 0;
#else
return (curIntf->flags & NETIF_FLAG_POINTTOPOINT) == 0;
#endif // LWIP_VERSION_MAJOR > 1
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
return (curAddr->ifa_flags & IFF_MULTICAST) != 0;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
else
return false;
}
InterfaceAddressIterator::InterfaceAddressIterator()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
curIntf = netif_list;
curAddrIndex = 0;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
int rv;
rv = getifaddrs(&addrsList);
if (rv != -1) {
curAddr = addrsList;
} else {
curAddr = addrsList = NULL;
return;
}
// Advance the iterator until we're sure that the current element has
// a valid AF_INET or AF_INET6 address.
while ((curAddr != NULL) &&
((curAddr->ifa_addr == NULL) ||
((curAddr->ifa_addr->sa_family != AF_INET6)
#if INET_CONFIG_ENABLE_IPV4
&& (curAddr->ifa_addr->sa_family != AF_INET)
#endif // INET_CONFIG_ENABLE_IPV4
)))
{
curAddr = curAddr->ifa_next;
}
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
InterfaceAddressIterator::~InterfaceAddressIterator()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
curIntf = NULL;
curAddrIndex = 0;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (addrsList != NULL)
freeifaddrs(addrsList);
curAddr = addrsList = NULL;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
bool InterfaceAddressIterator::Next()
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
while (curIntf != NULL)
{
curAddrIndex++;
if (curAddrIndex >= LWIP_IPV6_NUM_ADDRESSES)
{
curIntf = curIntf->next;
curAddrIndex = 0;
continue;
}
if (ip6_addr_isvalid(netif_ip6_addr_state(curIntf, curAddrIndex)))
return true;
}
return false;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (curAddr != NULL)
while (true)
{
curAddr = curAddr->ifa_next;
if (curAddr == NULL)
break;
if (curAddr->ifa_addr != NULL &&
(curAddr->ifa_addr->sa_family == AF_INET6
#if INET_CONFIG_ENABLE_IPV4
|| curAddr->ifa_addr->sa_family == AF_INET
#endif // INET_CONFIG_ENABLE_IPV4
))
return true;
}
return false;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
IPAddress InterfaceAddressIterator::GetAddress()
{
IPAddress rv = IPAddress::Any;
if (HasCurrent())
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
rv = IPAddress::FromIPv6(*netif_ip6_addr(curIntf, curAddrIndex));
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
if (curAddr->ifa_addr->sa_family == AF_INET6)
{
rv = IPAddress::FromIPv6(((struct sockaddr_in6*)curAddr->ifa_addr)->sin6_addr);
}
#if INET_CONFIG_ENABLE_IPV4
else if (curAddr->ifa_addr->sa_family == AF_INET)
{
rv = IPAddress::FromIPv4(((struct sockaddr_in*)curAddr->ifa_addr)->sin_addr);
}
#endif // INET_CONFIG_ENABLE_IPV4
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
return rv;
}
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
uint8_t InterfaceAddressIterator::GetIPv6PrefixLength()
{
uint8_t prefixLen = 0;
if (curAddr->ifa_addr->sa_family == AF_INET6)
{
struct sockaddr_in6& netmask = *(struct sockaddr_in6 *)(curAddr->ifa_netmask);
for (int i = 0; i < 16; i++, prefixLen += 8)
{
uint8_t b = netmask.sin6_addr.s6_addr[i];
if (b != 0xFF)
{
if ((b & 0xF0) == 0xF0)
prefixLen += 4;
else
b = b >> 4;
if ((b & 0x0C) == 0x0C)
prefixLen += 2;
else
b = b >> 2;
if ((b & 0x02) == 0x02)
prefixLen++;
break;
}
}
}
return prefixLen;
}
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
InterfaceId InterfaceAddressIterator::GetInterface()
{
InterfaceId rv = INET_NULL_INTERFACEID;
if (HasCurrent())
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
rv = curIntf;
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
rv = if_nametoindex(curAddr->ifa_name);
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
return rv;
}
bool InterfaceAddressIterator::SupportsMulticast()
{
if (HasCurrent())
{
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
#if LWIP_VERSION_MAJOR > 1
return (curIntf->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6)) == 0;
#else
return (curIntf->flags & NETIF_FLAG_POINTTOPOINT) == 0;
#endif // LWIP_VERSION_MAJOR > 1
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
return (curAddr->ifa_flags & IFF_MULTICAST) != 0;
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
}
else
return false;
}
} // namespace Inet
} // namespace nl