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"
23 #include <sys/types.h>
26 #include <sys/socket.h>
31 #include <sys/ioctl.h>
33 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
38 #include "caipnwmonitor.h"
39 #include "caadapterutils.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include <coap/utlist.h>
45 #define TAG "IP_MONITOR"
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 adapter changes callback interface.
54 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
57 * Create new interface item.
59 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
60 const char *addr, int flags);
63 * Add new network interface in list.
65 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
66 char *name, int family, const char *addr, int flags);
69 * Pass the changed network status through the stored callback.
71 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
74 * Callback function to received connection state changes.
76 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
80 * Callback function to received device state changes.
82 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
84 int CAGetPollingInterval(int interval)
89 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
91 CAIPCBData_t *cbitem = NULL;
92 LL_FOREACH(g_adapterCallbackList, cbitem)
94 if (cbitem && cbitem->adapter)
96 cbitem->callback(cbitem->adapter, status);
101 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
102 CATransportAdapter_t adapter)
106 OIC_LOG(ERROR, TAG, "callback is null");
107 return CA_STATUS_INVALID_PARAM;
110 CAIPCBData_t *cbitem = NULL;
111 LL_FOREACH(g_adapterCallbackList, cbitem)
113 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
115 OIC_LOG(DEBUG, TAG, "this callback is already added");
120 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
123 OIC_LOG(ERROR, TAG, "Malloc failed");
124 return CA_STATUS_FAILED;
127 cbitem->adapter = adapter;
128 cbitem->callback = callback;
129 LL_APPEND(g_adapterCallbackList, cbitem);
134 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
136 CAIPCBData_t *cbitem = NULL;
137 CAIPCBData_t *tmpCbitem = NULL;
138 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
140 if (cbitem && adapter == cbitem->adapter)
142 OIC_LOG(DEBUG, TAG, "remove specific callback");
143 LL_DELETE(g_adapterCallbackList, cbitem);
151 u_arraylist_t *CAFindInterfaceChange()
153 u_arraylist_t *iflist = NULL;
154 char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
155 struct sockaddr_nl sa = { 0 };
156 struct iovec iov = { .iov_base = buf,
157 .iov_len = sizeof (buf) };
158 struct msghdr msg = { .msg_name = (void *)&sa,
159 .msg_namelen = sizeof (sa),
163 ssize_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
165 for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
167 if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
171 struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
173 if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
178 int ifiIndex = ifi->ifi_index;
180 iflist = CAIPGetInterfaceInformation(ifiIndex);
184 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
191 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
192 CATransportAdapter_t adapter)
194 OIC_LOG(DEBUG, TAG, "IN");
196 if (!g_adapterCallbackList)
198 // Initialize Wifi service
199 wifi_error_e ret = wifi_initialize();
200 if (WIFI_ERROR_NONE != ret)
202 OIC_LOG(ERROR, TAG, "wifi_initialize failed");
203 return CA_STATUS_FAILED;
206 // Set callback for receiving state changes
207 ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
208 if (WIFI_ERROR_NONE != ret)
210 OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
211 return CA_STATUS_FAILED;
214 // Set callback for receiving connection state changes
215 ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
216 if (WIFI_ERROR_NONE != ret)
218 OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
219 return CA_STATUS_FAILED;
223 return CAIPSetNetworkMonitorCallback(callback, adapter);
226 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
228 OIC_LOG(DEBUG, TAG, "IN");
230 CAIPUnSetNetworkMonitorCallback(adapter);
231 if (!g_adapterCallbackList)
233 // Reset callback for receiving state changes
234 wifi_error_e ret = wifi_unset_device_state_changed_cb();
235 if (WIFI_ERROR_NONE != ret)
237 OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
240 // Reset callback for receiving connection state changes
241 ret = wifi_unset_connection_state_changed_cb();
242 if (WIFI_ERROR_NONE != ret)
244 OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
247 // Deinitialize Wifi service
248 ret = wifi_deinitialize();
249 if (WIFI_ERROR_NONE != ret)
251 OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
259 * Used to send netlink query to kernel and recv response from kernel.
261 * @param[in] idx desired network interface index, 0 means all interfaces.
262 * @param[out] iflist linked list.
265 static bool CAIPGetAddrInfo(int idx, u_arraylist_t *iflist)
267 if ((idx < 0) || (iflist == NULL))
272 struct ifaddrs *ifp = NULL;
273 if (-1 == getifaddrs(&ifp))
275 OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno));
279 struct ifaddrs *ifa = NULL;
280 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
287 int family = ifa->ifa_addr->sa_family;
288 if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family))
293 int ifindex = if_nametoindex(ifa->ifa_name);
294 if (idx && (ifindex != idx))
299 char ipaddr[MAX_ADDR_STR_SIZE_CA] = {0};
300 if (family == AF_INET6)
302 struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa->ifa_addr;
303 inet_ntop(family, (void *)&(in6->sin6_addr), ipaddr, sizeof(ipaddr));
305 else if (family == AF_INET)
307 struct sockaddr_in *in = (struct sockaddr_in*) ifa->ifa_addr;
308 inet_ntop(family, (void *)&(in->sin_addr), ipaddr, sizeof(ipaddr));
311 if ((strcmp(ipaddr, IFC_ADDR_LOOP_IPV4) == 0) ||
312 (strcmp(ipaddr, IFC_ADDR_LOOP_IPV6) == 0) ||
313 (strcmp(ifa->ifa_name, IFC_LABEL_LOOP) == 0))
315 OIC_LOG(DEBUG, TAG, "LOOPBACK continue!!!");
319 CAResult_t result = CAAddInterfaceItem(iflist, ifindex,
320 ifa->ifa_name, family,
321 ipaddr, ifa->ifa_flags);
322 if (CA_STATUS_OK != result)
324 OIC_LOG(ERROR, TAG, "CAAddInterfaceItem fail");
336 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
338 u_arraylist_t *iflist = u_arraylist_create();
341 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
345 if (!CAIPGetAddrInfo(desiredIndex, iflist))
353 u_arraylist_destroy(iflist);
357 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
358 char *name, int family, const char *addr, int flags)
360 CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
363 return CA_STATUS_FAILED;
365 bool result = u_arraylist_add(iflist, ifitem);
368 OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
370 return CA_STATUS_FAILED;
376 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
377 const char *addr, int flags)
379 CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
382 OIC_LOG(ERROR, TAG, "Malloc failed");
386 OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
387 ifitem->index = index;
388 ifitem->family = family;
389 OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
390 ifitem->flags = flags;
395 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
398 OIC_LOG(DEBUG, TAG, "IN");
400 if (WIFI_CONNECTION_STATE_ASSOCIATION == state
401 || WIFI_CONNECTION_STATE_CONFIGURATION == state)
403 OIC_LOG(DEBUG, TAG, "Connection is in Association State");
407 if (WIFI_CONNECTION_STATE_CONNECTED == state)
409 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
413 CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
416 OIC_LOG(DEBUG, TAG, "OUT");
419 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
421 OIC_LOG(DEBUG, TAG, "IN");
423 if (WIFI_DEVICE_STATE_ACTIVATED == state)
425 OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
429 CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
430 OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
433 OIC_LOG(DEBUG, TAG, "OUT");