1 /******************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
21 #include "caipinterface.h"
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/select.h>
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
38 #include <linux/netlink.h>
39 #include <linux/rtnetlink.h>
43 #include "caipnwmonitor.h"
44 #include "caadapterutils.h"
46 #include "oic_malloc.h"
47 #include "oic_string.h"
48 #include <coap/utlist.h>
50 #define TAG "OIC_CA_IP_MONITOR"
53 * Mutex for synchronizing access to cached interface and IP address information.
55 static oc_mutex g_networkMonitorContextMutex = NULL;
58 * Used to storing network interface.
60 static u_arraylist_t *g_netInterfaceList = NULL;
63 * Used to storing adapter changes callback interface.
65 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
68 * Initialize the network interface monitoring list.
70 static CAResult_t CAIPInitializeNetworkMonitorList();
73 * Destroy the network interface monitoring list.
75 static void CAIPDestroyNetworkMonitorList();
78 * Compare the interface with the already added interface in list.
80 static bool CACmpNetworkList(uint32_t ifiindex);
83 * Add new network interface in list.
85 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
88 * Remove network interace from list.
90 static void CARemoveNetworkMonitorList(int ifiindex);
93 * Pass the changed network status through the stored callback.
95 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
98 * Create new interface item.
100 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
101 const char *addr, int flags);
103 static CAResult_t CAIPInitializeNetworkMonitorList()
105 if (!g_networkMonitorContextMutex)
107 g_networkMonitorContextMutex = oc_mutex_new();
108 if (!g_networkMonitorContextMutex)
110 OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
111 return CA_STATUS_FAILED;
115 if (!g_netInterfaceList)
117 g_netInterfaceList = u_arraylist_create();
118 if (!g_netInterfaceList)
120 OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
121 CAIPDestroyNetworkMonitorList();
122 return CA_STATUS_FAILED;
128 static void CAIPDestroyNetworkMonitorList()
130 if (g_netInterfaceList)
132 u_arraylist_destroy(g_netInterfaceList);
133 g_netInterfaceList = NULL;
136 if (g_networkMonitorContextMutex)
138 oc_mutex_free(g_networkMonitorContextMutex);
139 g_networkMonitorContextMutex = NULL;
143 static bool CACmpNetworkList(uint32_t ifiindex)
145 if (!g_netInterfaceList)
147 OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
151 oc_mutex_lock(g_networkMonitorContextMutex);
153 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
154 for (uint32_t list_index = 0; list_index < list_length; list_index++)
156 CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
158 if (currItem->index == ifiindex)
160 oc_mutex_unlock(g_networkMonitorContextMutex);
164 oc_mutex_unlock(g_networkMonitorContextMutex);
168 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
170 VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
171 VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
173 oc_mutex_lock(g_networkMonitorContextMutex);
174 bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
177 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
178 oc_mutex_unlock(g_networkMonitorContextMutex);
179 return CA_STATUS_FAILED;
181 oc_mutex_unlock(g_networkMonitorContextMutex);
185 static void CARemoveNetworkMonitorList(int ifiindex)
187 VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
189 oc_mutex_lock(g_networkMonitorContextMutex);
191 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
192 for (uint32_t list_index = 0; list_index < list_length; list_index++)
194 CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
195 g_netInterfaceList, list_index);
196 if (removedifitem && ((int)removedifitem->index) == ifiindex)
198 if (u_arraylist_remove(g_netInterfaceList, list_index))
200 OICFree(removedifitem);
201 oc_mutex_unlock(g_networkMonitorContextMutex);
207 oc_mutex_unlock(g_networkMonitorContextMutex);
211 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
212 CATransportAdapter_t adapter)
214 CAResult_t res = CAIPInitializeNetworkMonitorList();
215 if (CA_STATUS_OK == res)
217 return CAIPSetNetworkMonitorCallback(callback, adapter);
222 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
224 CAIPDestroyNetworkMonitorList();
225 return CAIPUnSetNetworkMonitorCallback(adapter);
228 int CAGetPollingInterval(int interval)
233 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
235 CAIPCBData_t *cbitem = NULL;
236 LL_FOREACH(g_adapterCallbackList, cbitem)
238 if (cbitem && cbitem->adapter)
240 cbitem->callback(cbitem->adapter, status);
241 CALogAdapterStateInfo(cbitem->adapter, status);
246 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
247 CATransportAdapter_t adapter)
251 OIC_LOG(ERROR, TAG, "callback is null");
252 return CA_STATUS_INVALID_PARAM;
255 CAIPCBData_t *cbitem = NULL;
256 LL_FOREACH(g_adapterCallbackList, cbitem)
258 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
260 OIC_LOG(DEBUG, TAG, "this callback is already added");
265 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
268 OIC_LOG(ERROR, TAG, "Malloc failed");
269 return CA_STATUS_FAILED;
272 cbitem->adapter = adapter;
273 cbitem->callback = callback;
274 LL_APPEND(g_adapterCallbackList, cbitem);
279 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
281 CAIPCBData_t *cbitem = NULL;
282 CAIPCBData_t *tmpCbitem = NULL;
283 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
285 if (cbitem && adapter == cbitem->adapter)
287 OIC_LOG(DEBUG, TAG, "remove specific callback");
288 LL_DELETE(g_adapterCallbackList, cbitem);
296 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
297 const char *addr, int flags)
299 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
302 OIC_LOG(ERROR, TAG, "Malloc failed");
306 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
307 ifitem->index = index;
308 ifitem->family = family;
309 OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
310 ifitem->flags = flags;
315 u_arraylist_t *CAFindInterfaceChange()
317 u_arraylist_t *iflist = NULL;
319 char buf[4096] = { 0 };
320 struct nlmsghdr *nh = NULL;
321 struct sockaddr_nl sa = { .nl_family = 0 };
322 struct iovec iov = { .iov_base = buf,
323 .iov_len = sizeof (buf) };
324 struct msghdr msg = { .msg_name = (void *)&sa,
325 .msg_namelen = sizeof (sa),
329 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
331 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
333 if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
338 if (RTM_DELADDR == nh->nlmsg_type)
340 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
341 int ifiIndex = ifa->ifa_index;
342 bool isFound = CACmpNetworkList(ifiIndex);
345 CARemoveNetworkMonitorList(ifiIndex);
346 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
351 // Netlink message type is RTM_NEWADDR.
352 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
353 int ifiIndex = ifa->ifa_index;
355 iflist = CAIPGetInterfaceInformation(ifiIndex);
358 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
366 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
368 if (desiredIndex < 0)
370 OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
374 u_arraylist_t *iflist = u_arraylist_create();
377 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
381 struct ifaddrs *ifp = NULL;
382 if (-1 == getifaddrs(&ifp))
384 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
385 u_arraylist_destroy(iflist);
389 struct ifaddrs *ifa = NULL;
390 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
396 int family = ifa->ifa_addr->sa_family;
397 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
402 int ifindex = if_nametoindex(ifa->ifa_name);
403 if (desiredIndex && (ifindex != desiredIndex))
408 int length = u_arraylist_length(iflist);
410 for (int i = length-1; i >= 0; i--)
412 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
415 && (int)ifitem->index == ifindex
416 && ifitem->family == (uint16_t)family)
427 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
430 OIC_LOG(ERROR, TAG, "Malloc failed");
434 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
435 ifitem->index = ifindex;
436 ifitem->family = family;
437 ifitem->flags = ifa->ifa_flags;
439 if (ifitem->family == AF_INET6)
441 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
442 inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
443 sizeof(ifitem->addr));
445 else if (ifitem->family == AF_INET)
447 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
448 inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
449 sizeof(ifitem->addr));
452 bool result = u_arraylist_add(iflist, ifitem);
455 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
459 bool isFound = CACmpNetworkList(ifitem->index);
462 CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
463 ifitem->addr, ifitem->flags);
464 CAResult_t ret = CAAddNetworkMonitorList(newifitem);
465 if (CA_STATUS_OK != ret)
470 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
471 OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
483 u_arraylist_destroy(iflist);