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 <sys/types.h>
24 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
32 #include <arpa/inet.h>
33 #include <netinet/in.h>
34 #include <net_connection.h>
36 #include "caipinterface.h"
37 #include "caipnwmonitor.h"
38 #include "caadapterutils.h"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
42 #include <coap/utlist.h>
44 #define TAG "OIC_CA_IP_MONITOR"
45 #define MAX_INTERFACE_INFO_LENGTH (1024)
46 #define NETLINK_MESSAGE_LENGTH (4096)
47 #define IFC_LABEL_LOOP "lo"
48 #define IFC_ADDR_LOOP_IPV4 "127.0.0.1"
49 #define IFC_ADDR_LOOP_IPV6 "::1"
52 * Used to storing a connection handle for managing data connections.
54 static connection_h connection = NULL;
57 * Used to storing adapter changes callback interface.
59 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
62 * Create new interface item.
64 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
65 const char *addr, int flags);
68 * Add new network interface in list.
70 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
71 char *name, int family, const char *addr, int flags);
74 * Pass the changed network status through the stored callback.
76 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
79 * Callback function to received connection state changes.
81 static void CAIPConnectionStateChangedCb(connection_type_e type, void* userData);
83 int CAGetPollingInterval(int interval)
88 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
90 CAIPCBData_t *cbitem = NULL;
91 LL_FOREACH(g_adapterCallbackList, cbitem)
93 if (cbitem && cbitem->adapter)
95 cbitem->callback(cbitem->adapter, status);
100 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
101 CATransportAdapter_t adapter)
105 OIC_LOG(ERROR, TAG, "callback is null");
106 return CA_STATUS_INVALID_PARAM;
109 CAIPCBData_t *cbitem = NULL;
110 LL_FOREACH(g_adapterCallbackList, cbitem)
112 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
114 OIC_LOG(DEBUG, TAG, "this callback is already added");
119 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
122 OIC_LOG(ERROR, TAG, "Malloc failed");
123 return CA_STATUS_FAILED;
126 cbitem->adapter = adapter;
127 cbitem->callback = callback;
128 LL_APPEND(g_adapterCallbackList, cbitem);
133 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
135 CAIPCBData_t *cbitem = NULL;
136 CAIPCBData_t *tmpCbitem = NULL;
137 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
139 if (cbitem && adapter == cbitem->adapter)
141 OIC_LOG(DEBUG, TAG, "remove specific callback");
142 LL_DELETE(g_adapterCallbackList, cbitem);
150 u_arraylist_t *CAFindInterfaceChange()
152 u_arraylist_t *iflist = NULL;
153 char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
154 struct sockaddr_nl sa = { 0 };
155 struct iovec iov = { .iov_base = buf,
156 .iov_len = sizeof (buf) };
157 struct msghdr msg = { .msg_name = (void *)&sa,
158 .msg_namelen = sizeof (sa),
162 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
164 for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
166 if (nh != NULL && (nh->nlmsg_type != RTM_DELADDR && nh->nlmsg_type != RTM_NEWADDR))
171 struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
177 if (RTM_DELADDR == nh->nlmsg_type)
179 CloseMulticastSocket();
182 int ifiIndex = ifi->ifi_index;
183 iflist = CAIPGetInterfaceInformation(ifiIndex);
186 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
189 CreateMulticastSocket();
194 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
195 CATransportAdapter_t adapter)
197 if (!g_adapterCallbackList)
199 // Initialize Connections.
200 connection_error_e ret = connection_create(&connection);
201 if (CONNECTION_ERROR_NONE != ret)
203 OIC_LOG(ERROR, TAG, "connection_create failed");
204 return CA_STATUS_FAILED;
207 // Set callback for receiving state changes.
208 ret = connection_set_type_changed_cb(connection, CAIPConnectionStateChangedCb, NULL);
209 if (CONNECTION_ERROR_NONE != ret)
211 OIC_LOG(ERROR, TAG, "connection_set_type_changed_cb failed");
212 return CA_STATUS_FAILED;
216 OIC_LOG(DEBUG, TAG, "Initialize network monitoring successfully");
217 return CAIPSetNetworkMonitorCallback(callback, adapter);
220 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
222 OIC_LOG(DEBUG, TAG, "IN");
224 CAIPUnSetNetworkMonitorCallback(adapter);
225 if (!g_adapterCallbackList)
227 // Reset callback for receiving state changes.
230 connection_error_e ret = connection_unset_type_changed_cb(connection);
231 if (CONNECTION_ERROR_NONE != ret)
233 OIC_LOG(ERROR, TAG, "connection_unset_type_changed_cb failed");
236 // Deinitialize Wifi service.
237 ret = connection_destroy(connection);
238 if (CONNECTION_ERROR_NONE != ret)
240 OIC_LOG(ERROR, TAG, "connection_destroy failed");
246 OIC_LOG(DEBUG, TAG, "Network monitoring terminated successfully");
251 * Used to send netlink query to kernel and recv response from kernel.
253 * @param[in] idx desired network interface index, 0 means all interfaces.
254 * @param[out] iflist linked list.
257 static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
259 if ((idx < 0) || (iflist == NULL))
264 struct ifaddrs *ifp = NULL;
265 if (-1 == getifaddrs(&ifp))
267 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
271 struct ifaddrs *ifa = NULL;
272 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
279 int family = ifa->ifa_addr->sa_family;
280 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
285 int ifindex = if_nametoindex(ifa->ifa_name);
286 if (idx && (ifindex != idx))
291 char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
292 if (family == AF_INET6)
294 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
295 inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
297 else if (family == AF_INET)
299 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
300 inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
303 if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
304 (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
305 (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
307 OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
311 CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
312 ifa->ifa_name, family,
313 ipaddr, ifa->ifa_flags);
314 if (CA_STATUS_OK != result)
316 OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
328 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
330 u_arraylist_t *iflist = u_arraylist_create();
333 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
337 if (!CAIPGetAddrInfo(desiredIndex, iflist))
345 u_arraylist_destroy(iflist);
349 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
350 char *name, int family, const char *addr, int flags)
352 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
355 return CA_STATUS_FAILED;
357 bool result = u_arraylist_add(iflist, ifitem);
360 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
362 return CA_STATUS_FAILED;
368 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
369 const char *addr, int flags)
371 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
374 OIC_LOG(ERROR, TAG, "Malloc failed");
378 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
379 ifitem->index = index;
380 ifitem->family = family;
381 OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
382 ifitem->flags = flags;
387 void CAIPConnectionStateChangedCb(connection_type_e type, void* userData)
391 case CONNECTION_TYPE_DISCONNECTED:
392 OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_DISCONNECTED");
393 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
395 case CONNECTION_TYPE_ETHERNET:
396 OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_ETHERNET");
397 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
399 case CONNECTION_TYPE_WIFI:
400 OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_WIFI");
401 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
403 case CONNECTION_TYPE_CELLULAR:
404 OIC_LOG(DEBUG, TAG, "Connection is in CONNECTION_TYPE_CELLULAR");
405 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);