*
******************************************************************/
-#include "caipinterface.h"
-
#include <sys/types.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
#include <wifi.h>
+#include <net_connection.h>
+#include "caipinterface.h"
+#include "caipnwmonitor.h"
#include "caadapterutils.h"
#include "logger.h"
#include "oic_malloc.h"
#include "oic_string.h"
+#include <coap/utlist.h>
+
+#define TAG "OIC_CA_IP_MONITOR"
+
+#define NETLINK_MESSAGE_LENGTH (4096)
+#define IFC_LABEL_LOOP "lo"
+#define IFC_ADDR_LOOP_IPV4 "127.0.0.1"
+#define IFC_ADDR_LOOP_IPV6 "::1"
-#define TAG "IP_MONITOR"
-#define MAX_INTERFACE_INFO_LENGTH (1024)
+/**
+ * Used to storing a connection handle for managing data connections.
+ */
+static connection_h connection = NULL;
+/**
+ * Used to storing adapter changes callback interface.
+ */
+static struct CAIPCBData_t *g_adapterCallbackList = NULL;
+
+/**
+ * Create new interface item.
+ */
static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
- uint32_t addr, int flags);
+ const char *addr, int flags);
+/**
+ * Add new network interface in list.
+ */
static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
- char *name, int family, uint32_t addr, int flags);
-
-static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
- void *userData);
+ char *name, int family, const char *addr, int flags);
-static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
+/**
+ * Pass the changed network status through the stored callback.
+ */
+static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
+/**
+ * Callback function to received connection state changes.
+ */
+static void CAIPConnectionStateChangedCb(connection_type_e type, void* userData);
int CAGetPollingInterval(int interval)
{
return interval;
}
-CAInterface_t *CAFindInterfaceChange()
+static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
{
- char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
- struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
-
- int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
- if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+ CAIPCBData_t *cbitem = NULL;
+ LL_FOREACH(g_adapterCallbackList, cbitem)
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
- return NULL;
+ if (cbitem && cbitem->adapter)
+ {
+ cbitem->callback(cbitem->adapter, status);
+ }
}
+}
- CAInterface_t *foundNewInterface = NULL;
-
- struct ifreq* ifr = ifc.ifc_req;
- size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
- size_t ifreqsize = ifc.ifc_len;
-
- CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
- if (!previous)
+CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
+ CATransportAdapter_t adapter)
+{
+ if (!callback)
{
- OIC_LOG(ERROR, TAG, "OICMalloc failed");
- return NULL;
+ OIC_LOG(ERROR, TAG, "callback is null");
+ return CA_STATUS_INVALID_PARAM;
}
- memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
- size_t numprevious = caglobals.ip.nm.numIfItems;
-
- if (ifreqsize > caglobals.ip.nm.sizeIfItems)
+ CAIPCBData_t *cbitem = NULL;
+ LL_FOREACH(g_adapterCallbackList, cbitem)
{
-
- CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
- if (!items)
+ if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
{
- OIC_LOG(ERROR, TAG, "OICRealloc failed");
- OICFree(previous);
- return NULL;
+ OIC_LOG(DEBUG, TAG, "this callback is already added");
+ return CA_STATUS_OK;
}
- caglobals.ip.nm.ifItems = items;
- caglobals.ip.nm.sizeIfItems = ifreqsize;
}
- caglobals.ip.nm.numIfItems = 0;
- for (size_t i = 0; i < interfaces; i++)
+ cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
+ if (!cbitem)
{
- struct ifreq* item = &ifr[i];
- char *name = item->ifr_name;
- struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
- uint32_t ipv4addr = sa4->sin_addr.s_addr;
+ OIC_LOG(ERROR, TAG, "Malloc failed");
+ return CA_STATUS_FAILED;
+ }
+
+ cbitem->adapter = adapter;
+ cbitem->callback = callback;
+ LL_APPEND(g_adapterCallbackList, cbitem);
+
+ return CA_STATUS_OK;
+}
- if (ioctl(s, SIOCGIFFLAGS, item) < 0)
+CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
+{
+ CAIPCBData_t *cbitem = NULL;
+ CAIPCBData_t *tmpCbitem = NULL;
+ LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
+ {
+ if (cbitem && adapter == cbitem->adapter)
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
- continue;
+ OIC_LOG(DEBUG, TAG, "remove specific callback");
+ LL_DELETE(g_adapterCallbackList, cbitem);
+ OICFree(cbitem);
+ return CA_STATUS_OK;
}
- int16_t flags = item->ifr_flags;
- if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
+ }
+ return CA_STATUS_OK;
+}
+
+u_arraylist_t *CAFindInterfaceChange()
+{
+ u_arraylist_t *iflist = NULL;
+ char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
+ struct sockaddr_nl sa = { 0 };
+ struct iovec iov = { .iov_base = buf,
+ .iov_len = sizeof (buf) };
+ struct msghdr msg = { .msg_name = (void *)&sa,
+ .msg_namelen = sizeof (sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1 };
+
+ ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
+
+ for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
+ {
+ if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
{
continue;
}
- if (ioctl(s, SIOCGIFINDEX, item) < 0)
+ struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
+ if (!ifi)
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
continue;
}
- int ifIndex = item->ifr_ifindex;
- caglobals.ip.nm.ifItems[i].ifIndex = ifIndex; // refill interface list
- caglobals.ip.nm.numIfItems++;
+ int ifiIndex = ifi->ifi_index;
- if (foundNewInterface)
- {
- continue; // continue updating interface list
- }
-
- // see if this interface didn't previously exist
- bool found = false;
- for (size_t j = 0; j < numprevious; j++)
- {
- if (ifIndex == previous[j].ifIndex)
- {
- found = true;
- break;
- }
- }
- if (found)
+ iflist = CAIPGetInterfaceInformation(ifiIndex);
+ if (!iflist)
{
- OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
- continue;
+ OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
+ return NULL;
}
-
- foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
}
-
- OICFree(previous);
- return foundNewInterface;
+ return iflist;
}
-CAResult_t CAIPStartNetworkMonitor()
+CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
+ CATransportAdapter_t adapter)
{
- OIC_LOG(DEBUG, TAG, "IN");
-
- // Initialize Wifi service
- wifi_error_e ret = wifi_initialize();
- if (WIFI_ERROR_NONE != ret)
+ if (!g_adapterCallbackList)
{
- OIC_LOG(ERROR, TAG, "wifi_initialize failed");
- return CA_STATUS_FAILED;
- }
+ // Initialize Wifi service.
+ if (WIFI_ERROR_NONE != wifi_initialize())
+ {
+ OIC_LOG(ERROR, TAG, "wifi_initialize failed");
+ }
- // Set callback for receiving state changes
- ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
- if (WIFI_ERROR_NONE != ret)
- {
- OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
- return CA_STATUS_FAILED;
- }
+ // Initialize Connections.
+ connection_error_e ret = connection_create(&connection);
+ if (CONNECTION_ERROR_NONE != ret)
+ {
+ OIC_LOG(ERROR, TAG, "connection_create failed");
+ return CA_STATUS_FAILED;
+ }
- // Set callback for receiving connection state changes
- ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
- if (WIFI_ERROR_NONE != ret)
- {
- OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
- return CA_STATUS_FAILED;
+ // Set callback for receiving state changes.
+ ret = connection_set_type_changed_cb(connection, CAIPConnectionStateChangedCb, NULL);
+ if (CONNECTION_ERROR_NONE != ret)
+ {
+ OIC_LOG(ERROR, TAG, "connection_set_type_changed_cb failed");
+ return CA_STATUS_FAILED;
+ }
}
- OIC_LOG(DEBUG, TAG, "OUT");
- return CA_STATUS_OK;
+ OIC_LOG(DEBUG, TAG, "Initialize network monitoring successfully");
+ return CAIPSetNetworkMonitorCallback(callback, adapter);
}
-CAResult_t CAIPStopNetworkMonitor()
+CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
{
OIC_LOG(DEBUG, TAG, "IN");
- // Reset callback for receiving state changes
- wifi_error_e ret = wifi_unset_device_state_changed_cb();
- if (WIFI_ERROR_NONE != ret)
+ CAIPUnSetNetworkMonitorCallback(adapter);
+ if (!g_adapterCallbackList)
{
- OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
- }
+ // Deinitialize Wifi service.
+ if (WIFI_ERROR_NONE != wifi_deinitialize())
+ {
+ OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
+ }
- // Reset callback for receiving connection state changes
- ret = wifi_unset_connection_state_changed_cb();
- if (WIFI_ERROR_NONE != ret)
- {
- OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
- }
+ // Reset callback for receiving state changes.
+ if (connection)
+ {
+ connection_error_e ret = connection_unset_type_changed_cb(connection);
+ if (CONNECTION_ERROR_NONE != ret)
+ {
+ OIC_LOG(ERROR, TAG, "connection_unset_type_changed_cb failed");
+ }
- // Deinitialize Wifi service
- ret = wifi_deinitialize();
- if (WIFI_ERROR_NONE != ret)
- {
- OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
+ // Deinitialize Wifi service.
+ ret = connection_destroy(connection);
+ if (CONNECTION_ERROR_NONE != ret)
+ {
+ OIC_LOG(ERROR, TAG, "connection_destroy failed");
+ }
+ connection = NULL;
+ }
}
- OIC_LOG(DEBUG, TAG, "OUT");
+ OIC_LOG(DEBUG, TAG, "Network monitoring terminated successfully");
return CA_STATUS_OK;
}
-u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
+/**
+ * Used to send netlink query to kernel and recv response from kernel.
+ *
+ * @param[in] idx desired network interface index, 0 means all interfaces.
+ * @param[out] iflist linked list.
+ *
+ */
+static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
{
- u_arraylist_t *iflist = u_arraylist_create();
- if (!iflist)
+ if ((idx < 0) || (iflist == NULL))
{
- OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
- return NULL;
+ return false;
}
- char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
- struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
-
- int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
- if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
+ struct ifaddrs *ifp = NULL;
+ if (-1 == getifaddrs(&ifp))
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
- u_arraylist_destroy(iflist);
- return NULL;
+ OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
+ return false;
}
- struct ifreq* ifr = ifc.ifc_req;
- size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
- size_t ifreqsize = ifc.ifc_len;
-
- if (ifreqsize > caglobals.ip.nm.sizeIfItems)
+ struct ifaddrs *ifa = NULL;
+ for (ifa = ifp; ifa; ifa = ifa->ifa_next)
{
- CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
- if (!items)
+ if (!ifa->ifa_addr)
{
- OIC_LOG(ERROR, TAG, "OICRealloc failed");
- goto exit;
+ continue;
}
- caglobals.ip.nm.ifItems = items;
- caglobals.ip.nm.sizeIfItems = ifreqsize;
- }
- caglobals.ip.nm.numIfItems = 0;
- for (size_t i = 0; i < interfaces; i++)
- {
- CAResult_t result = CA_STATUS_OK;
- struct ifreq* item = &ifr[i];
- char *name = item->ifr_name;
- struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
- uint32_t ipv4addr = sa4->sin_addr.s_addr;
-
- if (ioctl(s, SIOCGIFFLAGS, item) < 0)
+ int family = ifa->ifa_addr->sa_family;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
continue;
}
- int16_t flags = item->ifr_flags;
- if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
+
+ int ifindex = if_nametoindex(ifa->ifa_name);
+ if (idx && (ifindex != idx))
{
continue;
}
- if (ioctl(s, SIOCGIFINDEX, item) < 0)
+
+ char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
+ if (family == AF_INET6)
{
- OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
- continue;
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
+ inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
}
-
- int ifindex = item->ifr_ifindex;
- caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
- caglobals.ip.nm.numIfItems++;
-
- if (desiredIndex && (ifindex != desiredIndex))
+ else if (family == AF_INET)
{
- continue;
+ struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
+ inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
}
- // Add IPv4 interface
- result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
- if (CA_STATUS_OK != result)
+ if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
+ (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
+ (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
{
- goto exit;
+ OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
+ continue;
}
- // Add IPv6 interface
- result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
+ CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
+ ifa->ifa_name, family,
+ ipaddr, ifa->ifa_flags);
if (CA_STATUS_OK != result)
{
+ OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
goto exit;
}
}
+ freeifaddrs(ifp);
+ return true;
+
+exit:
+ freeifaddrs(ifp);
+ return false;
+}
+
+u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
+{
+ u_arraylist_t *iflist = u_arraylist_create();
+ if (!iflist)
+ {
+ OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
+ return NULL;
+ }
+
+ if (!CAIPGetAddrInfo(desiredIndex, iflist))
+ {
+ goto exit;
+ }
+
return iflist;
exit:
}
static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
- char *name, int family, uint32_t addr, int flags)
+ char *name, int family, const char *addr, int flags)
{
CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
if (!ifitem)
}
static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
- uint32_t addr, int flags)
+ const char *addr, int flags)
{
CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
if (!ifitem)
OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
ifitem->index = index;
ifitem->family = family;
- ifitem->ipv4addr = addr;
+ OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
ifitem->flags = flags;
return ifitem;
}
-void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
- void *userData)
+void CAIPConnectionStateChangedCb(connection_type_e type, void* userData)
{
- OIC_LOG(DEBUG, TAG, "IN");
-
- if (WIFI_CONNECTION_STATE_ASSOCIATION == state
- || WIFI_CONNECTION_STATE_CONFIGURATION == state)
- {
- OIC_LOG(DEBUG, TAG, "Connection is in Association State");
- return;
- }
-
- if (WIFI_CONNECTION_STATE_CONNECTED == state)
+ switch (type)
{
- CAWakeUpForChange();
+ case CONNECTION_TYPE_DISCONNECTED:
+ OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_DISCONNECTED");
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
+ break;
+ case CONNECTION_TYPE_ETHERNET:
+ OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_ETHERNET");
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
+ break;
+ case CONNECTION_TYPE_WIFI:
+ OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_WIFI");
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
+ break;
+ case CONNECTION_TYPE_CELLULAR:
+ OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_CELLULAR");
+ CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
+ break;
+ default:
+ break;
}
- else
- {
- u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
- if (!iflist)
- {
- OIC_LOG_V(ERROR, TAG, "get interface info failed");
- return;
- }
- u_arraylist_destroy(iflist);
- }
-
- OIC_LOG(DEBUG, TAG, "OUT");
-}
-
-void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
-{
- OIC_LOG(DEBUG, TAG, "IN");
-
- if (WIFI_DEVICE_STATE_ACTIVATED == state)
- {
- OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
- }
- else
- {
- CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
- OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
- }
-
- OIC_LOG(DEBUG, TAG, "OUT");
}