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 "caipnwmonitor_common.h"
45 #include "caadapterutils.h"
47 #include "oic_malloc.h"
48 #include "oic_string.h"
49 #include <coap/utlist.h>
51 #define TAG "OIC_CA_IP_MONITOR"
54 * Mutex for synchronizing access to cached interface and IP address information.
56 static oc_mutex g_networkMonitorContextMutex = NULL;
59 * Used to storing network interface.
61 static u_arraylist_t *g_netInterfaceList = NULL;
64 * Used to storing adapter changes callback interface.
66 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
69 * Initialize the network interface monitoring list.
71 static CAResult_t CAIPInitializeNetworkMonitorList();
74 * Destroy the network interface monitoring list.
76 static void CAIPDestroyNetworkMonitorList();
79 * Compare the interface with the already added interface in list.
81 static bool CACmpNetworkList(uint32_t ifiindex);
84 * Add new network interface in list.
86 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem);
89 * Remove network interace from list.
91 static void CARemoveNetworkMonitorList(int ifiindex);
94 * Pass the changed network status through the stored callback.
96 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
99 * Create new interface item.
101 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
102 const char *addr, int flags);
104 static CAResult_t CAIPInitializeNetworkMonitorList()
106 if (!g_networkMonitorContextMutex)
108 g_networkMonitorContextMutex = oc_mutex_new();
109 if (!g_networkMonitorContextMutex)
111 OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
112 return CA_STATUS_FAILED;
116 if (!g_netInterfaceList)
118 g_netInterfaceList = u_arraylist_create();
119 if (!g_netInterfaceList)
121 OIC_LOG(ERROR, TAG, "u_arraylist_create has failed");
122 CAIPDestroyNetworkMonitorList();
123 return CA_STATUS_FAILED;
129 static void CAIPDestroyNetworkMonitorList()
131 if (g_netInterfaceList)
133 u_arraylist_destroy(g_netInterfaceList);
134 g_netInterfaceList = NULL;
137 if (g_networkMonitorContextMutex)
139 oc_mutex_free(g_networkMonitorContextMutex);
140 g_networkMonitorContextMutex = NULL;
144 static bool CACmpNetworkList(uint32_t ifiindex)
146 if (!g_netInterfaceList)
148 OIC_LOG(ERROR, TAG, "g_netInterfaceList is NULL");
152 oc_mutex_lock(g_networkMonitorContextMutex);
154 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
155 for (uint32_t list_index = 0; list_index < list_length; list_index++)
157 CAInterface_t *currItem = (CAInterface_t *) u_arraylist_get(g_netInterfaceList,
159 if (currItem->index == ifiindex)
161 oc_mutex_unlock(g_networkMonitorContextMutex);
165 oc_mutex_unlock(g_networkMonitorContextMutex);
169 static CAResult_t CAAddNetworkMonitorList(CAInterface_t *ifitem)
171 VERIFY_NON_NULL(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
172 VERIFY_NON_NULL(ifitem, TAG, "ifitem is NULL");
174 oc_mutex_lock(g_networkMonitorContextMutex);
175 bool result = u_arraylist_add(g_netInterfaceList, (void *) ifitem);
178 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
179 oc_mutex_unlock(g_networkMonitorContextMutex);
180 return CA_STATUS_FAILED;
182 oc_mutex_unlock(g_networkMonitorContextMutex);
186 static void CARemoveNetworkMonitorList(int ifiindex)
188 VERIFY_NON_NULL_VOID(g_netInterfaceList, TAG, "g_netInterfaceList is NULL");
190 oc_mutex_lock(g_networkMonitorContextMutex);
192 uint32_t list_length = u_arraylist_length(g_netInterfaceList);
193 for (uint32_t list_index = 0; list_index < list_length; list_index++)
195 CAInterface_t *removedifitem = (CAInterface_t *) u_arraylist_get(
196 g_netInterfaceList, list_index);
197 if (removedifitem && ((int)removedifitem->index) == ifiindex)
199 if (u_arraylist_remove(g_netInterfaceList, list_index))
201 OICFree(removedifitem);
202 oc_mutex_unlock(g_networkMonitorContextMutex);
208 oc_mutex_unlock(g_networkMonitorContextMutex);
212 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
213 CATransportAdapter_t adapter)
215 CAResult_t res = CAIPInitializeNetworkMonitorList();
216 if (CA_STATUS_OK == res)
218 return CAIPSetNetworkMonitorCallback(callback, adapter);
223 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
225 CAIPDestroyNetworkMonitorList();
226 return CAIPUnSetNetworkMonitorCallback(adapter);
229 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
231 CAIPPassNetworkChangesToAdapterInternal(status, g_adapterCallbackList, CA_IP_NW_COMMON_LINUX);
234 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
235 CATransportAdapter_t adapter)
237 return CAIPSetNetworkMonitorCallbackInternal(callback, adapter, g_adapterCallbackList);
240 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
242 return CAIPUnSetNetworkMonitorCallbackInternal(adapter, g_adapterCallbackList);
245 static CAInterface_t *CANewInterfaceItem(int index, const char *name, int family,
246 const char *addr, int flags)
248 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
251 OIC_LOG(ERROR, TAG, "Malloc failed");
255 OICStrcpy(ifitem->name, sizeof (ifitem->name), name);
256 ifitem->index = index;
257 ifitem->family = family;
258 OICStrcpy(ifitem->addr, sizeof (ifitem->addr), addr);
259 ifitem->flags = flags;
264 u_arraylist_t *CAFindInterfaceChange()
266 u_arraylist_t *iflist = NULL;
268 char buf[4096] = { 0 };
269 struct nlmsghdr *nh = NULL;
270 struct sockaddr_nl sa = { .nl_family = 0 };
271 struct iovec iov = { .iov_base = buf,
272 .iov_len = sizeof (buf) };
273 struct msghdr msg = { .msg_name = (void *)&sa,
274 .msg_namelen = sizeof (sa),
278 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
280 for (nh = (struct nlmsghdr *)buf; nh != NULL && NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
282 if (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR)
287 if (RTM_DELADDR == nh->nlmsg_type)
289 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
290 int ifiIndex = ifa->ifa_index;
291 bool isFound = CACmpNetworkList(ifiIndex);
294 CARemoveNetworkMonitorList(ifiIndex);
295 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
300 // Netlink message type is RTM_NEWADDR.
301 struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nh);
302 int ifiIndex = ifa->ifa_index;
304 iflist = CAIPGetInterfaceInformation(ifiIndex);
307 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
315 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
317 if (desiredIndex < 0)
319 OIC_LOG_V(ERROR, TAG, "invalid index : %d", desiredIndex);
323 u_arraylist_t *iflist = u_arraylist_create();
326 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
330 struct ifaddrs *ifp = NULL;
331 if (-1 == getifaddrs(&ifp))
333 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
334 u_arraylist_destroy(iflist);
338 struct ifaddrs *ifa = NULL;
339 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
345 int family = ifa->ifa_addr->sa_family;
346 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
351 int ifindex = if_nametoindex(ifa->ifa_name);
352 if (desiredIndex && (ifindex != desiredIndex))
357 int length = u_arraylist_length(iflist);
359 for (int i = length-1; i >= 0; i--)
361 CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
364 && (int)ifitem->index == ifindex
365 && ifitem->family == (uint16_t)family)
376 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t));
379 OIC_LOG(ERROR, TAG, "Malloc failed");
383 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name);
384 ifitem->index = ifindex;
385 ifitem->family = family;
386 ifitem->flags = ifa->ifa_flags;
388 if (ifitem->family == AF_INET6)
390 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
391 inet_ntop(ifitem->family, (void *)&(in6->sin6_addr), ifitem->addr,
392 sizeof(ifitem->addr));
394 else if (ifitem->family == AF_INET)
396 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
397 inet_ntop(ifitem->family, (void *)&(in->sin_addr), ifitem->addr,
398 sizeof(ifitem->addr));
401 bool result = u_arraylist_add(iflist, ifitem);
404 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
408 bool isFound = CACmpNetworkList(ifitem->index);
411 CAInterface_t *newifitem = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
412 ifitem->addr, ifitem->flags);
413 CAResult_t ret = CAAddNetworkMonitorList(newifitem);
414 if (CA_STATUS_OK != ret)
419 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
420 OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family);
432 u_arraylist_destroy(iflist);