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"
47 #define MAX_INTERFACE_INFO_LENGTH (1024)
49 #define NETLINK_MESSAGE_LENGTH (4096)
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 * Used to passing the network status changes to adapter.
76 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
79 * Callback function to received connection state changes.
81 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
85 * Callback function to received device state changes.
87 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
90 int CAGetPollingInterval(int interval)
95 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
97 CAIPCBData_t *cbitem = NULL;
98 LL_FOREACH(g_adapterCallbackList, cbitem)
100 if (cbitem && cbitem->adapter)
102 cbitem->callback(cbitem->adapter, status);
107 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
108 CATransportAdapter_t adapter)
112 OIC_LOG(ERROR, TAG, "callback is null");
113 return CA_STATUS_INVALID_PARAM;
116 CAIPCBData_t *cbitem = NULL;
117 LL_FOREACH(g_adapterCallbackList, cbitem)
119 if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
121 OIC_LOG(DEBUG, TAG, "this callback is already added");
126 cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
129 OIC_LOG(ERROR, TAG, "Malloc failed");
130 return CA_STATUS_FAILED;
133 cbitem->adapter = adapter;
134 cbitem->callback = callback;
135 LL_APPEND(g_adapterCallbackList, cbitem);
140 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
142 CAIPCBData_t *cbitem = NULL;
143 CAIPCBData_t *tmpCbitem = NULL;
144 LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
146 if (cbitem && adapter == cbitem->adapter)
148 OIC_LOG(DEBUG, TAG, "remove specific callback");
149 LL_DELETE(g_adapterCallbackList, cbitem);
157 u_arraylist_t *CAFindInterfaceChange()
159 u_arraylist_t *iflist = NULL;
160 char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
161 struct sockaddr_nl sa = { 0 };
162 struct iovec iov = { .iov_base = buf,
163 .iov_len = sizeof (buf) };
164 struct msghdr msg = { .msg_name = (void *)&sa,
165 .msg_namelen = sizeof (sa),
169 size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
171 for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
173 if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
178 struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
180 if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
185 int ifiIndex = ifi->ifi_index;
186 iflist = CAIPGetInterfaceInformation(ifiIndex);
190 OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
197 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
198 CATransportAdapter_t adapter)
200 OIC_LOG(DEBUG, TAG, "IN");
202 if (!g_adapterCallbackList)
204 // Initialize Wifi service
205 wifi_error_e ret = wifi_initialize();
206 if (WIFI_ERROR_NONE != ret)
208 OIC_LOG(ERROR, TAG, "wifi_initialize failed");
209 return CA_STATUS_FAILED;
212 // Set callback for receiving state changes
213 ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
214 if (WIFI_ERROR_NONE != ret)
216 OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
217 return CA_STATUS_FAILED;
220 // Set callback for receiving connection state changes
221 ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
222 if (WIFI_ERROR_NONE != ret)
224 OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
225 return CA_STATUS_FAILED;
229 return CAIPSetNetworkMonitorCallback(callback, adapter);
232 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
234 OIC_LOG(DEBUG, TAG, "IN");
236 CAIPUnSetNetworkMonitorCallback(adapter);
237 if (!g_adapterCallbackList)
239 // Reset callback for receiving state changes
240 wifi_error_e ret = wifi_unset_device_state_changed_cb();
241 if (WIFI_ERROR_NONE != ret)
243 OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
246 // Reset callback for receiving connection state changes
247 ret = wifi_unset_connection_state_changed_cb();
248 if (WIFI_ERROR_NONE != ret)
250 OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
253 // Deinitialize Wifi service
254 ret = wifi_deinitialize();
255 if (WIFI_ERROR_NONE != ret)
257 OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
264 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
266 u_arraylist_t *iflist = u_arraylist_create();
269 OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
273 char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
274 struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
276 int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
277 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
279 OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
280 u_arraylist_destroy(iflist);
284 struct ifreq* ifr = ifc.ifc_req;
285 size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
286 size_t ifreqsize = ifc.ifc_len;
288 if (ifreqsize > caglobals.ip.nm.sizeIfItems)
290 CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
293 OIC_LOG(ERROR, TAG, "OICRealloc failed");
296 caglobals.ip.nm.ifItems = items;
297 caglobals.ip.nm.sizeIfItems = ifreqsize;
300 caglobals.ip.nm.numIfItems = 0;
301 for (size_t i = 0; i < interfaces; i++)
303 struct ifreq* item = &ifr[i];
304 char *name = item->ifr_name;
306 if (ioctl(s, SIOCGIFFLAGS, item) < 0)
308 OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
311 int16_t flags = item->ifr_flags;
312 if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
316 if (ioctl(s, SIOCGIFINDEX, item) < 0)
318 OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
322 int ifindex = item->ifr_ifindex;
323 caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
324 caglobals.ip.nm.numIfItems++;
326 if (desiredIndex && (ifindex != desiredIndex))
331 // Get address of network interface.
332 char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
333 struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
334 inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
336 // Add IPv4 interface
337 CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, addr, flags);
338 if (CA_STATUS_OK != result)
343 // Add IPv6 interface
344 result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, addr, flags);
345 if (CA_STATUS_OK != result)
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");